答读者问:BeanFactoryPostProcessor 似乎失效了?
创始人
2025-07-05 18:01:28
0

有小伙伴在学习 Spring 源码视频的时候,看了松哥讲的 BeanFactoryPostProcessor 的用法之后,提出了这样一个问题:

图片图片

图片图片

我来跟大家补充一下这个问题的上下文:

我讲了 BeanFactoryPostProcessor,分析了其原理,也讲了具体的使用场景,一个典型的使用场景是我们在 XML 中定义 Bean 的时候,如果 Bean 的属性是使用了 properties 文件占位符如 ${db.username} 这种,那么在 BeanFactoryPostProcessor 阶段,就会对这个占位符进行处理,将其替换成真正的 value。然后我还顺手给大家举了一个例子,我在 XML 文件中定义 Bean 的时候,给 Bean 的某一个属性设置 value 为 ^username,然后在 BeanFactoryPostProcessor 中,我将 ^username 改为某一个字符串。

小伙伴看了松哥讲的内容之后,也照着写了一个,就是上面图片中的代码,不同的是,他是将 XML 配置改为了 Java 代码配置,结果发现属性 hok 并未变为 NB,因此有了上述问题。

我觉得这个问题问的很好,给了小伙伴们一个从其他方面理解 Spring 的机会,这也是我前面一直强调的,这次的 Spring 视频需要各位小伙伴一起发力,大家有关于 Spring 的任何问题都可以提,我负责通过源码来回答你。

问题分析

这个问题的分析,得先从 BeanDefinition 开始。在讲 BeanFactoryPostProcessor 之前,松哥已经和小伙伴们分析过 BeanDefinition 了,无论我们是通过 Java 代码还是通过 XML 文件定义的 Bean 对象,在解析称为 Bean 对象之前,得先解析成为 BeanDefinition,BeanDefinition 则有不同的分类,对于 XML 文件定义的 Bean,最终解析为 GenericBeanDefinition,而通过 @Bean 注解定义的 Bean 则解析为 ConfigurationClassBeanDefinition。

但是这两个的处理原理显然是有差异的。

对于 XML 定义的 Bean 来说,很明显 XML 中的所有属性都要先解析到 BeanDefinition 中,包括我们在 XML 中配置的 Bean 的各种属性,这一步是在 Spring 容器 refresh 方法中构建 BeanFactory 的时候完成的(obtainFreshBeanFactory 方法),这一步完成之后,在后面的步骤会去执行容器中所有的 BeanFactoryPostProcessor(invokeBeanFactoryPostProcessors),此时就会把前面解析出来的 BeanDefinition 中带有占位符的属性给替换过来,最后在 refresh 方法中执行 finishBeanFactoryInitialization 方法完成 Bean 的初始化。

按照上面这一套流程顺序,占位符被解析成为正常字符串没什么问题。

但是,如果是 @Bean 注解配置的 Bean,则会有所差异。

首先,@Bean 注解所标记的方法要被解析为一个 ConfigurationClassBeanDefinition,这个过程本身是通过 ConfigurationClassPostProcessor 来完成的,而 ConfigurationClassPostProcessor 本质上其实就是一个 BeanFactoryPostProcessor,换言之,@Bean 注解标记的方法是在 BeanFactoryPostProcessor 中被解析为 ConfigurationClassBeanDefinition 的。ConfigurationClassBeanDefinition 这个 BeanDefinition 主要用来记录 @Bean 注解所标记的方法所属的对象、方法的名称、方法对象、方法参数、注解的参数等等信息,把这些信息记录下来,将来在初始化 Bean 的时候,通过反射执行目标方法就可以了,即方法里边的内容是什么,ConfigurationClassBeanDefinition 其实并不关心。

最后则是和 XML 一样,在 finishBeanFactoryInitialization 方法中完成 Bean 的初始化。

经过上面分析,小伙伴们可以看到,通过 @Bean 注解定义的 Bean,我们为属性赋值是在方法内部完成的,这些方法内部的逻辑其实并未被解析到 BeanDefinition 中,显然也没有必要把方法内部的逻辑解析到 BeanDefinition 上去,因此,通过 @Bean 注解定义的 Bean,如果属性中使用了占位符,是无法通过 BeanFactoryPostProcessor 自动解析的。

好啦,现在小伙伴提出的问题大家伙都明白了吧?

相关内容

热门资讯

PHP新手之PHP入门 PHP是一种易于学习和使用的服务器端脚本语言。只需要很少的编程知识你就能使用PHP建立一个真正交互的...
网络中立的未来 网络中立性是什... 《牛津词典》中对“网络中立”的解释是“电信运营商应秉持的一种原则,即不考虑来源地提供所有内容和应用的...
各种千兆交换机的数据接口类型详... 千兆交换机有很多值得学习的地方,这里我们主要介绍各种千兆交换机的数据接口类型,作为局域网的主要连接设...
粉嫩如何诠释霸道 东芝M805... “霸道粉”是个什么玩意东芝M805拿过来的时候,笔者扑哧笑了,不是笑这款笔记本,而是笑这款产品的颜色...
什么是大数据安全 什么是大数据... 在《为什么需要大数据安全分析》一文中,我们已经阐述了一个重要观点,即:安全要素信息呈现出大数据的特征...
如何利用交换机和端口设置来管理... 在网络管理中,总是有些人让管理员头疼。下面我们就将介绍一下一个网管员利用交换机以及端口设置等来进行D...
全面诠释网络负载均衡 负载均衡的出现大大缓解了服务器的压力,更是有效的利用了资源,提高了效率。那么我们现在来说一下网络负载...
如何允许远程连接到MySQL数... [[277004]]【51CTO.com快译】默认情况下,MySQL服务器仅侦听来自localhos...
30分钟搞定iOS自定义相机 最近公司的项目中用到了相机,由于不用系统的相机,UI给的相机切图,必须自定义才可以。就花时间简单研究...
Intel将Moblin社区控... 本周二,非营利机构Linux基金会宣布,他们将担负起Moblin社区的管理工作,而这之前,Mobli...