Spring的AOP开发-基于xml配置的AOP

基于xml配置的AOP

xml方式AOP快速入门

  • 在前面我们自己编写的AOP基础代码还存在一些问题,主要是

  • 我们可以通过配置文件解决上述问题
    • 配置增强的范围(配置目标对象)---切点表达式
    • 配置目标对象被哪些通知方法所增强,以及执行的顺序
    • 配置文件的设计,配置文件(注解)的解析工作,Spring已经帮我们封装好了。在java web中设计到一些该知识点,具体文章参照内容管理-CSDN创作中心,其中AOP相关知识点。

  • xml方式配置AOP的步骤
    • 导入AOP相关坐标
      *

      XML 复制代码
              <dependency>
                  <groupId>org.aspectj</groupId>
                  <artifactId>aspectjweaver</artifactId>
                  <version>1.9.19</version>
              </dependency>
    • 准备目标类、增强类、并配置给Spring管理

    • 配置切点表达式(哪些方法被增强)

    • 配置织入(切点被哪些通知方法增强,是前置增强还是后置增强)

运行测试类

java 复制代码
package com.example.Test;


import com.example.Service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestMyAOP {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = applicationContext.getBean(UserService.class);
        userService.show1();
    }
}

运行结果如下

xml方式AOP配置详解

  • xml配置AOP还是很简单的,具体细节如下
    • 切点表达式的配置方式

    • 切点表达式的配置语法

      • execution([访问修饰符] 返回类型 包名.类名.方法名(参数))
      • 访问修饰符可以省略不写
      • 返回值类型、某一级包名、类名、方法名可以使用表示*表示任意
      • 包名与类名之间使用单点.表示该包下的类,使用双点..表示该包及其子包下的类
      • 参数列表可以使用两个点..表示任意参数
      • 也可以参考java web专栏往期文章:AOP进阶-切入点表达式-execution-CSDN博客
    • 通知类型

      • AspectJ的通知由以下通知类型
      通知类型 描述
      Before 在目标方法执行之前执行的通知,用于进行准备工作或检查
      After 在目标方法执行之后执行的通知,用于进行清理工作或资源释放,最终都会执行
      AfterReturning 在目标方法正常执行并返回结果后执行的通知,用于处理返回值或记录结果,目标方法异常时,不再执行
      AfterThrowing 在目标方法抛出异常后执行的通知,用于捕获和处理异常
      Around 在目标方法执行前后都可以执行的通知,用于包裹目标方法的执行过程、控制和干预,目标方法异常时,环绕后方法不再执行
      StaticInitialization 静态初始化代码块的通知,当类被加载时执行
      Initialization 对象初始化代码块的通知,当对象被创建时执行
      FieldGet 字段读取操作的通知,当访问字段时执行
      FieldSet 字段赋值操作的通知,当修改字段值时执行
      MethodExecution 方法执行的通知,包括Before、After、AfterReturning和AfterThrowing等通知的集合
      • 参考文章:AOP进阶-通知类型-CSDN博客,在该文章中使用的是注解方式来配置AOP。
      • 以下是通过xml方式来配置AOP前5种通知方式的代码示例
        • 5种通知方法
          *

          java 复制代码
          package com.example.advice;
          
          
          import org.aspectj.lang.ProceedingJoinPoint;
          
          // 自定义增强类,内部提供增强方法
          public class MyAdvice {
              // todo 前置通知
              public void beforeAdvice() {
                  System.out.println("前置通知");
          
              }
          
              // todo 后置通知
              public void afterAdvice() {
                  System.out.println("后置通知");
          
              }
          
              // todo 环绕通知
              public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
                  // 前置通知
                  System.out.println("环绕通知:前置通知");
                  Object res = proceedingJoinPoint.proceed(); // 执行目标方法
                  System.out.println("环绕通知中目标方法执行了");
                  // 后置通知
                  System.out.println("环绕通知:后置通知");
                  return res;
              }
          
              // todo 异常通知
              public void afterThrowingAdvice() {
                  System.out.println("异常抛出通知...出现异常才会执行");
              }
          
              // todo 最终通知
              public void endAdvice() {
                  System.out.println("最终通知....怎么样都会通知");
              }
          
          }
        • xml配置文件

          XML 复制代码
          <?xml version="1.0" encoding="UTF-8"?>
          <beans xmlns="http://www.springframework.org/schema/beans"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xmlns:aop="http://www.springframework.org/schema/aop"
                 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                     http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
              <!-- 配置目标类 -->
              <bean id="userService" class="com.example.Service.ServiceImpl.UserServiceImpl"/>
              <!-- 配置通知类 -->
              <bean id="myAdvice" class="com.example.advice.MyAdvice"/>
              <!-- AOP配置 -->
              <aop:config>
                  <!-- 切点表达式,指定哪些方法被增强 -->
                  <aop:pointcut id="MyPointCut"
                                expression="execution(void com.example.Service.ServiceImpl.UserServiceImpl.*(..))"/>
          
                  <!-- 配置织入,指定哪些切点与哪些通知进行结合 -->
                  <aop:aspect ref="myAdvice">
                      <!--            前置通知-->
                      <aop:before method="beforeAdvice" pointcut-ref="MyPointCut"/>
                      <!--            后置通知-->
                      <aop:after-returning method="afterAdvice" pointcut-ref="MyPointCut"/>
                      <!--            环绕通知-->
                      <aop:around method="around" pointcut-ref="MyPointCut"></aop:around>
                      <!--            异常通知-->
                      <aop:after-throwing method="afterThrowingAdvice" pointcut-ref="MyPointCut"/>
                      <!--            最终通知-->
                      <aop:after method="endAdvice" pointcut-ref="MyPointCut"/>
                  </aop:aspect>
              </aop:config>
          </beans>
        • 测试代码

          java 复制代码
          package com.example.Test;
          
          
          import com.example.Service.UserService;
          import org.springframework.context.ApplicationContext;
          import org.springframework.context.support.ClassPathXmlApplicationContext;
          
          public class TestMyAOP {
              public static void main(String[] args) {
                  ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
                  UserService userService = applicationContext.getBean(UserService.class);
                  userService.show1();
              }
          }
          • 运行结果如下

        • 上述的运行结果也多多少少体现了各种通知类型的通知顺序, 具体可以参照文章:AOP进阶-通知顺序-CSDN博客,同时由于目标方法没有运行错误,所以,异常通知类无法通知,造出异常后:


  • AOP的配置两种方式
    • 使用<advisor>配置切面,使用较少,创建一个类,实现不同的类型的通知接口,从而不用在配置文件设置通知类型。

      • 实现通知接口的类(增强类,指定通知类型)
        *

        java 复制代码
        package com.example.advice;
        
        import org.springframework.aop.AfterReturningAdvice;
        import org.springframework.aop.MethodBeforeAdvice;
        
        import java.lang.reflect.Method;
        
        public class MyAdvice2 implements MethodBeforeAdvice, AfterReturningAdvice {
            @Override
            public void before(Method method, Object[] objects, Object o) throws Throwable {
                System.out.println("前置通知~~~~~~");
            }
        
            @Override
            public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
                System.out.println("后置通知~~~~~~");
            }
        
        
        }
      • 配置文件(该配置文件中并没有指定通知类型)
        *

        XML 复制代码
        <?xml version="1.0" encoding="UTF-8"?>
        <beans xmlns="http://www.springframework.org/schema/beans"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xmlns:aop="http://www.springframework.org/schema/aop"
               xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                   http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
            <!-- 配置目标类 -->
            <bean id="userService" class="com.example.Service.ServiceImpl.UserServiceImpl"/>
            <!-- 配置通知类 -->
            <bean id="myAdvice2" class="com.example.advice.MyAdvice2"/>
            <aop:config>
                <aop:pointcut id="MyPointCut" expression="execution(* com.example.Service.ServiceImpl.UserServiceImpl.*(..))"/>
                <aop:advisor advice-ref="myAdvice2" pointcut-ref="MyPointCut"></aop:advisor>
            </aop:config>
        
        </beans>
      • 测试类

        java 复制代码
        package com.example.Test;
        
        
        import com.example.Service.UserService;
        import org.springframework.context.ApplicationContext;
        import org.springframework.context.support.ClassPathXmlApplicationContext;
        
        public class TestMyAOP {
            public static void main(String[] args) {
                ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext2.xml");
                UserService userService = applicationContext.getBean(UserService.class);
                userService.show1();
            }
        }
      • 运行结果如下

    • 使用<aspect>配置切面,上述配置中都是使用的该方法

  • Spring定义了一个Advice接口,实现该接口的类都可以作为通知类出现(一般都是实现其子类)
  • 两种配置方案的比较
    • 语法形式不同
      • advisor是通过实现接口来确认通知类型
      • aspect是通过配置确认通知类型,更加灵活
    • 可配置的切面数量不同
      • 一个advisor只能配置一个固定通知和一个切点表达式
      • 一个aspect可以配置多个通知和多个切点表达式
    • 使用场景不同
      • 运行任意搭配情况下可以使用aspect进行配置
      • 如果通知类型单一、切面单一的情况下可以使用advisor进行配置
      • 在通知类型已经固定,不用人为指定通知类型时,可以使用advisor进行配置,例如后面会学习的Spring事务控制的配置。

明天再来,p90

xml方式AOP原理剖析

相关推荐
小灰灰__15 分钟前
IDEA加载通义灵码插件及使用指南
java·ide·intellij-idea
夜雨翦春韭18 分钟前
Java中的动态代理
java·开发语言·aop·动态代理
程序媛小果39 分钟前
基于java+SpringBoot+Vue的宠物咖啡馆平台设计与实现
java·vue.js·spring boot
追风林44 分钟前
mac m1 docker本地部署canal 监听mysql的binglog日志
java·docker·mac
芒果披萨1 小时前
El表达式和JSTL
java·el
duration~2 小时前
Maven随笔
java·maven
zmgst2 小时前
canal1.1.7使用canal-adapter进行mysql同步数据
java·数据库·mysql
跃ZHD2 小时前
前后端分离,Jackson,Long精度丢失
java
blammmp2 小时前
Java:数据结构-枚举
java·开发语言·数据结构
暗黑起源喵3 小时前
设计模式-工厂设计模式
java·开发语言·设计模式