SpringBoot 拦截器 过滤器 监听器和aop使用总结

 

根据实现原理分成下面两大类:

Filter和Listener:依赖Servlet容器,基于函数回调实现。可以拦截所有请求,覆盖范围更广,但无法获取ioc容器中的bean。
Interceptor和aop:依赖spring框架,基于java反射和动态代理实现。只能拦截controller的请求,可以获取ioc容器中的bean。

执行顺序:

Filter  > Listener > Interceptor > aop

       监听器:listener是servlet规范中定义的一种特殊类。用于监听servletContext、HttpSession和servletRequest等域对象的创建和销毁事件。监听域对象的属性发生修改的事件。用于在事件发生前、发生后做一些必要的处理。其主要可用于以下方面:1、统计在线人数和在线用户2、系统启动时加载初始化信息3、统计网站访问量4、记录用户访问路径。

  过滤器:Filter是Servlet技术中最实用的技术,Web开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。它主要用于对用户请求进行预处理,也可以对HttpServletResponse进行后处理。使用Filter的完整流程:Filter对用户请求进行预处理,接着将请求交给Servlet进行处理并生成响应,最后Filter再对服务器响应进行后处理。

  拦截器:Interceptor 在AOP(Aspect-Oriented Programming)中用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作。比如日志,安全等。一般拦截器方法都是通过动态代理的方式实现。可以通过它来进行权限验证,或者判断用户是否登陆,或者是像12306 判断当前时间是否是购票时间。

 

 

一:过滤器(可通过配置类或者注解两种方式实现)

1,通过配置类来实现,在只实现过滤器的接口,并不需要通过任何注解注入IOC容器,都通过配置类来注入。

package com.chitic.supplywater.common.aop;


import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

/**
 * @Description //TODO
 * @Author GaoX
 * @Date 2020/9/16 8:55
 */
//@WebFilter(filterName = "myFilter",urlPatterns = {"/*"})
public class AFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

    }

    @Override
    public void destroy() {

    }
}

注册过滤器

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import pers.kerry.demo.webfilter.filter.AFilter;
import pers.kerry.demo.webfilter.filter.BFilter;

@Configuration
public class FilterConfig {
    @Bean
    public FilterRegistrationBean AFilter() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        AFilter aFilter=new AFilter();
        filterRegistrationBean.setFilter(aFilter);
        filterRegistrationBean.addUrlPatterns("*");
        filterRegistrationBean.setName("AFilter");
        filterRegistrationBean.setOrder(1);
        return filterRegistrationBean;
    }

    @Bean
    public FilterRegistrationBean BFilter() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        BFilter bFilter=new BFilter();
        filterRegistrationBean.setFilter(bFilter);
        filterRegistrationBean.addUrlPatterns("*");
        filterRegistrationBean.setName("BFilter");
        filterRegistrationBean.setOrder(2);
        return filterRegistrationBean;
    }
}

2,注解方式

@WebFilter(filterName = "myFilter",urlPatterns = {"/*"})

启动类@ServletComponentScan

 

二:监听器(可通过配置类或者注解两种方式实现)

Listener监听器也是Servlet层面的,可以用于监听Web应用中某些对象、信息的创建、销毁和修改等动作发生,然后做出相应的响应处理。根据监听对象,将监听器分为3类:

  1. ServletContextListener:对应application,实现接口ServletContextListener。在整个Web服务中只有一个,在Web服务关闭时销毁。可用于做数据缓存,例如结合redis,在Web服务创建时从数据库拉取数据到缓存服务器。
  2. HttpSessionListener:对应session会话,实现接口HttpSessionListener。在会话起始时创建,一端关闭会话后销毁。可用作获取在线用户数量。
  3. ServletRequestListener:对应request,实现接口ServletRequestListener。request对象是客户发送请求时创建的,用于封装请求数据,请求处理完毕后销毁。可用作封装用户信息。
package com.chitic.supplywater.common.aop;

import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

/**
 * @Description //TODO
 * @Author GaoX
 * @Date 2020/9/16 8:54
 */
//@WebListener
public class listener1 implements HttpSessionListener {
    private int count = 0;


    @Override
    public void sessionCreated(HttpSessionEvent se) {
        count++;
        se.getSession().getServletContext().setAttribute("count", count);
        System.out.println("新增在线人数,当前在线人数:"+count);
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        count--;
        se.getSession().getServletContext().setAttribute("count", count);
        System.out.println("删减在线人数,当前在线人数:"+count);
    }
}

注册监听器

package com.chitic.supplywater.common.aop;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyListener  {

     
    @Bean
    public ServletListenerRegistrationBean listenerRegist() {
        ServletListenerRegistrationBean srb = new ServletListenerRegistrationBean();
        srb.setListener(new listener1());
        System.out.println("listener");
        return srb;
    }
}

 

三:拦截器(Interceptor)

Interceptor拦截器和Filter和Listener有本质上的不同,前面二者都是依赖于Servlet容器,而Interceptor则是依赖于Spring框架,是aop的一种表现,基于Java的动态代理实现的。 

  1. 声明拦截器的类:1,通过实现 HandlerInterceptor接口;2,继承HandlerInterceptorAdapter类; 实现preHandle、postHandle和afterCompletion方法。
  2. 通过配置类配置拦截器:通过实现WebMvcConfigurer接口,实现addInterceptors方法。

      

package com.chitic.supplywater.common.aop;

import org.springframework.lang.Nullable;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @Description //TODO
 * @Author GaoX
 * @Date 2020/9/16 8:54
 */
public class HandlerInterceptorAdapter1 extends HandlerInterceptorAdapter {

    /**
     * This implementation always returns {@code true}.
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {

        return true;
    }

    /**
     * This implementation is empty.
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                           @Nullable ModelAndView modelAndView) throws Exception {
    }

    /**
     * This implementation is empty.
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
                                @Nullable Exception ex) throws Exception {
    }

    /**
     * This implementation is empty.
     */
    @Override
    public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response,
                                               Object handler) throws Exception {
    }

}

注册拦截器

package com.chitic.supplywater.common.aop;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class MywebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new HandlerInterceptorAdapter1())
                .addPathPatterns("/**");
    }
     
}

 

四:aop

相比较于拦截器,Spring 的aop则功能更强大,封装的更细致,需要单独引用 jar包。

pom.xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

 

在定义AOP的类时,不需要和前面拦截器一样麻烦了,只需要通过注解,底层实现逻辑都通过IOC框架实现好了,涉及到的注解如下:

  • @Aspect:将一个 java 类定义为切面类。
  • @Pointcut:定义一个切入点,可以是一个规则表达式,比如下例中某个 package 下的所有函数,也可以是一个注解等。
  • @Before:在切入点开始处切入内容。
  • @After:在切入点结尾处切入内容,无论是否有异常,都会执行,类似于finally。
  • @AfterReturning:在切入点 return 内容之后处理逻辑,只有执行成功会执行,异常不会。
  • @Around:在切入点前后切入内容,并自己控制何时执行切入点自身的内容。原则上可以替代@Before和@After。
  • @AfterThrowing:用来处理当切入内容部分抛出异常之后的处理逻辑。
  • @Order(100):AOP 切面执行顺序, @Before 数值越小越先执行,@After 和 @AfterReturning 数值越大越先执行。

DemoAspect.java

 
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * @Aspect 注解 使之成为切面类
 * @Component 注解 把切面类加入到IOC容器中
 */
@Aspect
@Component
public class DemoAspect {

    @Pointcut( "execution( public * pers.kerry.demo.webfilter.controller.DemoController.*(..) )")
    public void doPointcut(){
    }

    @Before("doPointcut()")
    public void doBefore(){
        System.out.println("==doBefore==");
    }

    @After("doPointcut()")
    public void doAfter(){
        System.out.println("==doAfter==");
    }

    @AfterReturning("doPointcut()")
    public void doAfterReturning(){
        System.out.println("==doAfterReturning==");
    }

    /**
     * 环绕通知返回值类型Object,对应所有被拦截方法的返回值类型,不能为void
     */
    @Around("doPointcut()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint)throws Throwable{
        System.out.println("==doAround.before==");
        Object ret=proceedingJoinPoint.proceed();
        System.out.println("==doAround.after==");
        return ret;
    }
}
 

 

SpringBootApplication 上使用@ServletComponentScan 注解后
Servlet可以直接通过@WebServlet注解自动注册
Filter可以直接通过@WebFilter注解自动注册
Listener可以直接通过@WebListener 注解自动注册

 

posted @ 2019-04-10 15:51  高木子  阅读(6184)  评论(0编辑  收藏  举报