Spring源码之BeanDefinition后置处理程序

我们都知道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方法,截图如下:
在这里插入图片描述
Spring源码之BeanDefinition后置处理程序_第1张图片

实践是检验真理的唯一标准

通过源码我们可以知道,在容器实例化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。

你可能感兴趣的:(Spring源码,spring)