当前位置: 首页 > news >正文

Spring之【详解AOP】

目录

前言

定义切面类

registerBeanPostProcessors

一、注册Bean后置处理器,拦截Bean的创建过程

二、使用后置处理器委托执行注册Bean后置处理器的逻辑

三、获取到AnnotationAwareAspectJAutoProxyCreator的beanName

四、创建AnnotationAwareAspectJAutoProxyCreator对象

五、注册AnnotationAwareAspectJAutoProxyCreator

构建Advisors

一、AbstractAutowireCapableBeanFactory的createBean方法中会执行InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation方法回调

二、AnnotationAwareAspectJAutoProxyCreator是InstantiationAwareBeanPostProcessor,所以这里会执行到它的postProcessBeforeInstantiation方法(在它的父类AbstractAutoProxyCreator中定义)

三、将增强器放入BeanFactoryAspectJAdvisorsBuilder的advisorsCache集合中

定义一个需要被增强的业务类

创建业务类的代理对象放入单例池中

一、业务类的实例化

二、业务类的初始化

三、Bean后置处理器的初始化后方法回调

四、创建业务类的代理对象

五、放入singletonObjects中的是业务类的代理对象

从容器中获取业务类对象,并执行其添加了@Log注解的方法

一、测试结果

二、通过源码分析其运行流程


前言

  • Spring容器启动时,在AbstractApplicationContext的refresh方法的invokeBeanFactoryPostProcessors这一步骤中执行了ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法
  • 该方法会解析到@EnableAspectJAutoProxy注解上的@Import中的value为AspectJAutoProxyRegistrar.class
  • 通过判断得知AspectJAutoProxyRegistrar是ImportBeanDefinitionRegistrar接口的实现类,进而调用到AspectJAutoProxyRegistrar的registerBeanDefinitions方法,将AnnotationAwareAspectJAutoProxyCreator对应的RootBeanDefinition对象放入容器中的beanDefinitionMap集合中
  • AnnotationAwareAspectJAutoProxyCreator是一个BeanPostProcessor,它会在AbstractApplicationContext的refresh方法的registerBeanPostProcessors这一步骤中通过beanFactory的getBean方法进行实例化和初始化得到其对象,并存入AbstractBeanFactory的beanPostProcessors集合中
  • 该BeanPostProcessor将会作用于后续其他bean的getBean的流程

定义切面类

  • 自定义注解
package spring.aop;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** 该注解只能用在方法上*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
}
  • 切面类(切入点+增强逻辑)
package spring.aop;import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;/*** 切面*/
@Aspect
@Component
public class LogAspect {/*** 切入点表达式* 增强有@Log注解的方法*/@Pointcut("@annotation(spring.aop.Log)")public void pointCut() {}/*** 定义前置增强逻辑*/@Before("pointCut()")public void before() {System.out.println("Log...before...");}/*** 定义后置增强逻辑*/@After("pointCut()")public void after() {System.out.println("Log...after...");}
}

registerBeanPostProcessors

一、注册Bean后置处理器,拦截Bean的创建过程

二、使用后置处理器委托执行注册Bean后置处理器的逻辑

三、获取到AnnotationAwareAspectJAutoProxyCreator的beanName

四、创建AnnotationAwareAspectJAutoProxyCreator对象

五、注册AnnotationAwareAspectJAutoProxyCreator

构建Advisors

此时容器中已经有AnnotationAwareAspectJAutoProxyCreator这个后置处理器,它就会作用于接下来Bean的创建过程,在它之后的第一个Bean的getBean过程中,其就会构建Advisors并放入BeanFactoryAspectJAdvisorsBuilder的advisorsCache集合中

一、AbstractAutowireCapableBeanFactory的createBean方法中会执行InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation方法回调

二、AnnotationAwareAspectJAutoProxyCreator是InstantiationAwareBeanPostProcessor,所以这里会执行到它的postProcessBeforeInstantiation方法(在它的父类AbstractAutoProxyCreator中定义)

三、将增强器放入BeanFactoryAspectJAdvisorsBuilder的advisorsCache集合中

定义一个需要被增强的业务类

  • 业务类的register方法添加了自定义的@Log注解
package spring.aop;import org.springframework.stereotype.Service;@Service
public class AccountService {/*** 需要被增强的方法*/@Logpublic void register() {System.out.println("AccountService#register...");}
}

创建业务类的代理对象放入单例池中

Bean组件在实例化之后会执行初始化逻辑,初始化逻辑中在执行完初始化方法后会执行BeanPostProcessor的postProcessAfterInitialization方法,也就是会执行AnnotationAwareAspectJAutoProxyCreator的postProcessAfterInitialization方法

一、业务类的实例化

  • getBean

  • doGetBean

  • createBean

  • doCreateBean

二、业务类的初始化

  • Bean属性填充

  • Bean的初始化逻辑

三、Bean后置处理器的初始化后方法回调

  • 执行AnnotationAwareAspectJAutoProxyCreator的postProcessAfterInitialization方法

  • 为Bean获取增强逻辑

四、创建业务类的代理对象

  • 根据拿到的增强逻辑createProxy

  • 这里是通过CGLIB创建代理对象

  • 拿到了业务类的代理对象,这里可以看到代理对象中既保存了增强逻辑,同时也保存了目标对象

五、放入singletonObjects中的是业务类的代理对象

  • 执行完AnnotationAwareAspectJAutoProxyCreator的postProcessAfterInitialization方法(实际定义在其父类中)后返回的是Bean的代理对象

  • 将代理对象放入singletonObjects集合中

从容器中获取业务类对象,并执行其添加了@Log注解的方法

一、测试结果

  • 从容器中获取到的是代理对象
package spring.aop;import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class AopMain {public static void main(String[] args) {// 容器启动AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);// 从容器中获取业务类对象AccountService accountService = applicationContext.getBean(AccountService.class);// 执行其@Log的方法accountService.register();}
}

  • 执行了增强逻辑

二、通过源码分析其运行流程

  • 开始执行代理对象的方法

  • 执行到CglibAopProxy的intercept方法

  • 获取到目标方法

  • 获取到拦截器链

  • 通过代理对象、目标对象、目标类、目标方法、拦截器链创建ReflectiveMethodInvocation对象

  • 调用proceed方法,currentInterceptorIndex用于记录下标,因为拦截器链是一个List,执行一个可以通过下标++获取下一个

  • 调用MethodInterceptor的invoke方法

  • 拿到前置增强器

  • 执行前置增强逻辑(通过反射调用切面的before方法)

  • 执行目标方法(通过反射调用目标方法)

  • 执行后置增强逻辑(同样是通过反射执行切面类的后置增强逻辑)

http://www.dtcms.com/a/324472.html

相关文章:

  • 使用 Docker-Compose 部署 Redis 三主三从集群(含 Exporter 监控)
  • SQL Server从入门到项目实践(超值版)读书笔记 23
  • Windows 11 安装 JDK 11
  • ThreadLocal的原理是什么,使用场景有哪些?
  • 【自动化运维神器Ansible】playbook案例解析:Handlers与Notify机制深度解析
  • Vue3入门到精通:2.4 Vue3动态组件与异步组件深度解析
  • leetcode经典题目——单调栈
  • 【Python 工具人快餐 · 第 7 份 · 完结】
  • Redis 监控与优化方案(C++项目)
  • [激光原理与应用-221]:设计 - 皮秒紫外激光器 - 常见技术难题、原因与解决方案
  • 北京天津廊坊唐山打捞失物日记
  • Docker-04:CGroups资源控制组
  • Go语言--语法基础8--函数定义与调用--错误处理
  • Java学习第一百二十三部分——HTTP/HTTPS
  • 基于VuePress2开发文档自部署及嵌入VUE项目
  • 【RH134知识点问答题】第 4 章 归档和传输文件
  • 【浮点数存储】结构、精度说明
  • 联邦学习之------VT合谋
  • Pico+unity VR入门开发超详细笔记2025
  • 人形机器人强化学习入门实践1part
  • stm32没有CMSIS文件
  • Redis如何实现一个分布式锁?
  • 第4章 程序段的反复执行3 do-whiile语句P139练习(题及答案)
  • [Linux]学习笔记系列 -- [arm][lib]
  • C++的嵌套结构体
  • Deep Learning MNIST手写数字识别 Mac
  • 【从源码角度深度理解 CPython 的垃圾回收机制】:第2课循环引用:标记清除-分代回收
  • 7.企业级AD活动目录的备份与恢复策略
  • 【celeba】-数据集的介绍
  • 驱动电路设计