AI智能
改变未来

Spring5源码分析之@Configuration注解的详解。希望读者能够耐着性子看完


前言:

对于Spring创建Bean的方式我相信大家 并不陌生,绝大数同学其实都知道Spring最初就是通过xml的方式去初始化Bean并完成依赖注入的工作,但是在Spring3.0之后,在spring framework模块中提供了了

@Confirguration

这个注解,并通过搭配@Bean等注解,可以完全不依赖xml配置,在运行时完成Bean的创建和初始化工作。

@Configuration注解的简单实用(demo)

package com.vipbbo.selfdemo.spring.configuration;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;@Configurationpublic class CustomBeanConfig {/*** @Bean注解声明了一个bean,bean名称默认为方法名 beanImpl* @return*/@BeanIBean beanImpl(){return new BeanImpl();}}interface IBean{}class BeanImpl implements IBean{}

注意:默认情况下Bean的名称和方法名称相同,也可以通过name属性来进行修改指定

比如:
@Bean(name = "customName")

@Configuratio注解的分析

首先我们先上述案例点击**@Configuration**注解看一下源码,如下:

  • 看源码(
    Configuration.java

    )

@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Componentpublic @interface Configuration {@AliasFor(annotation = Component.class)String value() default "";Boolean proxyBeanMethods() default true;}
  • 源码分析

我们看到源码里面,@Configuration标记了@Component元注解,因此可以被@ComponentScan扫描并处理,在Spring容器初始化时Configuration类会被注册到Bean容器中,最后还会被实例化。

使用@Autowired、@Inject注解

因为**@Configuration本身也是一个@Component,因此配置类本身也会被注册到应用上下文,并且也可以使用IOC的@Autowired、@Inject**等注解来注入所需的Bean,我们来修改一下之前的Demo,如下:

@Configurationpublic class CustomBeanConfig {@Autowiredprivate Environment environment;/*** 、 @Bean注解声明了一个bean,bean名称默认为方法名 beanImpl* @return*/@BeanIBean beanImpl(){return new BeanImpl();}}

@ComponentScan注解的使用

配置类也可以自己添加注解@ComponentScan,来显示扫描需使用的组件。

@Configuration使用@Component进行元注解,因此@Configuration类也可以被组件扫描到(特别是使用XML元素)

例如:

@Configuration@ComponentScan("com.vipbbo")public class CustomBeanConfig {// 略......}

注解@Controller @Service @Repository @Component

  • @Controller : 表明标识的"类"是一个Controller,也就是控制器,可以把它理解为MVC模式下的Controller角色。这个注解是一个特殊的@Component,允许实现类通过类路径的扫描扫描到。它通常与@RequestMapping 注解一起使用。

  • @Service: 表明这个带注解的类是一个"Service",也就是服务层,可以把它理解为MVC 模式中的Service层这个角色,这个注解也是一个特殊的@Component,允许实现类通过类路径的扫描扫描到

  • @Repository: 表明这个注解的类是一个"Repository",团队实现了JavaEE 模式中像是作为"Data Access Object" 可能作为DAO来使用,当与 PersistenceExceptionTranslationPostProcessor 结合使用时,这样注释的类有资格获得Spring转换的目的。这个注解也是@Component 的一个特殊实现,允许实现类能够被自动扫描到

  • @Component: 表明这个注释的类是一个组件,当使用基于注释的配置和类路径扫描时,这些类被视为自动检测的候选者

  • 看源码

// @Controller@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Componentpublic @interface Controller {@AliasFor(annotation = Component.class)String value() default "";}// @Service@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Componentpublic @interface Service {@AliasFor(annotation = Component.class)String value() default "";}//  @Repository@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Componentpublic @interface Repository {@AliasFor(annotation = Component.class)String value() default "";}// @Component@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Indexedpublic @interface Component {String value() default "";}
  • 源码分析

我们可以看到**@Controller,@Service,@Repository这三个注解上面都有@Component这个注解;也就是说,上面四个注解标记的类都能够通过@ComponentScan扫描到,上面四个注解最大的区别就是使用的场景和语义不一样**,比如你定义一个Service类想要被Spring管理,你应该把它定义为@Service而不是@Controller因为我们从语义上讲,@Service更像是一个服务的类,而不是一个控制器的类,@Component通常被称作组件,它可以标记任何你没有严格予以说明的类,比如说是一个配置类,它不属于MVC的任何一层,这个时候你更习惯把它定义为@Component。

@Controller,@Service,@Repository的注解上都有@Component,所以这三个注解都可以用@Component进行替换

同@Import注解组合使用

新建一个配置类,例如数据库配置类:

@Configurationpublic class DatabaseConfig {@Beanpublic DataSource dataSource(){return new DataSource(){...};}}

然后再CustomBeanConfig中使用@Import来导入配置

@Configuration@ComponentScan("com.vipbbo")@Component@Import(DatabaseConfig.class)public class CustomBeanConfig {/*** 注入的bean在DatabaseConfig.class中定义*/@Autowiredprivate DataSource dataSource;}

最后执行:

ApplicationContext context = new AnnotationConfigApplicationContext(CustomBeanConfig.class);DatabaseConfig dataSourceConfig = context.getBean(DatabaseConfig.class);

执行过后你就会发现只注册了CustomBeanConfig.class,容器自动会把@Import指向的配置类初始化。

同@Profile注解组合使用

在配置类可以声明**@Profile**注解,仅当满足profile条件时,才会处理配置类,也可以将@Profile注解加载配置类中的每一个@Bean来实现更细粒度的条件控制。如下:

@Configuration@Profile("develop")public class DatabaseConfig {@Beanpublic DataSource dataSource(){return new DataSource(){// ...};}}

@Profile注解也接受稍复杂的环境表达式,支持 ** &、** |、 !** 三种符号来表达与、或、非的关系。**

上面的Bean仅会在 “develop” 环境同时被激活时才注册。

嵌套使用@Configuration

在配置类中可以创建静态内部类,并添加@Configuration注解,这样上下文只需要注册最外面的配置类,内部的配置类会自动被加载。这样做就省略了@Import,因为本身就在配置类内部,无需在特别指定了。比如:

@Configurationpublic class CustomBeanConfig {@Configurationpublic static class DatabaseConfig{@BeanDataSource dataSource(){return new DataSource() {...};}}}
注意注意注意注意!!!!!!!!!!

任何嵌套的@Configuration都必须是static的。

@Lazy初始化

默认情况下,配置类中的Bean都随着上下文被初始化,可以在配置类中添加

@Lazy

注解来延迟初始化,当然也可以在每个@Bean注解上添加,来实现更细粒度的控制。

@Configuration@Lazypublic class CustomConfig {@BeanCustomBean appBean(){return new AppBean();}}

配置类约束

  • 配置类必须为显式声明的类,而不能通过工厂类方法返回实例,运行时类增强。
  • 配置类不允许标记为
    final

  • 配置类必须全局可见(不允许定义在方法本地内部类中)。
  • 嵌套配置类必须声明为
    static

    内部类。

  • @Bean方法不可以在创建新的配置类(所有实例都当作Bean处理,不解析相关配置注解)

@Configuration源码

ApplicationContext的refresh方法

在之前的一篇文章spring源码阅读一中写过,Spring容器启动时,即ApplicationContext接口实现类的对象实例执行

refresh

方法时,在Bean初始化完成之前,有一个扩展点,用来操作BeanFactory,来扩展对应的功能,比如往BeanFactory中注册的BeanDefinition,我们回顾一下Application的refresh函数:

  • 看源码(
    AbstractApplicationContext.java

    )

@Overridepublic void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");// Prepare this context for refreshing.// 1.准备刷新的上下文 环境prepareRefresh();// 2.初始化beanFactory 并进行xml文件读取//ClassPathXmlApplicationContext 包含着beanFactory所提供的一切特征,在这一步会将复用//BeanFactory中的配置文件读取解析及其他功能,这一步之后// Tell the subclass to refresh the internal bean factory.ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// 3.对beanFactory的各种功能进行填充 、BeanFactory的预准备工作// Prepare the bean factory for use in this context.prepareBeanFactory(beanFactory);try {// 4.子类覆盖方法做额外处理 (具体的见 AbstractRefreshableWebApplicationContext 类中)/*BeanFactory的预准备工作(BeanFactory进行一些设置)* spring 之所以强大,为世人所推崇,除了它功能上为大家提供便利外,还因为它很好的架构,开放式的架构让使用它的程序员根据业务需要* 扩展已经存在的功能,* 这种开放式的设计spring随处可见,例如在本例中提供了空的函数实现postProcessBeanFactory 方便程序猿在业务上做进一步扩展 */// Allows post-processing of the bean factory in context subclasses.postProcessBeanFactory(beanFactory);StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");/* 5.激活beanFactory的处理器 (Bean的后置处理器)* ===========详解=========* BeanFactoryPostProcessor 接口和 BeanFactoryProcessor 类似,都可以对bean定义(配置元数据)进行处理,也就是说SpringIOC允许* BeanFactoryPostProcessor 在容器实际实例化任何其他的bean之前来读取配置元数据,并可能修改它,也可以配置多个BeanFactoryPostProcessor* ,可以通过order属性来控制BeanFactoryPostProcessor的执行顺序(注意:此属性必须当BeanFactoryPostProcessor实现了Ordered* 接口时才可以赊账),因此在实现BeanFactoryPostProcessor时应该考虑实现Ordered接口* 如果想改变实现的bean实例(例如从配置源数据创建的对象),那最好使用BeanPostProcessor,同样的BeanFactoryPostProcessor,* 的作用域范围是容器级别的,它只是和你锁使用的容器有关。如果你在容器中定义了一个BeanFactoryPostProcessor,它仅仅对此容器的* bean进行后置处理,BeanFactoryPostProcessor不会对定义在另外一个容器的bean进行后置处理,即使两个容器都在同一个层次上。* 在spring中存在对BeanFactoryPostProcessor的典型应用,如:PropertyPlaceholderConfigure* */// Invoke factory processors registered as beans in the context.invokeBeanFactoryPostProcessors(beanFactory);// 6.注册拦截Bean创建的Bean拦截器(Bean的后置处理器,拦截Bean的创建),这里只是注册,真正调用的时候 是在getBean// Register bean processors that intercept bean creation.registerBeanPostProcessors(beanFactory);beanPostProcess.end();// 7.为上下文处理Message源,国际化处理 即不同语言的消息体// Initialize message source for this context.initMessageSource();// 8.初始化应用消息广播器 也就是事件派发器,并放入 ApplicationEventMulticaster 中// Initialize event multicaster for this context.initApplicationEventMulticaster();// 9.留给子类来初始化它的Bean 给子容器(子类),子类重写这个方法,在容器刷新的时候可以自定义逻辑// Initialize other special beans in specific context subclasses.onRefresh();// 10.在所有注册的Bean中查找Listener Bean 注册到广播器中// Check for listener beans and register them.registerListeners();// 初始化剩下的单实例(非惰性的)// Instantiate all remaining (non-lazy-init) singletons.finishBeanFactoryInitialization(beanFactory);// 最后一步完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出 ContentRefreshEvent 通知别人// Last step: publish corresponding event.finishRefresh();}catch (BeansException ex) {if (logger.isWarnEnabled()) {logger.warn("Exception encountered during context initialization - " +"cancelling refresh attempt: " + ex);}// Destroy already created singletons to avoid dangling resources.destroyBeans();// Reset \'active\' flag.cancelRefresh(ex);// Propagate exception to caller.throw ex;}finally {// Reset common introspection caches in Spring\'s core, since we// might not ever need metadata for singleton beans anymore...resetCommonCaches();contextRefresh.end();}}}
  • 源码分析

看这一行代码

invokeBeanFactoryPostProcessors(beanFactory);

,在这里初始化BeanFactory后,会激活各种BeanFactory处理器,我们来看看invokeBeanFactoryPostProcessors这个方法。

  • 看源码(
    PostProcessorRegistrationDelegate.java

    )

public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {// 1、首先调用 BeanDefinitionRegistryPostProcessors// Invoke BeanDefinitionRegistryPostProcessors first, if any.Set<String> processedBeans = new HashSet<>();// beanFactory是 BeanDefinitionRegistry 类型if (beanFactory instanceof BeanDefinitionRegistry) {BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;// 定义BeanFactoryPostProcessorList<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();// 定义BeanDefinitionRegistryPostProcessor集合List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();// 循环手动注册的 beanFactoryPostProcessorsfor (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {/* 如果是BeanDefinitionRegistryPostProcessor的实例话,* 则调用其 postProcessBeanDefinitionRegistry 方法,对bean进行注册操作*/if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {BeanDefinitionRegistryPostProcessor registryProcessor =(BeanDefinitionRegistryPostProcessor) postProcessor;registryProcessor.postProcessBeanDefinitionRegistry(registry);registryProcessors.add(registryProcessor);}// 否则则将其当做普通的BeanFactoryPostProcessor处理,直接加入regularPostProcessors集合,以备后续处理 else {regularPostProcessors.add(postProcessor);}}// Do not initialize FactoryBeans here: We need to leave all regular beans// uninitialized to let the bean factory post-processors apply to them!// Separate between BeanDefinitionRegistryPostProcessors that implement// PriorityOrdered, Ordered, and the rest.List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();// 首先调用实现了 PriorityOrdered (有限排序接口)的// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.String[] postProcessorNames =beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);}}// 排序sortPostProcessors(currentRegistryProcessors, beanFactory);// 加入registryProcessors集合registryProcessors.addAll(currentRegistryProcessors);// 调用所有实现了PriorityOrdered的的BeanDefinitionRegistryPostProcessors的postProcessBeanDefinitionRegistry方法,注册beaninvokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());// 清空currentRegistryProcessors,以备下次使用currentRegistryProcessors.clear();// 其次,调用实现了Ordered(普通排序接口)的BeanDefinitionRegistryPostProcessors// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);}}// 排序sortPostProcessors(currentRegistryProcessors, beanFactory);// 加入registryProcessors集合registryProcessors.addAll(currentRegistryProcessors);// 调用所有实现了PriorityOrdered的的BeanDefinitionRegistryPostProcessors的postProcessBeanDefinitionRegistry方法,注册beaninvokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());// 清空currentRegistryProcessors,以备下次使用currentRegistryProcessors.clear();// 最后,调用其他的BeanDefinitionRegistryPostProcessors// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.Boolean reiterate = true;while (reiterate) {reiterate = false;postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (!processedBeans.contains(ppName)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);reiterate = true;}}// 排序sortPostProcessors(currentRegistryProcessors, beanFactory);// 加入registryProcessors集合registryProcessors.addAll(currentRegistryProcessors);// 调用其他的 BeanDefinitionRegistryProcessors 的 postProcessorBeanDefinitionRegistry 方法invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());// 清空currentRegistryProcessors集合 以供下次使用currentRegistryProcessors.clear();}/* 现在调用所有的 BeanDefinitionRegistryPostProcessor (包括手动注册和配置文件注册) 和* 和 BeanFactoryPostProcessor(只有手动注册)的回调函数 -> postProcessBeanFactory*/// Now, invoke the postProcessBeanFactory callback of all processors handled so far.invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);}// 2.如果不是BeanDefinitionRegistry的实例,那么直接调用其他回调函数即可 -->postProcessBeanFactory else {// Invoke factory processors registered with the context instance.invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);}// 上面的代码已经处理完了所有的 BeanDefinitionRegistryPostProcessor 和 手动注册的 BeanFactoryPostProcessor// 接下来要处理通过配置文件注册的 BeanFactoryPostProcessor// Do not initialize FactoryBeans here: We need to leave all regular beans// uninitialized to let the bean factory post-processors apply to them!// 首先获取所有的BeanFactoryPostProcessor (注意:这里获取的集合会包含 BeanDefinitionRegistryPostProcessors)String[] postProcessorNames =beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,// Ordered, and the rest.// 这里 将实现了 PriorityOrdered Ordered的处理器和其他处理器区分开来,分别进行处理// PriorityOrdered有序处理器List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();// Ordered有序处理器List<String> orderedPostProcessorNames = new ArrayList<>();// 无序处理器List<String> nonOrderedPostProcessorNames = new ArrayList<>();for (String ppName : postProcessorNames) {if (processedBeans.contains(ppName)) {// 判断processedBeans是否包含当前处理器(processedBeans中的处理器已经处理过的  也就是上边第一步已经处理过的),如果包含则不做处理// skip - already processed in first phase above}// 加入到PriorityOrdered有序处理器集合 else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));}// 加入到Ordered有序处理器集合 else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {orderedPostProcessorNames.add(ppName);}// 加入到无序处理器集合 else {nonOrderedPostProcessorNames.add(ppName);}}// 首先调用实现了 PriorityOrdered 接口的处理器// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.sortPostProcessors(priorityOrderedPostProcessors, beanFactory);invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);// 其次 调用了 Ordered 接口的处理器// Next, invoke the BeanFactoryPostProcessors that implement Ordered.List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());for (String postProcessorName : orderedPostProcessorNames) {orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));}sortPostProcessors(orderedPostProcessors, beanFactory);invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);// 最后 调用了无序处理器// Finally, invoke all other BeanFactoryPostProcessors.List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());for (String postProcessorName : nonOrderedPostProcessorNames) {nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));}// 循环遍历  BeanFactoryPostProcessor 中的 postProcessBeanFactory 方法invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);// 清理元数据// Clear cached merged bean definitions since the post-processors might have// modified the original metadata, e.g. replacing placeholders in values...beanFactory.clearMetadataCache();}
  • 源码分析

我们着重看看一下

registryProcessor.postProcessBeanDefinitionRegistry(registry);

这行代码,然后看一下其实现类如图所示:

然后我们看一下

ConfigurationClassPostProcessor

这个类里面的

postProcessBeanDefinitionRegistry

方法

  • 看源码(
    ConfigurationClassPostProcessor.java

    )

@Overridepublic 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);// 解析Java类配置beanprocessConfigBeanDefinitions(registry);}

继续查看解析Java类配置Bean的方法processConfigBeanDefinition(registry)

  • 看源码(
    ConfigurationClassPostProcessor.java

    )

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {List<BeanDefinitionHolder> configCandidates = new ArrayList<>();// 所有已经注册的BeanString[] candidateNames = registry.getBeanDefinitionNames();// 清楚Bean定义信息for (String beanName : candidateNames) {BeanDefinition beanDef = registry.getBeanDefinition(beanName);if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {if (logger.isDebugEnabled()) {logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);}}// 1. 如果当前Bean是JavaBean配置类(含有@Configuration注解的类), 则加入到集合 configCandidates 中 else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));}}// Return immediately if no @Configuration classes were found// 没有 @Configuration 注解的类直接退出if (configCandidates.isEmpty()) {return;}// Sort by previously determined @Order value, if applicable// 多个Java 配置类 按 @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 contextSingletonBeanRegistry sbr = null;if (registry instanceof SingletonBeanRegistry) {sbr = (SingletonBeanRegistry) registry;if (!this.localBeanNameGeneratorSet) {BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(AnnotationConfigUtils.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// 初始化一个 ConfigurationClassParser 解析器 ,可以解析 @Configuration 配置类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 {StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse");// 2. 解析Java配置类parser.parse(candidates);// 主要校验配置类不能使用 final 修饰符修饰 (CGLIB代理是生成一个子类,因此原先的类不能使用final修饰)parser.validate();// 排除已处理过的配置类Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());configClasses.removeAll(alreadyParsed);// Read the model and create bean definitions based on its contentif (this.reader == null) {this.reader = new ConfigurationClassBeanDefinitionReader(registry, this.sourceExtractor, this.resourceLoader, this.environment,this.importBeanNameGenerator, parser.getImportRegistry());}// 3. 加载Bean 定义信息,主要实现将 @Bean @Configuration @Import @ImportResource  注册为Beanthis.reader.loadBeanDefinitions(configClasses);alreadyParsed.addAll(configClasses);processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end();// 清空已处理的配置类candidates.clear();// 再次获取容器中Bean定义数量,如果大于之前获取的Bean定义数量,则说明有新的Bean注册到容器中,需要再次解析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);// 新注册的Bean如果也是@Configuration配置类,则添加数据等待解析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 classesif (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();}}
  • 源码解析

processConfigBeanDefinitions这个方法大体可以划分为三个阶段:

  1. 阶段一:从容器中获取和Configuration有关系的BeanDefinition
  2. 以该BeanDefinition为起点,进行解析操作,得到解析结果集
  3. 将解析到的结果集加载到容器中,即构造成一个BeanDefinition放到容器中待初始化
1. 判断类是否与@Configuration有关

在上面第一步中,有@Configuration注解的会加入到集合当中,这个判断是在

ConfigurationClassUtils.checkConfigurationClassCandidate

当中实现的。

看源码之前先看一下

ConfigturationClassUtils.java

类中的一下代码,在下面的代码分析中都有用到。

private static final Set<String> candidateIndicators = new HashSet<>(8);static {candidateIndicators.add(Component.class.getName());candidateIndicators.add(ComponentScan.class.getName());candidateIndicators.add(Import.class.getName());candidateIndicators.add(ImportResource.class.getName());}
  • 看源码(
    ConfigurationClassUtils.java

    )

public static Boolean checkConfigurationClassCandidate(BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {String className = beanDef.getBeanClassName();if (className == null || beanDef.getFactoryMethodName() != null) {return false;}// 获取注解元数据信息AnnotationMetadata metadata;if (beanDef instanceof AnnotatedBeanDefinition &&className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {// Can reuse the pre-parsed metadata from the given BeanDefinition...metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();} else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {// Check already loaded Class if present...// since we possibly can\'t even load the class file for this Class.Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();if (BeanFactoryPostProcessor.class.isAssignableFrom(beanClass) ||BeanPostProcessor.class.isAssignableFrom(beanClass) ||AopInfrastructureBean.class.isAssignableFrom(beanClass) ||EventListenerFactory.class.isAssignableFrom(beanClass)) {return false;}metadata = AnnotationMetadata.introspect(beanClass);} else {try {MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);metadata = metadataReader.getAnnotationMetadata();}catch (IOException ex) {if (logger.isDebugEnabled()) {logger.debug("Could not find class file for introspecting configuration annotations: " +className, ex);}return false;}}// 注意这个方法 下面后进行一个匹配 看看是不是指定的注解 比如 @ConfigurationMap<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());// 查找当前注解是否与 @Configuration 相关// 该方法还会判断该注解上的注解是否有 @Configuration 一直往上寻找 因为有的注解是复合注解if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);}// 查找当前注解上是否有 @ComponentScan、@Component、@Import、@ImportResource 注解// 如果没有则查找Bean注解,同上,一直往上查找 else if (config != null || isConfigurationCandidate(metadata)) {beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);} else {return false;}// It\'s a full or lite configuration candidate... Let\'s determine the order value, if any.Integer order = getOrder(metadata);if (order != null) {beanDef.setAttribute(ORDER_ATTRIBUTE, order);}return true;}

继续看一下这里面的

isConfigurationCandidate

这个方法

  • 看源码(
    ConfigurationClassUtils.java

    )

public static Boolean isConfigurationCandidate(AnnotationMetadata metadata) {// Do not consider an interface or an annotation...if (metadata.isInterface()) {return false;}// Any of the typical annotations found?for (String indicator : candidateIndicators) {if (metadata.isAnnotated(indicator)) {return true;}}// Finally, let\'s look for @Bean methods...return hasBeanMethods(metadata);}

继续查看这个方法里面的

hasBeanMethods

方法:

  • 看源码(“)
static Boolean hasBeanMethods(AnnotationMetadata metadata) {try {return metadata.hasAnnotatedMethods(Bean.class.getName());}catch (Throwable ex) {if (logger.isDebugEnabled()) {logger.debug("Failed to introspect @Bean methods on class [" + metadata.getClassName() + "]: " + ex);}return false;}}
2. 解析Java配置类parse.parse(candidates)

parse.parse(candidates)方法最终调用processConfigurationClass方法来处理@Configuratin配置类,ConfigurationClassParser.procesConfigurationClass()方法代码如下:

  • 看源码(
    ConfigurationClassParser.java

    )

protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) 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);}}// Recursively process the configuration class and its superclass hierarchy.// ** 真正解析配置类 **SourceClass sourceClass = asSourceClass(configClass, filter);do {sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);}while (sourceClass != null);// 再次添加到到集合中this.configurationClasses.put(configClass, configClass);}
  • 源码解析

看上面代码中的真正解析配置类的那行代码

sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);

doProcessConfigurationClass方法主要是从配置类中解析所有Bean,包括处理内部类,父类以及各种注解ConfigurationClassParse.doProcessConfigurationClass()解析逻辑如下:

  • 看源码(
    ConfigurationClassParser.java

    )

@Nullableprotected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)throws IOException {if (configClass.getMetadata().isAnnotated(Component.class.getName())) {// Recursively process any member (nested) classes first// 递归处理任何成员(嵌套)类processMemberClasses(configClass, sourceClass, filter);}// Process any @PropertySource annotations// 处理@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// 处理@ComponentScan//获取@ComponentScan注解信息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// 按@CmponentScan注解扫描beanSet<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// 遍历扫描出的bean定义是否是配置类beanfor (BeanDefinitionHolder holder : scannedBeanDefinitions) {BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();if (bdCand == null) {bdCand = holder.getBeanDefinition();}// 如果扫描出的bean定义是配置类(含有@COnfiguration),则继续调用parse方法,内部再次调用doProcessConfigurationClas(),递归解析if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {parse(bdCand.getBeanClassName(), holder.getBeanName());}}}}// Process any @Import annotations//处理@Import注解processImports(configClass, sourceClass, getImports(sourceClass), filter, true);// Process any @ImportResource annotations// 处理@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// 处理@Bean注解Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);for (MethodMetadata methodMetadata : beanMethods) {// 将解析出的所有@Bean注解方法添加到configClass配置类信息中configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));}// Process default methods on interfaces// 处理接口中所有添加@Bean注解的方法,内部通过遍历所有接口,解析得到@Bean注解方法,并添加到configClass配置类信息中processInterfaces(configClass, sourceClass);// Process superclass, if any// 如果有父类,则返回父类,递归执行doProcessConfigurationClass()解析父类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 recursereturn sourceClass.getSuperClass();}}// No superclass -> processing is completereturn null;}

接下来说一下很重要的两个注解,

@Bean

@ComponentScan

的实现过程。在上面的doProcessConfigurationClass方法里

@ComponentScan注解解析过程

//获取@ComponentScan注解信息Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);

@ComponentScan注解解析,从上面的代码可以看出**@ComponentScan注解解析**通过调用

ComponentScanAnnotationParser

的parse方法完成,而parse()方法内部处理了一些scanner属性(过滤设置)和basePackages包名处理,最终通过调用

ClassPathBeanDefinitionScanner.doScan

方法实现扫描工作。

先来看一下ComponentScanAnnotationParser的parse方法

  • 看源码(
    ComponentScanAnnotationParser.java

    )

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));}scanner.setResourcePattern(componentScan.getString("resourcePattern"));for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {for (TypeFilter typeFilter : typeFiltersFor(filter)) {scanner.addIncludeFilter(typeFilter);}}for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {for (TypeFilter typeFilter : typeFiltersFor(filter)) {scanner.addExcludeFilter(typeFilter);}}Boolean lazyInit = componentScan.getBoolean("lazyInit");if (lazyInit) {scanner.getBeanDefinitionDefaults().setLazyInit(true);}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) {@Overrideprotected Boolean matchClassName(String className) {return declaringClass.equals(className);}});return scanner.doScan(StringUtils.toStringArray(basePackages));}

注意上面最后一行代码

scanner.doScan(StringUtils.toStringArray(basePackages));

doScan扫描basePackages下所有bean.

  • 看源码(
    ClassPathBeanDedefinitionScanner.java

    )

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) {// 根据 basePackage 加载包下所有Java文件,并扫描出所有Bean组件Set<BeanDefinition> candidates = findCandidateComponents(basePackage);// 遍历 beanDefinitionfor (BeanDefinition candidate : candidates) {// 解析作用域 ScopeScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);candidate.setScope(scopeMetadata.getScopeName());String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);if (candidate instanceof AbstractBeanDefinition) {postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);}// 通过注解解析到 candidate 结构中,主要是处理 Lazy primary DependsOn Role Description 这五个注解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);// 注册到IOC 容器中,主要是一些 @Component 组件,@Bean方法并没有在此处注册,BeanName和BeanDefinition键值对registerBeanDefinition(definitionHolder, this.registry);}}}return beanDefinitions;}

上面扫扫描出所有Bean组件的方法

findCandidateComponents

具体实现是在

ClassPathScanningCandidateComponentProvider

scanCandidateComponents

方法里面;如下:

  • 看源码(
    ClassPathScaningcandidateCommponentProvider.java

    )

private Set<BeanDefinition> scanCandidateComponents(String basePackage) {Set<BeanDefinition> candidates = new LinkedHashSet<>();try {// @ComponentScan("com.sl.springlearning.extension")// 包路径处理:packageSearchPath = classpath*:com/sl/springlearning/extension/**/*.classString packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +resolveBasePackage(basePackage) + \'/\' + this.resourcePattern;// 获取当前包下所有的class文件Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);Boolean traceEnabled = logger.isTraceEnabled();Boolean debugEnabled = logger.isDebugEnabled();for (Resource resource : resources) {if (traceEnabled) {logger.trace("Scanning " + resource);}if (resource.isReadable()) {try {MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);// 按照scanner过滤器过滤,比如配置类本身将被过滤掉,没有@Component等组件注解的类将过滤掉// 包含@Component注解的组件将创建BeanDefinitionif (isCandidateComponent(metadataReader)) {ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);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;}

@Bean注解解析过程

继续回到

ConfigutationClassParser.java

中的

doProcessConfigurationClass

这个方法里的对@Bean注解的解析。Set beanMethods = retrieveBeanMethodMetadata(sourceClass);

  • 看源码(
    ConfigurationClaSSParser.java

    )

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

retrieveBeanMethodMetadata

方法可以看到的是只是实现了**@Bean**方法的解析,但并未将实现Bean实例的创建。

3. 加载Bean定义信息this.reader.loadBeanDefinitions(configClasses)

继续回到

ConfigurationClassPostProcessor

类的

processConfigBeanDefinitions

方法,当调用完

praser

方法后,能得到一批ConfigurationClass集合,但是这时候只是获取到,而容器中还没有对应的注册信息,那么接下来就是对这批集合进行注册处理。

this.reader.loadBeanDefinitions(configClasses);

这行代码就是进行注册处理。

  • 看源码(
    ConfigurationClassBeanDefinitionReader.java

    )

public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();for (ConfigurationClass configClass : configurationModel) {loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);}}
  • 源码分析

ConfigurationClassBeanDefinitionReader.loadBeanDefinitions()方法的功能就是将之前解析出的configClasses配置类信息中所有配置相关的信息添加到Spring的Bean定义。主要是配置类中的@Bean注解方法,配置类@ImportResource和@Import(实现ImportBeanDefinitionRegistrar接口方式)的Bean注册

继续查看

loadBeanDefinitionsForConfigurationClass

方法

  • 看源码(
    ConfigurationClassBeanDefinitionReader.java

    )

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;}// 与@Import注解相关if (configClass.isImported()) {registerBeanDefinitionForImportedConfigurationClass(configClass);}// 将@Bean方法注册为beanfor (BeanMethod beanMethod : configClass.getBeanMethods()) {loadBeanDefinitionsForBeanMethod(beanMethod);}// 将configClass中中ImportResource指定的资源注册为beanloadBeanDefinitionsFromImportedResources(configClass.getImportedResources());// 将configClass中ImportedRegistrar注册为beanloadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());}

继续查看将@Bean方法注册为Bean的方法:

loadBeanDefinitionsForBeanMethod

  • 看源码(
    ConfigurationClassBeanDefinitionReader.java

    )

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?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// 获取@Bean注解是否有name属性,如:(@Bean(name="myBean"))List<String> names = new ArrayList<>(Arrays.asList(bean.getStringArray("name")));// 默认Bean的方法和名称相同,但是如果设置了name,就获取name作为BeanNameString beanName = (!names.isEmpty() ? names.remove(0) : methodName);// Register aliases even when overriddenfor (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 的 BeanDefinitionConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata, beanName);beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));// 设置工厂方法,// 后去的Bean实例化,getBean的时候,会判断BeanMethod是否存在FactoryMethod,如果存在就使用反射调用工厂方法,返回工厂方法的对象if (metadata.isStatic()) {// static @Bean methodif (configClass.getMetadata() instanceof StandardAnnotationMetadata) {beanDef.setBeanClass(((StandardAnnotationMetadata) configClass.getMetadata()).getIntrospectedClass());} else {beanDef.setBeanClassName(configClass.getMetadata().getClassName());}beanDef.setUniqueFactoryMethodName(methodName);} else {// instance @Bean methodbeanDef.setFactoryBeanName(configClass.getBeanName());beanDef.setUniqueFactoryMethodName(methodName);}if (metadata instanceof StandardMethodMetadata) {beanDef.setResolvedFactoryMethod(((StandardMethodMetadata) metadata).getIntrospectedMethod());}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);}String initMethodName = bean.getString("initMethod");if (StringUtils.hasText(initMethodName)) {beanDef.setInitMethodName(initMethodName);}String destroyMethodName = bean.getString("destroyMethod");beanDef.setDestroyMethodName(destroyMethodName);// Consider scopingScopedProxyMode 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 necessaryBeanDefinition 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, beanName);}if (logger.isTraceEnabled()) {logger.trace(String.format("Registering bean definition for @Bean method %s.%s()",configClass.getMetadata().getClassName(), beanName));}this.registry.registerBeanDefinition(beanName, beanDefToRegister);}
  • 源码解析

上面的代码比较多,主要看注释的核心部分,其目的主要是构造了BeanDefinition,然后注册进容器,而BeanDefinition的一些属性则是由注解中获取的;

另外,可以看到@Bean的方式构造的BeanDefinition的时候,与普通的不同,这种方式是会设置工厂方法去初始化,也就是说,咱们自定义的

CustomConfig

类型的appBean方法会被Spring当成一个工厂方法,也就是说这种方式与下列的初始化方式原理类似:

<bean id="customConfig" class="com.vipbbo.selfdemo.spring.configuration.CustomConfig"/><bean id="appBean" factory-bean="customConfig" factory-method="appBean"></bean>

总结

处理逻辑理了一遍之后,看ConfigurationClassPostProcessor处理器解析@Configuration配置类主要过程:

  1. Spring容器初始化时注册默认后置处理器ConfigurationClassPostProcessor
  2. Spring容器初始化执行refresh()方法中调用ConfigurationClassPostProcessor
  3. ConfigurationClassPostProcessor处理器借助ConfigurationClassParser完成配置类解析
  4. ConfigurationClassParser配置内解析过程中完成嵌套的MemberClass、@PropertySource注解、@ComponentScan注解(扫描package下的所有Class并进行迭代解析,主要是@Component组件解析及注册)、@ImportResource、@Bean等处理
  5. 完成@Bean注册,@ImportResource指定bean的注册以及@Import(实现ImportBeanDefinitionRegistrar接口方式)的Bean注册
  6. 有@Bean注解的方法在解析的时候作为iConfigurantionClass的一个属性,最后还是会转换成BeanDefinition进行处理,而实例化的时候会作为一个工厂方法进行Bean的创建

整理不易,如果对你有所帮助欢迎点赞关注微信搜索【码上遇见你】获取更多精彩内容

赞(0) 打赏
未经允许不得转载:爱站程序员基地 » Spring5源码分析之@Configuration注解的详解。希望读者能够耐着性子看完