• Spring原理:PostProcessor与AOP原理


    探究AOP原理

    前面我们提到了PostProcessor,它其实是Spring提供的一种后置处理机制,它可以让我们能够插手Bean、BeanFactory、BeanDefinition的创建过程,相当于进行一个最终的处理,而最后得到的结果(比如Bean实例、Bean定义等)就是经过后置处理器返回的结果,它是整个加载过程的最后一步。

    而AOP机制正是通过它来实现的,我们首先来认识一下第一个接口BeanPostProcessor,它相当于Bean初始化的一个后置动作,我们可以直接实现此接口:

    1. //注意它后置处理器也要进行注册
    2. @Component
    3. public class TestBeanProcessor implements BeanPostProcessor {
    4. @Override
    5. public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    6. System.out.println(beanName); //打印bean的名称
    7. return bean;
    8. }
    9. @Override
    10. public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    11. return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
    12. }
    13. }

    我们发现,此接口中包括两个方法,一个是postProcessAfterInitialization用于在Bean初始化之后进行处理,还有一个postProcessBeforeInitialization用于在Bean初始化之前进行处理,注意这里的初始化不是创建对象,而是调用类的初始化方法,比如:

    1. @Component
    2. public class TestBeanProcessor implements BeanPostProcessor {
    3. @Override
    4. public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    5. System.out.println("我是之后:"+beanName);
    6. return bean; //这里返回的Bean相当于最终的结果了,我们依然能够插手修改,这里返回之后是什么就是什么了
    7. }
    8. @Override
    9. public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    10. System.out.println("我是之前:"+beanName);
    11. return bean; //这里返回的Bean会交给下一个阶段,也就是初始化方法
    12. }
    13. }
    1. @Component
    2. public class TestServiceImpl implements TestService{
    3. public TestServiceImpl(){
    4. System.out.println("我是构造方法");
    5. }
    6. @PostConstruct
    7. public void init(){
    8. System.out.println("我是初始化方法");
    9. }
    10. TestMapper mapper;
    11. @Autowired
    12. public void setMapper(TestMapper mapper) {
    13. System.out.println("我是依赖注入");
    14. this.mapper = mapper;
    15. }
    16. ...

    而TestServiceImpl的加载顺序为:

    1. 我是构造方法
    2. 我是依赖注入
    3. 我是之前:testServiceImpl
    4. 我是初始化方法
    5. 我是之后:testServiceImpl

    现在我们再来总结一下一个Bean的加载流程:

    [Bean定义]首先扫描Bean,加载Bean定义 -> [依赖注入]根据Bean定义通过反射创建Bean实例 -> [依赖注入]进行依赖注入(顺便解决循环依赖问题)-> [初始化Bean]BeanPostProcessor的初始化之前方法 -> [初始化Bean]Bean初始化方法 -> [初始化Bean]BeanPostProcessor的初始化之前后方法 -> [完成]最终得到的Bean加载完成的实例

    利用这种机制,理解Aop的实现过程就非常简单了,AOP实际上也是通过这种机制实现的,它的实现类是AnnotationAwareAspectJAutoProxyCreator,而它就是在最后对Bean进行了代理,因此最后我们得到的结果实际上就是一个动态代理的对象(有关详细实现过程,这里就不进行列举了,感兴趣的可以继续深入)

    那么肯定有人有疑问了,这个类没有被注册啊,那按理说它不应该参与到Bean的初始化流程中的,为什么它直接就被加载了呢?

    还记得@EnableAspectJAutoProxy吗?我们来看看它是如何定义就知道了:

    1. @Target({ElementType.TYPE})
    2. @Retention(RetentionPolicy.RUNTIME)
    3. @Documented
    4. @Import({AspectJAutoProxyRegistrar.class})
    5. public @interface EnableAspectJAutoProxy {
    6. boolean proxyTargetClass() default false;
    7. boolean exposeProxy() default false;
    8. }

    我们发现它使用了@Import来注册AspectJAutoProxyRegistrar,那么这个类又是什么呢,我们接着来看:

    1. class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
    2. AspectJAutoProxyRegistrar() {
    3. }
    4. public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    5. //注册AnnotationAwareAspectJAutoProxyCreator到容器中
    6. AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
    7. AnnotationAttributes enableAspectJAutoProxy = AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
    8. if (enableAspectJAutoProxy != null) {
    9. if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
    10. AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
    11. }
    12. if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
    13. AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
    14. }
    15. }
    16. }
    17. }

    它实现了接口,这个接口也是Spring提供的一种Bean加载机制,它支持直接向容器中添加Bean定义,容器也会加载这个Bean:

    • ImportBeanDefinitionRegistrar类只能通过其他类@Import的方式来加载,通常是启动类或配置类。
    • 使用@Import,如果括号中的类是ImportBeanDefinitionRegistrar的实现类,则会调用接口中方法(一般用于注册Bean)
    • 实现该接口的类拥有注册bean的能力。

    我们可以看到此接口提供了一个BeanDefinitionRegistry正是用于注册Bean的定义的。

    因此,当我们打上了@EnableAspectJAutoProxy注解之后,首先会通过@Import加载AspectJAutoProxyRegistrar,然后调用其registerBeanDefinitions方法,然后使用工具类注册AnnotationAwareAspectJAutoProxyCreator到容器中,这样在每个Bean创建之后,如果需要使用AOP,那么就会通过AOP的后置处理器进行处理,最后返回一个代理对象。

    我们也可以尝试编写一个自己的ImportBeanDefinitionRegistrar实现,首先编写一个测试Bean:

    1. public class TestBean {
    2. @PostConstruct
    3. void init(){
    4. System.out.println("我被初始化了!");
    5. }
    6. }
    1. public class TestBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    2. @Override
    3. public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    4. BeanDefinition definition = BeanDefinitionBuilder.rootBeanDefinition(Student.class).getBeanDefinition();
    5. registry.registerBeanDefinition("lbwnb", definition);
    6. }
    7. }

    观察控制台输出,成功加载Bean实例。

    BeanPostProcessor差不多的还有BeanFactoryPostProcessor,它和前者一样,也是用于我们自己处理后置动作的,不过这里是用于处理BeanFactory加载的后置动作,BeanDefinitionRegistryPostProcessor直接继承自BeanFactoryPostProcessor,并且还添加了新的动作postProcessBeanDefinitionRegistry,你可以在这里动态添加Bean定义或是修改已经存在的Bean定义,这里我们就直接演示BeanDefinitionRegistryPostProcessor的实现:

    1. @Component
    2. public class TestDefinitionProcessor implements BeanDefinitionRegistryPostProcessor {
    3. @Override
    4. public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
    5. System.out.println("我是Bean定义后置处理!");
    6. BeanDefinition definition = BeanDefinitionBuilder.rootBeanDefinition(TestBean.class).getBeanDefinition();
    7. registry.registerBeanDefinition("lbwnb", definition);
    8. }
    9. @Override
    10. public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
    11. System.out.println("我是Bean工厂后置处理!");
    12. }
    13. }

    在这里注册Bean定义其实和之前那种方法效果一样。

    最后,我们再完善一下Bean加载流程(加粗部分是新增的):

    [Bean定义]首先扫描Bean,加载Bean定义 -> [Bean定义]Bean定义和Bean工厂后置处理 -> [依赖注入]根据Bean定义通过反射创建Bean实例 -> [依赖注入]进行依赖注入(顺便解决循环依赖问题)-> [初始化Bean]BeanPostProcessor的初始化之前方法 -> [初始化Bean]Bean初始化方法 -> [初始化Bean]BeanPostProcessor的初始化之前后方法 -> [完成]最终得到的Bean加载完成的实例

    最后我们再来研究一下ApplicationContext中的refresh()方法:

    1. public void refresh() throws BeansException, IllegalStateException {
    2. synchronized(this.startupShutdownMonitor) {
    3. StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
    4. this.prepareRefresh();
    5. ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
    6. //初始化Bean工厂
    7. this.prepareBeanFactory(beanFactory);
    8. try {
    9. this.postProcessBeanFactory(beanFactory);
    10. StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
    11. //调用所有的Bean工厂、Bean注册后置处理器
    12. this.invokeBeanFactoryPostProcessors(beanFactory);
    13. //注册Bean后置处理器(包括Spring内部的)
    14. this.registerBeanPostProcessors(beanFactory);
    15. beanPostProcess.end();
    16. //国际化支持
    17. this.initMessageSource();
    18. //监听和事件广播
    19. this.initApplicationEventMulticaster();
    20. this.onRefresh();
    21. this.registerListeners();
    22. //实例化所有的Bean
    23. this.finishBeanFactoryInitialization(beanFactory);
    24. this.finishRefresh();
    25. } catch (BeansException var10) {
    26. if (this.logger.isWarnEnabled()) {
    27. this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var10);
    28. }
    29. this.destroyBeans();
    30. this.cancelRefresh(var10);
    31. throw var10;
    32. } finally {
    33. this.resetCommonCaches();
    34. contextRefresh.end();
    35. }
    36. }
    37. }

    我们可以给这些部分分别打上断点来观察一下此方法的整体加载流程。

  • 相关阅读:
    IIs部署发布vue项目测试环境
    23、Flink TaskManager 内存调优
    环境多介质逸度模型与典型案例【代码】应用
    神经网络理论及应用答案,神经网络收敛速度慢
    vxe表格行拖拽
    亚马逊云科技Build On学习心得
    C#往数据库上传文件
    proxmox PVE 安装 黑苹果
    图论(算法竞赛、蓝桥杯)--Dijkstra算法最短路
    常用的git相关问题汇总
  • 原文地址:https://blog.csdn.net/Leon_Jinhai_Sun/article/details/126444835