软件编程
位置:首页>> 软件编程>> java编程>> ImportBeanDefinitionRegistrar手动控制BeanDefinition创建注册详解

ImportBeanDefinitionRegistrar手动控制BeanDefinition创建注册详解

作者:刨红薯的小羊竿尔  发布时间:2021-11-11 18:49:18 

标签:ImportBeanDefinitionRegistrar,BeanDefinition,创建注册

一、什么是ImportBeanDefinitionRegistrar

ImportBeanDefinitionRegistrar接口是也是spring的扩展点之一,ImportBeanDefinitionRegistrar类只能通过其他类 @Import的方式来加载,通常是启动类或配置类。它可以支持我们自己写的代码封装成BeanDefinition对象;实现此接口的类会回调postProcessBeanDefinitionRegistry方法,注册到spring容器中。

把bean注入到spring容器不止有 @Service @Component等注解方式;还可以实现此接口,这种方式是最灵活的,能在registerBeanDefinitions方法中获取到BeanDefinitionRegistry容器注册对象,可以手动控制BeanDefinition的创建和注册。

public interface ImportBeanDefinitionRegistrar {
   default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
       this.registerBeanDefinitions(importingClassMetadata, registry);
   }
   default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
   }
}

二、ImportBeanDefinitionRegistrar使用很简单

加载指定类

定义一个类TestImportBeanDefinitionRegistrar实现ImportBeanDefinitionRegistrar接口,在配置类TestConfiguration加上注解@Import一个TestImportBeanDefinitionRegistrar实现类,重写registerBeanDefinitions方法,手动注册bean,实现注册BeanDefinition到容器中,也可以实现一些Aware接口,以便获取Spring的一些数据。加载指定DataSource类如下:

public class TestImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar,ResourceLoaderAware,BeanFactoryAware {
   private static ResourceLoader resourceLoader;
   private static BeanFactory beanFactory;
   @Override
   public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
     //创建DataSourceBean
     GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
     beanDefinition.setBeanClass(DataSource.class);
     beanDefinition.setSynthetic(true);
     MutablePropertyValues mpv = beanDefinition.getPropertyValues();
     //spring名称约定为defaultTargetDataSource和targetDataSources
     mpv.addPropertyValue("defaultTargetDataSource", defaultTargetDataSource);
     mpv.addPropertyValue("targetDataSources", DataSourceSet.getTargetDataSourcesMap());
     beanDefinitionRegistry.registerBeanDefinition("dataSource", beanDefinition);
   }
     @Override
     public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
         this.beanFactory=beanFactory;
     }
     @Override
     public void setResourceLoader(ResourceLoader resourceLoader) {
         this.resourceLoader=resourceLoader;
     }
}
@Import(TestImportBeanDefinitionRegistrar.class)
@Configuration
public class TestConfiguration {
}

这样就注册了一个bean名字是dataSource,有两个属性分别是defaultTargetDataSource和targetDataSources。那么使用这个类直接用 @Autowired和@Resource注入即可。

加载扫描器类

如果我们并不知道需要register哪些bean。这里我们还需要借助一个扫描器类ClassPathBeanDefinitionScanner,通过扫描器获取我们需要注册的bean。首先创建一个@Mapper注解,再新建一个CountryMapper类,使用该Mapper注解。

@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
public @interface Mapper {
}
@Mapper
public class CountryMapper {
}

创建一个MyClassPathBeanDefinitionScanner类继承ClassPathBeanDefinitionScanner,扫描使用@Mapper的注解的类,ClassPathBeanDefinitionScanner又继承ClassPathScanningCandidateComponentProvider类,ClassPathScanningCandidateComponentProvider中有两个TypeFilter集合,includeFilters、excludeFilters。满足任意includeFilters会被加载,同样的满足任意excludeFilters不会被加载。

@Slf4j
public class MyClassPathBeanDefinitionScanner extends ClassPathBeanDefinitionScanner{
   public MyClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) {
       super(registry, useDefaultFilters);
   }
   protected void registerFilters() {
       addIncludeFilter(new AnnotationTypeFilter(Mapper.class));
   }
   @Override
   protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
       return super.doScan(basePackages);
   }
}

registerFilters()方法

核心代码就是registerFilters()方法,然后在我们的ImportBeanDefinitionRegistrar实现类中调用:

public class MapperAutoConfiguredMyBatisRegistrar
       implements ImportBeanDefinitionRegistrar{
   @Override
   public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
       MyClassPathBeanDefinitionScanner scanner = new MyClassPathBeanDefinitionScanner(registry, false);
       scanner.setResourceLoader(resourceLoader);
       scanner.registerFilters();
       scanner.doScan("com.faderw.school.domain");
   }
}

这里我们自定义带有@Mapper注解的类CountryMapper就被注入到IOC容器了,可以直接使用噢。

三、ImportBeanDefinitionRegistrar原理

TestImportBeanDefinitionRegistrar是被TestConfiguration类import导入的,所以要加载到TestImportBeanDefinitionRegistrar必然要先加载TestConfiguration才行;所以先看Configuration的代码,找到ConfigurationClassPostProcessor类,它实现了BeanDefinitionRegistryPostProcessor接口

Map<String, BeanDefinitionRegistryPostProcessor> beanMap =
beanFactory.getBeansOfType(BeanDefinitionRegistryPostProcessor.class, true, false);
List<BeanDefinitionRegistryPostProcessor> registryPostProcessorBeans =
new ArrayList<BeanDefinitionRegistryPostProcessor>(beanMap.values());
OrderComparator.sort(registryPostProcessorBeans);
for (BeanDefinitionRegistryPostProcessor postProcessor : registryPostProcessorBeans) {
postProcessor.postProcessBeanDefinitionRegistry(registry);
}

从spring容器中拿到实现了BeanDefinitionRegistryPostProcessor接口的类。拿到后执行对应的postProcessBeanDefinitionRegistry方法:

//从invokeBeanFactoryPostProcessors方法调过来
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
RootBeanDefinition iabpp = new RootBeanDefinition(ImportAwareBeanPostProcessor.class);
iabpp.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(IMPORT_AWARE_PROCESSOR_BEAN_NAME, iabpp);
//取得registry的id并做判重处理或记录
int registryId = System.identityHashCode(registry);
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanDefinitionRegistry already called for this post-processor against " + registry);
}
if (this.factoriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called for this post-processor against " + registry);
}
//保存处理过的registry,避免重复处理
this.registriesPostProcessed.add(registryId);
//处理java配置形式的bean定义
processConfigBeanDefinitions(registry);
}

最后调用了processConfigBeanDefinitions方法处理java配置形式的bean定义:

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
Set<BeanDefinitionHolder> configCandidates = new LinkedHashSet<BeanDefinitionHolder>();
//加载当前已知所有bean定义
for (String beanName : registry.getBeanDefinitionNames()) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
//   判断对应bean是否为配置类,如果是,则加入到configCandidates
// @Configuration, @Component, @ComponentScan, @Import, @Bean等注解
if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
//如果找不到@configuration类,则立即返回
if (configCandidates.isEmpty()) {
return;
}
...........
// 实例化ConfigurationClassParser 为了解析 各个配置类
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
System.out.println("ConfigurationClassPostProcessor bd " + bd.getBeanClassName());
try {
if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
parser.parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
}
else {
parser.parse(bd.getBeanClassName(), holder.getBeanName());
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException("Failed to load bean class: " + bd.getBeanClassName(), ex);
}
}
parser.validate();
......

ConfigurationClassParser#parse方法:

public void parse(String className, String beanName) throws IOException {
       MetadataReader reader = this.metadataReaderFactory.getMetadataReader(className);
       processConfigurationClass(new ConfigurationClass(reader, beanName));
}

processConfigurationClass方法:

protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
       ...................
       do {
            //重点
            metadata = doProcessConfigurationClass(configClass, metadata);
       }
       while (metadata != null);
.................
}

doProcessConfigurationClass方法:

protected AnnotationMetadata doProcessConfigurationClass(ConfigurationClass configClass, AnnotationMetadata metadata) throws IOException {
// Recursively process any member (nested) classes first
processMemberClasses(metadata);
// Process any @PropertySource annotations
//处理@PropertySource  加载外面资源文件
AnnotationAttributes propertySource = MetadataUtils.attributesFor(metadata,
org.springframework.context.annotation.PropertySource.class);
if (propertySource != null) {
processPropertySource(propertySource);
}
// Process any @ComponentScan annotations
//处理  @ComponentScan 扫描包
AnnotationAttributes componentScan = MetadataUtils.attributesFor(metadata, ComponentScan.class);
if (componentScan != null) {
// The config class is annotated with @ComponentScan -> perform the scan immediately
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, metadata.getClassName());
// Check the set of scanned definitions for any further config classes and parse recursively if necessary
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
if (ConfigurationClassUtils.checkConfigurationClassCandidate(holder.getBeanDefinition(), this.metadataReaderFactory)) {
this.parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName());
}
}
}
//处理@Import注解
// Process any @Import annotations
Set<Object> imports = new LinkedHashSet<Object>();
Set<String> visited = new LinkedHashSet<String>();
collectImports(metadata, imports, visited);
if (!imports.isEmpty()) {
processImport(configClass, metadata, imports, true);
}
// Process any @ImportResource annotations
if (metadata.isAnnotated(ImportResource.class.getName())) {
AnnotationAttributes importResource = MetadataUtils.attributesFor(metadata, ImportResource.class);
String[] resources = importResource.getStringArray("value");
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
for (String resource : resources) {
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
configClass.addImportedResource(resolvedResource, readerClass);
}
}
// Process individual @Bean methods
//处理@Bean注解
Set<MethodMetadata> beanMethods = metadata.getAnnotatedMethods(Bean.class.getName());
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
// Process superclass, if any
if (metadata.hasSuperClass()) {
String superclass = metadata.getSuperClassName();
if (!superclass.startsWith("java") && !this.knownSuperclasses.containsKey(superclass)) {
this.knownSuperclasses.put(superclass, configClass);
// superclass found, return its annotation metadata and recurse
if (metadata instanceof StandardAnnotationMetadata) {
Class<?> clazz = ((StandardAnnotationMetadata) metadata).getIntrospectedClass();
return new StandardAnnotationMetadata(clazz.getSuperclass(), true);
}
else {
MetadataReader reader = this.metadataReaderFactory.getMetadataReader(superclass);
return reader.getAnnotationMetadata();
}
}
}
// No superclass -> processing is complete
return null;
}

processImport方法:

private void processImport(ConfigurationClass configClass, AnnotationMetadata metadata,
Collection<?> classesToImport, boolean checkForCircularImports) throws IOException {
       if (checkForCircularImports && this.importStack.contains(configClass)) {
           this.problemReporter.error(new CircularImportProblem(configClass, this.importStack, configClass.getMetadata()));
       }else {
           this.importStack.push(configClass);
           try {
               for (Object candidate : classesToImport) {
                       Object candidateToCheck = (candidate instanceof Class ? (Class) candidate :
                                       this.metadataReaderFactory.getMetadataReader((String) candidate));
                       //实现ImportSelector接口的处理
                       if (checkAssignability(ImportSelector.class, candidateToCheck)) {
                               // Candidate class is an ImportSelector -> delegate to it to determine imports
                               Class<?> candidateClass = (candidate instanceof Class ? (Class) candidate :
                                               this.resourceLoader.getClassLoader().loadClass((String) candidate));
                               ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
                               processImport(configClass, metadata, Arrays.asList(selector.selectImports(metadata)), false);
                       }
                       //实现ImportBeanDefinitionRegistrar接口的处理
                       else if (checkAssignability(ImportBeanDefinitionRegistrar.class, candidateToCheck)) {
                               // Candidate class is an ImportBeanDefinitionRegistrar ->
                               // delegate to it to register additional bean definitions
                               Class<?> candidateClass = (candidate instanceof Class ? (Class) candidate :
                                               this.resourceLoader.getClassLoader().loadClass((String) candidate));
                               ImportBeanDefinitionRegistrar registrar =
                                               BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
                               invokeAwareMethods(registrar);
                               //调用该类的registerBeanDefinitions方法
                               registrar.registerBeanDefinitions(metadata, this.registry);
                       }
                       else {
                               //候选类不是importSelector或importBeanDefinitionRegistrar
                               //@Configuration类的处理
                               // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
                               // process it as a @Configuration class
                               this.importStack.registerImport(metadata,
                                               (candidate instanceof Class ? ((Class) candidate).getName() : (String) candidate));
                               processConfigurationClass(candidateToCheck instanceof Class ?
                                               new ConfigurationClass((Class) candidateToCheck, true) :
                                               new ConfigurationClass((MetadataReader) candidateToCheck, true));
                       }
               }
       }
       catch (ClassNotFoundException ex) {
               throw new NestedIOException("Failed to load import candidate class", ex);
       }
       finally {
               this.importStack.pop();
       }
   }
}

最终调用了DefaultListableBeanFactory的registerBeanDefinition方法,这里就是处理ImportBeanDefinitionRegistrar接口实现类的地方:

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
       Assert.hasText(beanName, "Bean name must not be empty");
       Assert.notNull(beanDefinition, "BeanDefinition must not be null");
       if("configurationTest".equals(beanName)){
               System.out.println(" registerBeanDefinition(String beanName, BeanDefinition beanDefinition) " + beanName);
       }
       if (beanDefinition instanceof AbstractBeanDefinition) {
               try {
                       ((AbstractBeanDefinition) beanDefinition).validate();
               }
               catch (BeanDefinitionValidationException ex) {
                       throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                                       "Validation of bean definition failed", ex);
               }
       }
         // old? 还记得 “允许 bean 覆盖” 这个配置吗?allowBeanDefinitionOverriding
       BeanDefinition oldBeanDefinition;
       synchronized (this.beanDefinitionMap) {
                 // 之后会看到,所有的 Bean 注册后会放入这个 beanDefinitionMap 中
               oldBeanDefinition = this.beanDefinitionMap.get(beanName);
               // 处理重复名称的 Bean 定义的情况
               if (oldBeanDefinition != null) {
                       if (!this.allowBeanDefinitionOverriding) {
                                // 如果不允许覆盖的话,抛异常
                               throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                                               "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
                                               "': There is already [" + oldBeanDefinition + "] bound.");
                       }
                       else {
                               if (this.logger.isInfoEnabled()) {
                                       this.logger.info("Overriding bean definition for bean '" + beanName +
                                                       "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
                               }
                       }
               }
               else {
                       //添加beanDefinitionNames
                       this.beanDefinitionNames.add(beanName);
                       this.frozenBeanDefinitionNames = null;
               }
               // 覆盖
               this.beanDefinitionMap.put(beanName, beanDefinition);
       }
       if (oldBeanDefinition != null || containsSingleton(beanName)) {
               resetBeanDefinition(beanName);
       }
}
public void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
   Assert.hasText(beanName, "'beanName' must not be empty");
   synchronized (this.beanDefinitionMap) {
           BeanDefinition bd = this.beanDefinitionMap.remove(beanName);
           if (bd == null) {
                   if (this.logger.isTraceEnabled()) {
                           this.logger.trace("No bean named '" + beanName + "' found in " + this);
                   }
                   throw new NoSuchBeanDefinitionException(beanName);
           }
           this.beanDefinitionNames.remove(beanName);
           this.frozenBeanDefinitionNames = null;
   }
   resetBeanDefinition(beanName);
}

这段代码主要就是把定义的bean放到beanDefinitionMap里去。beanDefinitionMap维护的就是bean的定义,当需要获取的时候就从里面拿到对应的BeanDefinition,根据BeanDefinition生成一个对象

来源:https://juejin.cn/post/7180731318123118653

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com