欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

ImportBeanDefinitionRegistrar手動(dòng)控制BeanDefinition創(chuàng)建注冊(cè)詳解

 更新時(shí)間:2022年12月26日 11:19:57   作者:刨紅薯的小羊竿爾  
這篇文章主要為大家介紹了ImportBeanDefinitionRegistrar手動(dòng)控制BeanDefinition創(chuàng)建注冊(cè)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

一、什么是ImportBeanDefinitionRegistrar

ImportBeanDefinitionRegistrar接口是也是spring的擴(kuò)展點(diǎn)之一,ImportBeanDefinitionRegistrar類只能通過(guò)其他類 @Import的方式來(lái)加載,通常是啟動(dòng)類或配置類。它可以支持我們自己寫的代碼封裝成BeanDefinition對(duì)象;實(shí)現(xiàn)此接口的類會(huì)回調(diào)postProcessBeanDefinitionRegistry方法,注冊(cè)到spring容器中。

把bean注入到spring容器不止有 @Service @Component等注解方式;還可以實(shí)現(xiàn)此接口,這種方式是最靈活的,能在registerBeanDefinitions方法中獲取到BeanDefinitionRegistry容器注冊(cè)對(duì)象,可以手動(dòng)控制BeanDefinition的創(chuàng)建和注冊(cè)。

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

二、ImportBeanDefinitionRegistrar使用很簡(jiǎn)單

加載指定類

定義一個(gè)類TestImportBeanDefinitionRegistrar實(shí)現(xiàn)ImportBeanDefinitionRegistrar接口,在配置類TestConfiguration加上注解@Import一個(gè)TestImportBeanDefinitionRegistrar實(shí)現(xiàn)類,重寫registerBeanDefinitions方法,手動(dòng)注冊(cè)bean,實(shí)現(xiàn)注冊(cè)BeanDefinition到容器中,也可以實(shí)現(xiàn)一些Aware接口,以便獲取Spring的一些數(shù)據(jù)。加載指定DataSource類如下:

public class TestImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar,ResourceLoaderAware,BeanFactoryAware {
    private static ResourceLoader resourceLoader; 
    private static BeanFactory beanFactory;
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
      //創(chuàng)建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 {
}

這樣就注冊(cè)了一個(gè)bean名字是dataSource,有兩個(gè)屬性分別是defaultTargetDataSource和targetDataSources。那么使用這個(gè)類直接用 @Autowired和@Resource注入即可。

加載掃描器類

如果我們并不知道需要register哪些bean。這里我們還需要借助一個(gè)掃描器類ClassPathBeanDefinitionScanner,通過(guò)掃描器獲取我們需要注冊(cè)的bean。首先創(chuàng)建一個(gè)@Mapper注解,再新建一個(gè)CountryMapper類,使用該Mapper注解。

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

創(chuàng)建一個(gè)MyClassPathBeanDefinitionScanner類繼承ClassPathBeanDefinitionScanner,掃描使用@Mapper的注解的類,ClassPathBeanDefinitionScanner又繼承ClassPathScanningCandidateComponentProvider類,ClassPathScanningCandidateComponentProvider中有兩個(gè)TypeFilter集合,includeFilters、excludeFilters。滿足任意includeFilters會(huì)被加載,同樣的滿足任意excludeFilters不會(huì)被加載。

@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實(shí)現(xiàn)類中調(diào)用:

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導(dǎo)入的,所以要加載到TestImportBeanDefinitionRegistrar必然要先加載TestConfiguration才行;所以先看Configuration的代碼,找到ConfigurationClassPostProcessor類,它實(shí)現(xiàn)了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容器中拿到實(shí)現(xiàn)了BeanDefinitionRegistryPostProcessor接口的類。拿到后執(zhí)行對(duì)應(yīng)的postProcessBeanDefinitionRegistry方法:

        //從invokeBeanFactoryPostProcessors方法調(diào)過(guò)來(lái)
	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);
		}
		//保存處理過(guò)的registry,避免重復(fù)處理
		this.registriesPostProcessed.add(registryId);
		 //處理java配置形式的bean定義
		processConfigBeanDefinitions(registry);
	}

最后調(diào)用了processConfigBeanDefinitions方法處理java配置形式的bean定義:

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
		Set<BeanDefinitionHolder> configCandidates = new LinkedHashSet<BeanDefinitionHolder>();
		//加載當(dāng)前已知所有bean定義
		for (String beanName : registry.getBeanDefinitionNames()) {
			BeanDefinition beanDef = registry.getBeanDefinition(beanName);
			//   判斷對(duì)應(yīng)bean是否為配置類,如果是,則加入到configCandidates
			// @Configuration, @Component, @ComponentScan, @Import, @Bean等注解
			if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
				configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
			}
		}
		//如果找不到@configuration類,則立即返回
		if (configCandidates.isEmpty()) {
			return;
		}
...........
		 // 實(shí)例化ConfigurationClassParser 為了解析 各個(gè)配置類
		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 {
             //重點(diǎn)
             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));
                        //實(shí)現(xiàn)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);
                        }
                        //實(shí)現(xiàn)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);
                                //調(diào)用該類的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();
        }
    }
}

最終調(diào)用了DefaultListableBeanFactory的registerBeanDefinition方法,這里就是處理ImportBeanDefinitionRegistrar接口實(shí)現(xiàn)類的地方:

 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 覆蓋” 這個(gè)配置嗎?allowBeanDefinitionOverriding
        BeanDefinition oldBeanDefinition;
        synchronized (this.beanDefinitionMap) {
                  // 之后會(huì)看到,所有的 Bean 注冊(cè)后會(huì)放入這個(gè) beanDefinitionMap 中
                oldBeanDefinition = this.beanDefinitionMap.get(beanName);
                // 處理重復(fù)名稱的 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維護(hù)的就是bean的定義,當(dāng)需要獲取的時(shí)候就從里面拿到對(duì)應(yīng)的BeanDefinition,根據(jù)BeanDefinition生成一個(gè)對(duì)象。

以上就是ImportBeanDefinitionRegistrar手動(dòng)控制BeanDefinition創(chuàng)建注冊(cè)詳解的詳細(xì)內(nèi)容,更多關(guān)于BeanDefinition創(chuàng)建注冊(cè)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論