-- 以下内容均基于2.1.8.RELEASE版本
在《SpringBoot启动过程的分析》系列文章中简要的对SpringBoot整体的启动流程作了梳理,但并未针对诸多细节进行分析。前面的篇章中介绍了从SpringBoot应用程序入口开始执行,一直到上下文刷新完成。期间它加载了所有的类,但是并未直接指出它是在哪个环节加载的类,在加载的过程中如何处理的,以及我们在程序入口所使用的各种注解是如何解析的。本文将对这一疑惑进行解答。
要分析SpringBoot加载类的过程,就必须清晰的知道我们的类到底在哪个环节被加载的。也就是需要定位到加载类的入口,如何来确定这个入口呢?通过阅读spring-framework的官方文档可以得知我们可以从ApplicationContext中来通过getBean()方法来获取Bean。那么通过这个入口就能找到存放Bean的地方,找到存放Bean的地方就可以通过调试得知它在什么时候被加载进来,进而确定Bean加载的入口。
找到Bean存放位置
这里通过一个简单示例来展示如何寻找Bean存放位置
public static void main(String[] args) {
SpringApplication application = new SpringApplication(Example.class);
ConfigurableApplicationContext context = application.run(args);
// 从容器中获取一个Bean
Example2 example2 = context.getBean(Example2.class);
}
上述代码是一个非常常见的获取Bean的代码,跟踪context.getBean()方法就能找到它存放的位置。
// AbstractApplicationContext.class
public <T> T getBean(Class<T> requiredType) throws BeansException {
assertBeanFactoryActive();
// 从BeanFactory获取Bean
return getBeanFactory().getBean(requiredType);
}
// DefaultListableBeanFactory.class
public <T> T getBean(Class<T> requiredType) throws BeansException {
return getBean(requiredType, (Object[]) null);
}
public <T> T getBean(Class<T> requiredType, @Nullable Object... args) throws BeansException {
Assert.notNull(requiredType, "Required type must not be null");
// 可以看到Object对象是这里获取的
Object resolved = resolveBean(ResolvableType.forRawClass(requiredType), args, false);
if (resolved == null) {
throw new NoSuchBeanDefinitionException(requiredType);
}
return (T) resolved;
}
// ...中间省略部分代码
private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
List<String> result = new ArrayList<>();
// ① Check all bean definitions.
for (String beanName : this.beanDefinitionNames) {
// ...中间省略部分代码
}
return StringUtils.toStringArray(result);
}
① - 一路跟踪下来,可以看到所有的Bean都是在BeanFactory的beanDefinitionNames里面存放。因此关注这个属性何时被赋值就可以找到Bean加载的入口。
确定Bean在哪个环节被加载
当得知Bean存放于BeanFactory的beanDefinitionNames属性中,在启动阶段关注这个属性值的变化即可确定它在哪个阶段被赋值,可以肯定的是,它一定是在上下文容器创建完毕之后才会加载,因为容器都没有怎么存放。下图就展示了在创建完毕之后的上下文中Bean的初始化数量。
图: 创建完毕上下文容器
图中所展示的几个Bean是SpringBoot内置的处理器,在SpringBoot启动过程的分析-创建应用程序上下文一文中已经介绍过此处不再次解读。在创建完毕上下文之后有两个重要操作:预处理上下文、刷新上下文。那么初始化类必然就在这两个步骤中间了。首先在刷新上下文处打断点,看看在预处理上下文时是否初始化了其他的Bean。
图:预处理上下文完毕
此处可以发现它多了一个"Example"的类,单并未出现其他新的类,Example类是笔者调试程序的入口,在前面文章中也已经介绍过。因此可以断定,其他的类肯定在刷新上下文容器的时候被加载。快速确定方法就是在刷新上下文容器下方打断点,查看beanDefinitionNames的内容变化。在确定了是刷新容器时加载所有类之后,进入刷新容器的代码,可以看到它也清晰的划分了多个步骤,和上面一样,以每个方法为界,观察bean的加载情况。
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
//...省略部分代码
}
}
笔者在经过调试之后确定了会在invokeBeanFactoryPostProcessors(beanFactory);这个方法内部加载所有的类。至此就确定了Bean的实际加载点。
通过BeanFactoryPostProcessor加载所有的类
提示:
下文中所提到的"BeanFactoryPostProcessor",均表示类型为BeanFactoryPostProcessor的接口统称,包括了它的扩展接口BeanDefinitionRegistryPostProcessor以及他们的实现类。
invokeBeanFactoryPostProcessors()方法是加载并调用所有的BeanFactoryProcessor,我们在前面的文章中已经详细介绍了它的执行流程和业务细节,不明白的同学可以再去回顾一下SpringBoot启动过程的分析-刷新ApplicationContext。这里再重申一下有关于BeanFactoryPostProcessor的相关概念。加强了这些概念,后续对其他代码的理解也会更容易。
BeanFactoryPostProcessor,是Spring内部诸多PostProcessor中的一种,注意它的前缀名称为BeanFactory,Bean工厂意味着它可以创建Bean,根据它的注释描述可以得知它可以修改Bean的定义,也可以修改Bean的属性值,但是它只能用于处理BeanDefinition,而不能处理Bean的实例。简单说就是,它可以在类实例化之前去修改它。另外一个BeanDefinitionRegistryPostProcessor它继承了BeanFactoryPostProcessor,对其进行了扩展,主要用于修改上下文中的Bean定义,加载所有常规的Bean,添加Bean。简单点理解就是它要比BeanFactoryPostProcessor更先执行。主要用于注册Bean。
在调用AbstractApplicationContext.invokeBeanFactoryPostProcessors()方法的时候需要注意它传入的BeanFactoryPostProcessor参数,具体可以看代码:
// AbstractApplicationContext.java
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
// ①
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
// ...省略部分代码
}
public List<BeanFactoryPostProcessor> getBeanFactoryPostProcessors() {
return this.beanFactoryPostProcessors;
}
① - 这里需要注意传入的参数,它由getBeanFactoryPostProcessors()方法提供,而这个方法返回的是AbstractApplicationContext.beanFactoryPostProcessor这个属性值。这个属性内部所定义的BeanFactoryPostProcessor都是在ApplicationContextInitializer的扩展中添加进来的,而创建上下文容器时添加的内部的处理器则存放在DefaultListableBeanFactory.beanDefinitionNames这个属性中。所以在处理BeanFactoryPostProcessor的时候首先处理的是ApplicationContextInitializer中的内容。
通过两处不同的BeanFactoryPostProcessor可以反推出BeanFactoryPostProcessor初始化的两种方式:
- 通过ConfigurableApplicationContext.addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor)来添加
- 通过BeanDefinitionRegistry.registerBeanDefinition(String beanName, BeanDefinition beanDefinition)来注册一个Bean
实际上对于Bean加载不光包括我们自己编写的业务代码,也包括SpringBoot自己的其他组件。因为BeanFactoryPostProcessor本身也是一个类。他们在ApplicationContextInitializer接口中被添加,或是在BeanDefinitionRegistry中被注册。区别就是一个是直接添加实例,一个是注册BeanDefinition。言归正传回到Bean的加载中来;此处对于通过ApplicationContextInitializer接口中被添加的BeanFactoryPostProcessor不作分析,因为代码比较简洁,他们本身也没涉及过多的操作,感兴趣的可以自己debug。这里重点分析通过BeanDefinitionRegistry注册的BeanFactoryPostProcessor即DefaultListableBeanFactory.beanDefinitionNames这个属性中注册的类。内置的BeanFactoryPostProcessor是在容器创建的时候加入的,可参考之前的分析注册内定的BeanFactoryPostProcessor。
经过查看这些内置的类,只有ConfigurationClassPostProcessor和类加载相关。
ConfigurationClassPostProcessor
主要用于对@Configuration注解进行处理。在SpringBoot应用中,往往都是从一个Main函数开始,启动类上面也必须使用@SpringBootApplication注解来标明它的身份;因此@Configuration注解也代表着应用的起点;因在BeanFactoryPostProcessor被调用的时候是按照优先级来的,首先被调用的是BeanDefinitionRegistryPostProcessor,所以首先执行postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)方法。
// ConfigurationClassPostProcessor.java
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
// ①
int registryId = System.identityHashCode(registry);
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException("postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
}
// ②
if (this.factoriesPostProcessed.contains(registryId)) {
throw new IllegalStateException("postProcessBeanFactory already called on this post-processor against " + registry);
}
// ③
this.registriesPostProcessed.add(registryId);
// ④
processConfigBeanDefinitions(registry);
}
① - 获取注册ID
② - 判断当前Processor是否被执行过
③ - 添加到已处理列表
④ - 处理配置相关的BeanDefinition
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
// 获取所有已注册的BeanDefinition,寻找具有@Configuration注解的类
String[] candidateNames = registry.getBeanDefinitionNames();
// 遍历所有的beanName
for (String beanName : candidateNames) {
// 根据名称找到BeanDefinition
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
// 判断当前类是Full模式还是Lite模式,就为了打印个日志?No,查看日志内容,打印的是:当前类已经被当做一个configuration类被处理过。
// 那就意味着默认情况下它是没有设置ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE 这个属性的。
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) || ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
// 判断当前处理的类是不是完整的配置类,也就是是否被@Configuration注解修饰,若被修饰则会给当前的BeanDefinition设置一个attribute(org.springframework.context.annotation.ConfigurationClassPostProcessor.configurationClass = full)
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
// 加入配置候选列表
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
// 若没有被@Configuration注解的类,直接返回
// Return immediately if no @Configuration classes were found
if (configCandidates.isEmpty()) {
return;
}
// 根据优先级排序
// Sort by previously determined @Order value, if applicable
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});
// 设置BeanNameGenerator用于生成稍后检测到的Bean的名称
// Detect any custom bean name generation strategy supplied through the enclosing application context
SingletonBeanRegistry sbr = null;
if (registry instanceof SingletonBeanRegistry) {
sbr = (SingletonBeanRegistry) registry;
if (!this.localBeanNameGeneratorSet) {
BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
if (generator != null) {
this.componentScanBeanNameGenerator = generator;
this.importBeanNameGenerator = generator;
}
}
}
if (this.environment == null) {
this.environment = new StandardEnvironment();
}
// 新建一个配置类解析器,用于解析所有@Configuration注解的类
// Parse each @Configuration class
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
// 将要被解析的配置类
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
// 已经被解析的配置类
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
// ① 开始解析配置类
parser.parse(candidates);
parser.validate();
// ② 获取解析到的配置类
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
// ③ 构建Reader对象,为加载Bean做准备 Read the model and create bean definitions based on its content
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
// ④ 从配置类开始加载Bean
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
candidates.clear();
if (registry.getBeanDefinitionCount() > candidateNames.length) {
String[] newCandidateNames = registry.getBeanDefinitionNames();
Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
Set<String> alreadyParsedClasses = new HashSet<>();
for (ConfigurationClass configurationClass : alreadyParsed) {
alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
}
for (String candidateName : newCandidateNames) {
if (!oldCandidateNames.contains(candidateName)) {
BeanDefinition bd = registry.getBeanDefinition(candidateName);
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
!alreadyParsedClasses.contains(bd.getBeanClassName())) {
candidates.add(new BeanDefinitionHolder(bd, candidateName));
}
}
}
candidateNames = newCandidateNames;
}
}
while (!candidates.isEmpty());
// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
}
if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
// Clear cache in externally provided MetadataReaderFactory; this is a no-op
// for a shared cache since it'll be cleared by the ApplicationContext.
((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
}
}
根据上面的void processConfigBeanDefinitions(BeanDefinitionRegistry registry)方法中的do-while循环可以看到,它内部是按照解析@Configuration->取出@Configuration->构建BeanDefinitionReader->从@Configuration读取BeanDefinition的流程来完成类的加载。
开始解析@Configuration类
@Configuration注解是Spring中基于Java配置容器中的一个注解,属于类级别的注解,它主要用于标明一组@Bean定义的来源。通常@Configuration和@Bean同时使用。
// ConfigurationClassParser.java
public void parse(Set<BeanDefinitionHolder> configCandidates) {
// 遍历所有具有@Configuration注解的类
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
if (bd instanceof AnnotatedBeanDefinition) {
// 解析AnnotatedBeanDefinition类型的配置类(可以获取类的注解元数据)
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
}
else {
parse(bd.getBeanClassName(), holder.getBeanName());
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
}
}
this.deferredImportSelectorHandler.process();
}
// 包装为ConfigurationClass对象
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(metadata, beanName));
}
// 判断是否已经执行过
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
ConfigurationClass existingClass = this.configurationClasses.get(configClass);
if (existingClass != null) {
if (configClass.isImported()) {
if (existingClass.isImported()) {
existingClass.mergeImportedBy(configClass);
}
// Otherwise ignore new imported config class; existing non-imported class overrides it.
return;
}
else {
// Explicit bean definition found, probably replacing an import.
// Let's remove the old one and go with the new one.
this.configurationClasses.remove(configClass);
this.knownSuperclasses.values().removeIf(configClass::equals);
}
}
// 包装为SourceClass便于统一处理
// Recursively process the configuration class and its superclass hierarchy.
SourceClass sourceClass = asSourceClass(configClass);
do {
// 这里才开始处理配置类
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
while (sourceClass != null);
this.configurationClasses.put(configClass, configClass);
}
// 真正开始处理配置的方法
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
throws IOException {
// 优先处理@Component注解
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
// 递归处理
// Recursively process any member (nested) classes first
processMemberClasses(configClass, sourceClass);
}
// 处理@PropertySource注解
// 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");
}
}
// 处理@ComponentScan注解
// 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());
}
}
}
}
// 处理@Import注解
// Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), true);
// 处理@ImportResource注解
// 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);
}
}
// 处理单个@Bean方法
// 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配置类同时也和其他注解有关联,这里说的关联是其他注解的行为会影响配置类本身的状态。例如方法中提到的@Component、@ComponentScan、@PropertySource、@Import、@Bean、@ImportResource。
处理@Component注解
@Component注解表示被修饰的类将会被识别为受Spring管理的类。将会被注册到Bean容器中。
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) {
// 判断是否有@Configuration或者@Component注解
if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) && !memberClass.getMetadata().getC
lassName().equals(configClass.getMetadata().getClassName())) {
candidates.add(memberClass);
}
}
// 排序
OrderComparator.sort(candidates);
// 检测是否有循环导入(@Import)的问题
for (SourceClass candidate : candidates) {
if (this.importStack.contains(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
// 递归调用处理
processConfigurationClass(candidate.asConfigClass(configClass));
}
finally {
this.importStack.pop();
}
}
}
}
}
在该方法中,主要用于处理当前传入的configClass内部的嵌套类、成员类中是否有@Configuration、@Component注解。一般来说@Configuratio
n都是单独使用的一个类。
处理@PropertySource注解
@PropertySource注解用于加载指定的properties配置文件到Spring的Environment中
// 内部实现比较简单,自行debug即可
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");
}
}
处理@ComponentScan注解
@ComponentScan注解用于指明当前应用将扫描哪些包下的具有@Component注解的类。这个注解必须添加到@Configuration类中
// 根据ComponentScans配置的包路径查找带@Component注解的类
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() && !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
// 获取所有带@Component注解的类
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());
}
}
}
}
这里重点分析它是如何查找@ComponentScans注解的,跳过无用的调用链,查看真正开始查找的方法。
// AnnotationConfigUtils.java
// 需要注意的是参数:metadata代表从哪里获取,containerClassName表示包含注解(例如@ComponentScans,它本身的值可以包含多个@ComponentScan),annotationClassName是当前要获取的目标注解也就是@ComponentScan
static Set<AnnotationAttributes> attributesForRepeatable(AnnotationMetadata metadata, String containerClassName, String annotationClassName) {
Set<AnnotationAttributes> result = new LinkedHashSet<>();
// ①
// Direct annotation present?
addAttributesIfNotNull(result, metadata.getAnnotationAttributes(annotationClassName, false));
// ②
// Container annotation present?
Map<String, Object> container = metadata.getAnnotationAttributes(containerClassName, false);
if (container != null && container.containsKey("value")) {
for (Map<String, Object> containedAttributes : (Map<String, Object>[]) container.get("value")) {
addAttributesIfNotNull(result, containedAttributes);
}
}
// Return merged result
return Collections.unmodifiableSet(result);
}
① - 此处为@ComponentScan,称之为直接注解”,即在类上面直接声明的注解。
// StandardAnnotationMetadata.class
public Map<String, Object> getAnnotationAttributes(String annotationName, boolean classValuesAsString) {
return (this.annotations.length > 0 ? AnnotatedElementUtils.getMergedAnnotationAttributes(getIntrospectedClass(), annotationName, classValuesAsString, this.nestedAnnotationsAsMap) : null);
}
// AnnotatedElementUtils.class
public static AnnotationAttributes getMergedAnnotationAttributes(AnnotatedElement element,
String annotationName, boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
AnnotationAttributes attributes = searchWithGetSemantics(element, null, annotationName, new MergedAnnotationAttributesProcessor(classValuesAsString, nestedAnnotationsAsMap));
AnnotationUtils.postProcessAnnotationAttributes(element, attributes, classValuesAsString, nestedAnnotationsAsMap);
return attributes;
}
// 通过一系列的重载方法,最终调用此方法
private static <T> T searchWithGetSemantics(AnnotatedElement element,
Set<Class<? extends Annotation>> annotationTypes, @Nullable String annotationName,
@Nullable Class<? extends Annotation> containerType, Processor<T> processor,
Set<AnnotatedElement> visited, int metaDepth) {
if (visited.add(element)) {
try {
// Start searching within locally declared annotations
// 获取当前元素声明的所有注解
List<Annotation> declaredAnnotations = Arrays.asList(AnnotationUtils.getDeclaredAnnotations(element));
// 获取这些注解中指定的类型
T result = searchWithGetSemanticsInAnnotations(element, declaredAnnotations, annotationTypes, annotationName, containerType, processor, visited, metaDepth);
if (result != null) {
return result;
}
if (element instanceof Class) { // otherwise getAnnotations doesn't return anything new
Class<?> superclass = ((Class<?>) element).getSuperclass();
if (superclass != null && superclass != Object.class) {
List<Annotation> inheritedAnnotations = new LinkedList<>();
for (Annotation annotation : element.getAnnotations()) {
if (!declaredAnnotations.contains(annotation)) {
inheritedAnnotations.add(annotation);
}
}
// Continue searching within inherited annotations
result = searchWithGetSemanticsInAnnotations(element, inheritedAnnotations,
annotationTypes, annotationName, containerType, processor, visited, metaDepth);
if (result != null) {
return result;
}
}
}
}
catch (Throwable ex) {
AnnotationUtils.handleIntrospectionFailure(element, ex);
}
}
return null;
}
private static <T> T searchWithGetSemanticsInAnnotations(@Nullable AnnotatedElement element,
List<Annotation> annotations, Set<Class<? extends Annotation>> annotationTypes,
@Nullable String annotationName, @Nullable Class<? extends Annotation> containerType,
Processor<T> processor, Set<AnnotatedElement> visited, int metaDepth) {
// 遍历所有注解
// Search in annotations
for (Annotation annotation : annotations) {
// 获取当前注解类型
Class<? extends Annotation> currentAnnotationType = annotation.annotationType();
if (!AnnotationUtils.isInJavaLangAnnotationPackage(currentAnnotationType)) {
// 判断是否处理过、当前注解的名称是否和将要查找的一致、是否默认处理(默认为true,请debug的时候注意传入的参数)
if (annotationTypes.contains(currentAnnotationType) || currentAnnotationType.getName().equals(annotationName) || processor.alwaysProcesses()) {
// 若匹配,则查找内部的注解属性
T result = processor.process(element, annotation, metaDepth);
if (result != null) {
if (processor.aggregates() && metaDepth == 0) {
processor.getAggregatedResults().add(result);
}
else {
return result;
}
}
}
// 如果没有找到
// Repeatable annotations in container?
else if (currentAnnotationType == containerType) {
for (Annotation contained : getRawAnnotationsFromContainer(element, annotation)) {
T result = processor.process(element, contained, metaDepth);
if (result != null) {
// No need to post-process since repeatable annotations within a
// container cannot be composed annotations.
processor.getAggregatedResults().add(result);
}
}
}
}
}
// Recursively search in meta-annotations
for (Annotation annotation : annotations) {
Class<? extends Annotation> currentAnnotationType = annotation.annotationType();
if (!AnnotationUtils.hasPlainJavaAnnotationsOnly(currentAnnotationType)) {
T result = searchWithGetSemantics(currentAnnotationType, annotationTypes, annotationName, containerType, processor, visited, metaDepth + 1);
if (result != null) {
processor.postProcess(element, annotation, result);
if (processor.aggregates() && metaDepth == 0) {
processor.getAggregatedResults().add(result);
}
else {
return result;
}
}
}
}
return null;
}
// AnnotatedElementUtils.class内部类AnnotatedElementUtils.class
public AnnotationAttributes process(@Nullable AnnotatedElement annotatedElement, Annotation annotation, int metaDepth) {
return AnnotationUtils.retrieveAnnotationAttributes(annotatedElement, annotation, this.classValuesAsString, this.nestedAnnotationsAsMap);
}
// AnnotationUtils.class
static AnnotationAttributes retrieveAnnotationAttributes(@Nullable Object annotatedElement,
Annotation annotation, boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
Class<? extends Annotation> annotationType = annotation.annotationType();
AnnotationAttributes attributes = new AnnotationAttributes(annotationType);
// 遍历注解的方法,获取属性名称和属性值,填充至AnnotationAttributes对象内部(实际上就是个Map)
for (Method method : getAttributeMethods(annotationType)) {
try {
Object attributeValue = method.invoke(annotation);
Object defaultValue = method.getDefaultValue();
if (defaultValue != null && ObjectUtils.nullSafeEquals(attributeValue, defaultValue)) {
attributeValue = new DefaultValueHolder(defaultValue);
}
attributes.put(method.getName(), adaptValue(annotatedElement, attributeValue, classValuesAsString, nestedAnnotationsAsMap));
}
catch (Throwable ex) {
if (ex instanceof InvocationTargetException) {
Throwable targetException = ((InvocationTargetException) ex).getTargetException();
rethrowAnnotationConfigurationException(targetException);
}
throw new IllegalStateException("Could not obtain annotation attribute value for " + method, ex);
}
}
return attributes;
}
② - 此处为@ComponentScans,称之为”容器注解”,它可以包含多个@ComponentScan,代码逻辑和获取直接注解@ComponentScan并没有太大差异,可自行debug
处理到这一步,仅仅是获取到了所有的@ComponentScan注解,接下来还需要解析注解里面配置的包路径
// ConfigurationClassParser.class 284行
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());
// 检查返回的BeanDefinition里面是否有其他的配置类,如果需要的话会递归进行解析
// 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());
}
}
}
// 以下代码为获取BeanDefinition的具体流程
// ComponentScanAnnotationParser.class
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
// 构建扫描器
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry, componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);
// 构建类名生成器
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) {
scanner.setScopedProxyMode(scopedProxyMode);
}
else {
Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");
scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));
}
// 获取资源模式(注解配置扫描包都是扫描class因此此处为:**/*.class)
scanner.setResourcePattern(componentScan.getString("resourcePattern"));
// 获取@ComponentScan注解里面配置的include过滤器
for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {
for (TypeFilter typeFilter : typeFiltersFor(filter)) {
scanner.addIncludeFilter(typeFilter);
}
}
// 获取@ComponentScan注解里面配置的exclude过滤器
for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {
for (TypeFilter typeFilter : typeFiltersFor(filter)) {
scanner.addExcludeFilter(typeFilter);
}
}
// 获取@ComponentScan注解里面配置的lazyInit值
boolean lazyInit = componentScan.getBoolean("lazyInit");
if (lazyInit) {
scanner.getBeanDefinitionDefaults().setLazyInit(true);
}
// 获取需要扫描的路径集合
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);
Collections.addAll(basePackages, tokenized);
}
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);
}
});
// 通过扫描器扫描指定路径下的具有@Component注解的类
return scanner.doScan(StringUtils.toStringArray(basePackages));
}
// ClassPathBeanDefinitionScanner.class
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
// 查找所有@Component注解标识的类
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
// 获取作用域元数据
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
// 生成类名
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
// 对普通的Bean 进行处理
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
// 对包含有注解的Bean进行处理,比如@Lazy、@Primary
if (candidate instanceof AnnotatedBeanDefinition) {
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
// 检查当前加载的Bean名称是否有冲突
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
// ClassPathScanningCandidateComponentProvider.class
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
}
else {
// 真正开始搜索类的方法
return scanCandidateComponents(basePackage);
}
}
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
try {
// 获取资源的路径
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + resolveBasePackage(basePackage) + '/' + this.resourcePattern;
// 获取所有资源
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
boolean traceEnabled = logger.isTraceEnabled();
boolean debugEnabled = logger.isDebugEnabled();
// 为每一个类生成BeanDefinition对象
for (Resource resource : resources) {
if (traceEnabled) {
logger.trace("Scanning " + resource);
}
if (resource.isReadable()) {
try {
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
// 判断是否具有@Component注解
if (isCandidateComponent(metadataReader)) {
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setResource(resource);
sbd.setSource(resource);
if (isCandidateComponent(sbd)) {
if (debugEnabled) {
logger.debug("Identified candidate component class: " + resource);
}
candidates.add(sbd);
}
else {
if (debugEnabled) {
logger.debug("Ignored because not a concrete top-level class: " + resource);
}
}
}
else {
if (traceEnabled) {
logger.trace("Ignored because not matching any filter: " + resource);
}
}
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to read candidate component class: " + resource, ex);
}
}
else {
if (traceEnabled) {
logger.trace("Ignored because not readable: " + resource);
}
}
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
}
return candidates;
}
至此,通过@ComponentScan注解配置扫描指定的包,到获取到具体的带有@Component注解的类已经全部获取完毕。
处理@Import注解
@Import注解主要用于引入另外一个@Configuration。和Spring XML配置文件中的
// ConfigurationClassParser.class 302行
// 处理@Import注解,请注意参数内部的getImports方法
processImports(configClass, sourceClass, getImports(sourceClass), true);
private Set<SourceClass> getImports(SourceClass sourceClass) throws IOException {
Set<SourceClass> imports = new LinkedHashSet<>();
Set<SourceClass> visited = new LinkedHashSet<>();
collectImports(sourceClass, imports, visited);
return imports;
}
// 递归获取@Import注解
private void collectImports(SourceClass sourceClass, Set<SourceClass> imports, Set<SourceClass> visited) throws IOException {
// 添加已处理的避免无限递归
if (visited.add(sourceClass)) {
// 获取传入资源上的注解列表
for (SourceClass annotation : sourceClass.getAnnotations()) {
// 获取注解名称
String annName = annotation.getMetadata().getClassName();
// 若当前注解不是@Import则递归查找
if (!annName.equals(Import.class.getName())) {
collectImports(annotation, imports, visited);
}
}
// 添加已经获取的所有注解
imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value"));
}
}
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass, Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
if (importCandidates.isEmpty()) {
return;
}
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)) {
// Candidate class is an ImportSelector -> delegate to it to determine imports
Class<?> candidateClass = candidate.loadClass();
ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
ParserStrategyUtils.invokeAwareMethods(selector, this.environment, this.resourceLoader, this.registry);
if (selector instanceof DeferredImportSelector) {
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}
else {
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
processImports(configClass, currentSourceClass, importSourceClasses, false);
}
}
// 是否是ImportBeanDefinitionRegistrar的实现
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// Candidate class is an ImportBeanDefinitionRegistrar ->
// delegate to it to register additional bean definitions
Class<?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar = BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
ParserStrategyUtils.invokeAwareMethods(registrar, this.environment, this.resourceLoader, this.registry);
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
// 都不是的话把它当做@Configuration来处理
else {
// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
// process it as an @Configuration class
this.importStack.registerImport(currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
// 将其作为@Configuration处理
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();
}
}
}
processImports() 方法用于处理解析到的Import的类,分为3种类型"ImportSelector"的实现、"ImportBeanDefinitionRegistrar"的实现、"本身也是一个@Configuration"的实现。
ImporSelector的实现:
主要用于导入@Configuration配置类,并且可以实现EnvironmentAware、BeanFactoryAware、BeanClassLoaderAware、ResourceLoaderAware接口,并在调用ImportSelector.selectImports方法之前调用它们。
ImportBeanDefinitionRegistrar的实现:
用于导入导入@Configuration配置了,并可以注册BeanDefinition
@Configuration:
如果导入的是一个配置,则进入配置解析功能
处理@ImportResource注解
用于引入Spring xml配置文件,类似于Spring XML中的
@Configuration
@ImportResource("classpath:/com/acme/properties-config.xml")
public class AppConfig {
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean
public DataSource dataSource() {
return new DriverManagerDataSource(url, username, password);
}
}
源码解析:
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);
}
}
① - 获取@ImportResource注解的value值
② - 获取BeanDefinitionReader
③ - 处理资源路径下的占位符
④ - 将资源和对应的解析器存放至当前配置类的importedResources属性中,它是一个LinkedHashMap
处理@Bean注解
此处处理的是在配置类中具有@Bean注解的方法
// ①
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
// ②
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
// ④
private void processInterfaces(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
for (SourceClass ifc : sourceClass.getInterfaces()) {
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(ifc);
for (MethodMetadata methodMetadata : beanMethods) {
if (!methodMetadata.isAbstract()) {
// A default method or other concrete method on a Java 8+ interface...
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
}
processInterfaces(configClass, ifc);
}
}
// ⑤
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();
}
}
① - 获取所有具有@Bean注解的方法
② - 将获取到的方法包装为BeanMethod对象(表示一个具有@Bean注解的@Configuration类的方法)保存到当前配置类的beanMethods属性中
④ - 处理接口中具有@Bean注解的方法
⑤ - 处理父类中具有@Bean注解的方法
取出@Configuration
直接从Parser中取出之前解析时缓存的配置类,因为这段代码在do-while循环中,因此首先移除已处理的。
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
构建BeanDefinitionReader
若Reader为空,则创建,用于读取配置中的BeanDefinition
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
@Configuration读取BeanDefinition
前面对各种注解的的解析最终并没有处理解析的结果,而是将其放在了ConfigurationClass对象的属性当中存储,在这里将通过Reader来处理这
些不同来源的BeanDefinition。
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
// ①
for (ConfigurationClass configClass : configurationModel) {
// ②
loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
}
}
① - 遍历所有的@Configuration
② - 从@Configuration读取BeanDefinition
private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
// ①
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;
}
// ②
if (configClass.isImported()) {
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
// ③
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
loadBeanDefinitionsForBeanMethod(beanMethod);
}
// ④
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
// ⑤
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
① - 是否需要跳过
② - 当前配置类本身是否通过@Import导入,若有则将自身注册为BeanDefinition
③ - 当前配置类中是否有@Bean注解修饰的方法,若有则处理
④ - 加载从@ImportResource导入的XML文件中定义的Bean
⑤ - 加载从@Import导入的BeanDefinition
合并已处理的BeanDefinition
// ①
String[] candidateNames = registry.getBeanDefinitionNames();
if (registry.getBeanDefinitionCount() > candidateNames.length) {
// ②
String[] newCandidateNames = registry.getBeanDefinitionNames();
// ③
Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
// ④
Set<String> alreadyParsedClasses = new HashSet<>();
// ⑤
for (ConfigurationClass configurationClass : alreadyParsed) {
alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
}
// ⑥
for (String candidateName : newCandidateNames) {
// ⑦
if (!oldCandidateNames.contains(candidateName)) {
// ⑧
BeanDefinition bd = registry.getBeanDefinition(candidateName);
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
!alreadyParsedClasses.contains(bd.getBeanClassName())) {
candidates.add(new BeanDefinitionHolder(bd, candidateName));
}
}
}
// ⑨
candidateNames = newCandidateNames;
}
① - candidateNames 在方法的一开始就从registry中获取已经处理过的BeanDefinition名称
② - newCandidateNames 表示本次从配置类的解析中加载完毕BeanDefinition之后的BeanDefinition名称列表,它包含第一步里面的名称
③ - 将第一步的名称列表转换为Set集合
④ - 声明已解析的集合,此处用Set因为它可以保证元素不重复
⑤ - 遍历本次已经处理的所有类集合,将其加入第四步声明的Set集合内
⑥ - 遍历registry中现有的列表
⑦ - 当前的BeanDefinition必须是本次代码执行时加入的才进行处理
⑧ - 获取当前处理的类,判断是否为Configuration,并设置FULL模式和LITE模式
⑨ - 获取全部已经处理的类赋值给candidateNames
总结
SpringBoot中对于框架外的类加载从容器刷新阶段中的invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory)方法开始。用于调用BeanFactoryPostProcessor,位于org.springframework.context.annotation包下的ConfigurationClassPostProcessor.class实现了这个接口。
ConfigurationClassPostProcessor类并未直接实现BeanFactoryPostProcessor,而是实现了BeanDefinitionRegistryPostProcessor接口,BeanDefinitionRegistryPostProcessor继承了BeanFactoryPostProcessor。所以需要搞清楚他们各自方法的执行顺序。
在加载BeanDefinition之前,先获取所有的@Configuration,按照它的优先级排序。接着循环解析这些配置类,在解析的过程中又根据不同的注解来加载不同的内容。从而完成整个应用内部的BeanDefinition获取。