开发者

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

目录
  • 一、什么是ImportBeanDefinitionRegistrar
  • 二、ImportBeanDefinitionRegistrar使用很简单
    • registerFilters()方法
  • 三、ImportBeanDefinitionRegistrar原理

    一、什么是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类继承ClassPathBeanDefinitphpionScanner,扫描使用@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<BeanDefi编程nitionRegistryPostProcessor>(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 (IpythonOException 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, Componwww.devze.comentScan.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() : (Strinphpg) 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生成一个对象

    以上就是ImportBeanDefinitionRegistrar手动控制BeanDefinition创建注册详解的详细内容,更多关于BeanDefinition创建注册的资料请关注我们其它相关文章!

    0

    上一篇:

    下一篇:

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    最新开发

    开发排行榜