该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读

Spring 版本:5.1.14.RELEASE

开始阅读这一系列文章之前,建议先查看《深入了解 Spring IoC(面试题)》这一篇文章

该系列其他文章请查看:《死磕 Spring 之 IoC 篇 - 文章导读》

@Bean 等注解的实现原理

通过前面的一系列文章我们了解到 @Component 注解(及其派生注解)标注的 Class 类都会被解析成 BeanDefinition(Bean 的“前身”),然后会被初始化成 Bean 对象。那么 @Bean 注解不是 @Component 的派生注解,且用于标注方法,该注解的解析过程在前面的文章中没有提到,那么在 Spring 中是如何解析 @Bean 注解的呢?

可以先回顾一下《Spring 应用上下文 ApplicationContext》文章“BeanFactory 后置处理阶段”的小节中讲到,在创建好 BeanFactory 后会调用所有的 BeanFactoryPostProcessor 处理器对其进行后置处理。@Bean 注解就是在这个过程被解析的,解析过程大致就是遍历所有的 BeanDefinition,如果其内部包含 @Bean 标注的注解,则会将该方法解析出一个 BeanDefinition 对象并注册。当然,除了 @Bean 注解外,例如 @ComponentScan@Import@ImportResource@PropertySource 注解都是在该过程中进行解析的。那么接下来将分析整个的解析过程,入口在 ConfigurationClassPostProcessor 这个处理器中。

概览

主要涉及以下几个类:

  • org.springframework.context.annotation.ConfigurationClassPostProcessor,处理 Spring 应用上下文中的配置类,解析 @Bean 等注解,并进行 CGLIB 提升
  • org.springframework.context.annotation.ConfigurationClass,根据前面提到的配置类解析出来的对象,包含各种注解的信息,例如 @Bean@Import
  • org.springframework.context.annotation.ConfigurationClassParser,解析配置类,生成 ConfigurationClass 对象并保存
  • org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader配置类中 BeanDefinition 的读取器,根据 ConfigurationClass 解析出 BeanDefinition 并注册

配置类:带有 @Configuration 注解的类,如果这个类带有 @Component | @ComponentScan | @Import | @ImportSource 注解,或者内部存在 @Bean 的方法都算配置类

几个关键处理器的注册

处理器

关键的处理器:

  • ConfigurationClassPostProcessor:处理 Spring 应用上下文中的配置类,解析 @Bean 等注解,并进行 CGLIB 提升
  • AutowiredAnnotationBeanPostProcessor:解析 @Autowired@Value 注解标注的属性,获取对应属性值,进行依赖注入
  • CommonAnnotationBeanPostProcessor:会解析 @Resource 注解标注的属性,获取对应的属性值,进行依赖注入
  • EventListenerMethodProcessor:解析 @EventListener 注解标注的方法,会将其解析成 Spring 事件监听器并注册
  • DefaultEventListenerFactory:帮助 EventListenerMethodProcessor 将 @EventListener 注解标注的方法生成事件监听器

注册过程

《BeanDefinition 的解析过程(面向注解)》文章中讲到,如果在 XML 配置文件中配置了 <context:component-scan /> 标签,会通过 ClassPathBeanDefinitionScanner 扫描器进行解析;在《Spring 应用上下文 ApplicationContext》文章的“BeanFactory 创建阶段”小节中讲到,支持注解配置的 Spring 应用上下文会通过 ClassPathBeanDefinitionScanner 扫描器进行扫描。

在 ClassPathBeanDefinitionScanner 的扫描过程中会调用 AnnotationConfigUtils#registerAnnotationConfigProcessors(BeanDefinitionRegistry) 方法,如下:

public int scan(String... basePackages) {
// <1> 获取扫描前的 BeanDefinition 数量
int beanCountAtScanStart = this.registry.getBeanDefinitionCount(); // <2> 进行扫描,将过滤出来的所有的 .class 文件生成对应的 BeanDefinition 并注册
doScan(basePackages); // Register annotation config processors, if necessary.
// <3> 如果 `includeAnnotationConfig` 为 `true`(默认),则注册几个关于注解的 PostProcessor 处理器(关键)
// 在其他地方也会注册,内部会进行判断,已注册的处理器不会再注册
if (this.includeAnnotationConfig) {
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
} // <4> 返回本次扫描注册的 BeanDefinition 数量
return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
}

我们再来看到 AnnotationConfigUtils 的这个方法,如下:

public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
registerAnnotationConfigProcessors(registry, null);
} /**
* Register all relevant annotation post processors in the given registry.
* @param registry the registry to operate on
* @param source the configuration source element (already extracted)
* that this registration was triggered from. May be {@code null}.
* @return a Set of BeanDefinitionHolders, containing all bean definitions
* that have actually been registered by this call
*/
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) { DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
if (beanFactory != null) {
if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
}
if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
}
} Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8); // 处理 Spring 应用上下文中的配置类
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
} // 处理 @Autowired 以及 @Value 注解
if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
} // (条件激活)处理 JSR-250 注解 @Resource,如 @PostConstruct、@PreDestroy 等
// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
} // Processor 对象(条件激活)处理 JPA 注解场景
// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition();
try {
def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
AnnotationConfigUtils.class.getClassLoader()));
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
}
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
} // 处理标注 @EventListener 的 Spring 事件监听方法
if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
} // 用于 @EventListener 标注的事件监听方法构建成 ApplicationListener 对象
if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
} return beanDefs;
} private static BeanDefinitionHolder registerPostProcessor(
BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) { definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(beanName, definition);
return new BeanDefinitionHolder(definition, beanName);
}

整个过程就是将上面“处理器”小节中讲到的几个处理器进行注册

ConfigurationClassPostProcessor

org.springframework.context.annotation.ConfigurationClassPostProcessor,BeanDefinitionRegistryPostProcessor 处理器,解析配置类

构造方法

public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware { private static final String IMPORT_REGISTRY_BEAN_NAME =
ConfigurationClassPostProcessor.class.getName() + ".importRegistry"; private SourceExtractor sourceExtractor = new PassThroughSourceExtractor(); private ProblemReporter problemReporter = new FailFastProblemReporter(); @Nullable
private Environment environment; private ResourceLoader resourceLoader = new DefaultResourceLoader(); @Nullable
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); private MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(); private boolean setMetadataReaderFactoryCalled = false; /** 已处理过的 BeanDefinitionRegistry 的 ID */
private final Set<Integer> registriesPostProcessed = new HashSet<>(); /** 已处理过的 ConfigurableListableBeanFactory 的 ID */
private final Set<Integer> factoriesPostProcessed = new HashSet<>(); /** 用于扫描出 ConfigurationClass 中的 BeanDefinition 并注册 */
@Nullable
private ConfigurationClassBeanDefinitionReader reader; private boolean localBeanNameGeneratorSet = false; /* Using short class names as default bean names */
private BeanNameGenerator componentScanBeanNameGenerator = new AnnotationBeanNameGenerator();
}

实现了 BeanDefinitionRegistryPostProcessor 接口(继承了 BeanFactoryPostProcessor 接口)

《Spring 应用上下文 ApplicationContext》文章“BeanFactory 后置处理阶段”的小节可以知道,BeanDefinitionRegistryPostProcessor 优先于 BeanFactoryPostProcessor,所以我们先来看到前者的实现

1. postProcessBeanDefinitionRegistry 方法

postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) 方法,对 BeanDefinitionRegistry 的后置处理,其实这个入参就是 DefaultListableBeanFactory,如下:

@Override
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);
}

使用 registry 的哈希值作为 ID 保存在 registriesPostProcessed,保证同一个 BeanDefinitionRegistry 不会被重复处理,最后调用 processConfigBeanDefinitions(BeanDefinitionRegistry) 方法

2. processConfigBeanDefinitions 方法

processConfigBeanDefinitions(BeanDefinitionRegistry) 方法,处理配置类(过程有点长),如下:

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
// <1> 获取已有的 BeanDefinition 名称的集合
String[] candidateNames = registry.getBeanDefinitionNames(); // <2> 找出是**配置类**的 BeanDefinition 对象们
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
// 判断是否已经处理过,已处理则不再处理,保证不被二次处理
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
// 检查是否带有 @Configuration 注解,设置 isFullConfigurationClass
// 或者带有 @Component | @ComponentScan | @Import | @ImportSource | 内部存在 @Bean 的方法,设置为 isLiteConfigurationClass
// 符合上面其中一个条件都算**配置类**,需要进行处理
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
} // Return immediately if no @Configuration classes were found
// <3> 没有需要处理的**配置类**则直接 `return`
if (configCandidates.isEmpty()) {
return;
} // Sort by previously determined @Order value, if applicable
// <4> 根据 @Order 注解进行排序
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
}); // 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) {
// 探测名称为 org.springframework.context.annotation.internalConfigurationBeanNameGenerator 的自定义 Bean 名称生成器
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();
} // Parse each @Configuration class
// <5> 创建一个 `ConfigurationClassParser` 对象,用于解析符合条件的**配置类**
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 {
/**
* <5.1>
* 对所有的**配置类**进行解析,解析其内部的注解(@PropertySource、@ComponentScan、@Import、@ImportResource、@Bean)
* 每个**配置类**会生成一个 {@link ConfigurationClass} 对象
* 其中 @Bean 标注的方法转换成 {@link BeanMethod} 对象保存在 {@link ConfigurationClass#beanMethods} 集合中
*/
parser.parse(candidates);
/**
* <5.2>
* 对所有的 {@link ConfigurationClass} 对象进行校验
* Class 对象不能被 final 修饰,@Bean 标注的方法不能被 private 修饰
*/
parser.validate(); // <5.3> 获取解析出来的 ConfigurationClass 们,并移除已经处理过的对象
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed); // Read the model and create bean definitions based on its content
/*
* <5.4>
* 创建一个 ConfigurationClassBeanDefinitionReader 对象,用于扫描出 ConfigurationClass 中的 BeanDefinition 并注册
* 例如 @Bean 标注的方法需要注册、@ImportResource 注解配置的资源文件中配置的 Bean 需要注册
*/
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
/*
* <5.4.1>
* 扫描所有的 ConfigurationClass,注册相应的 BeanDefinition,主要有以下来源:
* 1. @Import 注解导入对象
* 2. 其内部定义的带有 @Bean 注解的方法
* 3. @ImportResource 注解导入资源
* 4. @Import 注解导入的 ImportBeanDefinitionRegistrar 接口的实现类可自定义实现注册相关 BeanDefinition
*/
this.reader.loadBeanDefinitions(configClasses);
// <5.5> 将这些 ConfigurationClass 保存至已解析的集合中
alreadyParsed.addAll(configClasses); candidates.clear();
/*
* <6>
* 从上述过程注册的 BeanDefinition 中,找到没有还解析过的 BeanDefinition 们,再循环解析
* 例如 @Bean 标注的方法是新注册的 BeanDefinition,也可能是一个**配置类**,但是还没有被这里解析过
*/
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.
// <7> 清理上述解析过程中产生的元数据缓存
((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
}
}

过程如下:

  1. 获取所有的 BeanDefinition 名称的集合
  2. 找出是配置类的 BeanDefinition 对象们,保存至 configCandidates 集合中
    • 判断是否已经处理过,已处理则不再处理,保证不被二次处理,否则
    • 检查是否带有 @Configuration 注解,或者带有 @Component | @ComponentScan | @Import | @ImportSource | 内部存在 @Bean 的方法,符合前面其中一个条件都算配置类,需要进行处理
  3. 上一步没有找到需要处理的配置类,则直接 return 返回
  4. 根据 @Order 注解对 configCandidates 集合中的配置类进行排序

  1. 创建一个 ConfigurationClassParser 对象,用于解析符合条件的配置类,会先生成 ConfigurationClass 对象保存至其内部,然后通过 ConfigurationClassBeanDefinitionReader 读取器从这些 ConfigurationClass 对象中解析出 BeanDefinition

    1. 【核心】对所有的配置类进行解析,调用 ConfigurationClassParser#parse(Set<BeanDefinitionHolder>) 方法,解析其内部的注解(@PropertySource@ComponentScan@Import@ImportResource@Bean)。每个配置类会生成一个 ConfigurationClass 对象,其中 @Bean 标注的方法转换成 BeanMethod 对象保存在 ConfigurationClass.beanMethods 集合中
    2. 对所有的 ConfigurationClass 对象进行校验:Class 对象不能被 final 修饰,@Bean 标注的方法不能被 private 修饰
    3. 获取上面解析出来的 ConfigurationClass 们,放入 configClasses 集合中,并移除已经处理过的对象
    4. 创建一个 ConfigurationClassBeanDefinitionReader 对象,调用其 loadBeanDefinitions(Set<ConfigurationClass>) 方法,扫描出 ConfigurationClass 中的 BeanDefinition 并注册。例如 @Bean 标注的方法需要注册、@ImportResource 注解配置的资源文件中配置的 Bean 需要注册
      1. 【核心】扫描所有的 ConfigurationClass,注册相应的 BeanDefinition,主要有以下来源:

        • @Import 注解导入对象
        • 其内部定义的带有 @Bean 注解的方法
        • @ImportResource 注解导入资源
        • @Import 注解导入的 ImportBeanDefinitionRegistrar 接口的实现类可自定义实现注册相关 BeanDefinition
    5. 将这些 ConfigurationClass 保存至 alreadyParsed 已解析的集合中
  2. 从上述过程注册的 BeanDefinition 中,找到没有还解析过的 BeanDefinition 们,再循环解析。例如 @Bean 标注的方法是新注册的 BeanDefinition,也可能又是一个配置类,但是还没有被这里解析过,所以需要再次扫描,如果还有未处理的配置类则需要进行处理
  3. 清理上述解析过程中产生的元数据缓存,例如通过 ASM 从 .class 文件中获取到的 Class 信息,需要清理

总结:先根据配置类生成 ConfigurationClass 对象,然后根据该对象解析出 BeanDefinition 并注册

配置类:带有 @Configuration 注解的类,如果这个类带有 @Component | @ComponentScan | @Import | @ImportSource 注解,或者内部存在 @Bean 的方法都算配置类

上面的第 5.15.4 分别对应 ConfigurationClassParser 和 ConfigurationClassBeanDefinitionReader 两个类,接下来会依次分析

3. postProcessBeanFactory 方法

postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) 方法,对 ConfigurableListableBeanFactory 的后置处理,其实这个入参就是 DefaultListableBeanFactory,和 postProcessBeanDefinitionRegistry(BeanDefinitionRegistry) 方法是同一个入参,如下:

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
int factoryId = System.identityHashCode(beanFactory);
if (this.factoriesPostProcessed.contains(factoryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + beanFactory);
}
this.factoriesPostProcessed.add(factoryId);
if (!this.registriesPostProcessed.contains(factoryId)) {
// BeanDefinitionRegistryPostProcessor hook apparently not supported...
// Simply call processConfigurationClasses lazily at this point then.
processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
} // CGLIB 提升
enhanceConfigurationClasses(beanFactory);
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}

如果这个 DefaultListableBeanFactory 没有处理过,这里会和上面的过程一样调用 processConfigBeanDefinitions(BeanDefinitionRegistry) 方法进行处理。接下来,会调用 enhanceConfigurationClasses(ConfigurableListableBeanFactory) 方法对 @Configuration 注解的配置类进行 CGLIB 提升,主要帮助实现 AOP 特性

4. enhanceConfigurationClasses 方法

enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) 方法,对 @Configuration 注解的配置类进行 CGLIB 提升,如下:

public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
for (String beanName : beanFactory.getBeanDefinitionNames()) {
BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
/*
* 如果配置了 @Configuration 注解
*/
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef)) {
/*
* 如果不是 AbstractBeanDefinition(Spring 内部 BeanDefinition 实现类都是它的子类),则抛出异常
*/
if (!(beanDef instanceof AbstractBeanDefinition)) {
throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" +
beanName + "' since it is not stored in an AbstractBeanDefinition subclass");
}
/*
* 如果这个 Bean 已经初始化了
*/
else if (logger.isInfoEnabled() && beanFactory.containsSingleton(beanName)) {
logger.info("Cannot enhance @Configuration bean definition '" + beanName +
"' since its singleton instance has been created too early. The typical cause " +
"is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor " +
"return type: Consider declaring such methods as 'static'.");
}
configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
}
}
if (configBeanDefs.isEmpty()) {
// nothing to enhance -> return immediately
/*
* 没有需要 CGLIB 提升的类则直接返回
*/
return;
} ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
AbstractBeanDefinition beanDef = entry.getValue();
// If a @Configuration class gets proxied, always proxy the target class
beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
try {
// Set enhanced subclass of the user-specified bean class
// 通过类加载器获取这个 BeanDefinition 的 Class 对象
Class<?> configClass = beanDef.resolveBeanClass(this.beanClassLoader);
if (configClass != null) {
// 通过 CGLIB 创建一个子类(代理类)
Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
if (configClass != enhancedClass) {
if (logger.isTraceEnabled()) {
logger.trace(String.format("Replacing bean definition '%s' existing class '%s' with " +
"enhanced class '%s'", entry.getKey(), configClass.getName(), enhancedClass.getName()));
}
// 设置该 BeanDefinition 的 Class 对象为 CGLIB 子类(代理类),用于帮助实现 AOP 特性
beanDef.setBeanClass(enhancedClass);
}
}
}
catch (Throwable ex) {
throw new IllegalStateException("Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
}
}
}

整个过程大致就是:如果是 @Configuration 注解标注的类,则通过 CGLIB 创建一个子类(代理类)并设置到这个 BeanDefinition 的 beanClass 属性中。这样一来, @Configuration 注解标注的类就得到了 CGLIB 的提升,主要帮助实现 AOP 相关特性,这里不做详细展述,具体过程请期待后续的 Spring AOP 相关文章

ConfigurationClass

org.springframework.context.annotation.ConfigurationClass,根据前面提到的配置类解析出来的对象,如下:

final class ConfigurationClass {
/**
* 元数据信息,根据通过它获取**配置类** Class 对象的所有信息
*/
private final AnnotationMetadata metadata; private final Resource resource; @Nullable
private String beanName; /**
* 假如这个 Class 对象是通过 @Import 注解被导入的
* 那么这个集合保存的就是该 @Import 注解标注的配置类,表示谁把它导入的
*/
private final Set<ConfigurationClass> importedBy = new LinkedHashSet<>(1); /**
* 带有 @Bean 注解的方法集合
*/
private final Set<BeanMethod> beanMethods = new LinkedHashSet<>(); /**
* 需要导入的资源集合
*/
private final Map<String, Class<? extends BeanDefinitionReader>> importedResources = new LinkedHashMap<>(); /**
* {@link Import} 注解导入的 ImportBeanDefinitionRegistrar 类型的对象
*/
private final Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> importBeanDefinitionRegistrars = new LinkedHashMap<>(); /**
* 需要跳过的 @Bean 注解的方法集合
*/
final Set<String> skippedBeanMethods = new HashSet<>(); /**
* Create a new {@link ConfigurationClass} with the given name.
* @param metadataReader reader used to parse the underlying {@link Class}
* @param beanName must not be {@code null}
* @see ConfigurationClass#ConfigurationClass(Class, ConfigurationClass)
*/
public ConfigurationClass(MetadataReader metadataReader, String beanName) {
Assert.notNull(beanName, "Bean name must not be null");
this.metadata = metadataReader.getAnnotationMetadata();
this.resource = metadataReader.getResource();
this.beanName = beanName;
} // ... 省略相关构造函数、getter、setter 方法 public void validate(ProblemReporter problemReporter) {
// A configuration class may not be final (CGLIB limitation)
if (getMetadata().isAnnotated(Configuration.class.getName())) {
if (getMetadata().isFinal()) {
problemReporter.error(new FinalConfigurationProblem());
}
}
for (BeanMethod beanMethod : this.beanMethods) {
beanMethod.validate(problemReporter);
}
} @Override
public boolean equals(Object other) {
return (this == other || (other instanceof ConfigurationClass &&
getMetadata().getClassName().equals(((ConfigurationClass) other).getMetadata().getClassName())));
} @Override
public int hashCode() {
return getMetadata().getClassName().hashCode();
} }

重写了 equals 方法,是同一个 Class 对象也是相等的

ConfigurationClassParser

org.springframework.context.annotation.ConfigurationClassParser,解析配置类,生成 ConfigurationClass 对象并保存

构造方法

class ConfigurationClassParser {

	private static final PropertySourceFactory DEFAULT_PROPERTY_SOURCE_FACTORY = new DefaultPropertySourceFactory();

	private static final Comparator<DeferredImportSelectorHolder> DEFERRED_IMPORT_COMPARATOR =
(o1, o2) -> AnnotationAwareOrderComparator.INSTANCE.compare(o1.getImportSelector(), o2.getImportSelector()); private final MetadataReaderFactory metadataReaderFactory; private final ProblemReporter problemReporter; private final Environment environment; private final ResourceLoader resourceLoader; private final BeanDefinitionRegistry registry; private final ComponentScanAnnotationParser componentScanParser; private final ConditionEvaluator conditionEvaluator; /**
* 保存**配置类**解析出来的 ConfigurationClass 对象
*/
private final Map<ConfigurationClass, ConfigurationClass> configurationClasses = new LinkedHashMap<>(); /**
* 保存**配置类**的父类对应的 ConfigurationClass 对象,也就是这个配置类对应的
*/
private final Map<String, ConfigurationClass> knownSuperclasses = new HashMap<>(); private final List<String> propertySourceNames = new ArrayList<>(); private final ImportStack importStack = new ImportStack(); private final DeferredImportSelectorHandler deferredImportSelectorHandler = new DeferredImportSelectorHandler(); public ConfigurationClassParser(MetadataReaderFactory metadataReaderFactory,
ProblemReporter problemReporter, Environment environment, ResourceLoader resourceLoader,
BeanNameGenerator componentScanBeanNameGenerator, BeanDefinitionRegistry registry) { this.metadataReaderFactory = metadataReaderFactory;
this.problemReporter = problemReporter;
this.environment = environment;
this.resourceLoader = resourceLoader;
this.registry = registry;
this.componentScanParser = new ComponentScanAnnotationParser(
environment, resourceLoader, componentScanBeanNameGenerator, registry);
this.conditionEvaluator = new ConditionEvaluator(registry, environment, resourceLoader);
}
}

1. parse 方法

parse(Set<BeanDefinitionHolder> configCandidates) 方法,对这些配置类进行解析,如下:

public void parse(Set<BeanDefinitionHolder> configCandidates) {
// 遍历所有的 BeanDefinition
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
if (bd instanceof AnnotatedBeanDefinition) {
// 解析,生成的 ConfigurationClass 对象保存在 `configurationClasses` 集合中
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
// 解析,生成的 ConfigurationClass 对象保存在 `configurationClasses` 集合中
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
}
else {
// 解析,生成的 ConfigurationClass 对象保存在 `configurationClasses` 集合中
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();
}

遍历这些配置类,调用 parse(...) 不同的重载方法进行解析,如下:

protected final void parse(@Nullable String className, String beanName) throws IOException {
Assert.notNull(className, "No bean class name for configuration class bean definition");
MetadataReader reader = this.metadataReaderFactory.getMetadataReader(className);
processConfigurationClass(new ConfigurationClass(reader, beanName));
} protected final void parse(Class<?> clazz, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(clazz, beanName));
} protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(metadata, beanName));
}

先为这个 配置类 创建一个 ConfigurationClass 对象,然后再调用 processConfigurationClass(ConfigurationClass) 方法进行解析

2. processConfigurationClass 方法

processConfigurationClass(ConfigurationClass configClass) 方法,解析配置类,所有信息都保存在这个 ConfigurationClass 中,如下:

protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
// @Conditional 的处理,是否需要跳过
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);
}
} // Recursively process the configuration class and its superclass hierarchy.
// 获取这个 ConfigurationClass 配置类的所在 Class 对象
SourceClass sourceClass = asSourceClass(configClass);
do {
// 解析 ConfigurationClass 对象,对相关注解(@PropertySource、@ComponentScan、@Import、@ImportResource、@Bean)进行解析
// 其中解析出带有 @Bean 注解方法保存至其中,@ImportResource 配置的资源也保存其中
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
// 父类循环解析
while (sourceClass != null); // 将该 ConfigurationClass 配置类保存
this.configurationClasses.put(configClass, configClass);
}

过程如下:

  1. 会先根据 @Conditional 注解判断是否需要跳过
  2. 调用 doProcessConfigurationClass(ConfigurationClass, SourceClass) 方法进行解析,会遍历父类
  3. 配置类对应的 ConfigurationClass 对象保存至 configurationClasses 集合中

3. doProcessConfigurationClass 方法

doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) 方法,解析配置类,所有信息都保存在这个 ConfigurationClass 中,如下:

protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
throws IOException { // <1> 先处理内部成员类
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
// Recursively process any member (nested) classes first
processMemberClasses(configClass, sourceClass);
} // Process any @PropertySource annotations
// <2> 处理 @PropertySource 注解,加载对应的资源
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
// <3> 处理 @ComponentScan 注解,扫描出指定包路径下的 BeanDefinition 们
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
// 底层会通过 ClassPathBeanDefinitionScanner 扫描指定的包路径,注册相关 BeanDefinition 们
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
// <4> 处理 @Import 注解,ImportSelector 和 ImportBeanDefinitionRegistrar 类型会有相关处理
// 注解中的 Class 对象也会生成一个 ConfigurationClass 对象,再进行处理
// 这个对象不同的是其内部 `importedBy` 属性不为空,保存了是被谁 Import 的
processImports(configClass, sourceClass, getImports(sourceClass), true); // Process any @ImportResource annotations
// <5> 处理 @ImportResource 注解,获取需要导入的资源配置信息
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
// <6> 解析出所有带有 @Bean 注解的方法,通过 ASM 保证每个方法定义的顺序
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
} // Process default methods on interfaces
// <6> 解析接口中带有 @Bean 注解的默认方法
processInterfaces(configClass, sourceClass); // Process superclass, if any
// <7> 如果有父类,则返回父类,再进行解析
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
// <8> 已经是顶部类,表示解析完成
return null;
}

过程大致如下:

  1. 先处理内部成员类,调用 processMemberClasses(...) 方法,如果内部成员类也是配置类,同样调用前面的 processConfigurationClass(ConfigurationClass)方法进行处理,这里不展开讲述
  2. 处理 @PropertySource 注解,加载出对应的 Resource 资源,将其添加至 Environment 环境中,这里不展开讲述
  3. 处理 @ComponentScan 注解,通过 ComponentScanAnnotationParser 扫描出指定包路径下的 BeanDefinition 们并注册,然后再遍历处理,如果是配置类,同样调用前面的 parse(...) 方法,这里不展开讲述
  4. 处理 @Import 注解中的 Class 对象,调用 processImports(...) 方法,这里不展开讲述,分为下面几种情况:
    • ImportSelector 的实现类:调用其 selectImports(AnnotationMetadata) 方法获取需要导入的 Class 类名,再次调用 processImports(...) 方法进行处理
    • ImportBeanDefinitionRegistrar 的实现类:将这个实现类保存在 ConfigurationClass.importBeanDefinitionRegistrars 集合中
    • 否则,为 @Import 注解中的 配置类 创建 ConfigurationClass 对象,同样调用processConfigurationClass(ConfigurationClass)方法进行处理
  5. 处理 @ImportResource 注解,获取需要导入的资源配置信息,将这些配置信息添加至 ConfigurationClass.importedResources 集合中
  6. 解析出所有带有 @Bean 注解的方法,底层通过 ASM(Java 字节码操作和分析框架)进行解析,然后将这些方法封装成 BeanMethod 对象,并保存至 ConfigurationClass.beanMethods 集合中,这里不展开讲述
  7. 如果有父类,则循环进行解析

整个过程就是解析配置类中的各种注解,解析结果都保存在 ConfigurationClass 中,所以说整个过程就是为配置类生成一个 ConfigurationClass 对象,将这些信息生成对应的 BeanDefinition 对象并注册到 Spring 上下文的过程还在后面,也就是下面要讲的 ConfigurationClassBeanDefinitionReader 读取器

ConfigurationClassBeanDefinitionReader

org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader配置类中 BeanDefinition 的读取器,根据 ConfigurationClass 解析出 BeanDefinition 并注册

1. loadBeanDefinitions 方法

loadBeanDefinitions(Set<ConfigurationClass>) 方法,从 ConfigurationClass 中加载出 BeanDefinition,如下:

public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
// 创建 @Conditional 注解的计算器
TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
// 遍历所有的 ConfigurationClass,进行处理
for (ConfigurationClass configClass : configurationModel) {
loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
}
}

遍历所有的 ConfigurationClass 对象,调用 loadBeanDefinitionsForConfigurationClass(...) 方法

2. loadBeanDefinitionsForConfigurationClass 方法

loadBeanDefinitionsForConfigurationClass(ConfigurationClass, TrackedConditionEvaluator) 方法,从 ConfigurationClass 中加载出 BeanDefinition 并注册,如下:

private void loadBeanDefinitionsForConfigurationClass(
ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) { // <1> 如果不符合 @Conditional 注解的条件,则跳过
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;
} // <2> 如果当前 ConfigurationClass 是通过 @Import 注解被导入的
if (configClass.isImported()) {
// <2.1> 根据该 ConfigurationClass 对象生成一个 BeanDefinition 并注册
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
// <3> 遍历当前 ConfigurationClass 中所有的 @Bean 注解标注的方法
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
// <3.1> 根据该 BeanMethod 对象生成一个 BeanDefinition 并注册(注意这里有无 static 修饰会有不同的配置)
loadBeanDefinitionsForBeanMethod(beanMethod);
} // <4> 对 @ImportResource 注解配置的资源进行处理,对里面的配置进行解析并注册 BeanDefinition
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
// <5> 通过 @Import 注解导入的 ImportBeanDefinitionRegistrar 实现类往 BeanDefinitionRegistry 注册 BeanDefinition
// Mybatis 集成 Spring 就是基于这个实现的,可查看 Mybatis-Spring 项目中的 MapperScannerRegistrar 这个类
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}

过程大致如下:

  1. 如果不符合 @Conditional 注解的条件,则跳过

  2. 如果当前 ConfigurationClass 是通过 @Import 注解被导入的

    1. 根据该 ConfigurationClass 对象生成一个 BeanDefinition 并注册,调用 registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass) 方法,如下:

      private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) {
      AnnotationMetadata metadata = configClass.getMetadata();
      // 为该 ConfigurationClass 配置类创建一个 BeanDefinition 对象
      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);
      // 注册该 BeanDefinition 对象
      this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());
      // 设置 Bean 的名称
      configClass.setBeanName(configBeanName);
      }

      根据这个类的元信息生成一个 AnnotatedGenericBeanDefinition 对象,并注册

  3. 遍历当前 ConfigurationClass 中所有的 @Bean 注解标注的方法

    1. 根据该 BeanMethod 对象生成一个 BeanDefinition 并注册(注意这里有无 static 修饰会有不同的配置),调用 loadBeanDefinitionsForBeanMethod(BeanMethod) 方法,在后面分析
  4. @ImportResource 注解配置的资源进行处理,对里面的配置进行解析并注册 BeanDefinition,通过 XmlBeanDefinitionReader 对该配置文件进行扫描,在前面的《BeanDefinition 的加载阶段(XML 文件)》文章中已经分析过

  5. 通过 @Import 注解导入的 ImportBeanDefinitionRegistrar 实现类往 BeanDefinitionRegistry 注册 BeanDefinition,也就是调用这个实现类的 registerBeanDefinitions(AnnotationMetadata, BeanDefinitionRegistry) 方法,自定义注册 BeanDefinition

该过程会把 ConfigurationClass 中的信息解析成 BeanDefinition 并注册,其中第 5 步可参考 Mybatis 集成 Spring 的项目中的 MapperScannerRegistrar 类,可参考我的另一篇文章《精尽MyBatis源码分析 - MyBatis-Spring 源码分析》

3. loadBeanDefinitionsForBeanMethod 方法

loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) 方法,将 @Bean 注解标注的方法解析成 BeanDefinition 并注册,如下:

private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
ConfigurationClass configClass = beanMethod.getConfigurationClass();
MethodMetadata metadata = beanMethod.getMetadata();
String methodName = metadata.getMethodName(); // Do we need to mark the bean as skipped by its condition?
// 如果不符合 @Conditional 注解的条件,则跳过
if (this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) {
configClass.skippedBeanMethods.add(methodName);
return;
}
if (configClass.skippedBeanMethods.contains(methodName)) {
return;
} // 获取 @Bean 注解元信息
AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);
Assert.state(bean != null, "No @Bean annotation attributes"); // Consider name and any aliases
List<String> names = new ArrayList<>(Arrays.asList(bean.getStringArray("name")));
String beanName = (!names.isEmpty() ? names.remove(0) : methodName); // Register aliases even when overridden
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;
} // 为该 BeanMethod 创建一个 BeanDefinition 对象
ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
beanDef.setResource(configClass.getResource());
beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource())); /*
* 如果该方法被 static 修饰
* 直接设置 `beanClassName` 和 `factoryMethodName` 属性,通过这两者就可以创建当前方法 Bean 对象
*/
if (metadata.isStatic()) {
// static @Bean method
beanDef.setBeanClassName(configClass.getMetadata().getClassName());
beanDef.setFactoryMethodName(methodName);
}
/*
* 否则,为内部方法
* 这里是设置 `factoryBeanName` 和 `factoryMethodName` 属性,通过这两者就可以创建当前 Bean 对象
* 和被 static 修饰的方法 Bean 对象不同的是,`factoryBeanName` 指定的 Bean 需要先被初始化,然后调用该方法创建当前方法 Bean 对象
* 而被 static 修饰可以直接通过其 Class 对象调用方法,无需先初始化 Bean 对象
*/
else {
// instance @Bean method
beanDef.setFactoryBeanName(configClass.getBeanName());
beanDef.setUniqueFactoryMethodName(methodName);
}
// 设置注入模式为构造器注入,因为方法可能带有参数,需要注入
beanDef.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
beanDef.setAttribute(org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor.
SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE); // 设置一些配置信息(没有配置则会有默认值)
AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata); // 如果配置了注入模式,则覆盖上面的'构造器注入'
Autowire autowire = bean.getEnum("autowire");
if (autowire.isAutowire()) {
beanDef.setAutowireMode(autowire.value());
} boolean autowireCandidate = bean.getBoolean("autowireCandidate");
if (!autowireCandidate) {
beanDef.setAutowireCandidate(false);
} // 如果配置了 `initMethod`,则设置初始化方法名称
String initMethodName = bean.getString("initMethod");
if (StringUtils.hasText(initMethodName)) {
beanDef.setInitMethodName(initMethodName);
} // 如果配置了 `destroyMethod`,则设置销毁方法名称
String destroyMethodName = bean.getString("destroyMethod");
beanDef.setDestroyMethodName(destroyMethodName); // Consider scoping
// 如果配置了 @Scope 注解,则进行相关配置
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);
} // 注册该 BeanDefinition 对象
this.registry.registerBeanDefinition(beanName, beanDefToRegister);
}

整个过程并不复杂,大致如下:

  1. 如果不符合 @Conditional 注解的条件,则跳过
  2. 获取 @Bean 注解元信息
  3. @Bean 标注的方法(被封装成了 BeanMethod 对象)创建一个 ConfigurationClassBeanDefinition 对象
  4. 根据注解元信息设置各种配置,例如 autowire(注入模式)、initMethod(初始化方法)、destroyMethod(销毁方法),对于 static 修饰的方法有区别,如下:
    • 静态方法会设置 beanClass(Class 对象)和 factoryMethodName(方法名称),可以直接调用 Class 对象的这个方法获取 Bean
    • 非静态方法需要设置 factoryBeanName(该方法所属 Bean 的名称)和 factoryMethodName(方法名称),需要先初始化这个所属 Bean,才能调用这个方法获取 Bean
  5. 注册这个 ConfigurationClassBeanDefinition 对象

总结

《Spring 应用上下文 ApplicationContext》中有一个“BeanFactory 后置处理阶段”,在创建好 DefaultListableBeanFactory 后会调用所有的 BeanDefinitionRegistryPostProcessor 和 BeanFactoryPostProcessor 对其进行处理,前者优先。

Spring 应用上下文中的 ConfigurationClassPostProcessor 就是一个 BeanDefinitionRegistryPostProcessor 处理器,它会对所有的配置类(包括其内部成员类)进行处理,会做以下事情:

  • 加载 @PropertySource 注解配置的资源到 Environment 环境中
  • 扫描 @ComponentScan 注解指定路径下的 BeanDefinition 们,如果也是配置类,会进行同样的处理过程
  • 解析出 @Import 注解配置的配置类,解析成 AnnotatedGenericBeanDefinition 并注册;其中配置的是 ImportSelector 实现类,则调用其selectImports(AnnotationMetadata) 方法获取配置类;如果配置的是 ImportBeanDefinitionRegistrar 实现类,则调用其registerBeanDefinitions(AnnotationMetadata, BeanDefinitionRegistry) 方法,自定义注册 BeanDefinition
  • 解析 @ImportResource 注解,加载配置的 XML 文件,解析出 BeanDefinition 们
  • 将这些配置类@Bean 注解的方法解析成 ConfigurationClassBeanDefinition 并注册

配置类:带有 @Configuration 注解的类,如果这个类带有 @Component | @ComponentScan | @Import | @ImportSource 注解,或者内部存在 @Bean 的方法都算配置类

除了上面这些处理,如果是 @Configuration 注解标注的类,还会进行 CGLIB 提升,主要帮助实现 AOP 相关特性,这里没有详细展述,具体过程请期待后续的 Spring AOP 相关文章

至此,Spring IoC 的相关文章已全部完成,希望这一系列文章可以让读者对 Spring 有更加全面的认识,如有错误或者疑惑的地方,欢迎指正!!!共勉 ‍

死磕Spring之IoC篇 - @Bean 等注解的实现原理的更多相关文章

  1. 死磕Spring之IoC篇 - @Autowired 等注解的实现原理

    该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...

  2. 死磕Spring之IoC篇 - Bean 的创建过程

    该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...

  3. 死磕Spring之IoC篇 - Bean 的“前身”

    该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...

  4. 死磕Spring之IoC篇 - 文章导读

    该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...

  5. 死磕Spring之IoC篇 - 开启 Bean 的加载

    该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...

  6. 死磕Spring之IoC篇 - BeanDefinition 的加载阶段(XML 文件)

    该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...

  7. 死磕Spring之IoC篇 - BeanDefinition 的解析阶段(XML 文件)

    该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...

  8. 死磕Spring之IoC篇 - 解析自定义标签(XML 文件)

    该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...

  9. 死磕Spring之IoC篇 - BeanDefinition 的解析过程(面向注解)

    该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...

随机推荐

  1. windows下进程间通信方法

    摘 要 随着人们对应用程序的要求越来越高,单进程应用在许多场合已不能满足人们的要求.编写多进程/多线程程序成为现代程序设计的一个重要特点,在多进程程序设计中,进程间的通信是不可避免的.Microsof ...

  2. ubuntu 16.04 i386 安装 ruby + bundler + rails ; 搭建简单的网站bitbar

    参考 http://gorails.com/setup/ubuntu/16.04 概述 Project 2 主要探究对web的攻击,本次试验共有6个部分. Project 2中攻击的是一个提供电子货币 ...

  3. 关于Google Chrome的使用小技巧!

    1 1 http://www.runoob.com/w3cnote/chrome-skip.html Chrome是Google公司开发的一个现代化的网页浏览器,作为三大浏览器之一 它搭载了被称为V8 ...

  4. React Security Best Practices All In One

    React Security Best Practices All In One Default XSS Protection with Data Binding Dangerous URLs Ren ...

  5. macOS 录屏 gif

    macOS 录屏 gif LICEcap bug 授权问题? 如何在 Mac 上录制屏幕 https://support.apple.com/zh-cn/HT208721 Command + Shif ...

  6. record terminal sessions

    record terminal sessions asciinema https://asciinema.org/ # install $ brew install asciinema # Start ...

  7. navigator.geolocation.getCurrentPosition

    navigator.geolocation.getCurrentPosition Geolocation API Specification 2nd Edition W3C Recommendatio ...

  8. OpenCVE-开源漏洞预警平台

    0x01简介 主程序主要是通过使用NVD提供的JSON数据来更新CVE数据,并在前端进行展示.然后通过邮件进行通知,目前也只支持邮件.这个开源预警平台看上去并不是很完善,因为CVE本身就具有预警滞后性 ...

  9. 【HTB靶场系列】靶机Carrier的渗透测试

    出品|MS08067实验室(www.ms08067.com) 本文作者:大方子(Ms08067实验室核心成员) Hack The Box是一个CTF挑战靶机平台,在线渗透测试平台.它能帮助你提升渗透测 ...

  10. c#初体验

    虚方法.抽象类.接口区别:虚方法:父类可能需要实例化,父类方法需要方法体,可以找到一个父类 抽象类:抽象方法,父类不能实例化,且父类方法不能实现方法体,不可以找出一个父类,需要抽象 接口:多继承 le ...