spring源码解析③-BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor以及BeanPostProcessor
BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor
一句话描述:手动完成BeanDefinition的注册
接口定义:
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor { /** * Modify the application context's internal bean definition registry after its * standard initialization. All regular bean definitions will have been loaded, * but no beans will have been instantiated yet. This allows for adding further * bean definitions before the next post-processing phase kicks in. * @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; }
@FunctionalInterface public interface BeanFactoryPostProcessor { /** * Modify the application context's internal bean factory after its standard * initialization. All bean definitions will have been loaded, but no beans * will have been instantiated yet. This allows for overriding or adding * properties even to eager-initializing beans. * @param beanFactory the bean factory used by the application context * @throws org.springframework.beans.BeansException in case of errors */ void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException; }
这里的实现可以了解下mybatis和spring整合
public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware { private String basePackage;//用于指定要扫描的包 private boolean addToConfig = true; private SqlSessionFactory sqlSessionFactory; private SqlSessionTemplate sqlSessionTemplate; private String sqlSessionFactoryBeanName; private String sqlSessionTemplateBeanName; private Class<? extends Annotation> annotationClass;//mapper接口上有指定的annotation才会被扫描 private Class<?> markerInterface;//mapper接口继承与指定的接口才会被扫描 private ApplicationContext applicationContext;//容器上下文 private String beanName; private boolean processPropertyPlaceHolders; private BeanNameGenerator nameGenerator; /** * This property lets you set the base package for your mapper interface files. * <p> * You can set more than one package by using a semicolon or comma as a separator. * <p> * Mappers will be searched for recursively starting in the specified package(s). * * @param basePackage base package name */ public void setBasePackage(String basePackage) { this.basePackage = basePackage; } /** * Same as {@code MapperFactoryBean#setAddToConfig(boolean)}. * * @param addToConfig * @see MapperFactoryBean#setAddToConfig(boolean) */ public void setAddToConfig(boolean addToConfig) { this.addToConfig = addToConfig; } /** * This property specifies the annotation that the scanner will search for. * <p> * The scanner will register all interfaces in the base package that also have the * specified annotation. * <p> * Note this can be combined with markerInterface. * * @param annotationClass annotation class */ public void setAnnotationClass(Class<? extends Annotation> annotationClass) { this.annotationClass = annotationClass; } /** * This property specifies the parent that the scanner will search for. * <p> * The scanner will register all interfaces in the base package that also have the * specified interface class as a parent. * <p> * Note this can be combined with annotationClass. * * @param superClass parent class */ public void setMarkerInterface(Class<?> superClass) { this.markerInterface = superClass; } /** * Specifies which {@code SqlSessionTemplate} to use in the case that there is * more than one in the spring context. Usually this is only needed when you * have more than one datasource. * <p> * @deprecated Use {@link #setSqlSessionTemplateBeanName(String)} instead * * @param sqlSessionTemplate */ @Deprecated public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) { this.sqlSessionTemplate = sqlSessionTemplate; } /** * Specifies which {@code SqlSessionTemplate} to use in the case that there is * more than one in the spring context. Usually this is only needed when you * have more than one datasource. * <p> * Note bean names are used, not bean references. This is because the scanner * loads early during the start process and it is too early to build mybatis * object instances. * * @since 1.1.0 * * @param sqlSessionTemplateName Bean name of the {@code SqlSessionTemplate} */ public void setSqlSessionTemplateBeanName(String sqlSessionTemplateName) { this.sqlSessionTemplateBeanName = sqlSessionTemplateName; } /** * Specifies which {@code SqlSessionFactory} to use in the case that there is * more than one in the spring context. Usually this is only needed when you * have more than one datasource. * <p> * @deprecated Use {@link #setSqlSessionFactoryBeanName(String)} instead. * * @param sqlSessionFactory */ @Deprecated public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) { this.sqlSessionFactory = sqlSessionFactory; } /** * Specifies which {@code SqlSessionFactory} to use in the case that there is * more than one in the spring context. Usually this is only needed when you * have more than one datasource. * <p> * Note bean names are used, not bean references. This is because the scanner * loads early during the start process and it is too early to build mybatis * object instances. * * @since 1.1.0 * * @param sqlSessionFactoryName Bean name of the {@code SqlSessionFactory} */ public void setSqlSessionFactoryBeanName(String sqlSessionFactoryName) { this.sqlSessionFactoryBeanName = sqlSessionFactoryName; } /** * * @since 1.1.1 * * @param processPropertyPlaceHolders */ public void setProcessPropertyPlaceHolders(boolean processPropertyPlaceHolders) { this.processPropertyPlaceHolders = processPropertyPlaceHolders; } /** * {@inheritDoc} */ @Override public void setApplicationContext(ApplicationContext applicationContext) { this.applicationContext = applicationContext; } /** * {@inheritDoc} */ @Override public void setBeanName(String name) { this.beanName = name; } /** * Gets beanNameGenerator to be used while running the scanner. * * @return the beanNameGenerator BeanNameGenerator that has been configured * @since 1.2.0 */ public BeanNameGenerator getNameGenerator() { return nameGenerator; } /** * Sets beanNameGenerator to be used while running the scanner. * * @param nameGenerator the beanNameGenerator to set * @since 1.2.0 */ public void setNameGenerator(BeanNameGenerator nameGenerator) { this.nameGenerator = nameGenerator; } /** * {@inheritDoc} */ @Override public void afterPropertiesSet() throws Exception { notNull(this.basePackage, "Property 'basePackage' is required"); } /** * {@inheritDoc} */ @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { // left intentionally blank } /** * {@inheritDoc} * 下面代码spring 注入mapper接口的扫描 * @since 1.0.2 */ @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { if (this.processPropertyPlaceHolders) {//占位符处理 processPropertyPlaceHolders(); } //实例化ClassPathMapperScanner,并对scanner相关属性进行配置 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();//根据上述配置,生成过滤器,只扫描合条件的class //扫描指定的包以及其子包 scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS)); } /* * BeanDefinitionRegistries are called early in application startup, before * BeanFactoryPostProcessors. This means that PropertyResourceConfigurers will not have been * loaded and any property substitution of this class' properties will fail. To avoid this, find * any PropertyResourceConfigurers defined in the context and run them on this class' bean * definition. Then update the values. */ private void processPropertyPlaceHolders() { Map<String, PropertyResourceConfigurer> prcs = applicationContext.getBeansOfType(PropertyResourceConfigurer.class); if (!prcs.isEmpty() && applicationContext instanceof ConfigurableApplicationContext) { BeanDefinition mapperScannerBean = ((ConfigurableApplicationContext) applicationContext) .getBeanFactory().getBeanDefinition(beanName); // PropertyResourceConfigurer does not expose any methods to explicitly perform // property placeholder substitution. Instead, create a BeanFactory that just // contains this mapper scanner and post process the factory. DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); factory.registerBeanDefinition(beanName, mapperScannerBean); for (PropertyResourceConfigurer prc : prcs.values()) { prc.postProcessBeanFactory(factory); } PropertyValues values = mapperScannerBean.getPropertyValues(); this.basePackage = updatePropertyValue("basePackage", values); this.sqlSessionFactoryBeanName = updatePropertyValue("sqlSessionFactoryBeanName", values); this.sqlSessionTemplateBeanName = updatePropertyValue("sqlSessionTemplateBeanName", values); } } private String updatePropertyValue(String propertyName, PropertyValues values) { PropertyValue property = values.getPropertyValue(propertyName); if (property == null) { return null; } Object value = property.getValue(); if (value == null) { return null; } else if (value instanceof String) { return value.toString(); } else if (value instanceof TypedStringValue) { return ((TypedStringValue) value).getValue(); } else { return null; } } }
ClassPathMapperScanner 收集@Mapper注解
@Override
public Set<BeanDefinitionHolder> doScan(String... basePackages) {
//通过父类的扫描,获取所有复合条件的BeanDefinitionHolder对象
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 {
//处理扫描得到的BeanDefinitionHolder集合,将集合中的每一个mapper接口转换成MapperFactoryBean后,注册至spring容器
processBeanDefinitions(beanDefinitions);
}
return beanDefinitions;
}
BeanPostProcessor
一句话描述:完成对bean的注解信息收集和IOC DI操作;在对象信息收集前,BeanDefinition实例化以及完成;包装成了BeanWrapper对象 ==>具体请看spring源码解析②
postProcessMergedBeanDefinition()完成对注解的收集;postProcessProperties()完成实例的DI
CommonAnnotationBeanPostProcessor
完成对@PostConstruct @PreDestroy@Resource注解的收集和DI

详细步骤如下:
1.收集bean实例化对象上是否包含@PostConstruct @PreDestroy注解信息收集

2.收集bean实例化对象上是否@Resource有注解信息收集

1和2这两部收集都会加入缓存里面;通过类的信息或者beanName作为key;注入信息为value

3.postProcessProperties完成注解信息的注入,实际上都是反射的思想

反射注入方法

说明:实例化过程中还是会调用getBean()方法:

AutowiredAnnotationBeanPostProcessor
完成对@Autowired@Value@Lookup注解的收集

同CommonAnnotationBeanPostProcessor一样的流程 ;
ConfigurationClassPostProcessor支持注解的核心类,重要!!!
一句话描述:完成了Spring “0”xml配置的方式
@Configuration@ComponentScan@Import@ImportResource@PropertySource@Order 等注解。
实现了 BeanDefinitionRegistryPostProcessor接口,完成了部分接口放入到beanFacory容器中
待整理!!!

浙公网安备 33010602011771号