在使用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过滤器作了如下总结: