目录
@ComponentScan与@ComponentScans
实现ImportBeanDefinitionRegistrar
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));
}