BeanPostProcessor——连接Spring IOC和AOP的桥梁

讲解思路:

  • BBP怎么用 —— 先学会怎么用,再去看原理
  • BBP的触发时机 —— 在整个Spring Bean初始化流程中的位置
  • BBP自己又是什么时候被创建的?
  • BBP是如何连接IOC和AOP的?

怎么用

BeanPostProcessor,直译过来,就是“对象后处理器”, 那么这个“后”,是指什么之后呢?

试试便知。

我们先写一个对象,Bean4BBP( 本文的所有代码,可到 Github 上下载 ):

@Componentpublic class Bean4BBP { private static final Logger log = LoggerFactory.getLogger(Bean4BBP.class); public Bean4BBP(){ log.info("construct Bean4BBP"); }}复制代码

然后再写一个BeanPostProcessor,这时发现它是一个接口,没关系,那就写一个类实现它,CustomBeanPostProcessor:

@Componentpublic class CustomBeanPostProcessor implements BeanPostProcessor { private static final Logger log = LoggerFactory.getLogger(CustomBeanPostProcessor.class); public CustomBeanPostProcessor() { log.info("construct CustomBeanPostProcessor"); } @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof Bean4BBP) { log.info("process bean before initialization"); } return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof Bean4BBP) { log.info("process bean after initialization"); } return bean; }}复制代码

然后启动我们的Spring Boot项目(直接运行Application类),看这几条日志打印的顺序:

construct CustomBeanPostProcessorconstruct Bean4BBPprocess bean before initializationprocess bean after initialization复制代码

BBP对象首先被创建,然后创建Bean4BBP对象,接着再先后执行BBP对象的postProcessBeforeInitialization和postProcessAfterInitialization方法。

结论:“对象后处理器”,指的是“ 对象创建后处理器 ”。

我们可以利用它,在对象创建之后,对对象进行修改(有什么场合需要用到?思考题,文末回答。)

那么,为什么要分postProcessBeforeInitialization和postProcessAfterInitialization呢?这里的Initialization是什么意思?

触发时机

我们只需要在CustomBeanPostProcessor的postProcessBeforeInitialization和postProcessAfterInitialization方法里,打上两个断点,一切自然明了。

断点进来,跟着调用栈这点蛛丝马迹往回走,真相大白:

在initializeBean方法里面,先后调用了applyBeanPostProcessorsBeforeInitialization和applyBeanPostProcessorsAfterInitialization方法,这两个方法内部,则分别去遍历系统里所有的BBP,然后逐个执行这些BBP对象的postProcessBeforeInitialization和postProcessAfterInitialization方法,去处理对象,以applyBeanPostProcessorsBeforeInitialization为例:

那么夹在applyBeanPostProcessorsBeforeInitialization和applyBeanPostProcessorsAfterInitialization方法中间的invokeInitMethods方法是做什么的呢?

其实这个方法就是Spring提供的,用于对象创建完之后,针对对象的一些初始化操作。这就好比你创建了一个英雄之后,你需要给他进行一些能力属性的初始化、服装初始化一样。

要验证这一点,很简单,只需让Bean4BBP实现InitializingBean接口:

@Componentpublic class Bean4BBP implements InitializingBean { private static final Logger log = LoggerFactory.getLogger(Bean4BBP.class); public Bean4BBP(){ log.info("construct Bean4BBP"); } @Override public void afterPropertiesSet() throws Exception { log.info("init Bean4BBP"); }}复制代码

然后重新启动工程,打印顺序如下:

construct CustomBeanPostProcessorconstruct Bean4BBPprocess bean before initializationinit Bean4BBPprocess bean after initialization复制代码

BBP是什么时候被初始化的

从上面的代码片段,我们已经知道,在对象创建之后,需要遍历BBP列表,对对象进行处理。

这也就意味着, BBP对象,必须在普通对象创建之前被创建

那么BBP都是在什么时候被创建的呢?

要回答这个问题,非常简单, 我们只需要在CustomBeanPostProcessor的构造函数里打个断点 (这下看到先学会用,再了解原理的好处了吧)

断点进来,继续利用调用栈,我们找寻到了AbstractApplicationContext的refresh()方法,这个方法里面调用了registerBeanPostProcessors方法,里头就已经把BBP列表创建好了,而普通对象的创建,是在之后的finishBeanFactoryInitialization方法里执行的:

网上有个图画的特别好,很好的展示了BBP在Spring对象初始化流程的位置:

(看到BBP在哪了吗?)

BBP的典型使用 - AOP

不知道大家在使用Spring AOP时,有没有发现,带有切面逻辑的对象,注入进来之后,都不是原来的对象了,比如下图:

调试信息显示,aspectService是一个…$$EnhanceBySpringCGlib的对象,这其实和Spring AOP用到的动态代理有关。

关于Spring AOP的原理,可以参考我之前的回答: 什么是面向切面编程AOP? - Javdroider Hong的回答 - 知乎

这也就意味着, 最终放进Spring容器的,必须是代理对象,而不是原先的对象 ,这样别的对象在注入时,才能获得带有切面逻辑的代理对象。

那么Spring是怎么做到这一点的呢?正是利用了这篇文章讲到的BBP。

显然,我只需要写一个BBP,在postProcessBeforeInitialization或者postProcessAfterInitialization方法中,对对象进行判断,看他需不需要织入切面逻辑,如果需要,那我就根据这个对象,生成一个代理对象,然后返回这个代理对象,那么最终注入容器的,自然就是代理对象了。

这个服务于Spring AOP的BBP,叫做 AnnotationAwareAspectJAutoProxyCreator .

利用idea的diagram功能,可以看出它和BBP的关系:

具体的创建代理对象并返回的逻辑,在postProcessAfterInitialization方法中,大家自行欣赏。

可以说,如果没有BBP,那么Spring AOP就只能叫AOP。

BBP是连接IOC和AOP的桥梁。

总结

这篇文章,主要通过对BBP的讲解,串联起之前讲到的关于Spring的知识,希望能够加深大家对Spring的理解。

回到开头提出的四个问题:

  • BBP怎么用 —— 先学会怎么用,再去看原理
  • BBP的触发时机 —— 在整个Spring Bean初始化流程中的位置
  • BBP自己又是什么时候被创建的?
  • BBP是如何连接IOC和AOP的?

最后:

给大家分享资深架构师录制的视频:(有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化、分布式架构)等这些成为架构师必备的内容,还有阿里大牛直播讲解技术!群号:685167672(无Java开发经验勿加,你听不懂)



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring IOC(Inversion of Control,控制反转)是Spring框架的核心特性之一,它通过将对象的创建和依赖关系的管理交给Spring容器来实现,降低了组件之间的耦合性。下面是Spring IOC的一些深入理解和使用方法: 1. 配置方式:Spring IOC提供了多种配置方式,包括XML配置、注解配置和Java配置。XML配置是最传统和常用的方式,可以通过在XML文件中定义bean来描述对象及其依赖关系;注解配置使用注解来标识对象及其依赖关系,更加简洁和方便;Java配置则是通过Java类来定义对象及其依赖关系。 2. Bean的定义:在Spring IOC中,对象称为Bean。Bean的定义包括类名、属性、构造函数参数等信息。在XML配置中,可以使用<bean>标签来定义Bean;在注解配置中,可以使用@Component等注解来标识Bean。 3. 依赖注入:Spring IOC通过依赖注入(Dependency Injection,DI)来管理对象之间的依赖关系。依赖注入可以通过构造函数注入、Setter方法注入和字段注入来实现。当Spring容器创建一个Bean时,会自动将其依赖的其他Bean注入进来。 4. 生命周期管理:Spring IOC容器负责管理Bean的生命周期。在Bean生命周期中,容器会在适当的时机调用Bean的初始化方法和销毁方法。可以通过在Bean类中定义@PostConstruct和@PreDestroy等注解方法来指定初始化和销毁方法。 5. AOP支持:Spring IOC提供了对面向切面编程(AOP)的支持。可以通过配置切面和增强器,将一些横切关注点(如日志、事务管理等)从业务逻辑中剥离出来,实现更好的代码解耦和复用。 6. 容器扩展点:Spring IOC容器提供了一些扩展点,可以通过实现相应的接口来对容器的行为进行定制。例如,可以实现BeanPostProcessor接口来在对象创建和初始化的过程中添加自定义逻辑。 总之,深入理解和使用Spring IOC可以帮助开发者更好地利用Spring框架的优势,实现松耦合、可测试、可扩展的应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值