Spring源码-如何修改BeanDefinition的属性
在实际开发中,我们有的时候并不是把所有的核心配置文件都存放到本地配置文件xxx..properties中的,而是通过远程去加载对应的配置文件信息。有的公司还有自己的独立配置中心系统,主要用来管理所有配置信息的。基于这个需求,其实我们利用Spring的后置处理器BeanFactoryPostProcessor扩展点是可以解决的,在Spring容器加载的时候就动态的远程获取到配置信息来更改配置。下面我们就一块来分析一下Spring给开发者预留的这个扩展点吧!
1. 首先,我们看一下本次的最为重要的二个类(BeanFactoryPostProcessor,BeanDefinitionRegistryPostProcessor),这二个类都能用于扩展。还有就是多个后置处理的调用顺序也是可以调整的,这个时候涉及到PriorityOrdered和Ordered,也比较重要。
2. 紧接着我们写几个测试类来测试一下他们的调用顺序。
applicationContent.xml中加入如下bean配置:
<bean class="cn.edu.his.pay.postprocess.My1"/>
<bean class="cn.edu.his.pay.postprocess.My2"/>
<bean class="cn.edu.his.pay.postprocess.My3"/>
<bean class="cn.edu.his.pay.postprocess.My4"/>
<bean class="cn.edu.his.pay.postprocess.My5"/>
<bean class="cn.edu.his.pay.postprocess.My6"/>
<bean class="cn.edu.his.pay.postprocess.My9"/>
<bean class="cn.edu.his.pay.postprocess.Student" id="student">
<property name="username" value="qrmc"></property>
<property name="password" value="123456"></property>
</bean>
My1.java
package cn.edu.his.pay.postprocess;
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
public class My1 implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory arg0) throws BeansException {
System.out.println("BeanFactoryPostProcessor my1");
BeanDefinition bd = arg0.getBeanDefinition("student");
MutablePropertyValues mpv = bd.getPropertyValues();
mpv.addPropertyValue("password", "fhdksafhldsafjl");
}
}
My2.java
package cn.edu.his.pay.postprocess;
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
public class My2 implements BeanDefinitionRegistryPostProcessor {
public void postProcessBeanFactory(ConfigurableListableBeanFactory arg0) throws BeansException {
// TODO Auto-generated method stub
}
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry arg0) throws BeansException {
System.out.println("BeanDefinitionRegistryPostProcessor my2");
BeanDefinition bd = arg0.getBeanDefinition("student");
MutablePropertyValues mpv = bd.getPropertyValues();
mpv.addPropertyValue("username", "qrmc-vip");
}
}
My3.java
package cn.edu.his.pay.postprocess;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.core.PriorityOrdered;
public class My3 implements BeanDefinitionRegistryPostProcessor, PriorityOrdered {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory arg0) throws BeansException {
// TODO Auto-generated method stub
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry arg0) throws BeansException {
System.out.println("BeanDefinitionRegistryPostProcessor PriorityOrdered my3");
}
@Override
public int getOrder() {
// TODO Auto-generated method stub
return 0;
}
}
My4.java
package cn.edu.his.pay.postprocess;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.core.PriorityOrdered;
public class My4 implements BeanDefinitionRegistryPostProcessor, PriorityOrdered {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory arg0) throws BeansException {
// TODO Auto-generated method stub
}
@Override
public int getOrder() {
// TODO Auto-generated method stub
return 1;
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry arg0) throws BeansException {
System.out.println("BeanDefinitionRegistryPostProcessor PriorityOrdered my4");
}
}
My5.java
package cn.edu.his.pay.postprocess;
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.core.Ordered;
public class My5 implements BeanDefinitionRegistryPostProcessor, Ordered {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory arg0)
throws BeansException {
// TODO Auto-generated method stub
}
@Override
public int getOrder() {
// TODO Auto-generated method stub
return 0;
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry arg0)
throws BeansException {
System.out.println("BeanDefinitionRegistryPostProcessor Ordered my5");
BeanDefinition bd = arg0.getBeanDefinition("student");
MutablePropertyValues mpv = bd.getPropertyValues();
mpv.addPropertyValue("school", "qiurimangcao"); //添加属性并复制
}
}
My6.java
package cn.edu.his.pay.postprocess;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.core.Ordered;
public class My6 implements BeanDefinitionRegistryPostProcessor, Ordered {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory arg0) throws BeansException {
// TODO Auto-generated method stub
}
@Override
public int getOrder() {
// TODO Auto-generated method stub
return 1;
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry arg0) throws BeansException {
System.out.println("BeanDefinitionRegistryPostProcessor Ordered my6");
}
}
执行后结果如下:
BeanDefinitionRegistryPostProcessor PriorityOrdered my3
BeanDefinitionRegistryPostProcessor PriorityOrdered my4
BeanDefinitionRegistryPostProcessor Ordered my5
BeanDefinitionRegistryPostProcessor Ordered my6
BeanDefinitionRegistryPostProcessor my2
BeanFactoryPostProcessor my1
2. Spring 核心部分源码如下:
BeanDefinitionRegistryPostProcessor 相关。
// 首先,调用实现PriorityOrdered的BeanDefinitionRegistryPostProcessor。
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
/* [
* org.springframework.context.annotation.internalConfigurationAnnotationProcessor,
* org.mybatis.spring.mapper.MapperScannerConfigurer#0,
* org.mybatis.spring.mapper.MapperScannerConfigurer#1,
* cn.edu.his.pay.postprocess.My2#0,
* cn.edu.his.pay.postprocess.My3#0,
* cn.edu.his.pay.postprocess.My4#0,
* cn.edu.his.pay.postprocess.My5#0,
* cn.edu.his.pay.postprocess.My6#0
* ]
* */
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) { //是否实现了PriorityOrdered接口
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
// 首先调用实现了PriorityOrdered接口的
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear(); //清空map
// 接下来,调用实现Ordered的BeanDefinitionRegistryPostProcessors。
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) { // 这里是实现orderd的调用
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
// 去调用实现Ordered接口的
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
// 最后,调用所有其他的BeanDefinitionRegistryPostProcessor,直到没有其他的出现。
boolean reiterate = true;
while (reiterate) {
reiterate = false;
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
reiterate = true;
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
// 调用
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
}
BeanFactoryPostProcessor 相关
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
/**
* [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,
* org.springframework.context.support.PropertySourcesPlaceholderConfigurer#0,
* org.mybatis.spring.mapper.MapperScannerConfigurer#0,
* org.mybatis.spring.mapper.MapperScannerConfigurer#1,
* cn.edu.his.pay.postprocess.My1#0, cn.edu.his.pay.postprocess.My2#0,
* cn.edu.his.pay.postprocess.My3#0, cn.edu.his.pay.postprocess.My4#0,
* cn.edu.his.pay.postprocess.My5#0,
* cn.edu.his.pay.postprocess.My6#0,
* org.springframework.context.support.PropertySourcesPlaceholderConfigurer#1
* ]
*/
// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (processedBeans.contains(ppName)) {
// skip - already processed in first phase above
}
else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// 首先,调用实现PriorityOrdered的BeanFactoryPostProcessor。
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
// 接下来,调用实现Ordered的BeanFactoryPostProcessors。
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
// 最后,调用所有其他BeanFactoryPostProcessor。
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
3. 结合源码和测试类测试结果可以得出:Spring是先对实现了BeanDefinitionRegistryPostProcessor 的类先进行调用,其次才是对实现了BeanFactoryPostProcessor 的类进行调用,除了这个因素外还有就是PriorityOrdered、Ordered和对应的getOrder的值。先调用的是PriorityOrdered的getOrder小的值,然后再调用PriorityOrdered大的值,紧接着再判断Ordered的getOrder小的值,然后再调用Ordered大的值。
4. 知道了多种后置处理器的调用顺序后,我们可以结合测试代码了解到如何去更改一个BeanDefinition的属性以及它们的类之间的关系,如下是BeanDefinition对属性的封装类图。
如上图,通过beanName可以从内存中取出对应的BeanDefinition,这样就可以直接拿到MutablePropertyValues,通过MutablePropertyValues的属性propertyValueList属性集合来修改或添加新值。