我们都知道Spring容器启动时,会通过配置文件或者注解的方式扫描需要实例化的类,封装成BeanDefinition放到BeanFactory中,那么在容器实例化Bean前,能不能通过外部的方式对BeanFactory进行修改呢……
看Spring的启动源码发现,在创建BeanFactory对象,并把需要实例化的类信息封装成BeanDefinition之后,调用了下面的代码
invokeBeanFactoryPostProcessors(beanFactory);
见名知意,调用bean工厂后置处理程序,也就是创建bean工厂完成后的处理程序,那么让我们看看它的具体实现,能不能通过这里在创建完bean工厂后,再对bean工厂进行处理呢。
找到这个方法的核心代码,一句句进行解析
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
//向下调用
resolvedBeanNames =
doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, true);
doGetBeanNamesForType方法的大概流程为:
List<String> result = new ArrayList<>();
for (String beanName : this.beanDefinitionNames) {
matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
if (matchFound) {
result.add(beanName);
}
}
从工厂里面取得所有的BeanDefinition,返回BeanDefinitionRegistryPostProcessor类型的BeanDefinition的集合,接下来循环这个集合
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
// 如果当前的类是实现了PriorityOrdered接口
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
// 实现了BeanDefinitionRegistryPostProcessor接口的类实例化
currentRegistryProcessors.add(beanFactory
.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
如果遍历到的当前类是PriorityOrdered,源码中PriorityOrdered是一个按照优先级排序的接口,也就是遍历到类实现了PriorityOrdered接口,那么把当前类实例化后,放到currentRegistryProcessors中,也就是
BeanDefinitionRegistryPostProcessor集合,接下里往下看
sortPostProcessors(currentRegistryProcessors, beanFactory);
这里需要对currentRegistryProcessors集合中的数据进行排序,至于为何要排序,后面再说,接下来来的我们的核心了,那就是循环调用实现了BeanDefinitionRegistryPostProcessor接口的类的postProcessBeanDefinitionRegistry方法。
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
/**
* Invoke the given BeanDefinitionRegistryPostProcessor beans.
*/
private static void invokeBeanDefinitionRegistryPostProcessors(
Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {
for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
postProcessor.postProcessBeanDefinitionRegistry(registry);
}
}
接下来就是对实现Ordered接口的BeanDefinitionRegistryPostProcessors的处理
// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
// 判断是否实现了Ordered接口
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
最终对既没有实现PriorityOrdered接口,也没有实现Ordered接口的BeanDefinitionRegistryPostProcessors的处理
// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
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();
}
最后就是对处理程序的回调函数进行回调
// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
private static void invokeBeanFactoryPostProcessors(Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {
for (BeanFactoryPostProcessor postProcessor : postProcessors) {
postProcessor.postProcessBeanFactory(beanFactory);
}
}
这个方法看着代码多,其实最终就是执行BeanDefinitionRegisterPostProcessors的postProcessBeanDefinitionRegistry和postProcessorBeanFactory方法,截图如下:
在这里插入图片描述
通过源码我们可以知道,在容器实例化bean之前,会调用BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry和postProcessBeanFactory方法,那么按道理来讲应该可以通过实现BeanDefinitionRegistryPostProcessor来对bean工厂进行处理,下面就以代码的方式新增加一个bean来验证,看看新增加的bean是否生效呢
首先写一个测试bean,注意类上面既没有配置注解,也没有在配置文件中配置bean,那么在不做其他处理的情况下是不会被Spring容器识别的
public class BeanTest {
private String beanName = "beanTest";
public void setBeanName(String beanName) {
this.beanName = beanName;
}
@Override
public String toString() {
return "BeanTest{" +
"beanName='" + beanName + '\'' +
'}';
}
}
再写一个BeanAddProcessor,实现了BeanDefinitionRegistryPostProcessor接口,注意加上注解,需要被Spring容器识别
@Component
public class BeanAddProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
genericBeanDefinition.setBeanClass(BeanTest.class);
MutablePropertyValues propertyValues = genericBeanDefinition.getPropertyValues();
propertyValues.add("beanName","afterBean");
registry.registerBeanDefinition("beanTest",genericBeanDefinition);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
}
最后写一个简单测试类验证,BeanTest能不能被打印出来
@Test
public void test8() {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
BeanTest beanTest = applicationContext.getBean("beanTest", BeanTest.class);
System.out.println(beanTest.toString());
}
最后的测试结果,控制台打印出:BeanTest{beanName=‘afterBean’},验证的结果和我们的期待的一致。
Spring容器启动时,会通过配置文件或者注解的方式扫描需要实例化的类,封装成BeanDefinition放到BeanFactory中,然而在bean实例化之前,Spring容器会回调实现了BeanDefinitionRegistryPostProcessor接口的类的postProcessBeanDefinitionRegistry方法和postProcessBeanFactory方法,那么我们可以在这里拿到bean工厂,对bean工厂进行操作,比如上文例子中,通过代码的方式新增加一个bean。