监听器,过滤器,拦截器和切面的使用示例、加载/执行顺序、生命周期

2 篇文章 0 订阅
1 篇文章 0 订阅

监听器,过滤器,拦截器和切面的使用示例、加载/执行顺序、生命周期

本博文示例代码可参考:GitHub
切换语言 | Language(On GitHub):中文版 | English Version

如何在spring boot项目中使用

1. 监听器

1.1. 实现接口ServletRequestListener。并且有许多类型的Listener。比如ServletRequestAttributeListener …
Gitter

1.2. 添加注解@WebListener

1.3. 让spring可以扫描到它,使用@ServletComponentScan指定可以扫描的类

下面是启动类的代码

@SpringBootApplication
@ServletComponentScan(basePackages = {"top.agno"})
public class TestApplication {

    public static void main(String[] args) {
        SpringApplication.run(TestApplication.class, args);
    }
}

下面是监听器类的代码

@Slf4j
@WebListener
public class CustomListenerA implements ServletRequestListener {

    public CustomListenerA() {
        log.info("监听器 {} 加载", this.getClass().getName());
    }

    @Override
    public void requestDestroyed(ServletRequestEvent sre) {
        log.info("监听器 {} 销毁", this.getClass().getName());
    }

    @Override
    public void requestInitialized(ServletRequestEvent sre) {
        log.info("监听器 {} 初始化", this.getClass().getName());
    }
}

2. 过滤器

过滤器在spring boot项目中有两种定义方法。

2.1. 使用@Configuration类或配置文件。
在Spring中,由@Configuration注解的类可以看作是配置文件。
所以我将只展示一种@Configuration方式。

2.1.1. @Configuration class.

@SpringBootApplication
@Configuration // @Step 1
@ServletComponentScan(basePackages = {"top.agno"})
public class TestApplication {

    public static void main(String[] args) {
        SpringApplication.run(TestApplication.class, args);
    }

    @Bean
    @Order(1)
    public FilterRegistrationBean customFilterA() { // @Step 2
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setEnabled(true);
        registration.setFilter(new CustomFilterA());
        registration.addUrlPatterns("/*");
        return registration;
    }
}

2.1.2. Filter class.

@Slf4j
public class CustomFilterA implements Filter /* implements Filter interface. */ {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("过滤器{}初始化...", this.getClass().getName());
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        log.info("执行过滤器{}逻辑...", this.getClass().getName());
        filterChain.doFilter(servletRequest, servletResponse);
        log.info("执行过滤器{}逻辑 执行结束...", this.getClass().getName());
    }

    @Override
    public void destroy() {
        log.info("过滤器{}销毁...", this.getClass().getName());
    }
}

2.2. Use @WebFilter annotation.

@Slf4j
@Order(-100)
@WebFilter(urlPatterns = "/*", filterName = "customFilterB") // @step 1. Add @WebFilter and set some params.
public class CustomFilterB implements Filter /* @step 2. implements Filter interface. */ {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("过滤器{}初始化...", this.getClass().getName());
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        log.info("执行过滤器{}逻辑...", this.getClass().getName());
        filterChain.doFilter(servletRequest, servletResponse);
        log.info("执行过滤器{}逻辑 执行结束...", this.getClass().getName());
    }

    @Override
    public void destroy() {
        log.info("过滤器{}销毁...", this.getClass().getName());
    }
}

3. 拦截器

拦截器也需要使用配置文件

3.1. 使用带有@Configuration的类来添加拦截器

@Configuration
class InterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new CustomInterceptorA()).addPathPatterns("/**");
        registry.addInterceptor(new CustomInterceptorB()).addPathPatterns("/**");
    }
}

附:不推荐使用抽象类WebMvcConfigurerAdapter,因为它已被废弃。可使用WebMvcConfigurer接口添加拦截器。

3.2. Interceptor class.

@Slf4j
public class CustomInterceptorA implements HandlerInterceptor {

    public CustomInterceptorA() {
        log.info("拦截器 {} 开始加载", this.getClass().getName());
    }

    // 请求处理之前调用
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("拦截器 {} preHandler 方法开始执行", this.getClass().getName());
        // return true 继续下面的逻辑
        // return false 本次拦截失效
        return true;
    }

    // 请求处理结束,视图渲染之前调用(Controller方法调用之后)
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("拦截器 {} postHandler 方法开始执行", this.getClass().getName());
    }

    // 请求结束,在 DispatcherServlet 渲染视图后调用
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("拦截器 {} afterCompletion 方法开始执行", this.getClass().getName());
    }
}

4. 切面

4.1. 定义一个注解 (@CustomAnnotation)

@Target(value = {ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomAnnotation {
    String value() default "";
}

4.2. 切面具体逻辑

@Aspect
@Slf4j
@Component
public class ControllerAspect {

    public ControllerAspect() {
        log.info("切面{}开始初始化", this.getClass().getName());
    }

    @Pointcut("@annotation(top.agno.project.test.web.aspects.CustomAnnotation)")
    public void controllerAspect(){}

    @Around("controllerAspect()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        log.info("切面{}开始执行", this.getClass().getName());
        Object returnContent = pjp.proceed();
        log.info("切面{}执行结束", this.getClass().getName());
        return returnContent;
    }
}

总结

初始化顺序: Listener(Constructor) > Filter(Init) > Aspect(Constructor) > Interceptor(Constructor)

执行顺序: Listener(initialized()) > Filter(doFilter | before doFilter()) > Interceptor(preHandler) > Aspect(Around | before processed()) >
business_logic() >
Aspect(Around | after processed()) > Interceptor(postHandler) > Interceptor(afterCompletion) > Filter(doFilter | after doFilter()) > Listener(destroy())

附.1. 当第一个请求进入时,DispatcherServlet将在Listener(initialized())之后初始化。
附.2. 有些Servlet容器并不受Spring Bean的管理,需要使用@ServletComponentScan去确保这些容器可以被扫描到。

效果图如下所示:

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值