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


    目录

    基于xml配置的AOP

    xml方式AOP快速入门

    xml方式AOP配置详解

    xml方式AOP原理剖析(后面再深入理解一下)

    AOP底层两种生成Proxy的方法


    基于xml配置的AOP

    xml方式AOP快速入门

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

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

    • xml方式配置AOP的步骤
      • 导入AOP相关坐标
          1. <dependency>
          2. <groupId>org.aspectjgroupId>
          3. <artifactId>aspectjweaverartifactId>
          4. <version>1.9.19version>
          5. dependency>
      • 准备目标类、增强类、并配置给Spring管理
      • 配置切点表达式(哪些方法被增强)
      • 配置织入(切点被哪些通知方法增强,是前置增强还是后置增强)

    运行测试类

    1. package com.example.Test;
    2. import com.example.Service.UserService;
    3. import org.springframework.context.ApplicationContext;
    4. import org.springframework.context.support.ClassPathXmlApplicationContext;
    5. public class TestMyAOP {
    6. public static void main(String[] args) {
    7. ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    8. UserService userService = applicationContext.getBean(UserService.class);
    9. userService.show1();
    10. }
    11. }

     运行结果如下

    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种通知方法        
              1. package com.example.advice;
              2. import org.aspectj.lang.ProceedingJoinPoint;
              3. // 自定义增强类,内部提供增强方法
              4. public class MyAdvice {
              5. // todo 前置通知
              6. public void beforeAdvice() {
              7. System.out.println("前置通知");
              8. }
              9. // todo 后置通知
              10. public void afterAdvice() {
              11. System.out.println("后置通知");
              12. }
              13. // todo 环绕通知
              14. public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
              15. // 前置通知
              16. System.out.println("环绕通知:前置通知");
              17. Object res = proceedingJoinPoint.proceed(); // 执行目标方法
              18. System.out.println("环绕通知中目标方法执行了");
              19. // 后置通知
              20. System.out.println("环绕通知:后置通知");
              21. return res;
              22. }
              23. // todo 异常通知
              24. public void afterThrowingAdvice() {
              25. System.out.println("异常抛出通知...出现异常才会执行");
              26. }
              27. // todo 最终通知
              28. public void endAdvice() {
              29. System.out.println("最终通知....怎么样都会通知");
              30. }
              31. }
          • xml配置文件

              1. "1.0" encoding="UTF-8"?>
              2. <beans xmlns="http://www.springframework.org/schema/beans"
              3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              4. xmlns:aop="http://www.springframework.org/schema/aop"
              5. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
              6. http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
              7. <bean id="userService" class="com.example.Service.ServiceImpl.UserServiceImpl"/>
              8. <bean id="myAdvice" class="com.example.advice.MyAdvice"/>
              9. <aop:config>
              10. <aop:pointcut id="MyPointCut"
              11. expression="execution(void com.example.Service.ServiceImpl.UserServiceImpl.*(..))"/>
              12. <aop:aspect ref="myAdvice">
              13. <aop:before method="beforeAdvice" pointcut-ref="MyPointCut"/>
              14. <aop:after-returning method="afterAdvice" pointcut-ref="MyPointCut"/>
              15. <aop:around method="around" pointcut-ref="MyPointCut">aop:around>
              16. <aop:after-throwing method="afterThrowingAdvice" pointcut-ref="MyPointCut"/>
              17. <aop:after method="endAdvice" pointcut-ref="MyPointCut"/>
              18. aop:aspect>
              19. aop:config>
              20. beans>
          • 测试代码

              1. package com.example.Test;
              2. import com.example.Service.UserService;
              3. import org.springframework.context.ApplicationContext;
              4. import org.springframework.context.support.ClassPathXmlApplicationContext;
              5. public class TestMyAOP {
              6. public static void main(String[] args) {
              7. ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
              8. UserService userService = applicationContext.getBean(UserService.class);
              9. userService.show1();
              10. }
              11. }
            • 运行结果如下

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


    • AOP的配置两种方式
      • 使用配置切面,使用较少,创建一个类,实现不同的类型的通知接口,从而不用在配置文件设置通知类型。
        • 实现通知接口的类(增强类,指定通知类型)
            1. package com.example.advice;
            2. import org.springframework.aop.AfterReturningAdvice;
            3. import org.springframework.aop.MethodBeforeAdvice;
            4. import java.lang.reflect.Method;
            5. public class MyAdvice2 implements MethodBeforeAdvice, AfterReturningAdvice {
            6. @Override
            7. public void before(Method method, Object[] objects, Object o) throws Throwable {
            8. System.out.println("前置通知~~~~~~");
            9. }
            10. @Override
            11. public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
            12. System.out.println("后置通知~~~~~~");
            13. }
            14. }
        • 配置文件(该配置文件中并没有指定通知类型)
            1. "1.0" encoding="UTF-8"?>
            2. <beans xmlns="http://www.springframework.org/schema/beans"
            3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            4. xmlns:aop="http://www.springframework.org/schema/aop"
            5. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
            6. http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
            7. <bean id="userService" class="com.example.Service.ServiceImpl.UserServiceImpl"/>
            8. <bean id="myAdvice2" class="com.example.advice.MyAdvice2"/>
            9. <aop:config>
            10. <aop:pointcut id="MyPointCut" expression="execution(* com.example.Service.ServiceImpl.UserServiceImpl.*(..))"/>
            11. <aop:advisor advice-ref="myAdvice2" pointcut-ref="MyPointCut">aop:advisor>
            12. aop:config>
            13. beans>
        • 测试类

            1. package com.example.Test;
            2. import com.example.Service.UserService;
            3. import org.springframework.context.ApplicationContext;
            4. import org.springframework.context.support.ClassPathXmlApplicationContext;
            5. public class TestMyAOP {
            6. public static void main(String[] args) {
            7. ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext2.xml");
            8. UserService userService = applicationContext.getBean(UserService.class);
            9. userService.show1();
            10. }
            11. }
        • 运行结果如下

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

    xml方式AOP原理剖析(后面再深入理解一下)

    •  首先根据自定义命名空间进行解析,为标签指定解析器,该解析器向Spring容器中注入AspectJAwareAduisorAutoProxyCreator(其本质是一个beanPostProcessor,在对应的after方法中生成bean的代理对象存储到容器中)源码真的难看(记住过程)。

    AOP底层两种生成Proxy的方法

    • 动态代理的实现的选择,在调用getProxy()方法时,我们可以选用的AopProxy接口有两个实现类,如上图,这两个都是动态生成代理对象的方式,一种是基于JDK的,一种是基于Cglib的
      • 代理技术使用条件配置方式
        JDK动态代理技术目标类有接口,是基于接口动态生成实现类的代理对象目标类有接口的情况下,默认方式
        Cglib动态代理技术目标类无接口且不能用final修饰,是基于被代理对象动态生成子对象为代理对象

        目标了无接口时,默认使用该方式;目标类有接口时,手动配置强制使用Cglib方式

         
      • 代理对象实质上是接口实现类的对象。 

  • 相关阅读:
    深入探讨安全验证:OAuth2.0、Cookie与Session、JWT令牌、SSO与开放授权平台设计
    在树莓派上控制GPIO常用的编程语言有哪些
    接收灵敏度和等效噪声带宽(ENBW)
    第一颗国产 单/双端口 MIPI CSI/DSI 至 HDMI 1.4 发射器 芯片LT9611
    详解诊断数据库ODX-D
    数列极差(c++题解)
    C-1练习题
    eclipse中open Type 、 open type in Hierachy、open Resource的区别
    什么是驱动程序签名,驱动程序如何获取数字签名?
    功能实现_用户认证_基于token_实现携带token访问购物车页面
  • 原文地址:https://blog.csdn.net/weixin_64939936/article/details/133580539