上一篇:Spring扩展点之BeanFactoryPostProcessor:彻底搞懂原理以及使用场景【源码分析】讲到了spring提供的BeanFactoryPostProcessor扩展点,主要目的是为了修改已经扫码好的beanDefinition,以达到bean的实例化按照我们的方式来。作为开发者,只需要实现BeanFactoryPostProcessor接口,并将其实现类加入到spring容器中,那么spring就会自动识别,并且去进行回调。
今天要讲的是BeanDefinitionRegistryPostProcessor扩展,他和BeanFactoryPostProcessor是在同一时间节点进行回调的,并且他的优先级是高于BeanFactoryPostProcessor,而他的作用是像spring容器中注册BeanDefinition。
由于文章内容是基于源码角度来讲的,考虑到有些朋友不需要看的如此的深入,所以在此贴出其简单的使用方式:和BeanFactoryPostProcessor一样,加上@Component注解,使其加入到spring容器中, Order注解只要是指定其执行顺序的,值越小,优先级越高,他会自动识别并在适当位置调用。
import com.spring.learn.core.bean.Person;
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Component
@Order(1)
public class BeanDefinitionRegistryPostProcessorExtension implements BeanDefinitionRegistryPostProcessor {
// 此接口是BeanFactoryPostProcessor的方法,
// 这里也需要重写是因为BeanDefinitionRegistryPostProcessor继承自BeanFactoryPostProcessor
// 如果我们只需要修改bean定义,那么只需实现BeanFactoryPostProcessor即可
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// 由于这里展示的是BeanDefinitionRegistryPostProcessor的使用,这里就不做操作了
}
/**
* 注册bean定义接口
*
* @param registry the bean definition registry used by the application context
* @throws BeansException
*/
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
// new一个RootBeanDefinition,传入我们需要加入spring容器的Class对象
RootBeanDefinition beanDefinition = new RootBeanDefinition(Person.class);
// 这里是给我们的对象赋值,如果不需要进行赋值,那么下面这里可忽略
MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
// key为属性名称,value为属性值
propertyValues.add("age", 10);
propertyValues.add("name", "list");
// 将我们自定义的bean定义加入到spring。
registry.registerBeanDefinition("person1", beanDefinition);
}
}
上面说到了BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor在同一时间节点执行的,并且BeanDefinitionRegistryPostProcessor执行的优先级是高于BeanFactoryPostProcessor。为什么呢?
我们来看BeanDefinitionRegistryPostProcessor接口的定义:
/**
* 扩展到标准的{@link BeanFactoryPostProcessor} SPI,
* 允许在常规BeanFactoryPostProcessor检测开始之前注册更多的bean定义。
* 特别是,BeanDefinitionRegistryPostProcessor可以注册更多的bean定义,
* 这些定义反过来又定义了BeanFactoryPostProcessor实例。
*
* 从上面的翻译来看,此接口的目的是为了提供给开发者想容器当中注册更多的beanDefinition,
* 从而可以动态的注册bean
*
* @author Juergen Hoeller
* @since 3.0.1
* @see org.springframework.context.annotation.ConfigurationClassPostProcessor
*/
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
/**
*
* 在标准初始化之后修改应用程序上下文的内部bean定义注册表。所有常规bean定义都已加载,
* 但还没有实例化bean。这允许在进入下一个后处理阶段之前添加更多的bean定义。
*
* @param registry the bean definition registry used by the application context
* @throws org.springframework.beans.BeansException in case of errors
*/
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}
可以看到BeanDefinitionRegistryPostProcessor是继承自BeanFactoryPostProcessor 的,所以上面我们实现了BeanDefinitionRegistryPostProcessor接口需要重写两个方法,其中一个是BeanFactoryPostProcessor 的。
接口上面也说到:此接口是提供给开发者向Spring容器当中注册更多的bean,因为spring生成bean实例是按照beanDefinition来进行实例化的。
此接口的好处不但可以完全控制是否加入某个bean,动态加入某些bean,并且还可以控制bean的生成过程,比如像其直接注入属性等操作。
mybatis-spring就是通过此扩展向spring容器中加入我们mapper的实现类的。
上面讲到BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor 在同一时间节点回调的,并且BeanDefinitionRegistryPostProcessor的优先级比BeanFactoryPostProcessor 高,那么我们就深入源码证实一下:
执行后置处理器的回调Spring是委托给PostProcessorRegistrationDelegate来进行具体实现的:
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
// Invoke BeanDefinitionRegistryPostProcessors first, if any.
// 如果存在BeanDefinitionRegistryPostProcessors,那么就会首先调用。
Set<String> processedBeans = new HashSet<>();
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
// 常规的beanFactory后置处理器
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
// bean定义注册的后置处理器
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
}
else {
regularPostProcessors.add(postProcessor);
}
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
// Separate between BeanDefinitionRegistryPostProcessors that implement
// PriorityOrdered, Ordered, and the rest.
// 获取BeanDefinitionRegistryPostProcessor扩展
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
// 首先,调用实现PriorityOrdered的 BeanDefinitionRegistryPostProcessor。
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
// 接下来,调用实现Ordered的BeanDefinitionRegistryPostProcessors。
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
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();
// 最后,调用所有其他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();
}
// 现在,调用到目前为止处理的所有处理器的postProcessBeanFactory回调。
// 先调用的是beanDefinition的后置处理器
// 然后调用的是普通的beanFactory后置处理器
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
}
else {
// Invoke factory processors registered with the context instance.
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}
// 接下来再从spring容器中获取普通的beanDefinition后置处理器
// 不要在这里初始化factorybean:我们需要保持所有常规bean未初始化,以便让bean工厂后处理器应用到它们!
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
// 就是这里从spring容器中获取到我们自定义的BeanFactory后置处理器,然后调用其方法。
// 上面那些是spring内置的BeanFactory后置处理器
// 根据:BeanFactoryPostProcessor类型,从所有bean定义中获取类名,因为bean定义已经扫描过了,所以这里能够拿到
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class,
true, false);
// 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)) {
// 跳过——已经在上面的第一阶段处理
}
else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
// 如果存在PriorityOrdered,它的优先级是最高的
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
// 如果指定了顺序的
orderedPostProcessorNames.add(ppName);
}
else {
// 如果没有指定顺序的
nonOrderedPostProcessorNames.add(ppName);
}
}
// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
// Finally, invoke all other BeanFactoryPostProcessors.
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
// Clear cached merged bean definitions since the post-processors might have
// modified the original metadata, e.g. replacing placeholders in values...
beanFactory.clearMetadataCache();
}
源码内容有点长,那么我们进行拆分:
// 首先,调用实现PriorityOrdered的 BeanDefinitionRegistryPostProcessor。
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
他首先调用的是从spring容器中获取到所有BeanDefinitionRegistryPostProcessor的实现类,
然后紧接着调用了其方法
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
执行完之后再获取所有BeanFactoryPostProcessor的实现类,
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class,
true, false);
最后执行
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
为啥要先执行BeanDefinitionRegistryPostProcessor的回调函数呢?因为BeanDefinitionRegistryPostProcessor的回调函数主要是提供给开发者像容器中添加beanDefinition的,这个步骤和spring扫码类,生成beanDefinition一样,而BeanFactoryPostProcessor的作用是提供给开发者修改beanDefinition的,在提供修改功能的时候,必须要保证到开发者能够获取到所有的beanDefinition,所以BeanDefinitionRegistryPostProcessor的回调是要先执行的。
接下来我们来看一下mybatis-spring是如何将mybatis和spring整合的。
首先我们来看一下配置:mybatis-spring提供的配置,用于注册mapper的
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="org.mybatis.spring.sample.mapper" />
</bean>
然后我们找到MapperScannerConfigurer:看到他实现了BeanDefinitionRegistryPostProcessor,并且有一个属性叫做basePackage
public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor,InitializingBean, ApplicationContextAware, BeanNameAware {
private String basePackage;
}
再结合上面的配置,它是让我们通过xml的方式将MapperScannerConfigurer 加入到spring容器中。
这就回到了上面说的,如果我要想要对BeanDefinitionRegistryPostProcessor进行扩展,只需要实现BeanDefinitionRegistryPostProcessor接口,并且加入到spring容器中,他会自动进行扫描,并且在适当的位置执行其回调函数。也就是说,mybatis-spring是通过此类实现BeanDefinitionRegistryPostProcessor来实现将mapper加入到spring容器的。
接下来我们看看postProcessBeanDefinitionRegistry方法的具体实现:
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
// 这里默认没有给值,所有默认为false,那么下面的方法不会执行
if (this.processPropertyPlaceHolders) {
processPropertyPlaceHolders();
}
// 创建一个ClassPathMapperScanner对象,
// 此类继承了ClassPathBeanDefinitionScanner,这里就用了spring中现成的扫描类了,
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
scanner.setAddToConfig(this.addToConfig);
scanner.setAnnotationClass(this.annotationClass);
scanner.setMarkerInterface(this.markerInterface);
scanner.setSqlSessionFactory(this.sqlSessionFactory);
scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);
scanner.setResourceLoader(this.applicationContext);
scanner.setBeanNameGenerator(this.nameGenerator);
scanner.registerFilters();
// 这个方法进行扫描,并且将BeanDefinition加入到spring容器中
scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
}
scan方法是父类的,而scan的主要工作交个了doScan来做的
public int scan(String... basePackages) {
int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
doScan(basePackages);
// Register annotation config processors, if necessary.
if (this.includeAnnotationConfig) {
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
}
ClassPathMapperScanner 重写了doScan方法,首先调用父类的doScan方法,
父类的doScan方法会将扫描到的beanDefinition加入到spring中,
然后返回扫描过后并且加入spring容器的BeanDefinitionHolder集合。
@Override
public Set<BeanDefinitionHolder> doScan(String... basePackages) {
Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
if (beanDefinitions.isEmpty()) {
logger.warn("No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration.");
} else {
// 进行mybatis的一系列处理
processBeanDefinitions(beanDefinitions);
}
return beanDefinitions;
}
然后如果扫描到的mapper定义不为空,那么进行mybatis的一系列处理:
private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
GenericBeanDefinition definition;
// 循环beanDefinition持有者集合
for (BeanDefinitionHolder holder : beanDefinitions) {
// 获取到beanDefinition
definition = (GenericBeanDefinition) holder.getBeanDefinition();
if (logger.isDebugEnabled()) {
logger.debug("Creating MapperFactoryBean with name '" + holder.getBeanName()
+ "' and '" + definition.getBeanClassName() + "' mapperInterface");
}
// the mapper interface is the original class of the bean
// but, the actual class of the bean is MapperFactoryBean
// mapper接口是bean的原始类,但是bean的实际类是MapperFactoryBean
// 向beanDefinition的构造参数列表中加入一个参数值:bean的名称
definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName()); // issue #59
/** 这里就要修改mapper的Class对象了,因为mapper接口的实现类,是通过mybatis动态代理过的
* 这里设置bean的Class为MapperFactoryBean,MapperFactoryBean是实现了FactoryBean的实现类
* spring在自动注入的时候,会实例化MapperFactoryBean,并且调用getObject方法返回真正的实例
* public T getObject() throws Exception {
* return getSqlSession().getMapper(this.mapperInterface);
* }
* getObject方法内部是调用getSqlSession然后里返回一个具体的mapper实现类的实例了
* 这里就不再深入的去研究mybatis通过动态代理生成mapper实例的过程了
*/
definition.setBeanClass(this.mapperFactoryBean.getClass());
// 添加addToConfig属性
definition.getPropertyValues().add("addToConfig", this.addToConfig);
// 下面就是一系列的对其属性赋值了
boolean explicitFactoryUsed = false;
if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) {
definition.getPropertyValues().add("sqlSessionFactory", new RuntimeBeanReference(this.sqlSessionFactoryBeanName));
explicitFactoryUsed = true;
} else if (this.sqlSessionFactory != null) {
definition.getPropertyValues().add("sqlSessionFactory", this.sqlSessionFactory);
explicitFactoryUsed = true;
}
if (StringUtils.hasText(this.sqlSessionTemplateBeanName)) {
if (explicitFactoryUsed) {
logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
}
definition.getPropertyValues().add("sqlSessionTemplate", new RuntimeBeanReference(this.sqlSessionTemplateBeanName));
explicitFactoryUsed = true;
} else if (this.sqlSessionTemplate != null) {
if (explicitFactoryUsed) {
logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
}
definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate);
explicitFactoryUsed = true;
}
if (!explicitFactoryUsed) {
if (logger.isDebugEnabled()) {
logger.debug("Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.");
}
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
}
}
}
这里重点说一下setBeanClass()方法:
private MapperFactoryBean<?> mapperFactoryBean = new MapperFactoryBean<Object>();
definition.setBeanClass(this.mapperFactoryBean.getClass());
这里能够看到他将所有的beanClass都设置为MapperFactoryBean.class。
为什么能够这样做呢?
然后我们继续看MapperFactoryBean:
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {}
他实现了FactoryBean接口,FactoryBean接口主要是用来创建实例的,通过getObject返回真正的实例。
然后看getObject的方法体:
@Override
public T getObject() throws Exception {
return getSqlSession().getMapper(this.mapperInterface);
}
这里通过SqlSession.getMapper返回特定的具体实现类。
而此方法就能够返回mapper接口对应的通过mybatis经过动态代理生成的实例。
当spring创建实例的时候,就是创建的是mybatis动态代理过后的对象了。
这里就很巧妙的返回各个接口的实现类,这样的设计是很值得我们学习的。
从我的角度来看,mybatis-spring整合的精髓除了使用BeanDefinitionRegistryPostProcessor的扩展,还很巧妙的利用了FactoryBean来返回其实例。这对于我们自己写组件有着很大的启发。