在使用Spring MVC開發TEST API的時候,咱們進場會使用Java的攔截機制來處理請求,Filter是Java自己自帶攔過濾器,Interceptor則是Spring自帶的攔截器,而Aspect是Spring AOP主要的使用場景有:日誌記錄、事務控制和異常處理,該篇文章主要說說它們是如何實現以及他們之間的差異。java
我對Filter過濾器作了如下總結:web
@Component public class TimeFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("初始化TimeFilter..."); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException { System.out.println("-------TimeFilter Start--------"); long start = new Date().getTime(); filterChain.doFilter(request, response); System.out.println("TimeFilter執行耗時:" + (new Date().getTime() - start)); System.out.println("-------TimeFilter End--------"); } @Override public void destroy() { System.out.println("銷燬TimeFilter..."); } }
注意:關於filterChain.doFilter(request,response,filterChain),執行filterChain.doFilter的意思是將請求轉發給過濾器臉上的下一個對象,若是沒有filter那就是你請求的資源。 通常filter都是一個鏈,web.xml 裏面配置了幾個就有幾個。一個一個的連在一塊兒 這裏指的是下一個Filter,request->filter1->filter2->filter3->...->response。app
咱們定義完Filter以後,若是咱們不使用@Component註解注入,可使用另外一種方式將Filter注入到咱們的容器中,這裏使用@Bean的形式定義,經過繼承WebMvcConfigurerAdapter抽象類來實現配置,最後返回registrationBean,這個方法主要有兩個好處就是第一咱們能夠經過 registrationBean.setUrlPatterns(urls) 來指明filter在哪些路徑下起做用,第二咱們可使用該方法區注入第三方的filter,緣由的不少地方放的filter並並非以@Component注入方式,這時候咱們就不能使用@Component第一種方式來注入了:ide
@Configuration public class WebConfig extends WebMvcConfigurerAdapter { @Autowired TimeInterceptor timeInterceptor; @Bean public FilterRegistrationBean charsetFilter(){ FilterRegistrationBean registrationBean = new FilterRegistrationBean(); TimeFilter timeFilter = new TimeFilter(); CharsetFilter charsetFilter = new CharsetFilter(); registrationBean.setFilter(charsetFilter); registrationBean.setFilter(timeFilter); //至關於@webFilter的@WebInitParam()註解的做用 Map<String,String> paramMap = new HashMap<>(); paramMap.put("charset","utf-8"); registrationBean.setInitParameters(paramMap); //至關於@webFilter的 urlPatterns = "/*"的做用 List<String> urls = new ArrayList<>(); urls.add("/*"); //urls.add("/user/*"); registrationBean.setUrlPatterns(urls); return registrationBean; }
咱們在controller中定義一個getInfo()方法:post
//請求路徑的{id}回傳到方法裏也就是傳到(@PathVariable String id)的id裏 @RequestMapping(value = "/user/{id:\\d+}",method = RequestMethod.GET) @JsonView(User.UserDetailView.class) //這裏由於UserDetailView繼承了UserSimpleView全部會返回username和password @ApiOperation("獲取用戶信息") public User getInfo(@PathVariable Integer id) { // throw new UserNotExistException(id); System.out.println("進入getInfo()服務"); User user = new User(); user.setId(1); user.setUsername("jacklin"); user.setPassword("123"); return user; }
當咱們調用controller中的getInfo()方法的時候,看看請求響應是否成以及控制檯的輸出:url
GET請求發送成功,返回200,控制檯輸出以下:spa
從上述結果,咱們能夠分析得出,當客戶端發送請求,到達Controller方法以前,先執行Filter初始化操做,接着進入Controller的方法體,最後執行完成,經過分析咱們明白了Filter的工做原理和方法的執行順序!3d
我對Interceptor過濾器作了如下總結(導圖中加粗部分是重點):日誌
** * @Author 林必昭 * @Date 2019/7/4 13:15 */ @Component public class TimeInterceptor implements HandlerInterceptor { /** * preHandle方法的返回值是boolean值,當返回的是false時候,不會進入controller裏的方法 */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("------->preHandle"); System.out.println(((HandlerMethod)handler).getBean().getClass().getName()); //獲取類名 System.out.println(((HandlerMethod)handler).getMethod().getName()); //獲取類中方法名 request.setAttribute("startTime",new Date().getTime()); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("------->postHandle"); long start = new Date().getTime(); System.out.println("TimeInterceptor執行耗時:"+" "+(new Date().getTime()-start)); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) throws Exception { System.out.println("------->afterCompletion"); long start = new Date().getTime(); System.out.println("TimeInterceptor執行耗時:"+" "+(new Date().getTime()-start)); System.out.println("Exception is "+ e); } }
一樣,咱們經過發送請求,觀察控制檯的輸出,來分析結果:code
從TimeInterceptor攔截器結果,咱們能夠分析得出,當客戶端發送請求,到達Controller方法以前,先執行Interceptor的preHandler方法,接着進入Controller的方法體,咱們能夠獲取到對應的Controller,接着執行postHandler方法,最後執行完成!
我對Aspect過濾器作了如下總結: