关联博文:
Spring中那些BeanFactoryPostProcessors详解(一)
Spring中那些BeanFactoryPostProcessors详解(二)
本文是对Spring中refresh分析之invokeBeanFactoryPostProcessors方法详解的一个补充,我们详细说明一下那些BeanFactoryPostProcessor在invokeBeanFactoryPostProcessors方法中的作用。
【1】CachingMetadataReaderFactoryPostProcessor
CachingMetadataReaderFactoryPostProcessor是SharedMetadataReaderFactoryContextInitializer的静态内部类实现了BeanDefinitionRegistryPostProcessor 和 PriorityOrdered接口。
主要用来注册CachingMetadataReaderFactory这个BeanDefinition并配置ConfigurationClassPostProcessor。如下所示其postProcessBeanFactory方法为空,我们主要看其postProcessBeanDefinitionRegistry方法。register方法会注册SharedMetadataReaderFactoryBean这个一个BeanDefinition,beanName如下所示:
org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory
ConfigurationWarningsPostProcessor是ConfigurationWarningsApplicationContextInitializer的静态内部类,实现了PriorityOrdered 和 BeanDefinitionRegistryPostProcessor接口主要用来打印一些警示信息,我们对这个不用过多关注。
【2】ConfigurationClassPostProcessor
这个重量级的处理器我们在SpringBoot自动配置原理解析系列分析中详细描述过其postProcessBeanDefinitionRegistry方法。而其postProcessBeanFactory呢则是对候选配置类做了增强并注册了ImportAwareBeanPostProcessor这样一个BeanPostProcessor用来对ImportAware类型做支持。
关于ConfigurationClassPostProcessor本文我们这里不做进一步分析,梳理其作用如下:
对于候选配置类使用CGLIB Enhancer增强
解析处理@PropertySource 注解
解析@ComponentScan注解,扫描@Configuration、@Service、@Controller、@Repository和@Component注解并注册BeanDefinition
解析@Import注解,然后进行实例化,并执行ImportBeanDefinitionRegistrar的registerBeanDefinitions逻辑,或者ImportSelector的selectImports逻辑或者将候选类作为配置类触发配置类解析过程
解析@ImportResource注解,并加载相关配置信息
解析方法级别@Bean注解并将返回值注册成BeanDefinition
注册ImportAwareBeanPostProcessor到容器中,用于处理ImportAware
【3】MapperScannerConfigurer
是的,这个我们在SSM年代很熟悉的扫描配置器也是一个BeanDefinitionRegistryPostProcessor。其是在什么时候注册BeanDefinition呢?是在ConfigurationClassPostProcessor的parse方法中。
如下所示@MapperScan注解导入了MapperScannerRegistrar。
这个MapperScannerRegistrar会做什么呢?其会注册一个MapperScannerConfigurer这样的BeanDefinition到BeanFactory中。如下图所示:
我们继续看MapperScannerConfigurer。其postProcessBeanFactory方法是个空方法,我们主要看其postProcessBeanDefinitionRegistry方法。简单来讲其会实例化一个扫描器ClassPathMapperScanner并触发对basePackage的扫描。
@Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { if (this.processPropertyPlaceHolders) { processPropertyPlaceHolders(); } //实例化并进行配置 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.setMapperFactoryBeanClass(this.mapperFactoryBeanClass); if (StringUtils.hasText(lazyInitialization)) { scanner.setLazyInitialization(Boolean.valueOf(lazyInitialization)); } //注册过滤器 scanner.registerFilters(); //触发基础包的扫描 scanner.scan( StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS)); }
ClassPathMapperScanner 继承自ClassPathBeanDefinitionScanner,其scan方法如下所示。
// ClassPathBeanDefinitionScanner public int scan(String... basePackages) { int beanCountAtScanStart = this.registry.getBeanDefinitionCount(); //实际扫描方法,触发子类ClassPathMapperScanner 的方法 doScan(basePackages); // Register annotation config processors, if necessary. //默认为true,在实例化AnnotatedBeanDefinitionReader时我们触发过这个registerAnnotationConfigProcessors //这里可以理解为一个补偿机制,本文这个方法没有任何作用 if (this.includeAnnotationConfig) { AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); } //返回本次扫描注册的数量 return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart); }
子类ClassPathMapperScanner 的doScan方法又调用了父类ClassPathMapperScanner 的doScan方法然后对beanDefinitions 做了后置处理包装为MapperFactoryBean。
@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 { //这里会包装为MapperFactoryBean processBeanDefinitions(beanDefinitions); } return beanDefinitions; }
父类ClassPathMapperScanner 的doScan方法我们在SpringBoot自动配置原理解析(五)中分析@ComponentScan注解解析过程中详细说明过,这里不再赘述。我们接下来看一下processBeanDefinitions方法。
private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) { GenericBeanDefinition definition; //遍历beanDefinitions for (BeanDefinitionHolder holder : beanDefinitions) { definition = (GenericBeanDefinition) holder.getBeanDefinition(); //比如com.recommend.mapper.SysAdviceMapper String beanClassName = definition.getBeanClassName(); LOGGER.debug(() -> "Creating MapperFactoryBean with name '" + holder.getBeanName() + "' and '" + beanClassName + "' mapperInterface"); // the mapper interface is the original class of the bean // but, the actual class of the bean is MapperFactoryBean //作为MapperFactoryBean的Class<T> mapperInterface成员 definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName); // issue #59 //设置BeanClass为MapperFactoryBean,其是一个FactoryBean哦 definition.setBeanClass(this.mapperFactoryBeanClass); //添加属性-值 definition.getPropertyValues().add("addToConfig", this.addToConfig); boolean explicitFactoryUsed = false; //尝试处理sqlSessionFactory属性值,本文这里sqlSessionFactoryBeanName为null 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; } //尝试处理sqlSessionTemplate属性值,本文这里sqlSessionTemplateBeanName为null 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; } //设置自动装配类型 AUTOWIRE_BY_TYPE=2 if (!explicitFactoryUsed) { LOGGER.debug(() -> "Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'."); definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); } // lazyInitialization默认为false definition.setLazyInit(lazyInitialization); } }
可以看到在这里为BeanDefinition设置了BeanClass为MapperFactoryBean,其是一个MapperFactoryBean,我们后面再实例化我们自己的XXXMapper时就会触发其getObject方法。而我们自己的原始接口类型比如com.recommend.mapper.SysAdviceMapper则作为MapperFactoryBean构造方法的参数。
// MapperFactoryBean public MapperFactoryBean(Class<T> mapperInterface) { this.mapperInterface = mapperInterface; } @Override public T getObject() throws Exception { return getSqlSession().getMapper(this.mapperInterface); }
【4】PropertySourceOrderingPostProcessor
其是ConfigFileApplicationListener的静态内部类,实现了BeanFactoryPostProcessor,和Ordered接口。其postProcessBeanFactory方法主要用来将我们的defaultProperties-PropertySource排到最后面,如果存在的话。
@Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { reorderSources(this.context.getEnvironment()); } private void reorderSources(ConfigurableEnvironment environment) { PropertySource<?> defaultProperties = environment.getPropertySources().remove(DEFAULT_PROPERTIES); // 本文这里为null if (defaultProperties != null) { environment.getPropertySources().addLast(defaultProperties); } }