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);

    }
 
注册到spring 中
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
    
    @SuppressWarnings("unused")
    @Autowired
    private TimeInterceptor timeInterceptor;
    
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(timeInterceptor);
    }

}

 

1.preHandler(): 这个方法是在controller调用之前调用,通过返回true或者false决定是否进入Controller层

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也没有处理的话,就会抛到容器内部

 

借鉴:

https://zhuanlan.zhihu.com/p/73799649

posted @ 2020-04-05 15:31  康大头  阅读(173)  评论(0)    收藏  举报