iT邦幫忙

DAY 24
0

無痛學習SpringMVC與Spring Security系列 第 24

[Interceptor]應用HandlerInterceptor於評估Controller的Performance

  • 分享至 

  • twitterImage
  •  

今天先插入一個小主題,個人覺得很實用,這支程式是在Spring MVC- A Beginner Guide中學到的,

Interceptor概念等同於filter,就是在Spring MVC處理Request與Response前與後作一些處理,在Spring MVC中提供HandlerInterceptor介面供開發者實作,必須Override preHandle方法(Spring MVC呼叫對應的Controller之前執行的方法)、postHandle(Controller處理完成一個Request後執行的發法)以及afterCompletion(一個Request/Response cycle後執行的方法)。

以今天的例子,我們的目的在於得到Controller處理一個Request所需的時間,Spring提供一個好用的計時物件StopWatch,要紀錄整個cycle,我們需要一個獨立的Thread來執行StopWatch,Java裡有一個ThreadLocal物件可以達到這個目的,整體來看,就是在呼叫Controller之前呼叫StopWatch的Start方法開始計時,整個Cycle完之後呼叫StopWatch的Stop方法,並呼叫getTotalTimeMillis方法即可得到整個cycle所需時間。

新增一個MonitorController實作HandlerInterceptor,其code如下:

public class MonitorInterceptor implements HandlerInterceptor {

	ThreadLocal<StopWatch> threadTimer=new ThreadLocal<>();
	//建立一個ThreadLocal物件,型別StopWatch可提供計時功能
	Logger logger=Logger.getLogger(this.getClass());
	
	private String getURLPath(HttpServletRequest request){
		String currentPath=request.getRequestURI(); 
		String queryString=request.getQueryString();
		queryString=queryString==null ? "" : "?"+queryString;
		return currentPath+queryString; //Request的完成Path
	}
	
	private String getCurrentTime(){
		DateFormat formatter=new SimpleDateFormat("MM/dd/yyyy 'at' hh:mm:ss");
		Calendar calendar=Calendar.getInstance();
		calendar.setTimeInMillis(System.currentTimeMillis());
		return formatter.format(calendar.getTime());
	}
	
	@Override
	public boolean preHandle(HttpServletRequest request,
			HttpServletResponse response, Object handler) throws Exception {
		// TODO Auto-generated method stub
		StopWatch stopWatch=new StopWatch(handler.toString()); 
		//New 一個StopWatch物件
		stopWatch.start(handler.toString());//開始計時
		threadTimer.set(stopWatch); //放入ThreadLocal由獨立的Thread計時
		
		//紀錄存取的網址
		logger.info("Accessing URL Path:"+ getURLPath(request));
		//紀錄呼叫Controller前的時間
		logger.info("Request processing started on:"+getCurrentTime());
		return true;
	}

	@Override
	public void postHandle(HttpServletRequest request,
			HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		// TODO Auto-generated method stub
		//紀錄Controller處理一個Request結束後的時間
		logger.info("Request processing ended on"+getCurrentTime());
	}

	@Override
	public void afterCompletion(HttpServletRequest request,
			HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		// TODO Auto-generated method stub
		StopWatch stopWatch=threadTimer.get(); //從ThreadLocal取得StopWatch物件
		stopWatch.stop(); //呼叫stop(),停止計數
		//呼叫StopWatch物件getTotalTimemillis方法,可得知處理一個Request,Controller花了多少時間
		logger.info("Total time taken for processing"+stopWatch.getTotalTimeMillis()+" ms");
		threadTimer.set(null); //清空ThreadLocal物件 ,以免與下次Request再設定同樣的StopWatch衝突
		logger.info("========================================");
	}
}

除了新增Class,同時需要在dispatchservletcontext.xml,宣告Interceptor並指定剛剛新增的class,其code如下:

<mvc:interceptors>
		<bean class="tw.blogger.springtech.springmvc.controller.interceptor.MonitorInterceptor" />
</mvc:interceptors>

另外要在Console輸出,在log4j.xml中加入MonitorInterceptor,code如下

<?xml version="1.0" encoding="UTF-8"?>

<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">

	<!-- Appenders -->
	<appender name="console" class="org.apache.log4j.ConsoleAppender">
		<param name="Target" value="System.out" />
		<layout class="org.apache.log4j.PatternLayout">
			<param name="ConversionPattern" value="%d{HH:mm:ss} [%t] %c{1} - %m%n" />
		</layout>
	</appender>
	
        ......

	<logger name="tw.blogger.springtech.springmvc.controller.interceptor">
		<level value="info" />
	</logger>
	
         .......

	<root>
		<priority value="warn" />
		<appender-ref ref="console" />
	</root>
	
</log4j:configuration>

啟動Server,首頁如下

Console顯示花了1ms

19:49:56 [http-nio-8080-exec-5] MonitorInterceptor - Request processing started on:10/23/2014 at 07:49:56
19:49:56 [http-nio-8080-exec-5] HttpSessionSecurityContextRepository - SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
19:49:56 [http-nio-8080-exec-5] MonitorInterceptor - Request processing ended on10/23/2014 at 07:49:56
19:49:56 [http-nio-8080-exec-5] DispatcherServlet - Null ModelAndView returned to DispatcherServlet with name 'dispatcher': assuming HandlerAdapter completed request handling
19:49:56 [http-nio-8080-exec-5] MonitorInterceptor - Total time taken for processing1 ms

要求輸出Excel畫面如下,

Console log顯示花了1226ms

19:52:42 [http-nio-8080-exec-7] MonitorInterceptor - Request processing ended on10/23/2014 at 07:52:42
19:52:42 [http-nio-8080-exec-7] ContentNegotiatingViewResolver - Requested media types are [application/vnd.ms-excel] based on Accept header types and producible media types [*/*])
19:52:42 [http-nio-8080-exec-7] ContentNegotiatingViewResolver - Returning [tw.blogger.springtech.springmvc.view.ExcelView: name 'excelView'] based on requested media type 'application/vnd.ms-excel'
19:52:42 [http-nio-8080-exec-7] DispatcherServlet - Rendering view [tw.blogger.springtech.springmvc.view.ExcelView: name 'excelView'] in DispatcherServlet with name 'dispatcher'
Hibernate: select dcn0_.prikey as prikey1_1_, dcn0_.category as category2_1_, dcn0_.completedDate as complete3_1_, dcn0_.issuedDate as issuedDa4_1_, dcn0_.no as no5_1_, dcn0_.rev as rev6_1_, dcn0_.trackNumber as trackNum7_1_ from DCN dcn0_
19:52:43 [http-nio-8080-exec-7] MonitorInterceptor - Total time taken for processing1226 ms
19:52:43 [http-nio-8080-exec-7] MonitorInterceptor - ========================================
19:52:43 [http-nio-8080-exec-7] DispatcherServlet - Successfully completed request
19:52:43 [http-nio-8080-exec-7] ExceptionTranslationFilter - Chain processed normally
19:52:43 [http-nio-8080-exec-7] SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed

明天繼續


上一篇
[Security] 自訂驗證(Customize Authentication)使用UserDetailsService(II)
下一篇
[Security]密碼加密及自訂存取被拒網頁(403)
系列文
無痛學習SpringMVC與Spring Security31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言