跟踪AnnotationConfigApplicationContext的构造方法,进入到了下面这个方法
public AnnotationConfigApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
在初始化IOC容器的reader属性时,会调用AnnotationConfigUtils.registerAnnotationConfigProcessors
向容器注册所有注解相关的处理器,如下
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) {
DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
...
Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
//注册beanDefinition
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
...
return beanDefs;
}
如上代码,该方法向容器中注册了一个名为ConfigurationClassPostProcessor
的后置处理器,是一个BeanFactoryPostProcessor
,该处理器的beanName
是org.springframework.context.annotation.internalConfigurationAnnotationProcessor
,主要用来获取所有的自定义beanDefinition
,也是我们这次问题的关键所在。
然后走到Spring中最重要的方法refresh
,ConfigurationClassPostProcessor
起作用的地方在其中的invokeBeanFactoryPostProcessors(beanFactory)
方法,这一步骤会执行所有BeanFactoryPostProcessor
其中的方法,如下。
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
// Invoke BeanDefinitionRegistryPostProcessors first, if any.
Set<String> processedBeans = new HashSet<>();
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
...
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
}
}
因为ConfigurationClassPostProcessor
实现了BeanDefinitionRegistryPostProcessor
,所以在执行getBeanNamesForType
时ConfigurationClassPostProcessor
会被初始化并放入容器中;getBeanNamesForType
方法会找到所有BeanDefinitionRegistryPostProcessor
类型的Bean并将它们初始化完全后放入容器中。
又因为ConfigurationClassPostProcessor
实现了PriorityOrdered
接口,所以它的postProcessBeanDefinitionRegistry
会被执行,该方法的功能主要体现在processConfigBeanDefinitions
中调用的parse
方法,该方法在ConfigurationClassParser
类上,它实际执行方法是doProcessConfigurationClass
,它会解析所有加了@Configuration
的类;
调用链如下
ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法
调用了ConfigurationClassPostProcessor的processConfigBeanDefinitions方法
而ConfigurationClassPostProcessor的processConfigBeanDefinitions方法
调用了 ConfigurationClassParser的parse方法(解析获得所有自定义bean信息)
ConfigurationClassParser的parse方法
调用了 ConfigurationClassParser的processConfigurationClass方法
ConfigurationClassParser的processConfigurationClass方法
调用了ConfigurationClassParser的doProcessConfigurationClass方法
doProcessConfigurationClass
代码如下:
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
throws IOException {
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
// Recursively process any member (nested) classes first
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.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
"]. Reason: Environment must implement ConfigurableEnvironment");
}
}
// Process any @ComponentScan annotations
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
for (AnnotationAttributes componentScan : componentScans) {
// The config class is annotated with @ComponentScan -> perform the scan immediately
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// Check the set of scanned definitions for any further config classes and parse recursively if needed
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
// Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), true);
// Process any @ImportResource annotations
AnnotationAttributes importResource =
AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
if (importResource != null) {
String[] resources = importResource.getStringArray("locations");
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
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
// Process default methods on interfaces
processInterfaces(configClass, sourceClass);
// Process superclass, if any
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;
}
上述代码篇幅过长,主要是解析指定标签获取到它们的定义信息。
按顺序主要包括下面这几个功能:
@Configuration
的匿名内部类;@PropertySource
注解;@ComponentScan
注解,会使用ComponentScanAnnotationParser
的parse
方法扫描获得所有指定目录下的所有BeanDefinitionHolder
,然后在递归的去解析这些类;@Import
注解;@ImportResource
注解;@Bean
方法;Interface
上的默认方法;SuperClass
;也就是processConfigBeanDefinitions
中调用的parse
方法会获取到所有需要管理的Bean定义信息,然后在parse
之后得到加载,如下
ConfigurationClassParser parser = new ConfigurationClassParser(...);
parser.parse(candidates); //解析
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
this.reader.loadBeanDefinitions(configClasses);
到此,就已经大致解释清楚了Spring是如何通过注解获取到所有自定义Bean的。
获取所有自定义Bean的功能主要体现ConfigurationClassPostProcessor
这个BeanFactory后置处理器中,它会在被调用执行postProcessBeanDefinitionRegistry
方法时加载所有自定义Bean信息到容器中,而扫描的关键就在于ConfigurationClassParser
的doProcessConfigurationClass
方法,它通过指定的@Configuration
类解析指定的注解。
在Spring Boot中也采用了相似的方法。