IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 【SpringMVC】Filter过滤器、AOP切面类、Interceptors拦截器各自的执行顺序 -> 正文阅读

[Java知识库]【SpringMVC】Filter过滤器、AOP切面类、Interceptors拦截器各自的执行顺序

文章内容:探究Filter过滤器、AOP切面类、interceptors,这几个类都有一个特性“拦截”(拦截器和过滤器实现的都是拦截功能,切面类是实现在某部分代码前执行特定代码,例如登录前要求用户验证)


提示:本文不深究Filter过滤器、AOP切面类、interceptors的原理,解释采用通俗易懂的方式进行解释,后续将针对三者写出详细的文章
点击跳转:AOP切面类详解


  • 原生的Filter:可以实现以下功能
    • 调用目标资源之前,让一段代码执行。
    • 是否调用目标资源(即是否让用户访问web资源)。
    • 调用目标资源之后,让一段代码执行。

Filter(过滤器) 的基本功能是对 Servlet 容器调用 Servlet (JSP)的过程进行拦截, 从而在 Servlet 处理请求前和 Servlet 响应请求后实现一些特殊的功能。

即在调用某个资源之前,能进行拦截


  • AOP切面类
    • 需要在核心业务前执行该辅助功能
    • 需要在核心业务执行之后执行该辅助功能
    • 需要在报错时候执行该辅助功能更
    • 需要在返回结果是执行该辅助功能
    • 需要在方法执行之前之后异常时执行该辅助功能

用动态代理来实现在执行某部分代码之前执行特定的代码
点击跳转:AOP切面类详解

需要注意:
返回通知(after-returning):当核心业务代码执行完成后执行,发生异常不执行
后置通知(after):不论目标方法是否发生异常都会执行,若无异常,则执行顺序在返回通知之后


  • Interceptor:拦截器:
    属于SpringMVC,实现的功能和过滤器一样,但是也有一些不同点
    • 工作平台不同:
      • 过滤器工作在 Servlet 容器中
      • 拦截器工作在 SpringMVC 的基础上

    • 拦截范围不同:
      • 过滤器:能够拦截到的最大范围是整个 Web 应用
      • 拦截器:能够拦截到的最大范围是整个 SpringMVC 负责的请求

    • IOC容器的支持:
      • 过滤器:想得到 IOC 容器需要调用专门的工具方法,是间接的
      • 拦截器:它自己就在 IOC 容器中,所以可以直接从 IOC 容器中装配组件,也就是可以直接得到 IOC 容器的支持

实现的功能和过滤器一样,开发使用的时候,假如可以用拦截器实现,就可以不用过滤器了



下面来研究,在存在多个过滤类/存在多个切面类/存在多个拦截器,其执行顺序

过滤器

1.准备工作:
准备两个过滤器(构成过滤器链),配置

public class Filter01 implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
        System.out.println("Filter01:初始化");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("Filter01:过滤");
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
        Filter.super.destroy();
        System.out.println("Filter01:过滤器销毁");
    }
}

public class Filter02 implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
        System.out.println("Filter02:初始化");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("Filter02:过滤");
        chain.doFilter(request,response);
    }

    @Override
    public void destroy() {
        Filter.super.destroy();
        System.out.println("Filter02:过滤器销毁");

    }
}

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <filter>
        <filter-name>Filter01</filter-name>
        <filter-class>com.example.demo_web.filter.Filter01</filter-class>
    </filter>
    <filter>
        <filter-name>Filter02</filter-name>
        <filter-class>com.example.demo_web.filter.Filter02</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>Filter02</filter-name>
        <url-pattern>/TestServlet</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>Filter01</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

</web-app>

执行顺序:

Filter02:初始化
Filter01:初始化
[2022-02-03 04:31:29,250] Artifact demo_web:war exploded: Artifact is deployed successfully
[2022-02-03 04:31:29,250] Artifact demo_web:war exploded: Deploy took 991 milliseconds
Filter02:过滤
Filter01:过滤

执行顺序:过滤器链执行顺序和设置的filter-mapping先后顺序有关,先设置先过滤,和filter标签顺序无关
注意:使用多个过滤器时,构成过滤器链,假如在dofilter方法中如果没有 chain.doFilter(request,response);那么请求在进入第一个过滤器后无法通过



切面类

1.准备工作
两个切面类

@Aspect
@Component
public class TestAOP2 {

    @Before(value = "execution(public int com.Calc.add(int ,int ))")
    public void printLogBefore(JoinPoint joinPoint){
        System.out.println("TEST2:Before");
    }
    @AfterReturning(
            value = "execution(public int com.Calc.add(int ,int ))",
            returning = "returnValue"//定义的形参名字
    )

    public void printLogAfterSuccess(JoinPoint joinPoint,Object returnValue){
        System.out.println("TEST2:AfterReturning");
    }

    @AfterThrowing(
            value ="execution(public int com.Calc.add(int ,int ))",
            throwing = "targetException"
    )
    public void printLogAfterException(JoinPoint joinPoint,Throwable targetException){
        System.out.println("TEST2:printLogAfterException");
    }

    @After("execution(public int com.Calc.add(int ,int ))")
    public void printLogFinish(){
        System.out.println("TEST2:After");
    }
}
@Aspect
@Component
public class TestAOP3 {

    @Before(value = "execution(public int com.Calc.add(int ,int ))")
    public void printLogBefore(JoinPoint joinPoint){
        System.out.println("TEST3:Before");
    }
    @AfterReturning(
            value = "execution(public int com.Calc.add(int ,int ))",
            returning = "returnValue"
    )

    public void printLogAfterSuccess(JoinPoint joinPoint,Object returnValue){
        System.out.println("TEST3:AfterReturning");
    }

    @AfterThrowing(
            value ="execution(public int com.Calc.add(int ,int ))",
            throwing = "targetException"
    )
    public void printLogAfterException(JoinPoint joinPoint,Throwable targetException){
        System.out.println("TEST3:printLogAfterException");
    }

    @After("execution(public int com.Calc.add(int ,int ))")
    public void printLogFinish(){
        System.out.println("TEST3:After");
    }
}

无抛错情况下:

TEST2:Before
TEST3:Before
TEST3:AfterReturning
TEST3:After
TEST2:AfterReturning
TEST2:After

有抛错

TEST2:Before
TEST3:Before
TEST3:AfterReturning
TEST3:After
TEST2:AfterReturning
TEST2:After

执行顺序:
Spring 官方文档中是这样描述的:当在不同切面定义的两条相同类型通知都需要在同一连接点上运行时,除非另行指定,否则执行顺序是不确定的。 您可以通过指定优先级来控制执行顺序。 通过在切面类中实现 org.springframework.core.Ordered 接口或使用 @Order 注解对其进行注解。 给定两个切面,从 Ordered.getValue()(或 @Order 注解值)返回较低值的切面具有较高的优先级。
不过针对上面的描述,亲测,在不设定优先级的情况下,两个切面类执行顺序和其类名的排序有关,看下图,TestAOP2排序先于TestAOP3,TestAOP2就先执行

Test2和Test3,记住他们的类名排序顺序和结果
在这里插入图片描述

TEST2:Before
TEST3:Before
TEST3:AfterReturning
TEST3:After
TEST2:AfterReturning
TEST2:After

现在我们把Test3命名为Test1
在这里插入图片描述
执行结果

TEST1:Before
TEST2:Before
TEST2:AfterReturning
TEST2:After
TEST1:AfterReturning
TEST1:After


拦截器

1.准备工作:
两个拦截器,然后在spring-mvc文件中配置拦截器


    <mvc:interceptors>
            <bean class="com.mvc.interceptor.Interceptor01"/>
            <bean class="com.mvc.interceptor.Interceptor02"/>
    </mvc:interceptors>

public class Interceptor01 implements HandlerInterceptor {
    private Logger logger= LoggerFactory.getLogger(this.getClass());
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        logger.debug("Interceptor01:preHandle");

        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        logger.debug("Interceptor01:postHandle");

        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        logger.debug("Interceptor01:afterCompletion");
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}
public class Interceptor02 implements HandlerInterceptor {

    private Logger logger= LoggerFactory.getLogger(this.getClass());
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        logger.debug("Interceptor02:afterCompletion");
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        logger.debug("Interceptor02:postHandle");
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        logger.debug("Interceptor02:preHandle");

        return true;
    }
}

2.测试:

[http-nio-8080-exec-21] DEBUG com.mvc.interceptor.Interceptor01 - Interceptor01:preHandle
[http-nio-8080-exec-21] DEBUG com.mvc.interceptor.Interceptor02 - Interceptor02:preHandle
[http-nio-8080-exec-21] DEBUG com.mvc.interceptor.Interceptor02 - Interceptor02:postHandle
[http-nio-8080-exec-21] DEBUG com.mvc.interceptor.Interceptor01 - Interceptor01:postHandle
[http-nio-8080-exec-21] DEBUG com.mvc.interceptor.Interceptor02 - Interceptor02:afterCompletion
[http-nio-8080-exec-21] DEBUG com.mvc.interceptor.Interceptor01 - Interceptor01:afterCompletion

两个拦截器的顺序执行,其实是比较难记下来的。

  • preHandle()方法:和配置的顺序一样
  • 目标handler方法
  • postHandle()方法:和配置的顺序相反
  • 渲染视图
  • afterCompletion()方法:和配置的顺序相反
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-02-05 21:35:51  更:2022-02-05 21:36:07 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 10:33:23-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码