Spring基础一 过滤器、拦截器、切面
演示基于 spring boot 1.5.6、 springframework 4.3.10。
1.过滤器
简介:
首先,过滤器是服务端的一个组件,是基于servlet实现从客户端访问服务端web资源的一种拦截机制,对请求request和响应response都进行过滤,依赖于serverlet容器,使用时,实现Filter接口:
例子一: 使用自己定义的过滤器:
1 @Component //注册为spring 组件 2 public class TimeFiler implements Filter { 3 4 5 @Override //过滤器初始化事件, 在项目启动的时候执行 6 public void init(FilterConfig filterConfig) throws ServletException { 7 System.out.println("初始化过滤器哦"); 8 } 9 10 @Override 11 public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { 12 System.out.println("过滤器开始执行"); 13 long start=new Date().getTime(); 14 filterChain.doFilter(servletRequest,servletResponse); 15 long end= new Date().getTime(); 16 System.out.println("请求耗时:"+(end-start)); 17 } 18 19 @Override 20 public void destroy() { 21 22 } 23 }
@Configuration public class WebConfig extends WebMvcConfigurerAdapter { // @Bean public FilterRegistrationBean timeFilter() { FilterRegistrationBean registrationBean = new FilterRegistrationBean(); TimeFilter timeFilter = new TimeFilter(); registrationBean.setFilter(timeFilter); List<String> urls = new ArrayList<>(); urls.add("/*"); registrationBean.setUrlPatterns(urls); return registrationBean; } }
解释:
1. init方法是过滤器的初始化方法,当web容器创建这个bean的时候就会执行,这个方法可以读取web.xml里面的参数
2.doFilter方法是执行过滤的请求的核心,当客户端请求访问web资源时,这个时候我们可以拿到request里面的参数,对数据进行处理后,通过filterChain方法将请求将请求放行,放行后我们也可以通过response对响应进行处理(比如压缩响应),然后会传递到下一个过滤器
3.destory方法是当web容器中的过滤器实例被销毁时,会被执行,释放资源
2.拦截器
简介:
这个要和过滤器区分开,过滤器依赖serverlet容器,获取request和response处理,是基于函数回调,简单说就是“去取你想取的”,拦截器是通过java反射机制,动态代理来拦截web请求,是“拒你想拒绝的”,他只拦截web请求,但不拦截静态资源。
@Component public class TimeInterceptor implements HandlerInterceptor { /* (non-Javadoc) * @see org.springframework.web.servlet.HandlerInterceptor#preHandle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object) */ @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; } /* (non-Javadoc) * @see org.springframework.web.servlet.HandlerInterceptor#postHandle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object, org.springframework.web.servlet.ModelAndView) */ @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle"); Long start = (Long) request.getAttribute("startTime"); System.out.println("time interceptor 耗时:"+ (new Date().getTime() - start)); } /* (non-Javadoc) * @see org.springframework.web.servlet.HandlerInterceptor#afterCompletion(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object, java.lang.Exception) */ @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion"); Long start = (Long) request.getAttribute("startTime"); System.out.println("time interceptor 耗时:"+ (new Date().getTime() - start)); System.out.println("ex is "+ex); }
@Configuration public class WebConfig extends WebMvcConfigurerAdapter { @SuppressWarnings("unused") @Autowired private TimeInterceptor timeInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(timeInterceptor); } }
2.postHandler():在请求进入控制层之后调用,但是在处理请求抛出异常时不会调用
3.afterCompletion(): 在请求处理完成之后,也就是在DispatherServlet渲染了视图之后执行,也就是说这个方法必定是执行,包含异常信息,它的主要作用就是清理资源
3.切面
切片编程,在网上看到了一个很贴切的说法,面对的是处理过程中的方法或者阶段,以获得各部分的低耦合性的隔离效果,它是基于动态代理,它关注的是行为和过程
例子:
@Aspect @Component public class TimeAspect { @Around("execution(* com.kang.user.controller.UserController.*(..))") public Object handleTime(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{ System.out.println("切面-time aspect is start."); // 获取前端访问API的时候所携带的参数 for (Object object : proceedingJoinPoint.getArgs()) { System.out.println(object); } long startTime = System.currentTimeMillis(); // 继续执行被拦截的方法 Object obj = proceedingJoinPoint.proceed(); System.out.println("切面-time aspect 耗时:" + (System.currentTimeMillis() - startTime)); System.out.println("切面-time aspect finish."); return obj; } }
- @Aspect(声明一个切面)
- @Before(相当于拦截器preHandler,在方法执行前调用)
- @After(相当于拦截器的afterComplement()在方法执行后调用)
- @AfterThrowing(方法抛出异常时调用)
- @AfterReturning(当方法返回时调用)
- @Around(包含以上方的执行顺序)
总结:
执行的顺序为filter--》interceptor--》ControllerAdvice--》Aspect,然后到大控制层,如果控制层抛出异常,最先也会被Aspect捕获,如果未处理,会继续向上一层抛出,如果到Filter也没有处理的话,就会抛到容器内部
借鉴:

浙公网安备 33010602011771号