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原理剖析

相关推荐
吾日三省吾码4 小时前
JVM 性能调优
java
弗拉唐5 小时前
springBoot,mp,ssm整合案例
java·spring boot·mybatis
oi775 小时前
使用itextpdf进行pdf模版填充中文文本时部分字不显示问题
java·服务器
少说多做3436 小时前
Android 不同情况下使用 runOnUiThread
android·java
知兀6 小时前
Java的方法、基本和引用数据类型
java·笔记·黑马程序员
蓝黑20206 小时前
IntelliJ IDEA常用快捷键
java·ide·intellij-idea
Ysjt | 深6 小时前
C++多线程编程入门教程(优质版)
java·开发语言·jvm·c++
shuangrenlong6 小时前
slice介绍slice查看器
java·ubuntu
牧竹子6 小时前
对原jar包解压后修改原class文件后重新打包为jar
java·jar