Spring5源码解析-Spring中的bean工厂后置处理器
Spring允许我们使用bean来进行大量的操作(这也是我们面向对象思想最常用的表达方式)。我们可以决定它们在容器中是否是(单例或者是原型)唯一实例。通过bean工厂后置处理器我们还可以在初始化
时进行一些额外的操作。
在这篇文章中,来介绍下bean factory post processor。在第一部分,我们来发现下这个概念背后玄机。之后我们会写一些有趣代码来让大伙更好地理解这个概念。
什么是Spring工厂的后置处理器?
有时我们可能需要在Spring应用程序中实现一些动态行为。举个简单的例子,假设在你的网站中,你要显示按时间来显示两个文本内容。上午的时候,你会显示“早安”。下午,显示的文字将是“下午好”。另外,你有两个日常部署,上午12点,另一个在晚上12点。需要强调的是,这个文本内容必须由一个bean来处理。我们现在有两个选择:每次部署时更改应用程序上下文文件(太麻烦了),或者定义一个实现org.springframework.beans.factory.config.BeanFactoryPostProcessor接口的bean 。第二个解决方案更优雅,因为我们只需要编写一次代码,然后就可以忽视它的存在了(无须次次去修改了)。
那么,这个优雅的BeanFactoryPostProcessor
是何方神圣?它是由bean实现的接口,它们可以修改其他bean的定义。请注意,只能修改定义,即构造函数参数,属性值。BeanFactoryPostProcessor
bean在初始化“正常”bean之前被调用,这就是为什么它能修改元数据的原因(meta data)。调用是通过org.springframework.context.support.AbstractApplicationContext的 protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory)来实现的:
1 | protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) { |
在PostProcessorRegistrationDelegate
里面,负责bean factory后置处理器执行的方法是:
1 | /** |
如你所见,由BeanFactoryPostProcessor
实现覆盖的主要方法是postProcessBeanFactory
。这也是我们来自己定制bean定义的地方。我们通过在org.springframework.beans.factory.config.BeanDefinition对象上进行定制。关于这点我已经在Spring5源码解析-Spring框架中的单例和原型bean的文章中已经写过,它们(BeanDefinition对象
)包含大量关于bean元数据的信息:构造函数参数,属性值或作用域。
一个简单的Spring bean厂后置处理器Demo
关于理论的重要部分已经都在前面进行了描述。在这部分中,我们将重点放在一个简单实用的案例上。你还记得第一部分的“早安”和“下午好”的例子?如果忘了,请回去再瞅眼的。接着,让我们尝试在代码中实现这种案例。首先,我们将在配置文件中定义一些bean:
1 | <bean class="com.migo.bean.BeanModifier"> |
第一个bean代表将实现BeanFactoryPostProcessor
接口的bean。第二个bean是注入的类,它会在页面中显示欢迎的文本内容。他们是两个bean的代码:
1 | // Welcomer.java |
如果现在是下午,输出应该是:
1 | Setting welcomeText to: Good afternoon |
我们可以看到,BeanModifier
在Welcomer
的真正初始化之前被调用。由于重写覆盖了postProcessBeanFactory
方法,这样我们可以通过检查日期,并为属性welcomeText
设置正确的值。
这篇文章虽短,但它描述了一些在一些“动态”场景中我们如何以一个更效率的方式来实现的实用操作。比如,你会碰到这种,我们常常见到一个游戏会有例行维护,那么我们会发现排行榜会在例行维护后刷新,你每次登录游戏也会对你的一些属性或者积分进行刷新,其实你每次登录就是又初始化了一遍你这个bean,这样,我们就可以做很多事情了,比如为最佳用户添加一些奖励积分。通过BeanFactoryPostProcessor
这个 bean,这种处理就可以在Java方法内自动完成,无须我们在每次部署时通过手动来完成。