ConfigurationClassPostProcessor的五种使用案例

本文深入解析Spring框架中ConfigurationClassPostProcessor的五种使用案例,包括对成员类的解析、@ComponentScan、@Import(实现ImportSelector和ImportBeanDefinitionRegistrar)、@ImportResource以及@Bean方法的处理。详细介绍了每个用法的实现原理及bean定义的注册时机。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Spring源码导读

目录

提纲doProcessConfigurationClass

五种使用案例

对成员类的解析

@ComponentScan与@ComponentScans

@Import

实现ImportSelector

实现ImportBeanDefinitionRegistrar

ImportResource

@Bean Method

这五种bean定义何时被注册

ConfigClass结构

这bean定义的注册

被导入类的bean定义

BeanMethod的注册

@ImportResource中的bean注册

ImportBeanDefinitionRegistrar的调用


 

 在ConfigurationClassPostProcessor章节,我们跟踪了postProcessBeanDefinitionRegistry处理链路。

本章用结合源码查看注解方式注册BeanDefinition的几种用法。

提纲doProcessConfigurationClass

这几种用法的实现都是在doProcessConfigurationClass中完成的。

大致看下,后面用案例一一讲解

protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
		throws IOException {

	// 处理成员类
	processMemberClasses(configClass, sourceClass);

	// Process any @PropertySource annotations
	for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
			sourceClass.getMetadata(), PropertySources.class,
			org.springframework.context.annotation.PropertySource.class)) {
		if (this.environment instanceof ConfigurableEnvironment) {
			processPropertySource(propertySource);
		}
		else {
			logger.warn("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
					"]. Reason: Environment must implement ConfigurableEnvironment");
		}
	}

	// 处理ComponentScan
	// 通过统一的取数模型, 取到ComponentScan注解的属性信息
	Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
			sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
	if (!componentScans.isEmpty() &&
			!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
		// 遍历每个componentScan
		for (AnnotationAttributes componentScan : componentScans) {
			// 使用ComponentScanAnnotationParser 对componentScan进行解析
			Set<BeanDefinitionHolder> scannedBeanDefinitions =
					this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
			
			// 将扫描后拿到的结果继续分析, 是否需要作为种子继续生根发芽
			for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
				BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
				if (bdCand == null) {
					bdCand = holder.getBeanDefinition();
				}
				// 判断新的BeanDefinition是否是配置类, 如果是则继续解析
				if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
					parse(bdCand.getBeanClassName(), holder.getBeanName());
				}
			}
		}
	}

	// 处理被@Import的类
	processImports(configClass, sourceClass, getImports(sourceClass), true);

	// 处理被@ImportResource的类
	// 通过统一的取数模型, 取到ImportResource的类注解的属性信息 
	AnnotationAttributes importResource =
			AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
	if (importResource != null) {
		// 通过locations获得其resources
		String[] resources = importResource.getStringArray("locations");
		// 获得其BeanDefinitionReader
		Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
		for (String resource : resources) {
			// resource进行一次解析, 因为resource中可能会有占位符情况
			String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
			// 不会立马调用,仅仅调用 this.importedResources.put(importedResource, readerClass) 将资源和信息保存起来
			configClass.addImportedResource(resolvedResource, readerClass);
		}
	}

	// 处理存在方法被@Bean注解的类
	// 提取方法被@Bean注解的类的Metadata:MethodMetadata
	Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
	for (MethodMetadata methodMetadata : beanMethods) {
		// 仅仅使用his.beanMethods.add(method);进行存储,而不会直接调用
		configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
	}

	// 处理接口上的 default methods有被@Bean注解的
	processInterfaces(configClass, sourceClass);

	// 处理超类
	if (sourceClass.getMetadata().hasSuperClass()) {
		String superclass = sourceClass.getMetadata().getSuperClassName();
		if (superclass != null && !superclass.startsWith("java") &&
				!this.knownSuperclasses.containsKey(superclass)) {
			this.knownSuperclasses.put(superclass, configClass);
			// Superclass found, return its annotation metadata and recurse
			return sourceClass.getSuperClass();
		}
	}

	// No superclass -> processing is complete
	return null;
}

五种使用案例

对成员类的解析

什么是成员类?见 《五种类型的class

案例:

public class RegisterMemberClassTest {
    @Component
    class InnerClass {

    }
    @Component
    public static class NestedClass {

    }
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(RegisterMemberClassTest.class);
        InnerClass person = context.getBean(InnerClass.class);
        System.out.println(person.toString());
    }
}

源码:

doProcessConfigurationClass 进来第一个就是处理了成员类

private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
	// 获得成员类
	Collection<SourceClass> memberClasses = sourceClass.getMemberClasses();
	if (!memberClasses.isEmpty()) {
		List<SourceClass> candidates = new ArrayList<>(memberClasses.size());
		for (SourceClass memberClass : memberClasses) {
			// 判断候选者是否是配置类 InnerClass和NestedClass注解了Component因此是配置类
			if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) &&
					!memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) {
				candidates.add(memberClass);
			}
		}
		OrderComparator.sort(candidates);
		// 对候选者进行处理
		for (SourceClass candidate : candidates) {
			// 这里是防止出现member类的循环
			if (this.importStack.contains(configClass)) {
				this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
			}
			else {
				// 将configClass压入栈
				this.importStack.push(configClass);
				try {
					// 递归处理, 注意这里会将candidate转化为ConfigurationClass, 转换时传入configClass作为它的importBy
					// 对应我们案例就是InnerClass和NestedClass是被RegisterMemberClassTest引入的
					processConfigurationClass(candidate.asConfigClass(configClass));
				}
				finally {
					// 出栈
					this.importStack.pop();
				}
			}
		}
	}
}

InnerClass是被NestedClass注解的,是一个轻量的配置类,又会进入processConfigurationClass的调用。

注意递归进度的时候会转化为ConfigurationClass 并将RegisterMemberClassTest作为了importBy传入加入到importedBy的集合中:

public ConfigurationClass asConfigClass(ConfigurationClass importedBy) throws IOException {
	if (this.source instanceof Class) {
		// 记录importBy
		return new ConfigurationClass((Class<?>) this.source, importedBy);
	}
	return new ConfigurationClass((MetadataReader) this.source, importedBy);
}

public ConfigurationClass(Class<?> clazz, @Nullable ConfigurationClass importedBy) {
	this.metadata = new StandardAnnotationMetadata(clazz, true);
	this.resource = new DescriptiveResource(clazz.getName());
	this.importedBy.add(importedBy);
}

这样就将二者加入到了parser.getConfigurationClasses()中,用于后面的注册。

 

@ComponentScan与@ComponentScans

被@ComponentScan注解的类可以作为种子,ConfigurationClassPostProcessor会扫描它配置的包的路径下的所有被Component注解的类。

@ComponentScans可以配置多个ComponentScan, 并且可以设置过滤

案例:

@ComponentScan(basePackages = "com.jack.ascp.purchase.app.test.spring.anno.configurationclassPostprocessor")
//@ComponentScans(value = { @ComponentScan(value = "com.yibai.spring.annotation"),
//        @ComponentScan(value = "com.yibai.spring.annotation", includeFilters = {
//                @ComponentScan.Filter(type = FilterType.CUSTOM, value = RegisterComponentScanTest.class) }) })
public class RegisterComponentScanTest {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(RegisterComponentScanTest.class);
        ComponentScanTest person = context.getBean(ComponentScanTest.class);
        System.out.println(person.toString());
    }
}

源码分析

protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
		throws IOException {

	// .........其他用法.......

	// ComponentScan用法
	// 通过统一的取数模型, 取到ComponentScan注解的属性信息
	Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
			sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
	if (!componentScans.isEmpty() &&
			!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
		// 遍历每个componentScan
		for (AnnotationAttributes componentScan : componentScans) {
			// 使用ComponentScanAnnotationParser 对componentScan进行解析
			Set<BeanDefinitionHolder> scannedBeanDefinitions =
					this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
			
			// 将扫描后拿到的结果继续分析, 是否需要作为种子继续生根发芽
			for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
				BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
				if (bdCand == null) {
					bdCand = holder.getBeanDefinition();
				}
				// 判断新的BeanDefinition是否是配置类, 如果是则继续解析
				if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
					parse(bdCand.getBeanClassName(), holder.getBeanName());
				}
			}
		}
	}
	
	// ......其他用法.......

}

ComponentScanAnnotationParser#parse:它的扫描其实用的就是ClassPathBeanDefinitionScanner,

注意:

1、我们虽然设置它的过滤器,但是它的默认过滤器就包含了Component的注解过滤器。

2、doCan中会对扫描的beanDefinition进行注册。而我们前面的“成员类的解析”是先加入到ConfigurationClasses中再进行注册的

3、扫描后生成的bean定义如果满足配置类要求,还会再次被回调parse。

public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {

	// 实际上就是创建ClassPathBeanDefinitionScanner进行扫描
	ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
			componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);

	// 对scanner进行初始化参数设置
	Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
	boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
	scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
			BeanUtils.instantiateClass(generatorClass));

	ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");
	if (scopedProxyMode != ScopedProxyMode.DEFAULT) {
		// 比如设置它的ScopedProxyMode
		scanner.setScopedProxyMode(scopedProxyMode);
	}
	else {
		Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");
		// 设置它的ScopeMetadataResolver
		scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));
	}

	// 设置 扫描的模式匹配符 
	// 从componentScan.getString("resourcePattern") 获取 resourcePattern = "**/*.class" 
	// ** 表示匹配多个文件夹, *.class代表所有class文件, 所有意思是扫描包下的所有子包的class文件。
	scanner.setResourcePattern(componentScan.getString("resourcePattern"));

	// 设置scanner的include过滤器
	for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {
		for (TypeFilter typeFilter : typeFiltersFor(filter)) {
			scanner.addIncludeFilter(typeFilter);
		}
	}
	// 设置scanner的排除过滤器
	for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {
		for (TypeFilter typeFilter : typeFiltersFor(filter)) {
			scanner.addExcludeFilter(typeFilter);
		}
	}

	// 是否懒加载
	boolean lazyInit = componentScan.getBoolean("lazyInit");
	if (lazyInit) {
		scanner.getBeanDefinitionDefaults().setLazyInit(true);
	}

	// 设置需要扫描的包的路径 将我们配置的basePackages ",; 	"进行分割
	Set<String> basePackages = new LinkedHashSet<>();
	String[] basePackagesArray = componentScan.getStringArray("basePackages");
	for (String pkg : basePackagesArray) {
		String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),
				ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
		// 将包这些分割后的包加入到basePackages中
		Collections.addAll(basePackages, tokenized);
	}
	
	// 设置如果设置了basePackageClasses 也加入到basePackages
	for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
		basePackages.add(ClassUtils.getPackageName(clazz));
	}
	if (basePackages.isEmpty()) {
		basePackages.add(ClassUtils.getPackageName(declaringClass));
	}

	scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
		@Override
		protected boolean matchClassName(String className) {
			return declaringClass.equals(className);
		}
	});
	
	// 针对basePackages进行扫描, 注意scanner的扫描后会自动注入bean定义
	// 如果没有设置其includeFilters过滤器,其实就是用它的默认的过滤器
	return scanner.doScan(StringUtils.toStringArray(basePackages));
}

@Import

实现ImportSelector

定义一个需要被注入的类

public class Person {
}

实现ImportSelector 接口, selectImports可以返回多个class的类名。根据这些类名Spring会将其进行注册。

public class ImportSelectorImpl implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{Person.class.getName()};
    }
}

testApp:

@Import(value = ImportSelectorImpl.class)
//@Import(value = ImportBeanDefinitionRegistrarImpl.class)
public class RegisterImportTest {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(RegisterImportTest.class);
        Person person = context.getBean(Person.class);
        System.out.println(person.toString());
    }
}

 

实现ImportBeanDefinitionRegistrar

还是基于上面Person 的例子。

实现ImportBeanDefinitionRegistrar,registerBeanDefinitions 可以戒断被@Import注解,获取Import注解类的AnnotationMetadata元数据和注册表registry

我们可以,直接在此处定义beanDefinition,这个方法会在后面被调用,但不是解析到被@Import的类之后就直接注入,而是将其hold住,在后面调用注册。

public class ImportBeanDefinitionRegistrarImpl implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
        beanDefinition.setBeanClassName(Person.class.getName());
        registry.registerBeanDefinition("person", beanDefinition);
    }
}

testApp

//@Import(value = ImportSelectorImpl.class)
@Import(value = ImportBeanDefinitionRegistrarImpl.class)
public class RegisterImportTest {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(RegisterImportTest.class);
        Person person = context.getBean(Person.class);
        System.out.println(person.toString());
    }
}

 

源码分析

doProcessConfigurationClass中调用processImports对它进行解析

protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
		throws IOException {
	// 。。。。。其他方式。。。。。。

	// 处理被@Import的类
	processImports(configClass, sourceClass, getImports(sourceClass), true);

	// 。。。。。其他方式。。。。。。
}

解析之前调用了getImports获取所有被@Import注解的SourceClass

private Set<SourceClass> getImports(SourceClass sourceClass) throws IOException {
	// 后面要进入递归搜寻
	// 所以这里用imports记录被搜寻到类
	Set<SourceClass> imports = new LinkedHashSet<>();
	// 用visited记录已经访问过的类
	Set<SourceClass> visited = new LinkedHashSet<>();
	// 递归搜寻
	collectImports(sourceClass, imports, visited);
	return imports;
}

private void collectImports(SourceClass sourceClass, Set<SourceClass> imports, Set<SourceClass> visited)
		throws IOException {

	// 将进来的sourceClass作为根进行搜寻,因为有可能目标类上还有其他注解,该注解上也注解了Import
	if (visited.add(sourceClass)) {
		for (SourceClass annotation : sourceClass.getAnnotations()) {
			// 获取其名称
			String annName = annotation.getMetadata().getClassName();
			// 如果该注解不是java的注解,并且不是Import注解则再次递归调用
			if (!annName.startsWith("java") && !annName.equals(Import.class.getName())) {
				collectImports(annotation, imports, visited);
			}
		}
		// 将Import上value配置的类(对应我们的案例就是ImportSelectorImpl.class 和 ImportBeanDefinitionRegistrarImpl.class)加入到imports
		// 注意value可以配置多个的
		imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value"));
	}
}

processImports:

private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
		Collection<SourceClass> importCandidates, boolean checkForCircularImports) {

	if (importCandidates.isEmpty()) {
		return;
	}

	// 检测是否出现了循环Import行为
	if (checkForCircularImports && isChainedImportOnStack(configClass)) {
		this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
	}
	else {
		this.importStack.push(configClass);
		try {
			for (SourceClass candidate : importCandidates) {
				// ImportSelector 的实现处理
				if (candidate.isAssignable(ImportSelector.class)) {
					// 加载它的类
					Class<?> candidateClass = candidate.loadClass();
					// 实例化这个ImportSelector
					ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
					// 如果selector实现了Aware接口,会调用它的这些Aware, 用于帮助实现者能获取更多的信息。
					// 可以在Aware获取,想要的一些信息
					// 如BeanClassLoaderAware、BeanFactoryAware、EnvironmentAware、ResourceLoaderAware
					ParserStrategyUtils.invokeAwareMethods(
							selector, this.environment, this.resourceLoader, this.registry);
					if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) {
						this.deferredImportSelectors.add(
								new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));
					}
					else {
					    // 调用 接口方法selectImports得到bean定义的类名
						String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
						// 根据类名生成SourceClass
						Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
						// 再次进行一次发芽,在我们案例中其是Person
						processImports(configClass, currentSourceClass, importSourceClasses, false);
					}
				}
				// ImportBeanDefinitionRegistrar实现的处理
				else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
					// 加载它的类
					Class<?> candidateClass = candidate.loadClass();
					// 实例化这个ImportBeanDefinitionRegistrar
					ImportBeanDefinitionRegistrar registrar =
							BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
					// 它也是有一次机会调用Aware方法的
					ParserStrategyUtils.invokeAwareMethods(
							registrar, this.environment, this.resourceLoader, this.registry);
					// 将这个类加入到configClass中, 注意它没有再次进行调用
					// 它不能马上调用, 因为一旦调用就自定义的BeanDefintion进行注册了
					configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
				}
				else {
					// 在最后其实就是我们案例中的Person, 它无法再递归了, 但是它会进入这里
					// 用importStack中加入,防止后面会重复
					this.importStack.registerImport(
							currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
					// 虽然Person没有Import注解了,但是它可能有其他注解,因此将其转化为ConfigClass
					// 所以这里又会进入processConfigurationClass 进入其他方式的 "生根发芽"
					// 注意这里传入了configClass 作为它的importBy by谁?在我们案例中是我们的种子RegisterImportTest
					processConfigurationClass(candidate.asConfigClass(configClass));
				}
			}
		}
		catch (BeanDefinitionStoreException ex) {
			throw ex;
		}
		catch (Throwable ex) {
			throw new BeanDefinitionStoreException(
					"Failed to process import candidates for configuration class [" +
					configClass.getMetadata().getClassName() + "]", ex);
		}
		finally {
			this.importStack.pop();
		}
	}
}

 

 

注意:

Import注解类能获取多个import的类

  • 1、因为有可能目标类上还有其他注解,该注解上也注解了Import
  • 2、并且Import注解的value也可以多个比如value = {ImportSelectorImpl.class, XXXX.class}

这两个接口似乎太过单调,但是可以从其他途径获取有用信息用于bean定义

  • 1、两个案例这是为了演示,其实可以在在Import上加上一系列配置,我们实现其方法的时候,可以根据配置来自行决定哪些定义需要被加载
  • 2、如果selector实现了Aware接口,会调用它的这些Aware, 用于帮助实现者能获取更多的信息。可以在Aware获取,想要的一些信息

ImportBeanDefinitionRegistrar#registerBeanDefinitions 在解析的时候不会马上调用,而是将这个类加入到configClass中,  它不能马上调用, 因为一旦调用就自定义的BeanDefintion进行注册了

ImportResource

ImportResource 可以配置一个配置文件,Spring可以针对文件的解析模式进行对bean进行注册。它的默认reader是xml模式。

案例:

需要被注册的类

public class Person {
}

我们用properties模式演示,import_resource_demo.properties:

person.(class)=com.jack.ascp.purchase.app.test.spring.anno.Person

测试类:注意我指定了它BeanDefinitionReader为 PropertiesBeanDefinitionReader.class。

@ImportResource(value = "import_resource_demo.properties", reader = PropertiesBeanDefinitionReader.class)
public class RegisterImportResourceTest {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(RegisterImportResourceTest.class);
        Person person = context.getBean(Person.class);
        System.out.println(person.toString());
    }
}

源码分析

注意:它也是不会立马调用,仅仅调用 this.importedResources.put(importedResource, readerClass) 将资源和信息保存起来

protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
		throws IOException {
	
	// 。。。。。其他方式。。。。。。。


	// 处理被@ImportResource的类
	// 通过统一的取数模型, 取到ImportResource的类注解的属性信息 
	AnnotationAttributes importResource =
			AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
	if (importResource != null) {
		// 通过locations获得其resources
		String[] resources = importResource.getStringArray("locations");
		// 获得其BeanDefinitionReader
		Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
		for (String resource : resources) {
			// resource进行一次解析, 因为resource中可能会有占位符情况
			String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
			// 不会立马调用,仅仅调用 this.importedResources.put(importedResource, readerClass) 将资源和信息保存起来
			configClass.addImportedResource(resolvedResource, readerClass);
		}
	}

	// 。。。。。其他方式。。。。。。。

	return null;
}

@Bean Method

案例

public class RegisterBeanMethodApplication {
    @Bean
    public Person person() {
        return new Person();
    }

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(RegisterBeanMethodApplication.class);
        Person person = context.getBean(Person.class);
        System.out.println(person.toString());
    }
}

源码

注意:它也是一样只是先记录,不会马上调用

protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
		throws IOException {

	// .....其他方式......

	// 处理存在方法被@Bean注解的类
	// 提取方法被@Bean注解的类的Metadata:MethodMetadata
	Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
	for (MethodMetadata methodMetadata : beanMethods) {
		// 仅仅使用his.beanMethods.add(method);进行存储,而不会直接调用
		configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
	}

	// .....其他方式......
	return null;
}

retrieveBeanMethodMetadata:

private Set<MethodMetadata> retrieveBeanMethodMetadata(SourceClass sourceClass) {
	AnnotationMetadata original = sourceClass.getMetadata();
	// 获取注解了bean的method
	Set<MethodMetadata> beanMethods = original.getAnnotatedMethods(Bean.class.getName());
	if (beanMethods.size() > 1 && original instanceof StandardAnnotationMetadata) {
		// Try reading the class file via ASM for deterministic declaration order...
		// Unfortunately, the JVM's standard reflection returns methods in arbitrary
		// order, even between different runs of the same application on the same JVM.
		try {
			AnnotationMetadata asm =
					this.metadataReaderFactory.getMetadataReader(original.getClassName()).getAnnotationMetadata();
			Set<MethodMetadata> asmMethods = asm.getAnnotatedMethods(Bean.class.getName());
			if (asmMethods.size() >= beanMethods.size()) {
				Set<MethodMetadata> selectedMethods = new LinkedHashSet<>(asmMethods.size());
				for (MethodMetadata asmMethod : asmMethods) {
					for (MethodMetadata beanMethod : beanMethods) {
						if (beanMethod.getMethodName().equals(asmMethod.getMethodName())) {
							selectedMethods.add(beanMethod);
							break;
						}
					}
				}
				if (selectedMethods.size() == beanMethods.size()) {
					// All reflection-detected methods found in ASM method set -> proceed
					beanMethods = selectedMethods;
				}
			}
		}
		catch (IOException ex) {
			logger.debug("Failed to read class file via ASM for determining @Bean method order", ex);
			// No worries, let's continue with the reflection metadata we started with...
		}
	}
	return beanMethods;
}

 

这五种bean定义何时被注册

ConfigClass结构

这bean定义的注册

上面5个用法中,只有@ComponentScan与@ComponentScans方式会在解析阶段完成注册,因为它用的是ClassPathBeanDefinitionScanner

其他的,对成员类的解析,@Import,@Bean Method 方式的,解析阶段不会完成注册。

他们是何时被注册的?

processConfigBeanDefinitions(registry)

    =>this.reader.loadBeanDefinitions(configClasses)

        =>loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator)

ConfigurationClassBeanDefinitionReader#loadBeanDefinitions

public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
	TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
	// 遍历注册
	for (ConfigurationClass configClass : configurationModel) {
		loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
	}
}

private void loadBeanDefinitionsForConfigurationClass(
		ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {

	// 是否需要被跳过, 如果A importBy B和C, 只要任何一个importBy不跳过它,那么就可以被注册。
	if (trackedConditionEvaluator.shouldSkip(configClass)) {
		String beanName = configClass.getBeanName();
		if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
			this.registry.removeBeanDefinition(beanName);
		}
		this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
		return;
	}

	// 1) 被导入类的注册
	if (configClass.isImported()) {
		registerBeanDefinitionForImportedConfigurationClass(configClass);
	}
	
	// 2) BeanMethod的调用和注册
	for (BeanMethod beanMethod : configClass.getBeanMethods()) {
		loadBeanDefinitionsForBeanMethod(beanMethod);
	}

	// 3) mportedResource 的调用和注册
	loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
	// 4) ImportBeanDefinitionRegistrar 的调用
	loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}

被导入类的bean定义

被导入的类有

成员类,ImportSelector引入的类。

他们的ConfigClass都有importBy属性。

private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) {
	// 获得Metadata生成AnnotatedGenericBeanDefinition
	AnnotationMetadata metadata = configClass.getMetadata();
	AnnotatedGenericBeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata);

	ScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(configBeanDef);
	configBeanDef.setScope(scopeMetadata.getScopeName());
	// 使用名称生成器生成bean的名称
	String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry);
	AnnotationConfigUtils.processCommonDefinitionAnnotations(configBeanDef, metadata);

	// 注册
	BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(configBeanDef, configBeanName);
	definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
	this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());
	configClass.setBeanName(configBeanName);

	if (logger.isDebugEnabled()) {
		logger.debug("Registered bean definition for imported class '" + configBeanName + "'");
	}
}

BeanMethod的注册

loadBeanDefinitionsForBeanMethod:

private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
	ConfigurationClass configClass = beanMethod.getConfigurationClass();
	MethodMetadata metadata = beanMethod.getMetadata();
	String methodName = metadata.getMethodName();

	// 条件判断, 要不要跳过
	if (this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) {
		configClass.skippedBeanMethods.add(methodName);
		return;
	}
	if (configClass.skippedBeanMethods.contains(methodName)) {
		return;
	}

	
	AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);
	Assert.state(bean != null, "No @Bean annotation attributes");

	// 如果@Bean 上没有配置name, 那么方法名将作为beanName
	List<String> names = new ArrayList<>(Arrays.asList(bean.getStringArray("name")));
	String beanName = (!names.isEmpty() ? names.remove(0) : methodName);

	// 其他的作为别名
	for (String alias : names) {
		this.registry.registerAlias(beanName, alias);
	}

	// Has this effectively been overridden before (e.g. via XML)?
	if (isOverriddenByExistingDefinition(beanMethod, beanName)) {
		if (beanName.equals(beanMethod.getConfigurationClass().getBeanName())) {
			throw new BeanDefinitionStoreException(beanMethod.getConfigurationClass().getResource().getDescription(),
					beanName, "Bean name derived from @Bean method '" + beanMethod.getMetadata().getMethodName() +
					"' clashes with bean name for containing configuration class; please make those names unique!");
		}
		return;
	}

	// 生成一个ConfigurationClassBeanDefinition
	ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
	beanDef.setResource(configClass.getResource());
	beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));

	// 是否是静态的, 则将方法作为工厂方法名 FactoryMethodName 
	if (metadata.isStatic()) {
		// static @Bean method
		beanDef.setBeanClassName(configClass.getMetadata().getClassName());
		beanDef.setFactoryMethodName(methodName);
	}
	else {
		// 否则将原来的种子类的beanName, 设置为FactoryBeanName
		// 这里的FactoryBean 和 之前实现FactoryBean接口那种不一样
		// 它指定了一个固定的工厂方法setUniqueFactoryMethodName
		beanDef.setFactoryBeanName(configClass.getBeanName());
		beanDef.setUniqueFactoryMethodName(methodName);
	}
	
	// 这后面都是设置beanDef的各种属性了
	beanDef.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
	beanDef.setAttribute(RequiredAnnotationBeanPostProcessor.SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);

	AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);

	Autowire autowire = bean.getEnum("autowire");
	if (autowire.isAutowire()) {
		beanDef.setAutowireMode(autowire.value());
	}

	String initMethodName = bean.getString("initMethod");
	if (StringUtils.hasText(initMethodName)) {
		beanDef.setInitMethodName(initMethodName);
	}

	String destroyMethodName = bean.getString("destroyMethod");
	beanDef.setDestroyMethodName(destroyMethodName);

	// Consider scoping
	ScopedProxyMode proxyMode = ScopedProxyMode.NO;
	AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(metadata, Scope.class);
	if (attributes != null) {
		beanDef.setScope(attributes.getString("value"));
		proxyMode = attributes.getEnum("proxyMode");
		if (proxyMode == ScopedProxyMode.DEFAULT) {
			proxyMode = ScopedProxyMode.NO;
		}
	}

	// Replace the original bean definition with the target one, if necessary
	BeanDefinition beanDefToRegister = beanDef;
	if (proxyMode != ScopedProxyMode.NO) {
		BeanDefinitionHolder proxyDef = ScopedProxyCreator.createScopedProxy(
				new BeanDefinitionHolder(beanDef, beanName), this.registry,
				proxyMode == ScopedProxyMode.TARGET_CLASS);
		beanDefToRegister = new ConfigurationClassBeanDefinition(
				(RootBeanDefinition) proxyDef.getBeanDefinition(), configClass, metadata);
	}

	if (logger.isDebugEnabled()) {
		logger.debug(String.format("Registering bean definition for @Bean method %s.%s()",
				configClass.getMetadata().getClassName(), beanName));
	}

	// 注册
	this.registry.registerBeanDefinition(beanName, beanDefToRegister);
}

其实它是作为factory_method方式进行注册的(工厂方法模式)。

factory_method_bean的doCreate链路:

AbstractAutowireCapableBeanFactory#doCreateBean

    =》AbstractAutowireCapableBeanFactory#createBeanInstance

       =》AbstractAutowireCapableBeanFactory#instantiateUsingFactoryMethod

           =》ConstructorResolver#instantiateUsingFactoryMethod

当@Bean注解的方法为非静态时,会进入下面 factoryBeanName!=null 的情况, 这个factoryBeanName对应我们的案例就是RegisterBeanMethodApplication。

@ImportResource中的bean注册

private void loadBeanDefinitionsFromImportedResources(
		Map<String, Class<? extends BeanDefinitionReader>> importedResources) {

	Map<Class<?>, BeanDefinitionReader> readerInstanceCache = new HashMap<>();

	importedResources.forEach((resource, readerClass) -> {
		// 如果readerClass 没有配置或者配置了BeanDefinitionReader.class, 那么根据文件后缀进行选择reader
		// 如果文件的后缀是.groovy, 则使用GroovyBeanDefinitionReader
		// 其他默认XmlBeanDefinitionReader
		if (BeanDefinitionReader.class == readerClass) {
			if (StringUtils.endsWithIgnoreCase(resource, ".groovy")) {
				// When clearly asking for Groovy, that's what they'll get...
				readerClass = GroovyBeanDefinitionReader.class;
			}
			else {
				// Primarily ".xml" files but for any other extension as well
				readerClass = XmlBeanDefinitionReader.class;
			}
		}

		// 为了不每次都实例化一个reader, 先从缓存中去reader,
		BeanDefinitionReader reader = readerInstanceCache.get(readerClass);
		if (reader == null) {
			try {
				// 实例化reader
				reader = readerClass.getConstructor(BeanDefinitionRegistry.class).newInstance(this.registry);
				// Delegate the current ResourceLoader to it if possible
				if (reader instanceof AbstractBeanDefinitionReader) {
					AbstractBeanDefinitionReader abdr = ((AbstractBeanDefinitionReader) reader);
					abdr.setResourceLoader(this.resourceLoader);
					abdr.setEnvironment(this.environment);
				}
				readerInstanceCache.put(readerClass, reader);
			}
			catch (Throwable ex) {
				throw new IllegalStateException(
						"Could not instantiate BeanDefinitionReader class [" + readerClass.getName() + "]");
			}
		}

		// 调用reader进行加载,这里面就会注册
		reader.loadBeanDefinitions(resource);
	});
}

ImportBeanDefinitionRegistrar的调用

ImportBeanDefinitionRegistrar#registerBeanDefinitions一旦调用就注册

private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {
	registrars.forEach((registrar, metadata) ->
			registrar.registerBeanDefinitions(metadata, this.registry));
}

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值