前言

整理下以前分析过的springboot源码笔记,遗忘了方便查阅。springboot2.1.3版本。

springboot的启动流程

springboot启动类被@SpringBootApplication注解,该注解是个复合注解,注解的层次如下

@SpringBootApplication
     |-@SpringBootConfiguration
          |-@Configuration   //说明启动类是个配置类
              |-@Component   //说明启动类是个bean
     |-@EnableAutoConfiguration
          |-@AutoConfigurationPackage
              |-@Import(AutoConfigurationPackages.Registrar.class)
          |-@Import(AutoConfigurationImportSelector.class)  //
     |-@ComponentScan   //说明会扫描启动类所在包以及其子包下的被@Component注解的类为bean对象

先贴流程图图

springboot源码笔记

说下springboot大体启动流程:

Step1:创建SpringApplication对象
Step2:加载spring.factories文件内的ApplicationContextInitializer并实例化保存到属性SpringApplication.initializers集合
Step3:加载spring.factories文件内的ApplicationListener并实例化保存到属性SpringApplication.listeners集合

Step4:从该步骤开始进入run方法,加载META-INF/spring.factories文件内的SpringApplicationRunListener并实例化(默认是EventPublishingRunListener)保存到局部变量SpringApplicationRunListeners属性listeners集合

Step5:执行SpringApplicationRunListener的starting动作,触发spring.factories内的监听器ApplicatonListener

Step6:执行SpringApplicationRunListener的environmentPrepared动作,触发spring.factories内的监听器ApplicatonListener

Step7:创建ApplicationContext,springboot启动引入了web模块默认是AnnotationConfigServletWebServerApplicationContext

Step8:加载spring.factories文件内的SpringBootExceptionReporter并实例化,默认FailureAnalyzers,在springboot启动异常时候报告异常,这个通常不需要关注

Step9:执行spring.factories文件内的ApplicationContextInitializer

Step10:执行SpringApplicationRunListener的contextPrepared动作,触发spring.factories内的监听器ApplicatonListener

Step11:把springboot启动类注册为bean

Step12:执行SpringApplicationRunListener的contextLoaded动作,触发spring.factories内的监听器ApplicatonListener

Step13:IOC容器刷新,这个是spring的启动核心方法,这里只是spring内容,主要功能是扫描注解,把单例都注册为bean

Step14:添加JVM钩子方法,用于kill $PID关闭springboot容器

Step15:执行SpringApplication的afterRefresh方法,这个是protected空方法,供开发者实现,在IOC容器刷新后做一些处理。

Step16:执行SpringApplicationRunListener的started动作,触发spring.factories内的监听器ApplicatonListener

Step17:执行IOC容器中bean类型为ApplicationRunner、CommandLineRunner的run方法

Step18:执行SpringApplicationRunListener的running动作,触发spring.factories内的监听器ApplicatonListener

至此springboot启动完成

从流程图可知,springboot的启动本质就是IOC容器的启动,只是通过监听器扩展了功能,在springboot容器的不同阶段,执行对应的监听器执行功能而已。下面就分析IOC容器的启动

refresh()源码解释

spring boot启动,IOC的refresh()方法是在

AnnotationConfigServletWebServerApplicationContext.refresh()

即org.springframework.context.support.AbstractApplicationContext.refresh()内

@Override
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // Prepare this context for refreshing.
        prepareRefresh();//@1

        // Tell the subclass to refresh the internal bean factory.
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();//@2

        // Prepare the bean factory for use in this context.
        prepareBeanFactory(beanFactory);//@3

        try {
            // Allows post-processing of the bean factory in context subclasses.
            postProcessBeanFactory(beanFactory);//@4

            // Invoke factory processors registered as beans in the context.
            invokeBeanFactoryPostProcessors(beanFactory);//@5

            // Register bean processors that intercept bean creation.
            registerBeanPostProcessors(beanFactory);//@6

            // Initialize message source for this context.
            initMessageSource();//@7

            // Initialize event multicaster for this context.
            initApplicationEventMulticaster();//@8

            // Initialize other special beans in specific context subclasses.
            onRefresh();//@9

            // Check for listener beans and register them.
            registerListeners();//@10

            // Instantiate all remaining (non-lazy-init) singletons.
            finishBeanFactoryInitialization(beanFactory);//@11

            // Last step: publish corresponding event.
            finishRefresh();//@12
        }

        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();//@13
        }
    }
}

@1:context刷新前的准备工作,比如初始化placeholder属性配置,验证properties文件的合法性

@2:创建BeanFactory对象,即DefaultListableBeanFactory对象

@3:准备在此上下文中使用的bean工厂。即为DefaultListableBeanFactory对象的属性设置值,比如设置classloader,设置BeanPostProcessor、设置ignoredDependencyInterfaces、向beanFactory注册一些系统bean等工作。

@4:允许在上下文子类中对bean工厂进行后处理。注册WebApplicationContextServletContextAwareProcessor这个BeanPostProcessor到bean工厂。为什么要单独注册这个呢?原因是什么?

@5:调用在上下文中注册为bean的工厂处理器。该方法是spring的核心方法,核心扩展机制。即把BeanFactoryPostProcessor类型的bean实例化注册到applicationContext

@6:把类型是BeanPostProcessor的bean实例化并缓存到DefaultListableBeanFactory.beanPostProcessors集合,用于后面普通bean实例化的时候对bean进行修改。

@7:初始化MessageSource,用于国际化。

@8:初始化广播SimpleApplicationEventMulticaster,后续用于spring事件机制

@9:protected方法,用于扩展,对于引入了spring-web来说,那么这个钩子方法是用于启动tomcat

@10:1.获取spring初始化时候,缓存到AbstractApplicationContext.applicationListeners的监听器;2.获取类型ApplicationListener注册到BeanFactory的bean;把以上2中情况的监听器都缓存到SimpleApplicationEventMulticaster.defaultRetriever.applicationListeners集合,这样spring对bean实例化完毕后,就会执行监听器,做一些收尾工作。

@11: 把注册到BeanFactory的bean实例化并缓存到DefaultListableBeanFactory.singletonObjects,这里的finishBeanFactoryInitialization是个protected方法,我们开发可以自己继承实现。此外该方法也会冻结已经注册的bean,这样单例bean数量不会再变化。

@12:最后一步刷新,主要功能就是执行spring的监听器。事件机制也是spring的一大扩展点。我们的bean可以实现ApplicationListener接口,在bean实例化后做一些后续工作。

invokeBeanFactoryPostProcessors源码分析

这里的源码是refresh()的代码@5

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

    // Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
    // (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
    if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
        beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
        beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    }
}

public List<BeanFactoryPostProcessor> getBeanFactoryPostProcessors() {
    return this.beanFactoryPostProcessors;//@1
}

@1:返回IOC容器对象applicationContext注册的BeanFactoryPostProcessor集合,这些集合的元素是什么时候添加的呢?是在监听器、初始化时候添加的,具体可以debug,默认引入springboot-web时候该集合内容是[CachingMetadataReaderFactoryPostProcessor、ConfigurationWarningsPostProcessor、PropertySourceOrderingPostProcessor]

接着看invokeBeanFactoryPostProcessors方法

public static void invokeBeanFactoryPostProcessors(
			ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

    // Invoke BeanDefinitionRegistryPostProcessors first, if any.
    Set<String> processedBeans = new HashSet<>();//保存处理过的bean
    if (beanFactory instanceof BeanDefinitionRegistry) {//传入的beanFactory是DefaultListableBeanFactory
        BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
        List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();//保存实现了BeanFactoryPostProcessor但是未实现BeanDefinitionRegistryPostProcessor的bean
        List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();//保存实现了BeanDefinitionRegistryPostProcessor的bean

        //代码@0-begin
        for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
            if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {//遍历参数beanFactoryPostProcessors中是BeanDefinitionRegistryPostProcessor类型的bean
                BeanDefinitionRegistryPostProcessor registryProcessor =
                    (BeanDefinitionRegistryPostProcessor) postProcessor;
                /*
					 * 	比如执行的是CachingMetadataReaderFactoryPostProcessor、ConfigurationWarningsPostProcessor的postProcessBeanDefinitionRegistry方法
					 */
                registryProcessor.postProcessBeanDefinitionRegistry(registry);
                registryProcessors.add(registryProcessor);
            }
            else {
                regularPostProcessors.add(postProcessor);
            }
        }
        //代码@0-end

        // 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<>();

        // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
        /*
			 * 	代码@1-begin -> @1-end 功能是 获取注册到beanFactory的BeanDefinition,获取到的结果有[org.springframework.context.annotation.internalConfigurationAnnotationProcessor]
			 * 	对应的bean是ConfigurationClassPostProcessor,这个bean是注解方式启动的核心bean,如果该bean实现了PriorityOrdered,则执行其postProcessBeanDefinitionRegistry方法
			 */
        //代码@1-begin
        String[] postProcessorNames =
            beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
        for (String ppName : postProcessorNames) {
            if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {//ppName对应的bean实现了PriorityOrdered接口
                currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                processedBeans.add(ppName);
            }
        }
        sortPostProcessors(currentRegistryProcessors, beanFactory);
        registryProcessors.addAll(currentRegistryProcessors);
        invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);//代码@1.1,这里主要是去执行ConfigurationClassPostProcessor,该类会去加载bean,处理@Import、@Compoment、@Configuration
        currentRegistryProcessors.clear();
        //代码@1-end

        // Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
        /*
			 * 	@2-begin -> @2-end 功能是 获取注册到beanFactory的BeanDefinition,获取到的结果有[org.springframework.context.annotation.internalConfigurationAnnotationProcessor]
			 * 	对应的bean是ConfigurationClassPostProcessor,这个bean是注解方式启动的核心bean,如果该bean实现了Ordered,则执行其postProcessBeanDefinitionRegistry方法
			 */
        //代码@2-begin
        postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
        for (String ppName : postProcessorNames) {
            if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {//ppName对应的bean实现了Ordered接口
                currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                processedBeans.add(ppName);
            }
        }
        sortPostProcessors(currentRegistryProcessors, beanFactory);
        registryProcessors.addAll(currentRegistryProcessors);
        invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
        currentRegistryProcessors.clear();
        //代码@2-end

        // Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
        /*
			 * @3-begin -> @3-end功能是获取注册到beanFactory的类型是BeanDefinitionRegistryPostProcessor的BeanDefinition,实例化未实现PriorityOrdered、Ordered接口的bean,
			 * 	执行其postProcessBeanDefinitionRegistry方法
			 */
        //代码@3-begin
        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.addAll(currentRegistryProcessors);
            invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);//代码@3.1,执行postProcessBeanDefinitionRegistry方法
            currentRegistryProcessors.clear();
        }
        //代码@3-end

        // Now, invoke the postProcessBeanFactory callback of all processors handled so far.
        invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);//代码@4, 此处执行@1、@2、@3处实现了BeanDefinitionRegistryPostProcessor的bean的postProcessBeanFactory方法
        invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);//代码@5,此处执行只实现了BeanFactoryPostProcessor的bean的postProcessBeanFactory方法
    }

    else {//忽略
        // Invoke factory processors registered with the context instance.
        invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
    }

    // Do not initialize FactoryBeans here: We need to leave all regular beans
    // uninitialized to let the bean factory post-processors apply to them!
    String[] postProcessorNames =
        beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);//获取实现了BeanFactoryPostProcessor接口的bean

    // Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
    // Ordered, and the rest.
    //代码@6-begin
    List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();//保存实现了BeanFactoryPostProcessor和PriorityOrdered的bean
    List<String> orderedPostProcessorNames = new ArrayList<>();//保存实现了BeanFactoryPostProcessor和Ordered的bean名称
    List<String> nonOrderedPostProcessorNames = new ArrayList<>();//保存实现了BeanFactoryPostProcessor但不实现PriorityOrdered、Ordered的bean名称
    for (String ppName : postProcessorNames) {
        if (processedBeans.contains(ppName)) {//跳过实现了BeanDefinitionRegistryPostProcessor的bean
            // skip - already processed in first phase above
        }
        else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {//如果bean实现了BeanFactoryPostProcessor和PriorityOrdered
            priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));//实例化bean
        }
        else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {//如果bean实现了BeanFactoryPostProcessor和Ordered
            orderedPostProcessorNames.add(ppName);
        }
        else {
            nonOrderedPostProcessorNames.add(ppName);
        }
    }

    // First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
    sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
    invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);//执行postProcessBeanFactory方法,这里是PropertySourcesPlaceholderConfigurer,该bean工厂后置处理器是用于处理@value等
    //代码@6-end

    // Next, invoke the BeanFactoryPostProcessors that implement Ordered.
    //代码@7-begin
    List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
    for (String postProcessorName : orderedPostProcessorNames) {
        orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));//实例化实现了BeanFactoryPostProcessor和Ordered接口的bean
    }
    sortPostProcessors(orderedPostProcessors, beanFactory);
    invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
    //代码@7-end

    // Finally, invoke all other BeanFactoryPostProcessors.
    //代码@8-begin
    List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
    for (String postProcessorName : nonOrderedPostProcessorNames) {
        nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));//实例化实现了BeanFactoryPostProcessor但不实现PriorityOrdered、Ordered接口的bean
    }
    invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
    //代码@8-end

    // Clear cached merged bean definitions since the post-processors might have
    // modified the original metadata, e.g. replacing placeholders in values...
    beanFactory.clearMetadataCache();
}

代码@0处:遍历传入的参数beanFactoryPostProcessors,执行类型是BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法

代码@1处:获取类型是BeanDefinitionRegistryPostProcessor的bean,如果实现了PriorityOrdered接口,则实例化bean,并执行bean的postProcessBeanDefinitionRegistry方法。这里重要的就是ConfigurationClassPostProcessor,该类会向BeanDefination集合加入配置类引入的XxxBeanFactoryPostProcessor

代码@1.1处,主要是去执行ConfigurationClassPostProcessor,该类会去加载bean,处理@Import、@Compoment、@Configuration,这个是关键

代码@2处:获取类型是BeanDefinitionRegistryPostProcessor的bean,如果实现了Ordered接口,则实例化bean,并执行bean的postProcessBeanDefinitionRegistry方法

代码@3处:获取类型是BeanDefinitionRegistryPostProcessor但是不实现Ordered\PriorityOrdered接口的bean,实例化bean,并执行bean的postProcessBeanDefinitionRegistry方法。比如执行dubbo的ServiceAnnotationBeanPostProcessor,处理dubbo @Service

代码@4处:执行@1、@2、@3处实现了BeanDefinitionRegistryPostProcessor的bean的postProcessBeanFactory方法

代码@5处:执行参数beanFactoryPostProcessors中只实现了BeanFactoryPostProcessor的bean的postProcessBeanFactory方法

代码@6处:获取类型是BeanFactoryPostProcessor的bean,如果实现了PriorityOrdered接口,则实例化bean,并执行bean的postProcessBeanFactory方法

代码@7处:获取类型是BeanFactoryPostProcessor的bean,如果实现了Ordered接口,则实例化bean,并执行bean的postProcessBeanFactory方法

代码@8处:获取类型是BeanFactoryPostProcessor的bean,实例化bean,并执行bean的postProcessBeanFactory方法

通过上面8种情况,就把实现了BeanDefinitionRegistryPostProcessor或BeanFactoryPostProcessor的所有bean都进行了处理。

综上:代码@1、@2、@3是处理类型是BeanDefinitionRegistryPostProcessor的bean,代码@4、@5、@6是处理BeanFactoryPostProcessor的bean,BeanDefinitionRegistryPostProcessor是BeanFactoryPostProcessor的子接口,关系如图

springboot源码笔记

BeanFactoryPostProcessor是BeanFactory的后置处理器,是针对于beanFactory的扩展点,即spring会在beanFactory初始化之后,beanDefinition都已经loaded,但是bean还未创建前进行调用,可以修改,增加beanDefinition。通常扩展实现BeanFactoryPostProcessor即可,如果想在bean的加载前进行用户自定义功能,实现BeanDefinitionRegistryPostProcessor。如果要求有优先顺序,则需要实现PriorityOrdered或Ordered接口。

重点说下:

代码@1.1处:这里是执行的是ConfigurationClassPostProcessor,那么该bean是什么时候加载到BeanFactory的呢?是在org.springframework.boot.SpringApplication.createApplicationContext()这里地方,通过反射生成ConfigurableApplicationContext对象的时候,比如引入了springboot web模块,创建的是AnnotationConfigServletWebServerApplicationContext,该类实例化的时候如下:

public AnnotationConfigServletWebServerApplicationContext() {
    this.reader = new AnnotatedBeanDefinitionReader(this);//执行org.springframework.context.annotation.AnnotationConfigUtils.registerAnnotationConfigProcessors(BeanDefinitionRegistry, Object),注册spring内部bean,org.springframework.context.annotation.internalConfigurationAnnotationProcessor->ConfigurationClassPostProcessor
    this.scanner = new ClassPathBeanDefinitionScanner(this);
}

会自动注册内部bean ConfigurationClassPostProcessor,该类是注解启动的关键,处理@Configuration、@Compoment、@Import,该类功能后续再讲解。

代码@6处主要是执行PropertySourcesPlaceholderConfigurer,这个是属性处理,处理@Value

下面来看ConfigurationClassPostProcessor的功能,这个类是spring最核心最复杂的方法,自动装配就是该类实现的

ConfigurationClassPostProcessor源码分析

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

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
    List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
    String[] candidateNames = registry.getBeanDefinitionNames();//获取已经注册的bean名称集合,此时注册的bean除了spring内部bean就是用户启动的配置类,用户启动的配置类是在SpringApplication.prepareContext(ConfigurableApplicationContext, ConfigurableEnvironment, SpringApplicationRunListeners, ApplicationArguments, Banner)阶段的SpringApplication.load(ApplicationContext, Object[])注册用户启动的配置类为bean的

    for (String beanName : candidateNames) {
        BeanDefinition beanDef = registry.getBeanDefinition(beanName);
        if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||	//beanDef的属性上org.springframework.context.annotation.ConfigurationClassPostProcessor.configurationClass值为full
            ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {//beanDef的属性上org.springframework.context.annotation.ConfigurationClassPostProcessor.configurationClass值为lite
            //通常beanDef的属性上org.springframework.context.annotation.ConfigurationClassPostProcessor.configurationClass值为null,因此不进入该分支
            if (logger.isDebugEnabled()) {
                logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
            }
        }
        else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {//类上被@Configuration @Component、@ComponentScan、@Import、@ImportResource注解,或者方法上被@Bean注解
            configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
        }
    }

    // Return immediately if no @Configuration classes were found
    if (configCandidates.isEmpty()) {//springboot注解方式启动,configCandidates默认是启动的配置类,通常只有一个
        return;
    }

    // Sort by previously determined @Order value, if applicable
    configCandidates.sort((bd1, bd2) -> {
        int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
        int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
        return Integer.compare(i1, i2);
    });

    // Detect any custom bean name generation strategy supplied through the enclosing application context
    SingletonBeanRegistry sbr = null;
    if (registry instanceof SingletonBeanRegistry) {
        sbr = (SingletonBeanRegistry) registry;
        if (!this.localBeanNameGeneratorSet) {
            BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);//generator是在SpringApplication.prepareContext(ConfigurableApplicationContext, ConfigurableEnvironment, SpringApplicationRunListeners, ApplicationArguments, Banner)阶段的SpringApplication.postProcessApplicationContext(ConfigurableApplicationContext)注册的
            if (generator != null) {//false,存在generator
                this.componentScanBeanNameGenerator = generator;
                this.importBeanNameGenerator = generator;
            }
        }
    }

    if (this.environment == null) {
        this.environment = new StandardEnvironment();
    }

    // Parse each @Configuration class
    ConfigurationClassParser parser = new ConfigurationClassParser(
        this.metadataReaderFactory, this.problemReporter, this.environment,
        this.resourceLoader, this.componentScanBeanNameGenerator, registry);//创建配置类解析对象,比如dubbo解析@com.alibaba.dubbo.config.annotation.Service也是使用该类进行解析

    Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);//常规springboot方式启动,configCandidates内只有一个元素,即配置类
    Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
    do {
        parser.parse(candidates);//@@1//核心方法,解析配置类
        parser.validate();

        Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());//获取解析配置类得到的@Import引入的类、@ImportResource引入的资源文件、@Bean注解的方法 集合
        configClasses.removeAll(alreadyParsed);

        // Read the model and create bean definitions based on its content
        if (this.reader == null) {
            this.reader = new ConfigurationClassBeanDefinitionReader(
                registry, this.sourceExtractor, this.resourceLoader, this.environment,
                this.importBeanNameGenerator, parser.getImportRegistry());
        }
        this.reader.loadBeanDefinitions(configClasses);//@@2 //把@Import引入的类、@ImportResource引入的资源文件、@Bean注解的方法生成的对象 注册为bean 
        alreadyParsed.addAll(configClasses);

        candidates.clear();
        if (registry.getBeanDefinitionCount() > candidateNames.length) {//注册的bean数量有变化
            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));//把没有解析过的配置类保存到candidates,用于循环解析和注册过程
                    }
                }
            }
            candidateNames = newCandidateNames;
        }
    }
    while (!candidates.isEmpty());//如果解析配置类后,bean数量有变化,则candidates是非空,因此再继续循环执行解析配置类和注册bean过程,这样不断循环,直到candidates为空退出,这样就解决了配置类上还有配置类的情况

    // Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
    if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
        sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
    }

    if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
        // Clear cache in externally provided MetadataReaderFactory; this is a no-op
        // for a shared cache since it'll be cleared by the ApplicationContext.
        ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
    }
}

processConfigBeanDefinitions方法的核心是代码@@1和@@2处,代码@@1负责解析配置类,代码@@2负责把解析到的类注册为bean,下面先看@@1这个方法

public void parse(Set<BeanDefinitionHolder> configCandidates) {
    for (BeanDefinitionHolder holder : configCandidates) {
        BeanDefinition bd = holder.getBeanDefinition();
        try {
            if (bd instanceof AnnotatedBeanDefinition) {//注解方式启动执行该分支
                parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());//@1
            }
            else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
                parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
            }
            else {
                parse(bd.getBeanClassName(), holder.getBeanName());
            }
        }
        catch (BeanDefinitionStoreException ex) {
            throw ex;
        }
        catch (Throwable ex) {
            throw new BeanDefinitionStoreException(
                "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
        }
    }

    //解析配置类后,存在@Import引入DeferredImportSelector类型,比如springboot的自动装配AutoConfigurationImportSelector就是DeferredImportSelector
    this.deferredImportSelectorHandler.process();//@2 springboot自动装配的具体实现
}

配置类是注解,那么对应的BeanDefinition就是AnnotatedBeanDefinition,因此执行代码@1。代码@2处是处理@Import引入类是DeferredImportSelector类型,该类的解析后续再说。

接着看代码@1处

protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
    processConfigurationClass(new ConfigurationClass(metadata, beanName));
}

protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
    if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {//配置类不被@Conditional注解
        return;
    }

    //配置类被@Conditional注解
    ConfigurationClass existingClass = this.configurationClasses.get(configClass);
    if (existingClass != null) {//配置类如果已经被处理过了
        if (configClass.isImported()) {//配置类是被@Import引入的,避免重复处理,则不再解析
            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);
    do {
        sourceClass = doProcessConfigurationClass(configClass, sourceClass);//@@3 //解析配置类,核心方法 
    }
    while (sourceClass != null);//为null时候退出

    this.configurationClasses.put(configClass, configClass);//处理过的@Configuration、@Component、@bean、@Import引入的类都缓存到ConfigurationClassParser.configurationClasses集合上,后续获取该集合,从而注册为bean
}

processConfigurationClass方法的核心逻辑判断处理配置类,并把每个处理过的配置类(包括普通bean)都缓存到ConfigurationClassParser.configurationClasses集合

ConfigurationClassParser的debug图如下

springboot源码笔记

类结构图如下

springboot源码笔记

总之就是ConfigurationClassParser.configurationClasses集合缓存的是bean(@Componet扫描的bean、配置bean、@Import(ImportSelect类型)引入注册的bean)包装对象ConfigurationClasses,而每个ConfigurationClasses对象上又保存了@Bean、@Import(AutoConfigurationPackages.Registrar类型)引入。其中特殊的是@Import(DeferredImportSelector类型)是保存在ConfigurationClassParser.deferredImportSelectorHandler集合上,这个主要是springboot内部自动装配的实现。

processConfigurationClass处理流程图

springboot源码笔记

接着看doProcessConfigurationClass方法

@Nullable
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
    throws IOException {

    if (configClass.getMetadata().isAnnotated(Component.class.getName())) {//类是被@Component注解
        // Recursively process any member (nested) classes first
        //如果配置类被@Component注解,则处理该类上的内部类是配置类的情况,即把内部类处理后并缓存到ConfigurationClassParser.configurationClasses集合	
        processMemberClasses(configClass, sourceClass);//处理内部类上的@PropertySource、@ComponentScan、@Import、@ImportResource、@Bean注解情况,递归执行doProcessConfigurationClass
    }

    // Process any @PropertySource annotations
    //处理@PropertySources、PropertySource情况,没用过,暂时不清楚用途
    for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
        sourceClass.getMetadata(), PropertySources.class,
        org.springframework.context.annotation.PropertySource.class)) {//配置类被@PropertySource注解,没遇到过,忽略
        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注解,@SpringBootApplication是被@ComponentScan注解,默认是扫描启动类所在包下的类,如果被@Component注解,则注册为bean。
		 * 接着递归执行parse方法,判断这些用户自定义的bean上是否有被@Configuration注解 @Import @bean注解,这样就能把所有的用户自定义的bean上的注解都扫描完。
		 */
    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
            //扫描指定package下的被@Component注解的类注册为bean,除此外,如果用户自定义了includeFilter,则也会扫描自定义的注解为bean
            Set<BeanDefinitionHolder> scannedBeanDefinitions =
                this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());//扫描类解析为BeanDefinitionHolder,dubbo扫描@Service也是参考这个做的
            // Check the set of scanned definitions for any further config classes and parse recursively if needed
            //遍历扫描package注册的bean,把这些bean也进行解析,看看这些用户自定义bean上是否存在@Configuration,就是递归解析@Configuration
            for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
                BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
                if (bdCand == null) {
                    bdCand = holder.getBeanDefinition();
                }
                if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
                    // 类上被@Configuration @Component、@ComponentScan、@Import、@ImportResource注解,或者方法上被@Bean注解则递归调用parse
                    parse(bdCand.getBeanClassName(), holder.getBeanName());
                }
            }
        }
    }

    // Process any @Import annotations
    /*
		 * getImports是采用递归方式获取sourceClass上的@Import注解的value
		 * processImports把@Import注解的value保存到this.configurationClasses集合,供后续把@Import注解的value值集合都注册为bean
		 */
    processImports(configClass, sourceClass, getImports(sourceClass), true);

    // Process any @ImportResource annotations
    /*
		 * 处理@ImportResource注解,这个是为了兼容老应用是xml配置方式,目前已经过时很少使用了,不需要进行深究了
		 * 只需要知道ImportResource导入的资源也被保存到ConfigurationClass.importedResources,后面也会被注册为bean
		 */
    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注解,把生成的对象缓存到this.configurationClasses集合,后续会被注册为bean
		 */
    Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
    for (MethodMetadata methodMetadata : beanMethods) {
        configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
    }

    // Process default methods on interfaces
    /*
		 * 如果接口内的非抽象方法被@Bean注解,则把方法缓存到ConfigurationClass.beanMethods
		 */
    processInterfaces(configClass, sourceClass);

    // Process superclass, if any
    if (sourceClass.getMetadata().hasSuperClass()) {
        String superclass = sourceClass.getMetadata().getSuperClassName();
        if (superclass != null && !superclass.startsWith("java") &&
            !this.knownSuperclasses.containsKey(superclass)) {
            this.knownSuperclasses.put(superclass, configClass);
            // Superclass found, return its annotation metadata and recurse
            return sourceClass.getSuperClass();
        }
    }

    // No superclass -> processing is complete
    return null;
}

doProcessConfigurationClass功能逻辑如下:

springboot源码笔记

接着看processImports

private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
			Collection<SourceClass> importCandidates, boolean checkForCircularImports) {

    if (importCandidates.isEmpty()) {
        return;
    }

    if (checkForCircularImports && isChainedImportOnStack(configClass)) {
        this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
    }
    else {
        this.importStack.push(configClass);
        try {
            for (SourceClass candidate : importCandidates) {
                if (candidate.isAssignable(ImportSelector.class)) {//是ImportSelector的实现
                    // Candidate class is an ImportSelector -> delegate to it to determine imports
                    Class<?> candidateClass = candidate.loadClass();
                    ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);//实例化
                    ParserStrategyUtils.invokeAwareMethods(
                        selector, this.environment, this.resourceLoader, this.registry);//实现了Aware感知接口的处理
                    if (selector instanceof DeferredImportSelector) {//是DeferredImportSelector的实现
                        this.deferredImportSelectorHandler.handle(
                            configClass, (DeferredImportSelector) selector);//缓存到ConfigurationClassParser.DeferredImportSelectorHandler.deferredImportSelectors集合
                    }
                    else {
                        String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
                        Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
                        processImports(configClass, currentSourceClass, importSourceClasses, false);//@Import引入的是ImportSelector的实现,则递归调用processImports处理其上的@Import注解
                    }
                }
                else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {//是ImportBeanDefinitionRegistrar的实现
                    // Candidate class is an ImportBeanDefinitionRegistrar ->
                    // delegate to it to register additional bean definitions
                    Class<?> candidateClass = candidate.loadClass();
                    ImportBeanDefinitionRegistrar registrar =
                        BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
                    ParserStrategyUtils.invokeAwareMethods(
                        registrar, this.environment, this.resourceLoader, this.registry);
                    configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());//缓存到ConfigurationClass.importBeanDefinitionRegistrars集合
                }
                else {//@Import引入的非ImportSelector、ImportBeanDefinitionRegistrar实现,即一个普通java类,则递归处理其上面的@PropertySource、@ComponentScan、@Import、@ImportResource、@Bean,同时把该类缓存到ConfigurationClassParser.configurationClasses,后续被注册为bean
                    // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
                    // process it as an @Configuration class
                    this.importStack.registerImport(
                        currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
                    //spring.factories内的自动配置都是直接执行这里,通常是不执行上面两个分支
                    processConfigurationClass(candidate.asConfigClass(configClass));//@Import引入的对象递归去执行processConfigurationClass,这样就把@Import引入的对象也会缓存到ConfigurationClassParser.configurationClasses,后续被注册为bean。 或者是 处理spring.factories内的自动配置类
                }
            }
        }
        catch (BeanDefinitionStoreException ex) {
            throw ex;
        }
        catch (Throwable ex) {
            throw new BeanDefinitionStoreException(
                "Failed to process import candidates for configuration class [" +
                configClass.getMetadata().getClassName() + "]", ex);
        }
        finally {
            this.importStack.pop();
        }
    }
}

processImports方法主要功能是处理@Import注解,逻辑如下:

1.如果@Import引入的是DeferredImportSelector的实现,则缓存到ConfigurationClassParser.DeferredImportSelectorHandler.deferredImportSelectors集合

2.如果@Import引入的是ImportSelector的实现,则递归处理引入值上的@Import,直至没有@Import执行第4步

3.如果@Import引入的是ImportBeanDefinitionRegistrar,则缓存到ConfigurationClass.importBeanDefinitionRegistrars集合

4.如果@Import引入的是个普通类(包括配置类),没有实现DeferredImportSelector、ImportSelector、ImportBeanDefinitionRegistrar,则递归processConfigurationClass处理该普通类上的注解,并缓存普通类到ConfigurationClassParser.configurationClasses,后续该普通类被注册为bean。

由此可见,@Import引入是有ImportSelector实现(包括DeferredImportSelector实现)、ImportBeanDefinitionRegistrar实现,配置类、普通类,该注解的引入最终都会被注册为bean。

springboot源码笔记

DeferredImportSelector vs ImportSelector区别?

DeferredImportSelector 是ImportSelector的子接口,DeferredImportSelector 会在所有的@Configuration类加载完成之后再加载返回的配置类,同时DeferredImportSelector 的加载顺序可以通过@Order或者实现了Ordered接口来指定,同时DeferredImportSelector 提供了新方法getImportGroup()来跨DeferredImportSelector 实现自定义的Configutaion的加载顺序。

ImportSelector是在加载完@Configuration类之前,先去加载返回的配置类。

对于开发扩展来说,ImportSelector简单,直接实现ImportSelector即可,通常不需要使用DeferredImportSelector(太复杂,是springboot自动装配的实现)

接着回头看org.springframework.context.annotation.ConfigurationClassParser.parse(Set<BeanDefinitionHolder>)方法,该方法执行this.deferredImportSelectorHandler.process();是springboot自动装配的具体实现,处代码如下:

public void process() {
    List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
    this.deferredImportSelectors = null;
    try {
        if (deferredImports != null) {
            DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
            deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
            deferredImports.forEach(handler::register);//@1 执行DeferredImportSelectorGroupingHandler#register
            handler.processGroupImports();//@2
        }
    }
    finally {
        this.deferredImportSelectors = new ArrayList<>();
    }
}

代码@1:比如springboot,执行AutoConfigurationImportSelector#getImportGroup()获取AutoConfigurationGroup实例对象,并缓存到DeferredImportSelectorGroupingHandler.groupings,供代码@2处处理

代码@2:这个是自动装配的关键,即遍历@1处生成的groupings集合,加载META-INF/spring-autoconfigure-metadata.properties文件,该文件是OnCondition的方式确定哪些配置类要被加载(装配),该方法逻辑复杂,自己有些细节也没看明白,DeferredImportSelector接口是spring5比spring4多了实现,spring4的比较简单,见如下代码:

//spring4.3.2的处理DeferredImportSelector
private void processDeferredImportSelectors() {
    List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
    this.deferredImportSelectors = null;
    Collections.sort(deferredImports, DEFERRED_IMPORT_COMPARATOR);

    for (DeferredImportSelectorHolder deferredImport : deferredImports) {
        ConfigurationClass configClass = deferredImport.getConfigurationClass();
        try {
            String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata());//执行selectImports获取引入类
            processImports(configClass, asSourceClass(configClass), asSourceClasses(imports), false);
        }
        catch (BeanDefinitionStoreException ex) {
            throw ex;
        }
        catch (Throwable ex) {
            throw new BeanDefinitionStoreException("Failed to process import candidates for configuration class [" +
                                                   configClass.getMetadata().getClassName() + "]", ex);
        }
    }
}

public interface DeferredImportSelector extends ImportSelector {//spring4 DeferredImportSelector接口无具体实现

}

spring4就是执行selectImports获取获取引入类,处理引入类上的@Import注解,spring5对DeferredImportSelector接口增加了getImportGroup方法,增加这个方法的原因应该是随着装配类的增加,需要用group的方式进行集体装配。

接着回头查看processConfigBeanDefinitions这个顶层方法,该方法太复杂了,以至于看着后面前面的就有些遗忘了,该方法的功能流程如下:

springboot源码笔记

ConfigurationClassPostProcessor.postProcessBeanFactory(ConfigurableListableBeanFactory)功能很复杂,我们只需要知道它在spring的注解启动过程中做了哪些功能,这样才方便我们对spring进行扩展和定制,功能总结如下:

1.根据配置类扫描包下的类,类被@Component注解,则注册为bean。如果自定义了includeFilter,则也会扫描注册为bean。

2.扫描到的类上有@Import注解,则把引入的类(ImportSelector类型)注册为bean,@Import的功能很强大,该注解也就是在该方法内被解析的。

3.把@Bean注解方法的返回结果注册为bean。

4.把@ImportResource引入的资源注册为bean。比如引入的是xml配置的,把里面配置的bean都注册了。

总之,该方法就是扫描,把扫描结果和引入结果并注册bean。

BeanFactoryPostProcessor的扩展

通过前面1.2、1.3的分析,知道了PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory, List<BeanFactoryPostProcessor>)
ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(BeanDefinitionRegistry)的功能,那么我们写的BeanFactoryPostProcessor实现是如何被加载的呢?实际只需要在我们写的MyBeanFactoryPostProcessor实现上加上@Component,那么在ConfigurationClassPostProcessor.postProcessBeanFactory(ConfigurableListableBeanFactory)自然就会把我们自定义的MyBeanFactoryPostProcessor给注册为bean,接着在invokeBeanFactoryPostProcessors内会执行。

BeanFactoryPostProcessor是针对BeanFactory的扩展,作用就是在bean实例化前,注册一些bean,或者为一些特定的bean修改其属性等。后面spring实例化bean的时候还有个BeanPostProcessor,这个是对bean的扩展,用于在bean的初始化前后、实例化前后对bean进行修改,比如动态代理。

registerBeanPostProcessors源码分析,BeanPostProcessor

这里的源码是refresh()的代码@6

该方便和invokeBeanFactoryPostProcessors套路基本相同,首先也是获取已经注册的是BeanPostProcessor类型的bean,然后按照优先级顺序实例化BeanPostProcessor类型的bean,然后把这些BeanPostProcessor类型的bean缓存到BeanFactory,即缓存到DefaultListableBeanFactory.beanPostProcessors,即AbstractBeanFactory.beanPostProcessors集合,这样在后续普通bean实例化的时候,BeanPostProcessor就可以对bean进行修改了。

BeanFactoryPostProcessor vs BeanPostProcessor

BeanFactoryPostProcessor是对BeanFactory的扩展,在用户bean的实例化前对BeanFactory做一些前置处理,比如增加一些特定的内部bean,还有就是扫描,比如dubbo的扫描@Service,通常第三方框架要和spring整合一起,要使用到BeanFactoryPostProcessor,因为它的功能更加靠前。

BeanPostProcessor是对bean的扩展,对bean进行配置和修改,比如AOP功能就是使用的BeanPostProcessor在bean初始化完毕后,对bean生成动态代理类。

registerListeners源码分析

这里的源码是refresh()的代码@10

/**
	 * Add beans that implement ApplicationListener as listeners.
	 * Doesn't affect other listeners, which can be added without being beans.
	 */
protected void registerListeners() {
    // Register statically specified listeners first.
    for (ApplicationListener<?> listener : getApplicationListeners()) {//@1
        getApplicationEventMulticaster().addApplicationListener(listener);//@2
    }

    // Do not initialize FactoryBeans here: We need to leave all regular beans
    // uninitialized to let post-processors apply to them!
    String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
    for (String listenerBeanName : listenerBeanNames) {//@3
        getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);//@4
    }

    // Publish early application events now that we finally have a multicaster...
    Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
    this.earlyApplicationEvents = null;
    if (earlyEventsToProcess != null) {
        for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
            getApplicationEventMulticaster().multicastEvent(earlyEvent);
        }
    }
}

代码@1:遍历ApplicationContext创建后注册到其上面的监听器ApplicationListener,即AbstractApplicationContext.applicationListeners,把这些监听器缓存到SimpleApplicationEventMulticaster.defaultRetriever.applicationListeners集合上,而SimpleApplicationEventMulticaster又是保存在AbstractApplicationContext.applicationEventMulticaster属性上,这样用于后面bean实例化完毕后执行事件机制,即执行监听器方法onApplicationEvent。

那么问题来了:AbstractApplicationContext.applicationListeners的监听器是什么时候保存的呢?是在springboot的run方法内把spring.factories文件内的org.springframework.context.ApplicationListener对应的类对象保存的。具体保存的堆栈:

SpringApplication.run(String...)
SpringApplication.prepareContext(ConfigurableApplicationContext, ConfigurableEnvironment, SpringApplicationRunListeners, 	 ApplicationArguments, Banner)
SpringApplicationRunListeners.contextLoaded(ConfigurableApplicationContext)
EventPublishingRunListener.contextLoaded(ConfigurableApplicationContext)//把spring.factories文件内的org.springframework.context.ApplicationListener对应的类对象缓存到AbstractApplicationContext.applicationListeners集合

注意这些监听器并不是bean,因为没有注册到BeanFactory

代码@2:把spring.factories文件内的监听器缓存到SimpleApplicationEventMulticaster.defaultRetriever.applicationListeners集合上

代码@3:获取已经注册的类型是ApplicationListener的bean名称,此时这些监听器bean还未被实例

代码@4:把代码@3处的类型是监听器bean名称缓存到SimpleApplicationEventMulticaster.defaultRetriever.applicationListenerBeans集合上。这些未实例化的监听器bean,在实例化后被ApplicationListenerDetector这个BeanPostProcessor后置处理器处理添加到SimpleApplicationEventMulticaster.defaultRetriever.applicationListeners集合上,在finishRefresh()内的publishEvent方法进行广播的时候,执行对应的监听事件。

这里就涉及到AbstractApplicationContext和SimpleApplicationEventMulticaster之间的关系了,关系如图所示:

springboot源码笔记

从图上很清楚可以看出类之间的关闭,java语音是封装、继承、多态,这里类之间的关系就是封装。

从接口层面说:ApplicationContext保存了事件广播器ApplicationEventMulticaster。

这里ApplicationContext就是个事件源

事件是ApplicationEvent,包装了ApplicationContext。

监听器是ApplicationListener

ApplicationEventMulticaster实际就是个监听器的集合

事件源ApplicationContext有变化,就包装为事件ApplicationEvent给监听器,监听器ApplicationListener执行对应的动作。

事件机制的写法通常就是:事件源有个属性是监听器集合,事件源状态有变化,把事件源包装为事件,然后遍历监听器集合,每个监听器执行动作。tomcat的LifecycleBase、LifecycleListener、LifecycleEvent是这样,spring的事件机制也是如此。

ApplicationListener定义如下

ApplicationListener,是个泛型,在监听器集合执行的时候,会通过ResolvableType判断当前ApplicationListener的泛型是否和ApplicationEvent类型相同,相同才执行监听器。ApplicationListener 提供了 一个基于 ApplicationEvent 的泛型,所以你指定了某个类的监听者只会处理该类型的event。

如果自定义了监听器和事件,需要进行广播,那么service bean内直接注入个ApplicationEventPublisher即可,ApplicationEventPublisher是ApplicationContext的父接口,实际就是执行的AbstractApplicationContext.publishEvent(Object),注入是在ApplicationContextAwareProcessor.postProcessBeforeInitialization(Object, String)内注入的

finishBeanFactoryInitialization方法的preInstantiateSingletons源码解析

这里的源码是refresh()的代码@11

这里是bean创建流程,先看bean的创建流程图

springboot源码笔记

bean的创建总体分为,bean实例化,bean传播注入,bean初始化,每个步骤都会经过BeanPostProcessor集合的前后置处理。知道了这个流程,就知道如何对bean进行扩展了。

遍历BeanPostProcessor集合基本都是在AbstractAutowireCapableBeanFactory类的applyXXX()方法内进行遍历对bean进行处理。

BeanPostProcessor类型的处理,几个重要点

ApplicationContextAwareProcessor 是初始化前,如果bean是aware接口,则设置aware属性

ApplicationListenerDetector ,如果bean是监听器,则把实例化后的bean缓存到AbstractApplicationContext.applicationListeners

SmartInitializingSingleton说明

在preInstantiateSingletons()内如果已经注册的bean都已经创建完毕,那么遍历所有的bean,如果bean是SmartInitializingSingleton类型,则执行钩子方法afterSingletonsInstantiated(),是在所有单例bean(非懒加载对象)都已经被创建后执行,跟InitializingBean有点像。那么SmartInitializingSingleton的实际例子有什么呢?真想不出bean都实例化后,还进行收尾工作的需求是什么。spring有个EventListenerMethodProcessor内部bean,实现了SmartInitializingSingleton,该类在所有单例bean(非懒加载对象)都已经被创建后,查找被@EventListener注解的方法,把这个方法创建一个监听器ApplicationListenerMethodAdapter,加到ApplicationContext的监听器上,这样就可以通过注解方式来进行使用spring监听器了。但是实际上生成的ApplicationListenerMethodAdapter对象并不会被作为bean保存到IOC容器内,只是作为监听器集合的一个元素而已。个人认为@EventListener不如实现ApplicationListener好,有点鸡肋。

rocketmq starter内自动配置RocketMQTransactionConfiguration就实现了SmartInitializingSingleton,用于所有bean都初始化后,获取@RocketMQTransactionListener注解的bean,和spring处理@EventListener方式完全相同。

钩子接口的扩展机制

BeanFactoryPostProcessor

1.BeanFactoryPostProcessor:是针对于beanFactory的扩展点,即spring会在beanFactory初始化之后,beanDefinition都已经loaded,但是bean还未创建前进行调用,可以修改,增加beanDefinition
2.BeanDefinitionRegistryPostProcessor是BeanFactoryPostProcessor的子接口:是针对于beanFactory的扩展点,即spring会在调用BeanFactoryPostProcessor之前调用他。

具体使用就是实现BeanFactoryPostProcessor,加上@Component,这样就被加载到了。通常只实现BeanFactoryPostProcessor即可

BeanPostProcessor

1.BeanPostProcessor:是针对bean的扩展点,即spring会在bean初始化前后 调用方法对bean进行处理

2.InstantiationAwareBeanPostProcessor是BeanPostProcessor的子接口:是针对于bean的扩展点,即spring会在bean实例化前后进行调用
3.SmartInstantiationAwareBeanPostProcessor是InstantiationAwareBeanPostProcessor的子接口:是针对于bean的扩展点,预测已处理bean的最终类型,或者觉得bean实例化需要的构造函数,或者获取早期的bean
4.MergedBeanDefinitionPostProcessor是BeanPostProcessor的子接口:是针对于bean的扩展点,即spring会处理某个给定的beanDefinition于原本的bean进行merged

具体使用就是实现BeanPostProcessor,加上@Component,这样就被加载到了。通常只实现BeanPostProcessor即可

Aware

感知接口Aware

BeanNameAware,实现了这个接口的bean,可以获取beanName

BeanClassLoaderAware,实现了这个接口的bean,可以获取beanClassLoader

BeanFactoryAware,实现了这个接口的bean,可以获取BeanFactory

以上三个Aware接口是在bean实例化后进行注入。

下面这些Aware接口是在ApplicationContextAwareProcessor 这个BeanPostProcessor的bean初始化前置阶段注入

EnvironmentAware,实现了这个接口的bean,可以获取Environment

EmbeddedValueResolverAware,实现了这个接口的bean,可以获取StringValueResolver

ResourceLoaderAware,实现了这个接口的bean,可以获取ResourceLoader

ApplicationEventPublisherAware,实现了这个接口的bean,可以获取ApplicationEventPublisher,用于广播,而ApplicationEventPublisher是 ApplicationContext的父接口,因此实际获取的就是ApplicationContext

MessageSourceAware,实现了这个接口的bean,可以获取MessageSource

ApplicationContextAware,实现了这个接口的bean,可以获取ApplicationContext

InitializingBean、DisposableBean

如果bean实现了InitializingBean接口,则在bean的初始化阶段执行afterPropertiesSet(),对bean进行初始化,比如该bean作为一个SocketServer,则可以在afterPropertiesSet()内启动服务监听端口。

如果bean实现了DisposableBean接口,那么在spring容器关闭的时候,会执行destroy()销毁bean,比如bean启动了端口监听服务,那么可以在destroy()内关闭监听端口。

事件机制

spring事件机制

spring的事件机制涉及到事件源EventSource、事件EventObject、监听器Listener,事件是ApplicationEvent、监听器是ApplicatonListener,事件源通常就是ApplicaitonContext。

事件源ApplicaitonContext持有监听器集合(即广播对象ApplicationEventMulticaster ,持有监听器集合),ApplicaitonContext状态发生变化,则触发监听器执行,监听器只执行对应类型的ApplicationEvent。

几个重要的ApplicationEvent子类

ContextRefreshedEvent,在IOC容器finishRefresh()完成刷新阶段触发

事件机制在实际应用过程的作用:

通过Spring事件机制完成服务启动后的信息整理(类似于Dubbo的服务暴露机制)

通过Spring事件机制获取HTTP请求调用详情

开发者实现ApplicatonListener自定义监听器,实现ApplicationEvent自定义事件,如果需要广播,则可以通过实现ApplicationEventPublisherAware或者直接注入ApplicationEventPublisherAware来进行广播,触发自定义的监听器执行自定义事件

spring boot事件机制

springboot使用的监听器是SpringApplicationRunListener也是事件机制,SpringApplicationRunListener对starting 、environmentPrepared 、environmentPrepared 、contextPrepared 、contextLoaded 、started、running、failed动作做出对应监听

动作 事件 事件源
starting ApplicationStartingEvent SpringApplication
environmentPrepared ApplicationEnvironmentPreparedEvent SpringApplication
contextPrepared ApplicationContextInitializedEvent SpringApplication
contextLoaded ApplicationPreparedEvent SpringApplication
started ApplicationStartedEvent SpringApplication
running ApplicationReadyEvent SpringApplication
failed ApplicationFailedEvent SpringApplication

在springboot启动过程中,对于上述动作,都会触发监听器执行,监听器实际还是ApplicationListener,springboot启动创建SpringApplication的时候加载spring.factories内的org.springframework.context.ApplicationListener,加载org.springframework.boot.SpringApplicationRunListener默认是EventPublishingRunListener,EventPublishingRunListener持有事件源SpringApplication,广播(即监听器集合)SimpleApplicationEventMulticaster,在每个动作的时候,都让广播去遍历监听器执行监听动作,和spring的事件机制完全相同。如果我们需要在springboot启动的过程进行监听,则配置到spring.factories的org.springframework.context.ApplicationListener节点即可。springboot使用事件机制启动是真解耦呀,加啥功能,直接加个监听器即可。

springboot开发监听器的几种方式

1.监听器配置在spring.factories,这样springboot启动就会加载监听器,作用于springboot的启动阶段和IOC容器的启动完毕阶段,程序运行阶段。

2.bean直接实现ApplicationListener接口,这样只是作用于IOC容器的启动完毕阶段,程序运行阶段。

3.bean的方法上用@EventListener注解,功能同2。

FactoryBean

FactoryBean是个bean,IOC容器的getBean()方法获取这个类型是&beanName方式获取,常用于创建一类相同的bean,比如mybatis接口生成的bean,就是使用的FactoryBean。具体在mybatis分析的时候分析

BeanFactory是bean工厂,是spring的顶层接口,用于创建bean。

SmartInitializingSingleton

该类是在所有的单例bean(非懒加载)都创建后,如果bean是SmartInitializingSingleton类型,则执行,目前遇到的就是@EventListener的处理使用到了,其它需要上暂时没用到。

ImportBeanDefinitionRegistrar

ImportBeanDefinitionRegistrar的作用是注册bean,通常用于@Import中,那么ImportBeanDefinitionRegistrar和自定义的BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor的执行顺序是什么呢?

通过《invokeBeanFactoryPostProcessors源码分析》的分析:

先执行内部bean ConfigurationClassPostProcessor这个BeanDefinitionRegistryPostProcessor类型,这个类用于扫描和引入注册bean,那么在这个步骤的时候,@Import(ImportBeanDefinitionRegistrar类型)就会被执行,然后是执行自定义的BeanDefinitionRegistryPostProcessor,再执行自定义的BeanFactoryPostProcessor。

总结:

BeanDefinitionRegistryPostProcessor实现类只要加注解(@Component)就可以执行,而ImportBeanDefinitionRegister加注解(@Component)只是交给spring管理,并不会执行接口的方法,必须要在配置类中@Import()才会发挥作用;
ImportBeanDefinitionRegister执行顺序更早
mybatis中@MapperScan 注解就是利用ImportBeanDefinitionRegister
将接口生成代理类然后注册到BeanFactory中,这就是为什么mybatis中只有接口没有实现类的原因

springboot的自动装配机制

自动装配@EnableAutoConfiguration,核心原理是加载spring.factories文件内的org.springframework.boot.autoconfigure.EnableAutoConfiguration,然后根据@Conditional条件确定装配对应的XXXAutoConfiguration,这些XXXAutoConfiguration会被注册为内bean,同时也通过@Bean、@Import创建引入bean,这样就完成了对应功能的装配,具体看下面分析。

自动装配

自动装配源码分析

入口是this.deferredImportSelectorHandler.process(),就是在ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(BeanDefinitionRegistry)这个spring的核心内部BeanFactoryPostProcess调用:

springboot源码笔记

接着看process()方法

//DeferredImportSelectorHandler.process()
public void process() {
    List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;//保存是就是@Import(DeferredImportSelector类型)的对象集合
    this.deferredImportSelectors = null;
    try {
        if (deferredImports != null) {
            DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
            deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);//排序
            deferredImports.forEach(handler::register);//代码@1
            handler.processGroupImports();//代码@2
        }
    }
    finally {
        this.deferredImportSelectors = new ArrayList<>();//清空
    }
}

代码分析:

代码@1:执行DeferredImportSelectorGroupingHandler.register(DeferredImportSelectorHolder),把importGroup缓存到DeferredImportSelectorGroupingHandler.groupings集合,供代码@2处使用

代码@2:遍历DeferredImportSelectorGroupingHandler.groupings集合,获取经过@Conditional过滤后符合自动装配的XXXAutoConfiguration,然后执行processImports操作把XXXAutoConfiguration注册为bean、把XXXAutoConfiguration上的@Import进行导入,这样就把spring.factories内org.springframework.boot.autoconfigure.EnableAutoConfiguration对应的值就进行了自动装配。那么核心功能就是在代码@2处了

//DeferredImportSelectorGroupingHandler.processGroupImports()
public void processGroupImports() {
    for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {//代码@3
        grouping.getImports().forEach(entry -> {//代码@4
            ConfigurationClass configurationClass = this.configurationClasses.get(
                entry.getMetadata());//代码@5
            try {
                processImports(configurationClass, asSourceClass(configurationClass),
                               asSourceClasses(entry.getImportClassName()), false);//代码@6
            }
            catch (BeanDefinitionStoreException ex) {
                throw ex;
            }
            catch (Throwable ex) {
                throw new BeanDefinitionStoreException(
                    "Failed to process import candidates for configuration class [" +
                    configurationClass.getMetadata().getClassName() + "]", ex);
            }
        });
    }
}

代码@3:遍历是元素默认是一个,DeferredImportSelectorGrouping.group是AutoConfigurationGroup

代码@4:grouping.getImports()返回的是经过spring-autoconfigure-metadata.properties过滤掉的自动配置集合,然后遍历集合,处理XXXAutoConfiguration。

代码@5:通常就是springboot的启动类

代码@6:处理XXXAutoConfiguration,注册XXXAutoConfiguration为bean,把XXXAutoConfiguration方法上的@Bean注册为bean,把XXXAutoConfiguration上的@Import进行注册为bean。

其它地方前面都分析过,但是代码@4处是如何通过spring-autoconfigure-metadata.properties文件过滤掉不符合的自动装配的呢?下面进行分析

//DeferredImportSelectorGrouping.getImports()
public Iterable<Group.Entry> getImports() {
    for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {//代码@7 
        this.group.process(deferredImport.getConfigurationClass().getMetadata(),
                           deferredImport.getImportSelector());//代码@8 这里this.group.process方法传入的参数就是@Import(DeferredImportSelector类型)
    }
    return this.group.selectImports();//代码@9 返回过滤后的自动装配集合
}

代码@7:this.deferredImports缓存的是@Import(DeferredImportSelector类型)

代码@8:通过spring-autoconfigure-metadata.properties文件过滤spring.factories文件内的自动装配

代码@9:把经过spring-autoconfigure-metadata.properties过滤的自动装配进行排序,排序由@AutoConfigureOrder、@AutoConfigureBefore、@AutoConfigureAfter决定,最终返回经过过滤后返回排序好的自动装配集合。

核心是this.group.process方法,功能就是通过spring-autoconfigure-metadata.properties过滤

//AutoConfigurationGroup.process(AnnotationMetadata, DeferredImportSelector)
public void process(AnnotationMetadata annotationMetadata,
                    DeferredImportSelector deferredImportSelector) {
    Assert.state(
        deferredImportSelector instanceof AutoConfigurationImportSelector,
        () -> String.format("Only %s implementations are supported, got %s",
                            AutoConfigurationImportSelector.class.getSimpleName(),
                            deferredImportSelector.getClass().getName()));
    AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
        .getAutoConfigurationEntry(getAutoConfigurationMetadata(),//getAutoConfigurationMetadata()返回的就是加载了spring-autoconfigure-metadata.properties文件的Properties对象
                                   annotationMetadata);//代码@10
    this.autoConfigurationEntries.add(autoConfigurationEntry);//代码@11
    for (String importClassName : autoConfigurationEntry.getConfigurations()) {
        this.entries.putIfAbsent(importClassName, annotationMetadata);//代码@12
    }
}

代码@10:通过spring-autoconfigure-metadata.properties文件过滤spring.factories文件内的自动装配,把过滤结果(集合)封装为AutoConfigurationEntry

代码@11和代码12作用是为了后续对自动装配类的排序,排序是通过@AutoConfigureOrder、@AutoConfigureBefore、@AutoConfigureAfter。

接着看过滤的核心功能

 //org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.getAutoConfigurationEntry(AutoConfigurationMetadata, AnnotationMetadata)
//传入参数autoConfigurationMetadata是加载了spring-autoconfigure-metadata.properties文件的对象
//传入参数annotationMetadata通常表示的springboot启动类的直接注解对象@SpringBootApplication(如果启动类上加了其它的@XXEnable,那么就是多个),是个StandardAnnotationMetadata,StandardAnnotationMetadata.annotations是这个配置类上的直接注解数量(其实就是java.lang.Class.getAnnotations() 方法返回当前这个元素上的所有直接注释),StandardAnnotationMetadata.introspectedClass就是springboot启动类
protected AutoConfigurationEntry getAutoConfigurationEntry(
    	AutoConfigurationMetadata autoConfigurationMetadata,
    	AnnotationMetadata annotationMetadata) {
    if (!isEnabled(annotationMetadata)) {//如果环境变量存在spring.boot.enableautoconfiguration=false,则不启用自动装配
        return EMPTY_ENTRY;
    }
    AnnotationAttributes attributes = getAttributes(annotationMetadata);//代码@13
    List<String> configurations = getCandidateConfigurations(annotationMetadata,
                                                             attributes);//代码@14
    configurations = removeDuplicates(configurations);//代码@15
    Set<String> exclusions = getExclusions(annotationMetadata, attributes);//代码@16
    checkExcludedClasses(configurations, exclusions);//代码@17
    configurations.removeAll(exclusions);//代码@18
    configurations = filter(configurations, autoConfigurationMetadata);//代码@19,核心
    fireAutoConfigurationImportEvents(configurations, exclusions);//代码@20
    return new AutoConfigurationEntry(configurations, exclusions);//代码@21
}

代码@13:获取@EnableAutoConfiguration的属性,就是exclude和excludeName,用于排除自动装配。如果需要排除一些自动装配,可以在启动类上@SpringBootApplication(exclude = {RabbitAutoConfiguration.class,BatchAutoConfiguration.class}),这样就不会自动装配rabbitmq,spring bactch。

代码@14:加载spring.factories文件内的org.springframework.boot.autoconfigure.EnableAutoConfiguration对应的类到集合。这些都是自动装配类型。

代码@15:移除重复的自动装配类,防止用户开发的spring.factories文件内配置了重复的自动装配。

代码@16:获取排除自动装配类的名称集合。排除自动装配除了exclude外,还可以通过配置属性spring.autoconfigure.exclude来指定要排除的自动装配。

代码@17:检查如果排除的类不在spring.factories的org.springframework.boot.autoconfigure.EnableAutoConfiguration内,则抛出异常。

代码@18:从自动配置类移除排除的自动装配。

代码@19:这个是自动装配过滤的核心方法。就是根据spring-autoconfigure-metadata.properties内的条件来过滤spring.factories内的org.springframework.boot.autoconfigure.EnableAutoConfiguration自动装配类。

代码@20:事件机制,用作钩子。触发AutoConfigurationImportEvent事件,用户可以实现AutoConfigurationImportListenerAutoConfigurationImportEvent事件做出对应动作。这里的configurations是经过过滤后,符合自动装配的类。这里的AutoConfigurationImportListener要写到spring.factories内,默认是ConditionEvaluationReportAutoConfigurationImportListener。这里默认执行的是ConditionEvaluationReportAutoConfigurationImportListener.onAutoConfigurationImportEvent(AutoConfigurationImportEvent)

代码@21:把符合自动装配的类集合和排除自动装配类集合包装为AutoConfigurationEntry返回。

下面看自动装配过滤分析

private List<String> filter(List<String> configurations,
			AutoConfigurationMetadata autoConfigurationMetadata) {
    long startTime = System.nanoTime();
    String[] candidates = StringUtils.toStringArray(configurations);
    boolean[] skip = new boolean[candidates.length];
    boolean skipped = false;
    for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {//@22 
        invokeAwareMethods(filter);//@23
        boolean[] match = filter.match(candidates, autoConfigurationMetadata);//@24-begin
        for (int i = 0; i < match.length; i++) {
            if (!match[i]) {
                skip[i] = true;
                candidates[i] = null;
                skipped = true;
            }
        }//@24-end
    }
    if (!skipped) {//@25
        return configurations;
    }
    List<String> result = new ArrayList<>(candidates.length);//@26-begin
    for (int i = 0; i < candidates.length; i++) {
        if (!skip[i]) {
            result.add(candidates[i]);
        }
    }//@26-end
    return new ArrayList<>(result);
}

传入参数:

configurations:是spring.factories内的org.springframework.boot.autoconfigure.EnableAutoConfiguration对应的自动装配类。

autoConfigurationMetadata:是spring-autoconfigure-metadata.properties文件内的属性集合,用于过滤自动装配类。

代码@22:遍历spring.factories内的org.springframework.boot.autoconfigure.AutoConfigurationImportFilter过滤器,排序后即[OnClassCondition, OnWebApplicationCondition, OnBeanCondition]

代码@23:如果过滤器是BeanClassLoaderAware、BeanFactoryAware、EnvironmentAware、ResourceLoaderAware类型,则赋值过滤器属性。

代码@24:执行的分别是OnClassCondition, OnWebApplicationCondition, OnBeanCondition的match方法,匹配的话match[i]就是true,把对应的candidates[i]位置的自动装配类设置为null。candidates集合就是spring.factories的org.springframework.boot.autoconfigure.EnableAutoConfiguration。那么是如何实现过滤的呢?以OnClassCondition为例,把org.springframework.boot.autoconfigure.EnableAutoConfiguration内的org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration加上ConditionalOnClass,即org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration.ConditionalOnClass是否在spring-autoconfigure-metadata.properties文件内存在,存在则candidates[i]位置不变,否则设置candidates[i]为null。就是这么简单进行过滤的。

过滤总结如下:

OnClassCondition过滤:自动装配类.ConditionalOnClass在spring-autoconfigure-metadata.properties内存在

OnWebApplicationCondition过滤:自动装配类.ConditionalOnWebApplication在spring-autoconfigure-metadata.properties内存在

OnBeanCondition过滤:自动装配类.ConditionalOnBean在spring-autoconfigure-metadata.properties内存在 或者 自动装配类.ConditionalOnSingleCandidate在spring-autoconfigure-metadata.properties内存在

代码@25:如果自动装配都有没有被过滤掉一个,则直接返回所有的自动装配。通常不会,因为一个项目不可能把springboot的每个组件都引入了。

代码@26:把经过过滤后剩余的自动装配类集合保存到result返回。

以上是自动装配的过滤流程,下面看自动装配的具体实现:

继续回到下面代码

springboot源码笔记

grouping.getImports()返回的就是经过spring-autoconfigure-metadata.properties过滤后的自动装配类集合,对每个自动装配类处理其上的@Import注解。

接着看ConfigurationClassParser.processImports(ConfigurationClass configClass, SourceClass currentSourceClass, Collection<SourceClass> importCandidates, boolean checkForCircularImports)方法,该方法传入的configClass表示的是启动主类,currentSourceClass就是自动装配类,以自动装配AOP AopAutoConfiguration为例,接着执行的是ConfigurationClassParser.processConfigurationClass(ConfigurationClass configClass),判断自动装配类是否要进行装配代码如下

//传入参数configClass表示的就是自动装配类,比如AopAutoConfiguration
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
    if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
        return;
    }
    //省略其它代码, 自动装配 doProcessConfigurationClass
}
//自动装配类是否要进行跳过装配判断
//传入参数metadata是AnnotationMetadataReadingVisitor,即表示自动装配类上所有直接注解,比如 AopAutoConfiguration,注解是@Configuration、@ConditionalOnClass、@ConditionalOnProperty
public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
    if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {//未被@Conditional(包括@ConditionalOnXXX)注解,则说明不需要跳过,需要进行装配
        return false;
    }

    if (phase == null) {
        if (metadata instanceof AnnotationMetadata &&
            ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
            return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
        }
        return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
    }

    List<Condition> conditions = new ArrayList<>();
    for (String[] conditionClasses : getConditionClasses(metadata)) {//getConditionClasses(metadata)是获取@Conditional的值
        for (String conditionClass : conditionClasses) {
            Condition condition = getCondition(conditionClass, this.context.getClassLoader());
            conditions.add(condition);
        }
    }//把自动装配类上@Conditional的value实例化保持到conditions集合

    AnnotationAwareOrderComparator.sort(conditions);//按照@Order排序

    for (Condition condition : conditions) {
        ConfigurationPhase requiredPhase = null;
        if (condition instanceof ConfigurationCondition) {
            requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
        }
        if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {//condition.matches()方法进行匹配,比如AopAutoConfiguration的@ConditionalOnClass,如果可以加载到EnableAspectJAutoProxy.class, Aspect.class, Advice.class,AnnotatedElement.class,则说明可以进行自动装配
            return true;
        }
    }
    return false;
}

自动装配流程总结:

自动装配核心是根据spring-autoconfigure-metadata.properties来过滤spring.factories文件内的自动装配类,然后把经过过滤后的自动配置集合再根据@ConditionalOnXXX决定是否要进行自动装配,,进而处理自动装配类。这里涉及到两次过滤,分别是AutoConfigurationImportFilter和SpringBootCondition,见下图的蓝色部分

springboot源码笔记

​ 自动装配流程图

核心getAutoConfigurationEntry(AutoConfigurationMetadata, AnnotationMetadata)方法的执行堆栈

springboot源码笔记

自动装配疑问和解决

为什么要经过两次过滤呢?第一次的过滤(spring-autoconfigure-metadata.properties)是为了加快启动速度,实际没有也没关系(实际装配是以第二次过滤为结果进行装配),试想下,springboot目前很庞大了,引入了许多组件,如果直接在processConfigurationClass()方法内一个个的进行过滤,这样耗时就会长,启动就会慢,所以先进行一波过滤自动装配类。但是通过github查看springboot源码,发现spring-autoconfigure-metadata.properties在spring-boot-autoconfigure并不存在,但是实际项目中spring-boot-autoconfigure-2.1.3.RELEASE.jar中存在,这样是为什么呢?因为在springboot编译为jar时候,是通过spring-boot-autoconfigure-processor进行编译得来的,同时看到spring-boot-autoconfigure-2.1.3.RELEASE.jar内存在/META-INF/spring-configuration-metadata.json、/META-INF/additional-spring-configuration-metadata.json,这两个文件是用于用户写properties时候的自动提醒功能(比如在ide中输入logging. 会提醒输入level),这个可有可无,当然有了更好,方便用户,spring-configuration-metadata.json内容是springboot自动生成,additional-spring-configuration-metadata.json是对前者的补充,框架开发者手工维护。 spring-configuration-metadata.json文件是由spring-boot-configuration-processor生成。

自动装配实战

开发者要自定义一个配置类XXXAutoConfiguration,要在该配置类上加@Configuration,如果有开启条件,加上@ConditionalOnXXX,同时要把XXXAutoConfiguration加入到spring.factories文件内的org.springframework.boot.autoconfigure.EnableAutoConfiguration节点内。

如果自动装配类不加入到spring.factories文件内,那么写一个对应的EnableXXX也可以,在EnableXXX的@Import(ImportSelector类型),其中ImportSelector类型的selectImports方法自动装配类,这样自动装配类也会被注册为bean。

自动装配的核心就是@Conditional,根据不同的条件来进行装配,下面分析@Conditional

@Conditional原理与实战

@Conditional原理分析

以@ConditionalOnClass为例分析,比如要加上注解@Conditional,对应的处理类是OnClassCondition

springboot源码笔记

在《 自动装配流程图》内通过spring-autoconfigure-metadata.properties进行过滤的时候(第一个蓝色方框图处),使用的是OnClassCondition、OnWebApplicationCondition、OnBeanCondition,执行的是match方法(AutoConfigurationImportFilter接口)进行匹配过滤;在真正装配的时候(第二个蓝色方框图处)比如配置类上有@ConditionalOnClass,那么执行matches方法(Condition接口)。关系如下图所示

springboot源码笔记

AutoConfigurationImportFilter接口之FilteringSpringBootCondition分析

自动装配类集合的第一次过滤(通过spring-autoconfigure-metadata.properties过滤),依次过滤的是OnClassCondition、OnWebApplicationCondition、OnBeanCondition,入口是AutoConfigurationImportSelector.filter(List, AutoConfigurationMetadata),执行FilteringSpringBootCondition的match方法进行过滤,以OnClassCondition为例,核心是执行的OnClassCondition.getOutcomes(String[], AutoConfigurationMetadata),本质就是配置类.ConditionalOnClass是否在spring-autoconfigure-metadata.properties存在,存在则匹配,否则就过滤掉。

同理

OnBeanCondition是判断配置类.ConditionalOnBean或者配置类.ConditionalOnSingleCandidate是否在spring-autoconfigure-metadata.properties存在,存在则匹配,否则就过滤掉。

ConditionalOnWebApplication是判断配置类.OnWebApplicationCondition是否在spring-autoconfigure-metadata.properties存在,存在则匹配,否则就过滤掉。

开发自定义的OnXXXCondition在spring-boot-autoconfigure.properties内进行过滤步骤

在spring.factories的org.springframework.boot.autoconfigure.AutoConfigurationImportFilter节点加入自定义的OnXXXCondition,同时开发OnXXXCondition继承FilteringSpringBootCondition,实现getOutcomes方法即可。

Condition接口之SpringBootCondition

自动配置类装配前,通过@Conditional判断是否符合装配条件。具体实现就是OnXXXCondition.class。

自定义@ConditionalOnXXX的步骤:

在@ConditionalOnXXX上添加注解@Conditional(OnXXXCondition.class),开发OnXXXCondition继承SpringBootCondition重写getOutcomes方法即可。

自定义@ConditionalOnXXX,实战

写个@ConditionalOnActivatedMonitor,当环境存在my.endpoint.monitor.XXX.enable=true时候激活XXX监控,用法@ConditionalOnActivatedMonitor(name = "jvm")

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Documented
@Conditional(OnActivatedMonitorCondition.class)
public @interface ConditionalOnActivatedMonitor {

    /**
     * The name of the monitor.
     *
     * @return the name of the health indicator
     */
    String name();

    /**
     * 默认是启用状态
     */
    boolean enabled() default true;
}

public class OnActivatedMonitorCondition extends OnEndpointElementCondition {

    public static final String PREFIX = "my.endpoint.monitor.";
	private final String prefix;
    private final Class<? extends Annotation> annotationType;
    
    public OnActivatedMonitorCondition() {
        this(PREFIX, ConditionalOnActivatedMonitor.class);
    }
    public OnActivatedMonitorCondition(String prefix, Class<? extends Annotation> annotationType) {
        this.prefix = prefix;
        this.annotationType = annotationType;
    }
    //自动装配,实现getMatchOutcome即可
    @Override
    public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {

        AnnotationAttributes annotationAttributes = AnnotationAttributes
                .fromMap(metadata.getAnnotationAttributes(annotationType.getName()));//获取@ConditionalOnActivatedMonitor的属性

        String healthIndicator = annotationAttributes.getString("name");
        boolean enabled = annotationAttributes.getBoolean("enabled");
        Environment environment = context.getEnvironment();

        String enabledProperty = prefix + healthIndicator + ".enabled";

        boolean match = environment.getProperty(enabledProperty, Boolean.class, enabled);//环境存在该变量为true则激活

        return new ConditionOutcome(match,
                ConditionMessage.forCondition(annotationType)
                        .because(enabledProperty + " is " + match));
    }
}

自动装配类的顺序

配置类的装配顺序由@AutoConfigureOrder、@AutoConfigureBefore、@AutoConfigureAfter决定

@AutoConfigureOrder指定装配类的装配顺序

@AutoConfigureBefore在某个装配类之前进行装配

@AutoConfigureAfter在某个装配类之后进行装配

具体执行地方是

springboot源码笔记

执行堆栈是

springboot源码笔记

开发者如果要定义装配顺序,只需要写上以上三种中的顺序即可。

自定义starter

starter是个包集合,引入了这个,就引入了相关的依赖,比如引入spring-boot-starter-aop,那么就引入了spring-aop、aspectjweaver,就完成了自动装配。为什么就可以引入相关依赖呢?因为spring-boot-starter-aop-2.1.5.RELEASE.jar内就引入了spring-aop、aspectjweaver,在maven拉包的时候就会拉取pom文件spring-boot-starter-aop-2.1.5.RELEASE.pom,该XX.pom就是starter内的pom.xml。 实际查看spring-boot-starter-aop-2.1.5.RELEASE.jar时候里面是没有pom.xml的。

自定义starter步骤就是:

1.创建一个maven模块项目XXX-spring-boot,在该项目下创建spring.factories,增加org.springframework.boot.autoconfigure.EnableAutoConfiguration=XXXAutoConfiguration,然后开发好自动配置XXXAutoConfiguration

2.创建starter项目XXX-spring-boot-starter,里面只有一个pom.xml即可,该pom.xml要引入第1步的XXX-spring-boot

3.把XXX-spring-boot和XXX-spring-boot-starter上传到仓库,这样别的项目组就可以直接引用。

可以直接参考rocket springboot starter https://github.com/apache/rocketmq-spring

PS:

pring 官方的推荐写artifactId的方法是这样

官方命名格式为: spring-boot-starter-{name}
非官方建议命名格式:{name}-spring-boot-starter,通常自定义starter是这个名称规则

相关文章:

  • 2021-12-14
  • 2022-01-24
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2022-12-23
  • 2021-12-23
  • 2021-11-01
  • 2021-04-07
  • 2022-01-16
  • 2022-01-03
  • 2021-06-07
相关资源
相似解决方案