AOP是一种编程思想。
过滤器(Filter)和***(interceptor)两者都具有AOP的切面思想
  • 使用范围不同:Filter是Servlet规范规定的,只能用于Web程序中,依赖于serverlet容器。而***既可以用于Web程序,也可以用于Application、Swing程序、javaEE,javaSE等各种环境中。
  • 规范不同: Filter是在Servlet规范中定义的,是Servlet容器支持的。而***和切面是在Spring容器内的,是Spring框架支持的。strust2也有实现自己的***。
  • 使用的资源不同:同其他的代码块一样,***也是一个Spring的组件,归Spring管理,配置在Spring文件中,因此能使用Spring里的任何资源、对象,例如Service对象、数据源、事务管理等,通过loC注入到***即可:而Filter则不能。
  • 深度不同:Filter在只在Servlet前后起作用。而***能够深入到方法前后、异常抛出前后等,因此***的使用具有更大的弹性。所以在Spring构架的程序中,要优先使用***。
  • 过滤器可以修改request,而***不能
  • ***可以调用IOC容器中的各种依赖,而过滤器不能。
  • 过滤器只能在请求的前后使用,而***可以详细到每个方法。
  • ***可以多次被调用,而过滤器只能在容器初始化时被调用一次。

获取资源差异

  • Filter 是 java web 里面的,肯定获取不到 spring 里面 Controller 的信息。
  • Interceptor、Aspect 是和 spring 相关的,所以能获取到 Controller 的信息。

过滤器(Filter)         :可以拿到原始的http请求,但是拿不到你请求的控制器和请求控制器中的方法的信息。

***(Interceptor):可以拿到你请求的控制器和方法,却拿不到请求方法的参数。

切片   (Aspect)       :  可以拿到方法的参数,但是却拿不到http请求和响应的对象

底层实现

***是基于Java的反射机制(动态代理)的,而过滤器是基于函数回调。
spring AOP前面章节有介绍到spring的AOP底层实现。

函数回调概括:将某个对象已经各种参数传给类似过滤器的类,当这个过滤器调用完自己的方法之后才再次调用这个对象的方法。

触发时机

当收到请求响应时,执行的顺序为filter--》interceptor--》ControllerAdvice--》Aspect,
然后到大控制层,如果控制层抛出异常,最先也会被Aspect捕获,如果未处理,会继续向上一层抛出,如果到Filter也没有处理的话,就会抛到容器内部

注:@ControllerAdvice:异常拦截机制注解


具体用法:

【以下只概括简单的用法,具体其他的用法网上查】

Filter过滤器:

FilterRegisteration配置,设置要过滤的URL, 定义过滤器后会重写三个方法,分别是init(),doFilter(),和destory(),

  • init方法是过滤器的初始化方法,当web容器创建这个bean的时候就会执行,这个方法可以读取web.xml里面的参数

  • doFilter方法是执行过滤的请求的核心,当客户端请求访问web资源时,这个时候我们可以拿到request里面的参数,对数据进行处理后,通过filterChain方法将请求将请求放行,放行后我们也可以通过response对响应进行处理(比如压缩响应),然后会传递到下一个过滤器
  • destory方法是当web容器中的过滤器实例被销毁时,会被执行,释放资源
@Configuration
public class WebConfig {
    @Bean
    public RemoteIpFilter remoteIpFilter() {
        return new RemoteIpFilter();
    }
    
    /**
     * 注册第三方过滤器
     * 功能与spring mvc中通过配置web.xml相同
     * 可以添加过滤器锁拦截的 URL,拦截更加精准灵活
     * @return
     */
    @Bean
    public FilterRegistrationBean testFilterRegistration() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new MyFilter());
        // 过滤应用程序中所有资源,当前应用程序根下的所有文件包括多级子目录下的所有文件,注意这里*前有“/”
        registration.addUrlPatterns("/*");
        registration.addInitParameter("paramName", "paramValue");
        registration.setName("MyFilter");
        // 过滤器顺序
        registration.setOrder(1);
        return registration;
    }

    // 定义过滤器
    public class MyFilter implements Filter {
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            System.out.println("init");
        }

        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            HttpServletRequest request = (HttpServletRequest) servletRequest;
            System.out.println("this is MyFilter,url :" + request.getRequestURI());
            filterChain.doFilter(servletRequest, servletResponse);
        }

        @Override
        public void destroy() {
            System.out.println("destroy");
        }
    }
}

interceptor***

***作用

有什么作用呢?AOP面向切面有什么作用,那么***就有什么作用。

  • 日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算PV...
  • 权限检查:认证或者授权等检查
  • 性能监控:通过***在进入处理器之前记录开始时间,处理完成后记录结束时间,得到请求处理时间。
  • 通用行为:读取cookie得到用户信息并将用户对象放入请求头中,从而方便后续流程使用。

***集成接口HandlerInterceptor,实现拦截,接口方法有下面三种:

  1. preHandler(HttpServletRequest request, HttpServletResponse response, Object handler) 方法将在请求处理之前进行调用。SpringMVC中的Interceptor同Filter一样都是链式调用。每个Interceptor的调用会依据它的声明顺序依次执行,而且最先执行的都是Interceptor中的preHandle方法,所以可以在这个方法中进行一些前置初始化操作或者是对当前请求的一个预处理,也可以在这个方法中进行一些判断来决定请求是否要继续进行下去。该方法的返回值是布尔值Boolean 类型的,当它返回为false时,表示请求结束,后续的Interceptor和Controller都不会再执行;当返回值为true时就会继续调用下一个Interceptor 的preHandle 方法,如果已经是最后一个Interceptor 的时候就会是调用当前请求的Controller 方法。
  2. postHandler(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) 在当前请求进行处理之后,也就是Controller 方法调用之后执行,但是它会在DispatcherServlet 进行视图返回渲染之前被调用,所以我们可以在这个方法中对Controller 处理之后的ModelAndView 对象进行操作。
  3. afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex) 该方法也是需要当前对应的Interceptor的preHandle方法的返回值为true时才会执行。顾名思义,该方法将在整个请求结束之后,也就是在DispatcherServlet 渲染了对应的视图之后执行。这个方法的主要作用是用于进行资源清理工作的。

总结一点就是:

preHandle是请求执行前执行,通过返回true或者false决定是否进入Controller层

postHandle在请求进入控制层之后调用但是在处理请求抛出异常时不会调用

afterCompletion在请求处理完成之后,也就是在DispatherServlet渲染了视图之后执行,也就是说这个方法必定是执行,包含异常信息,它的主要作用就是清理资源

代码实现:

主方法继承WebMvcConfigurer

注意不用用WebMvcConfigurerAdapter,该方法已经被官方标注过时了,在java8是默认实现的。

所以我们需要使用的是WebMvcConfigurer进行静态资源的配置。

配置的主要有两项:一个是制定***,第二个是指定拦截的URL

@Slf4j
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    /**
     * ***注册类
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LogInterceptor()).addPathPatterns("/**");
    }
    /**
     * 定义***
     */
    public class LogInterceptor implements HandlerInterceptor {
        long start = System.currentTimeMillis();

        /**
         * 请求执行前执行
         */
        @Override
        public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
            log.info("preHandle");
            start = System.currentTimeMillis();
            return true;
        }
        /**
         * 请求结束执行
         */
        @Override
        public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
            log.info("Interceptor cost="+(System.currentTimeMillis()-start));
        }
        /**
         * 视图渲染完成后执行
         */
        @Override
        public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
            log.info("afterCompletion");
        }
    }
}

Aspect切片【Spring AOP】

注解说明(参考:https://www.cnblogs.com/sa-dan/p/6837219.html

1 @Aspect

作用是把当前类标识为一个切面供容器读取

2 @Before
标识一个前置增强方法,相当于BeforeAdvice的功能,相似功能的还有

3 @AfterReturning

后置增强,相当于AfterReturningAdvice,方法正常退出时执行

4 @AfterThrowing

异常抛出增强,相当于ThrowsAdvice

5 @After

final增强,不管是抛出异常或者正常退出都会执行

6 @Around

环绕增强,相当于MethodInterceptor

7 @DeclareParents

引介增强,相当于IntroductionInterceptor






参考资料: