Spring Boot 1.5.13 启动流程 简单分析

 

前言:关于Spring Boot的介绍已有很多,笔者平时使用的也很多,但是一直都是停留在使用层面,平时也时常好奇Spring Boot的原理,如何做到自动配置的,今天刚好有空,就自建了个项目调试了下,大概窥探了下Spring Boot的内部原理,分享出来,有不对的地方麻烦一定指正一波。

一、入口

Java项目自然从main函数开始看起

/**
 * @author fandong
 */
@SpringBootApplication
public class DemoApplication {

	public static void main(String[] args){
		SpringApplication.run(DemoApplication.class, args);
	}
	
}

内容很少,主要分为两个部分:

  1. @SpringBootApplication 注解
  2. SpringApplication.run(DemoApplication.class, args);   这个静态的run()

下面我们先简要看下 @SpringBootApplication注解,为后面分析run()方法做铺垫

二、@SpringBootApplication

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {}

前四个注解都是 平时自定义注解时常用的注解:

  • @Target 标识此注解的作用类型 
  • @Retention 标识注解的生命周期
  • @Documented  Java doc 相关注解
  • @Inherited  标识子类可继承

后三个注解是我们比较关心的也是和SpringBoot功能实现密切相关的注解

@ComponentScan:对应xml配置时的自动扫描功能,可以通过 basePackages指定扫描的目录,不指定的情况下,扫描注解作用类所在的包(即 启动类的所在的包,启动类放在根路径 则默认扫描根路径)

@SpringBootConfiguration:代码如下

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}

继承了 @Configuration的功能,将当前类作为一个 配置Bean

@EnableAutoConfiguration:自动装配核心注解

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({EnableAutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {};

    String[] excludeName() default {};
}
  1. 在理解之前首先需要先了解下  @Import注解:具体参照这篇  https://blog.csdn.net/everyok/article/details/81350905,作用就是根据提供的value值构造Bean提交给容器
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Import {
     
        /** 仔细看这边内容
         * {@link Configuration}, {@link ImportSelector}, {@link ImportBeanDefinitionRegistrar}
         * or regular component classes to import.
         */
        Class<?>[] value();
     
    }

    参照注释,@Import的value有四种选择

  2. @AutoConfigurationPackage
    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    
    //关注这一行
    @Import({Registrar.class})  
    public @interface AutoConfigurationPackage {
    }

    Registrar类是实现了 ImportBeanDefinitionRegistrar接口(参照上述@Import注解的说明)

    static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
            Registrar() {
            }
            
            public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
                
                //注册了注解类即主类的包名 调试可以验证这点
                AutoConfigurationPackages.register(registry, (new AutoConfigurationPackages.PackageImport(metadata)).getPackageName());
            }
    
            public Set<Object> determineImports(AnnotationMetadata metadata) {
                return Collections.singleton(new AutoConfigurationPackages.PackageImport(metadata));
            }
        }

     

  3. EnableAutoConfigurationImportSelector 类,这是 @Import注解value的另外一种类型

    //注意下继承关系 继承自 AutoConfigurationImportSelector 
    public class EnableAutoConfigurationImportSelector extends AutoConfigurationImportSelector {
        public EnableAutoConfigurationImportSelector() {
        }
    
        protected boolean isEnabled(AnnotationMetadata metadata) {
            return this.getClass().equals(EnableAutoConfigurationImportSelector.class) ? (Boolean)this.getEnvironment().getProperty("spring.boot.enableautoconfiguration", Boolean.class, true) : true;
        }
    }

    AutoConfigurationImportSelector 类中,主要关注  selectImports(AnnotationMetadata annotationMetadata)方法,代码如下

    public String[] selectImports(AnnotationMetadata annotationMetadata) {
            if (!this.isEnabled(annotationMetadata)) {
                return NO_IMPORTS;
            } else {
                try {
                    AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
                    AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
                    
                    //重点关注这一行的 getCandidateConfigurations方法
                    List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
                    configurations = this.removeDuplicates(configurations);
                    configurations = this.sort(configurations, autoConfigurationMetadata);
                    Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
                    this.checkExcludedClasses(configurations, exclusions);
                    configurations.removeAll(exclusions);
    
    
                    //依据  @ConditionalOnClass 和 forName 来筛选
                    configurations = this.filter(configurations, autoConfigurationMetadata);
                    this.fireAutoConfigurationImportEvents(configurations, exclusions);
                    return (String[])configurations.toArray(new String[configurations.size()]);
                } catch (IOException var6) {
                    throw new IllegalStateException(var6);
                }
            }
        }

    getCandidateConfigurations方法代码如下:

    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
            //关注loadFactoryNames方法
            List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
            Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
            return configurations;
        }

    loadFactoryNames代码如下:

    public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
            String factoryClassName = factoryClass.getName();
    
            try {
    
                //去 META-INF/spring.factories文件中读取给中需要自动配置的类名咯
                Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
                ArrayList result = new ArrayList();
    
                while(urls.hasMoreElements()) {
                    URL url = (URL)urls.nextElement();
                    Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
                    String factoryClassNames = properties.getProperty(factoryClassName);
                    result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
                }
    
                return result;
            } catch (IOException var8) {
                throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + "] factories from location [" + "META-INF/spring.factories" + "]", var8);
            }
        }

    META-INF/spring.factories 文件内容部分展示如下:

    # Auto Configure
    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
    org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
    org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
    org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
    org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
    org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
    org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
    org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration

    下面举个Gson()自动装配的简单例子来说明。 Spring Boot会在  容器启动之初 将 启动类封装为 BeanDefinition交给容器,容器在启动阶段会处理BeanDefinition中包含的 @Import注解,将相关的类封装为 BeanDefinition交给容器,这样在 实例化阶段就可以自动装配相关实例。

首先我们引入 Gson的maven依赖
META-INF/spring.factories 文件中 GsonAutoConfiguration 的代码如下:


@Configuration

//注意这一行 当前环境中有Gson类文件 则执行, 如何判断呢, forName
@ConditionalOnClass({Gson.class})
public class GsonAutoConfiguration {
    public GsonAutoConfiguration() {
    }

    @Bean

    //注意这一行 当前环境中没有 Gson类实例 则执行
    @ConditionalOnMissingBean
    public Gson gson() {
        return new Gson();
    }
}

 

三、SpringApplication.run(DemoApplication.class, args) 

说明:这是整个项目的起点,首先执行run方法,run方法中会执行上述讲的 @EnableAutoConfiguration的功能

run方法代码如下:

public static ConfigurableApplicationContext run(Object source, String... args) {
        return run(new Object[]{source}, args);
    }

public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
        
        //构建了 SpringApplication的实例,并调用实例的run方法
        //SpringApplication.run(DemoApplication.class, args)
        //这里的 sources 就是传进来的 DemoApplication.class 这个启动类对象
        return (new SpringApplication(sources)).run(args);
    }

先分析下 new SpringApplication(sources) 这个方法如何处理 sources

public SpringApplication(Object... sources) {
        this.bannerMode = Mode.CONSOLE;
        this.logStartupInfo = true;
        this.addCommandLineProperties = true;
        this.headless = true;
        this.registerShutdownHook = true;
        this.additionalProfiles = new HashSet();

        //关注这个
        this.initialize(sources);
    }

private void initialize(Object[] sources) {
        if (sources != null && sources.length > 0) {
            //将 sources添加到实例属性中,供后面使用
            this.sources.addAll(Arrays.asList(sources));
        }

        this.webEnvironment = this.deduceWebEnvironment();
        this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
        this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
        this.mainApplicationClass = this.deduceMainApplicationClass();
    }

实例run方法如下:

public ConfigurableApplicationContext run(String... args) {
        
        //计时器 执行的时间 
        //日志 Started DemoApplication in 11.358 seconds 中时间的由来
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        FailureAnalyzers analyzers = null;
        this.configureHeadlessProperty();

        //获取各种监听器 通过监听器可以将容器(ApplicationContext)的状态 starting、prepareEnvironment、prepareContext、finished等
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
        listeners.starting();

        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);

            //准备环境 获取各种自定义的、Jvm中的、系统中的配置
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);

            //在控制台打印 Logo,想要对Logo做手脚的研究下这个方法
            Banner printedBanner = this.printBanner(environment);

            //创建 容器 ApplicationContext实例
            context = this.createApplicationContext();

            //对 context 进行检查
            new FailureAnalyzers(context);

            //关注下这个方法 将 启动类注册到 ApplicationContext.BeanFactory.beanDefinitionMap中 下面会详细分析
            this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);

            //关注这个方法,包含了容器的主要启动流程,下面会详细分析
            this.refreshContext(context);

            this.afterRefresh(context, applicationArguments);
            listeners.finished(context, (Throwable)null);
            stopWatch.stop();
            if (this.logStartupInfo) {
            // Started DemoApplication in 11.358 seconds  这个日志在这里打印的
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
            }

            //返回 ApplicationContext实例,项目中需要这个实例的话可以保存下SpringApplication.run(DemoApplication.class, args)的返回值
            return context;
        } catch (Throwable var9) {
            this.handleRunFailure(context, listeners, (FailureAnalyzers)analyzers, var9);
            throw new IllegalStateException(var9);
        }
    }

1)、先调试下 this.prepareContext(context, environment, listeners, applicationArguments, printedBanner); 这个方法

private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
        context.setEnvironment(environment);
        this.postProcessApplicationContext(context);
        this.applyInitializers(context);
        listeners.contextPrepared(context);
        if (this.logStartupInfo) {
            this.logStartupInfo(context.getParent() == null);
            this.logStartupProfileInfo(context);
        }
        
        // 注册 项目的启动入参
        context.getBeanFactory().registerSingleton("springApplicationArguments", applicationArguments);
        if (printedBanner != null) {
            context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
        }
        
        // 这个sources 其实就是 启动类实例 
        Set<Object> sources = this.getSources();
        Assert.notEmpty(sources, "Sources must not be empty");

        //关注这个方法 检查启动类是否有 @Component注解,并构造对应的 BeanDefinition对象给 容器
        this.load(context, sources.toArray(new Object[sources.size()]));
        listeners.contextLoaded(context);
    }

this.load(context, sources.toArray(new Object[sources.size()]));  方法代码如下

protected void load(ApplicationContext context, Object[] sources) {
        if (logger.isDebugEnabled()) {
            logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
        }
        
        //通过 BeanDefinitionLoader 实例来完成 检查、构造 BeanDefinition实例的工作
        BeanDefinitionLoader loader = this.createBeanDefinitionLoader(this.getBeanDefinitionRegistry(context), sources);
        if (this.beanNameGenerator != null) {
            loader.setBeanNameGenerator(this.beanNameGenerator);
        }

        if (this.resourceLoader != null) {
            loader.setResourceLoader(this.resourceLoader);
        }

        if (this.environment != null) {
            loader.setEnvironment(this.environment);
        }
        
        //关注这个方法 包含了具体的逻辑
        loader.load();
    }

loader.load(); 方法代码如下

public int load() {
        int count = 0;
        Object[] var2 = this.sources;
        int var3 = var2.length;

        for(int var4 = 0; var4 < var3; ++var4) {
            Object source = var2[var4];
            
            //关注这一行 包含具体逻辑
            count += this.load(source);
        }

        return count;
    }

 count += this.load(source);  方法代码如下

private int load(Object source) {
        Assert.notNull(source, "Source must not be null");
        if (source instanceof Class) {
            
            // 匹配这个 if 
            return this.load((Class)source);
        } else if (source instanceof Resource) {
            return this.load((Resource)source);
        } else if (source instanceof Package) {
            return this.load((Package)source);
        } else if (source instanceof CharSequence) {
            return this.load((CharSequence)source);
        } else {
            throw new IllegalArgumentException("Invalid source type " + source.getClass());
        }
    }

return this.load((Class)source);  方法代码如下

private int load(Class<?> source) {
        if (this.isGroovyPresent() && BeanDefinitionLoader.GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
            BeanDefinitionLoader.GroovyBeanDefinitionSource loader = (BeanDefinitionLoader.GroovyBeanDefinitionSource)BeanUtils.instantiateClass(source, BeanDefinitionLoader.GroovyBeanDefinitionSource.class);
            this.load(loader);
        }

        
        // 关注这个  isComponent 方法 递归分析注解 
        //其中一条检索路径为 @SpringBootApplication -> @SpringBootConfiguration -> @Configuration -> @Component
        if (this.isComponent(source)) {
            
            // 注册方法 
            this.annotatedReader.register(new Class[]{source});
            return 1;
        } else {
            return 0;
        }
    }

从 this.annotatedReader.register(new Class[]{source});   一路跟踪到如下方法

public void registerBean(Class<?> annotatedClass, String name, Class<? extends Annotation>... qualifiers) {


        //将我们的启动类 包装为  BeanDefinition对象 下面会 完善相关的信息 Primary、LazyInit等
        AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
        if (!this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
            ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
            abd.setScope(scopeMetadata.getScopeName());
            String beanName = name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry);
            AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
            if (qualifiers != null) {
                Class[] var7 = qualifiers;
                int var8 = qualifiers.length;

                for(int var9 = 0; var9 < var8; ++var9) {
                    Class<? extends Annotation> qualifier = var7[var9];
                    if (Primary.class == qualifier) {
                        abd.setPrimary(true);
                    } else if (Lazy.class == qualifier) {
                        abd.setLazyInit(true);
                    } else {
                        abd.addQualifier(new AutowireCandidateQualifier(qualifier));
                    }
                }
            }

            BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
            definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);


            // 最终注册
            BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
        }
    }

总结下 prepareContext 方法的工作: 检查启动类是否带了 @Component 注解, 将启动类包装为  BeanDefinition实例 并注册到容器中,位置在  context ->  beanFactory -> beanDefinitionMap 中,调试可见, 这边是 Spring Boot的预先工作范围

2)、再来看下最为核心的  this.refreshContext(context);   方法,里面包含了容器启动的核心逻辑

一路跟踪找到最终的 refresh 方法,代码如下

public void refresh() throws BeansException, IllegalStateException {
        synchronized(this.startupShutdownMonitor) {
            this.prepareRefresh();
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            this.prepareBeanFactory(beanFactory);

            try {
                this.postProcessBeanFactory(beanFactory);

                //关注这个方法 包含了 @EnableAutoConfiguration 将需要的类包装为BeanDefinition提交给容器,以及扫描所有我们自己的 有@Component的类也会包装为BeanDefinition
                //其中会处理 @Import注解
                this.invokeBeanFactoryPostProcessors(beanFactory);

                //扫描所有的 BeanDefinition 如果有 BeanPostProcessor类型的 则将其注册到容器,具体调用在 Bean实例化阶段,用以改变Bean的行为
                this.registerBeanPostProcessors(beanFactory);

                this.initMessageSource();
                this.initApplicationEventMulticaster();
                this.onRefresh();
                this.registerListeners();

                // Bean实例化 以及 BeanFactory的处理
                this.finishBeanFactoryInitialization(beanFactory);
                this.finishRefresh();
            } catch (BeansException var9) {
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
                }

                this.destroyBeans();
                this.cancelRefresh(var9);
                throw var9;
            } finally {
                this.resetCommonCaches();
            }

        }
    }

this.invokeBeanFactoryPostProcessors(beanFactory);  方法代码如下:

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        

        //关注这个方法
        PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, this.getBeanFactoryPostProcessors());
        if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean("loadTimeWeaver")) {
            beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
            beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
        }

    }

PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, this.getBeanFactoryPostProcessors());这段代码很长,截取其中的关键方法如下

private static void invokeBeanDefinitionRegistryPostProcessors(Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {
        Iterator var2 = postProcessors.iterator();

        while(var2.hasNext()) {
            BeanDefinitionRegistryPostProcessor postProcessor = (BeanDefinitionRegistryPostProcessor)var2.next();


            //关注这个方法
            postProcessor.postProcessBeanDefinitionRegistry(registry);
        }

    }

 postProcessor.postProcessBeanDefinitionRegistry(registry);  代码如下

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);
        } else if (this.factoriesPostProcessed.contains(registryId)) {
            throw new IllegalStateException("postProcessBeanFactory already called on this post-processor against " + registry);
        } else {
            this.registriesPostProcessed.add(registryId);


            //关注这个方法
            this.processConfigBeanDefinitions(registry);
        }
    }

this.processConfigBeanDefinitions(registry);  部分方法如下

ConfigurationClassParser parser = new ConfigurationClassParser(this.metadataReaderFactory, this.problemReporter, this.environment, this.resourceLoader, this.componentScanBeanNameGenerator, registry);
            Set<BeanDefinitionHolder> candidates = new LinkedHashSet(configCandidates);
            HashSet alreadyParsed = new HashSet(configCandidates.size());

            do {
                // 处理 @Import注解
                parser.parse(candidates);

parser.parse(candidates);方法中最重要的是如下方法

private void processDeferredImportSelectors() {
        List<ConfigurationClassParser.DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
        this.deferredImportSelectors = null;
        Collections.sort(deferredImports, DEFERRED_IMPORT_COMPARATOR);
        Iterator var2 = deferredImports.iterator();

        while(var2.hasNext()) {
            ConfigurationClassParser.DeferredImportSelectorHolder deferredImport = (ConfigurationClassParser.DeferredImportSelectorHolder)var2.next();
            ConfigurationClass configClass = deferredImport.getConfigurationClass();

            try {

                
                //关注此方法 收集需要用到的 import信息
                String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata());
                this.processImports(configClass, this.asSourceClass(configClass), this.asSourceClasses(imports), false);
            } catch (BeanDefinitionStoreException var6) {
                throw var6;
            } catch (Throwable var7) {
                throw new BeanDefinitionStoreException("Failed to process import candidates for configuration class [" + configClass.getMetadata().getClassName() + "]", var7);
            }
        }

    }

String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata()); 收集import方法如下

AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);

//获取到前面说的 META-INF/spring.factories 下的所有配置类名称
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
configurations = this.removeDuplicates(configurations);
configurations = this.sort(configurations, autoConfigurationMetadata);
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);


//过滤 将不满足 @Conditional 注解要求的去除,采用了 二分法,主要是 反射 forName 构造 @ConditionalOnClass 要求的类, 成功即满足要求,失败则需要去除
configurations = this.filter(configurations, autoConfigurationMetadata);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return (String[])configurations.toArray(new String[configurations.size()]);

接下来就是 将符合要求的 通过 @AutoConfiguration @Import注解导入的各种 Configuration Bean 包装为 BeanDefinition,等待实例化的时候 调用 @Bean注解的方法生成Bean给 容器

总结下 refreshContext 的工作:其实就是对应了 Spring 容器的启动流程,扫描所有的 @Component注解标记的类,封装为BeanDefinition 到容器中,BeanDefinition中有 @Import等注解的,还要进一步处理, 这是 Spring容器的正常流程。但是为了做到自动装配,Spring Boot 在这之前,通过 prepareContext方法将标注了 @SpringBootApplication的启动类封装为 BeanDefinition添加到了容器中,这样在容器启动时 也就是 refreshContext方法中,会扫描所有的 @Import注解,将注解提供的类信息包装为BeanDefinition,而 @SpringBootApplication 注解上的 @Import注解提供的类恰恰是  META-INF/spring.factories 中的 校验过 @ConditionalOnClass 注解逻辑的 类,将满足当前环境要求的类封装为 BeanDefinition,这些类一般都是 工厂类,之后在 实例化阶段就可以自动实现相关类的实例化,也就是实现了 自动装配。

下面附上Spring容器启动流程

 

最后总结下 Spring Boot 主要启动流程:

prepareContext 

首先将启动类封装为 BeanDefinition给容器  

 

refreshContext

容器启动阶段(通过内置的 BeanFactoryPostProcessor 来完成以下 1、2的工作):

1、扫描所有的 @Component作用的类(直接或者间接作用)封装 BeanDefinition到容器中

2、处理 @Import等注解,将相关类同样 封装 BeanDefinition到容器中  (自动装配)

3、其它 自定义扩展的 BeanFactoryPostProcessor 实例 对  BeanDefinition 做出修改

Bean实例化阶段:

1、实例化Bean,有 @Autowired注解的 再去实例化对应的Bean并 注入

2、BeanFactory的处理,调用工厂方法生成Bean

3、BeanPostProcessor 对Bean实例做出修改,例如 生成代理类等

核心流程代码片段如下:



//关注下这个方法 将 启动类注册到 ApplicationContext.BeanFactory.beanDefinitionMap中 下面会详细分析
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);

//关注这个方法,包含了容器的主要启动流程,下面会详细分析
this.refreshContext(context);

//调用内置的和 自定义的  BeanFactoryPostProcessor 完成的功能包括:扫描并包装 BeanDefinition, 特殊注解如 @Import的处理
this.invokeBeanFactoryPostProcessors(beanFactory);

//扫描所有的 BeanDefinition 如果有 BeanPostProcessor类型的 则将其注册到容器,具体调用在 Bean实例化阶段,用以改变Bean的行为
this.registerBeanPostProcessors(beanFactory);

// Bean实例化 以及 BeanFactory的处理
this.finishBeanFactoryInitialization(beanFactory);

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值