Spring扩展点之BeanDefinitionRegistryPostProcessor:彻底搞懂原理以及使用场景【源码分析:揭开mybatis-spring的神秘面纱】

上一篇: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来返回其实例。这对于我们自己写组件有着很大的启发。

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值