SpringBoot启动类-源码分析

SpringBoot启动类源码分析

1.启动类代码:

package com.example.rfos;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication  // 1. 启动类的组合注解,实现Spring中的Bean的自动装配
public class RfosApplication {
    //主函数
    public static void main(String[] args)s {
        // 2. 调用SpringApplication.run启s动应用,RfosApplication.class 启动类 ,args接收命令行传参
        SpringApplication.run(RfosApplication.class, args);
    }

}

2.@SpringBootApplication注解源码分析

@SpringBootApplication注解主要由4类注解组成,分别为:JDK原生注解(4个)、@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan。

//1.位于主动装配的包中
package org.springframework.boot.autoconfigure;


@Target({ElementType.TYPE}) //当前注解的使用范围
@Retention(RetentionPolicy.RUNTIME) //注解的生命周期,运行时生效】
@Documented //	声明在生成 doc 文档时是否带着注解
@Inherited //声明是否子类会显示父类的注解,声明的此注解使用了Inherited元注解,表示此注解用在类上时,会被子类所继承
@SpringBootConfiguration //  该类是个配置类功能等同于xml配置文件,实现配置文件的功能
@EnableAutoConfiguration //  本质是@Import,自动导入功能。借助该注解的帮助,将所有符合自动配置条件的 bean 定义加载到 IOC 容器中。@EnableAutoConfiguration会根据类路径中的 jar 依赖为项目进行自动配置	

/*@ComponentScan 自动扫描并加载符合条件的组件(如@Component )或者 bean 定义, 最终将这些 bean 定义加载到 IOC 容器中. 也可以通过 basePackages 等属性来细粒度的定制 @ComponentScan 自动扫描的范围, 如果不指定, 则默认扫描 @ComponentScan 所在类的 package 及子包进行扫描。*/
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
    @AliasFor(
        annotation = EnableAutoConfiguration.class
    )
    Class<?>[] exclude() default {};

    @AliasFor(
        annotation = EnableAutoConfiguration.class
    )
    String[] excludeName() default {};

    @AliasFor(
        annotation = ComponentScan.class,
        attribute = "basePackages"
    )
    String[] scanBasePackages() default {};

    @AliasFor(
        annotation = ComponentScan.class,
        attribute = "basePackageClasses"
    )
    Class<?>[] scanBasePackageClasses() default {};

    @AliasFor(
        annotation = ComponentScan.class,
        attribute = "nameGenerator"
    )
    Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;

    @AliasFor(
        annotation = Configuration.class
    )
    boolean proxyBeanMethods() default true;
}

3.@SpringBootApplication的自动装配原理

这个META-INF/spring.factories是自动装配的核心文件

在这里插入图片描述

3.1 简述:

使用Spring Boot时,我们只需引入对应的Starters,Spring Boot启动时便会自动加载相关依赖,配置相应的初始化参数,在sprinBoot启动时由@SpringBootApplication注解会自动去maven中读取每个starter中的spring.factories文件,该文件里配置了所有需要被创建spring容器中的bean,并且进行自动配置把bean注入SpringContext**中,这便是Spring Boot的自动配置功能
在这里插入图片描述

3.2详细流程(三个重点注解):

@SpringBootConfiguration 首先表明该启动类是一个配置类;
@ComponentScan 扫描启动类所在的包以及子包下所有标记为Bean的组件并注册到IOC容器中
@EnableAutoConfiguration 实现自动装配的核心注解

3.3 @EnableAutoConfiguration源码分析

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class}) 
public @interface EnableAutoConfiguration {
    //用来覆盖开启/关闭自动配置的功能
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
    //exclude()和excludeName()可以排除指定的配置
    Class<?>[] exclude() default {};

    String[] excludeName() default {};
}
a.1 @Import({AutoConfigurationImportSelector.class}) 导入自动配置的选择器,用于导入自动配置的Bean

selectImports()方法为主要实现逻辑

a. 获取META-INF/spring.factoriesEnableAutoConfiguration所对应的Configuration类列表
b. 由@EnableAutoConfiguration注解中的exclude/excludeName参数筛选一遍
c. 再由私有内部类ConfigurationClassFilter筛选一遍,即不满足@Conditional的配置类

主要方法;

  1. isEnabled() 判断是否开启了自动配置

  2. selectImports()方法 基本包含了组件自动装配的所有处理逻辑

  3. getAutoConfigurationEntry() 该方法的作用就是要返回需要注册到IoC容器中的对象对应的类型的全类路径名称的字符串数组

  4. getAttributes () 获取自动配置类属性键值对

  5. getCandidateConfigurations()获取候选类名集合 ,获取需要自动配置类

  6. removeDuplicates () 去重

  7. getExclusions() 排除需要排除的配置类–exclude&excludeName&getExcludeAutoConfigurationsProperty

  8. getConfigurationClassFilter() 通过过滤器盘判断是否引相关组件,如果有则进行相关配置

  9. fireAutoConfigurationImportEvents() 根据spring.factories文件中的AutoConfigurationImportListener事件监听器发布并处理监听事件

  10. AutoConfigurationEntry() 返回最终需要托管的类

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
    //----省略部分代码----
    /*
    1. isEnabled() 判断是否开启了自动配置
    */
        protected boolean isEnabled(AnnotationMetadata metadata) {
        return this.getClass() == AutoConfigurationImportSelector.class ? (Boolean)this.getEnvironment().getProperty("spring.boot.enableautoconfiguration", Boolean.class, true) : true;
    }
    /*
    2. selectImports()方法 基本包含了组件自动装配的所有处理逻辑
    AnnotationMetadata 是用来访问指定类上的注解
    */
        public String[] selectImports(AnnotationMetadata annotationMetadata) {
            // 如果未开启自动装配,就返回空数组
        if (!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        } else {
            // 返回需要注册到IoC容器中的对象对应的类型的全类路径名称的字符串数组
            AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
            return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
        }
    }
    /*
    3. getAutoConfigurationEntry() 该方法的作用就是要返回需要注册到IoC容器中的对象对应的类型的全类路径名称的字符串数组
    */
    protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
        //未开启就返回空数组
        if (!this.isEnabled(annotationMetadata)) {
            return EMPTY_ENTRY;
        } else {
            //获取标注类的元信息
            AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
            //加载需要自动装配的候选类名集合
            List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
            //去重
            configurations = this.removeDuplicates(configurations);
            //排除需要排除的配置类
            Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
            this.checkExcludedClasses(configurations, exclusions);
            configurations.removeAll(exclusions);
            // 通过过滤器盘判断是否引相关组件,如果有则进行相关配置
            configurations = this.getConfigurationClassFilter().filter(configurations);
            //派发事件-根据spring.factories文件中的AutoConfigurationImportListener事件监听器发布并处理监听事件
            this.fireAutoConfigurationImportEvents(configurations, exclusions);
            // 返回最终需要托管的类
            return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
        }
    }
    /* 
    4. getAttributes () 获取属性键值对
    
    */
        protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) {
        String name = this.getAnnotationClass().getName();
        AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(name, true));
        Assert.notNull(attributes, () -> {
            return "No auto-configuration attributes found. Is " + metadata.getClassName() + " annotated with " + ClassUtils.getShortName(name) + "?";
        });
        return attributes;
    }
    /*
     5.getCandidateConfigurations()获取候选类名集合 
     而变量configurations 获取的就是自动加载的META-INF/spring.factories中的名为“org.springframework.boot.autoconfigure.EnableAutoConfiguration”的属性值,这里面就是目前spring boot的所有自动配置类。

    */
        protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        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;
    }
    /*
    6.removeDuplicates () 去重 
    */
        protected final <T> List<T> removeDuplicates(List<T> list) {
        return new ArrayList(new LinkedHashSet(list));
    }
    /*
    7. getExclusions() 排除需要排除的配置类--exclude&excludeName&getExcludeAutoConfigurationsProperty
    */
        protected Set<String> getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        Set<String> excluded = new LinkedHashSet();
        excluded.addAll(this.asList(attributes, "exclude"));
        excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName")));
        excluded.addAll(this.getExcludeAutoConfigurationsProperty());
        return excluded;
    }
    
    /*
    8. getConfigurationClassFilter() 通过过滤器盘判断是否引相关组件,如果有则进行相关配置
    */
    
        private AutoConfigurationImportSelector.ConfigurationClassFilter getConfigurationClassFilter() {
        if (this.configurationClassFilter == null) {
            List<AutoConfigurationImportFilter> filters = this.getAutoConfigurationImportFilters();
            Iterator var2 = filters.iterator();

            while(var2.hasNext()) {
                AutoConfigurationImportFilter filter = (AutoConfigurationImportFilter)var2.next();
                this.invokeAwareMethods(filter);
            }

            this.configurationClassFilter = new AutoConfigurationImportSelector.ConfigurationClassFilter(this.beanClassLoader, filters);
        }

        return this.configurationClassFilter;
    }
    /*
    9.fireAutoConfigurationImportEvents() 根据spring.factories文件中的AutoConfigurationImportListener事件监听器发布并处理监听事件
        */
        private void fireAutoConfigurationImportEvents(List<String> configurations, Set<String> exclusions) {
        List<AutoConfigurationImportListener> listeners = this.getAutoConfigurationImportListeners();
        if (!listeners.isEmpty()) {
            AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, configurations, exclusions);
            Iterator var5 = listeners.iterator();

            while(var5.hasNext()) {
                AutoConfigurationImportListener listener = (AutoConfigurationImportListener)var5.next();
                this.invokeAwareMethods(listener);
                listener.onAutoConfigurationImportEvent(event);
            }
        }

    }
    /**
    10. AutoConfigurationEntry() 返回最终需要托管的类
    */
            AutoConfigurationEntry(Collection<String> configurations, Collection<String> exclusions) {
            this.configurations = new ArrayList(configurations);
            this.exclusions = new HashSet(exclusions);
        }
    
    //----省略部分源码----
}
a.2 @AutoConfigurationPackage-负责保存标注相关注解的类的所在包路径

表示对于标注该注解的类的包,应当使用AutoConfigurationPackages注册,@AutoConfigurationPackage其实它是一个@Import。@import是什么?@import就是给容器中导入一个组件,这个组件叫什么呢?叫AutoConfigurationPackages.Registrar的组件

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({Registrar.class})
public @interface AutoConfigurationPackage {
    String[] basePackages() default {};

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

Registrar.class

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
    Registrar() {
    }
    
    /**
    egisterBeanDefinitions()方法将对应注解所在的包自动配置到容器中,方法具体如下:

register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
由于AutoConfigurationPackage注解标注在主类上,得到了主类的包名然后把这个包名最终封装(toArray(new String[0]))到我们的一个数组里面,然后给我们注册(register())进去,相当于我们这个Registrar就是把某一个包下的所有组件批量注册进容器
    */

    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
        AutoConfigurationPackages.register(registry, (String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0]));
    }
    //是获取需要导入到容器中的包名

    public Set<Object> determineImports(AnnotationMetadata metadata) {
        return Collections.singleton(new AutoConfigurationPackages.PackageImports(metadata));
    }
}

3.4 @ComponentScan源码分析

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.context.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.core.annotation.AliasFor;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
//注解是用于声明其它类型注解的元注解,来表示这个声明的注解是可重复的	
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
    //要扫描的包及其子包, 若要类型安全(避免写错包), 可以使用 basePackageClasses
    @AliasFor("basePackages")
    String[] value() default {};
    //要扫描的包及其子包
    @AliasFor("value")
    String[] basePackages() default {};
    //basePackages 的替代. 可考虑在每个 basePackage 中创建一个特殊的标记类或接口, 用于给这个属性引用
    Class<?>[] basePackageClasses() default {};
    //自定义bean名称生成器	
    Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
    //主要负责对Scope作用域注解的解析
    Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;

    ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;
    //需要扫描包中的那些资源,默认是:**/*.class,即会扫描指定包中所有的class文件
    String resourcePattern() default "**/*.class";
    //对扫描的类是否启用默认过滤器,默认为true
    boolean useDefaultFilters() default true;
    //过滤器:用来配置被扫描出来的那些类会被作为组件注册到容器中
    ComponentScan.Filter[] includeFilters() default {};
    //过滤器,和includeFilters作用刚好相反,用来对扫描的类进行排除的,被排除的类不会被注册到容器中
    ComponentScan.Filter[] excludeFilters() default {};
    //是否延迟加载-所谓延迟加载就是当在真正需要数据的时候,才真正执行数据加载操作。		
    boolean lazyInit() default f过来前期alse;
    // 这个注解可以同时使用多个。
    @Retention(RetentionPolicy.RUNTIME)
    @Target({})
    public @interface Filter {
        FilterType type() default FilterType.ANNOTATION;

        @AliasFor("classes")
        Class<?>[] value() default {};

        @AliasFor("value")
        Class<?>[] classes() default {};

        String[] pattern() default {};
    }
}

4.启动类入口主函数-SpringApplication.run(RfosApplication.class, args)-源码分析

首先,Spring Boot项目创建完成会默认生成一个名为 Application 的入口类,我们是通过该类的main方法启动Spring Boot项目的。在main方法中,通过SpringApplication的静态方法,即run方法进行SpringApplication类的实例化操作*,然后再针对实例化对象调用另外一个run方法来完成整个项目的初始化和启动。

SpringApplication调用的run方法的大致流程,如下图:

在这里插入图片描述

4.1 调用SpringApplication.run启动springboot应用

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

4.2 使用静态方法启动

   public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
        return run(new Class[]{primarySource}, args);
    }

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
//创建springapplication对象,调用函数run(args)
    return (new SpringApplication(primarySources)).run(args);
}

4.3 run方法启动SpringApplication最核心的逻辑

    public ConfigurableApplicationContext run(String... args) {
        //用来记录当前Spring Boot启动耗时
        StopWatch stopWatch = new StopWatch();
        //记录了启动开始时间
        stopWatch.start();
        //它是任何spring上下文的接口, 所以可以接收任何ApplicationContext实现
        ConfigurableApplicationContext context = null;
        //SpringBootExceptionReporter的作用就是对启动过程的异常进行分析、报告
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
        //1. 开启了Headless模式:
        this.configureHeadlessProperty();
        //去spring.factroies中读取了SpringApplicationRunListener 的组件, 就是用来发布事件或者运行监听器
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
        //发布1.ApplicationStartingEvent事件,在运行开始时发送
        listeners.starting();
        //
        Collection exceptionReporters;
        try {
            // 根据命令行参数 实例化一个ApplicationArguments
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
             // 预初始化环境: 读取环境变量,读取配置文件信息(基于监听器)
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
             忽略beaninfo的bean
            this.configureIgnoreBeanInfo(environment);
            // 打印Banner 横幅
            Banner printedBanner = this.printBanner(environment);
            // 根据webApplicationType创建Spring上下文
            context = this.createApplicationContext();
            exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
            //预初始化spring上下文
            this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            // 加载spring ioc 容器 **相当重要 由于是使用AnnotationConfigServletWebServerApplicationContext 启动的sring容器所以springboot对它做了扩展:
// 加载自动配置类:invokeBeanFactoryPostProcessors , 创建servlet容器onRefresh
            this.refreshContext(context);
            this.afterRefresh(context, applicationArguments);
            stopWatch.stop();
            if (this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
            }

            listeners.started(context);
            this.callRunners(context, applicationArguments);
        } catch (Throwable var10) {
            this.handleRunFailure(context, var10, exceptionReporters, listeners);
            throw new IllegalStateException(var10);
        }

        try {
            listeners.running(context);
            return context;
        } catch (Throwable var9) {
            this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
            throw new IllegalStateException(var9);
        }
    }

// 1.将java.awt.headless设置为true,表示运行在服务器器端,在没有显示器器和鼠标键盘的模式下工作,模拟输入输出设备功能。
private void configureHeadlessProperty() {
    //将java.awt.headless设置为true,表示运行在服务器器端,在没有显示器器和鼠标键盘的模式下工作,模拟输入输出设备功能。
    System.setProperty("java.awt.headless", System.getProperty("java.awt.headless", Boolean.toString(this.headless)));
}
//2. 去spring.factroies中读取了SpringApplicationRunListener 的组件, 就是用来发布事件或者运行监听器
private SpringApplicationRunListeners getRunListeners(String[] args) {
    Class<?>[] types = new Class[]{SpringApplication.class, String[].class};
    return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
// 3.获取相关的监听器实例
    private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
        ClassLoader classLoader = this.getClassLoader();
        Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
        List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
        //对监听器实例排序
        AnnotationAwareOrderComparator.sort(instances);
        return instances;
    }
//4. 查找并设置配置文件信息
//SpringApplication:
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {
    //根据应用类型,创建应用环境:如得到系统的参数、JVM及Servlet等参数,等
    ConfigurableEnvironment environment = this.getOrCreateEnvironment();
    //将 defaultProperties、commandLine及active-prifiles 属性加载到环境中
    //commandLine 在 args 中配置
    //其它参数可在如下4个路径中配置:servletConfigInitParams、servletContextInitParams、systemProperties、systemEnvironment
    this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
    //1.1 将 spirng.config 配置文件加载到环境中
    listeners.environmentPrepared((ConfigurableEnvironment)environment);
    this.bindToSpringApplication((ConfigurableEnvironment)environment);
    if (!this.isCustomEnvironment) {
        environment = (new EnvironmentConverter(this.getClassLoader())).convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass());
    }
	//加一个ConfigurationPropertySources
    ConfigurationPropertySources.attach((Environment)environment);
    return (ConfigurableEnvironment)environment;
}
根据应用类型,创建应用环境:如得到系统的参数、JVM及Servlet等参数,等
    private ConfigurableEnvironment getOrCreateEnvironment() {
        if (this.environment != null) {
            return this.environment;
        } else {
            switch(this.webApplicationType) {
            case SERVLET:
                return new StandardServletEnvironment();
            case REACTIVE:
                return new StandardReactiveWebEnvironment();
            default:
                return new StandardEnvironment();
            }
        }
    }
    //将 defaultProperties、commandLine及active-prifiles 属性加载到环境中
    //commandLine 在 args 中配置
    //其它参数可在如下4个路径中配置:servletConfigInitParams、servletContextInitParams、systemProperties、systemEnvironment
    protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
        if (this.addConversionService) {
            ConversionService conversionService = ApplicationConversionService.getSharedInstance();
            environment.setConversionService((ConfigurableConversionService)conversionService);
        }

        this.configurePropertySources(environment, args);
        this.configureProfiles(environment, args);
    }
//
    private boolean addConversionService;
//这里的getSharedInstance方法其实就是为了获取并返回ApplicationConversionService的sharedInstance属性,由于这个属性是静态的,所以它只会被初始化一次(也就是单例的)
    public static ConversionService getSharedInstance() {
        ApplicationConversionService sharedInstance = ApplicationConversionService.sharedInstance;
        if (sharedInstance == null) {
            Class var1 = ApplicationConversionService.class;
            synchronized(ApplicationConversionService.class) {
                sharedInstance = ApplicationConversionService.sharedInstance;
                if (sharedInstance == null) {
                    sharedInstance = new ApplicationConversionService();
                    ApplicationConversionService.sharedInstance = sharedInstance;
                }
            }
        }

// 5.打印Banner图标
    private Banner printBanner(ConfigurableEnvironment environment) {
        if (this.bannerMode == Mode.OFF) {
            return null;
        } else {
            ResourceLoader resourceLoader = this.resourceLoader != null ? this.resourceLoader : new DefaultResourceLoader((ClassLoader)null);
            SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter((ResourceLoader)resourceLoader, this.banner);
            return this.bannerMode == Mode.LOG ? bannerPrinter.print(environment, this.mainApplicationClass, logger) : bannerPrinter.print(environment, this.mainApplicationClass, System.out);
        }
    }
//7.根据webApplicationType创建Spring上下文
    protected ConfigurableApplicationContext createApplicationContext() {
        Class<?> contextClass = this.applicationContextClass;
        if (contextClass == null) {
            try {
                switch(this.webApplicationType) {
                case SERVLET:
                    contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext");
                    break;
                case REACTIVE:
                    contextClass = Class.forName("org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext");
                    break;
                default:
                    contextClass = Class.forName("org.springframework.context.annotation.AnnotationConfigApplicationContext");
                }
            } catch (ClassNotFoundException var3) {
                throw new IllegalStateException("Unable create a default ApplicationContext, please specify an ApplicationContextClass", var3);
            }
        }
        //通过BeanUtils.instantiateClass构造对象,必须要求是具有无参构造函数
        return (ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass);
    }
// 8.作用是读取spring.factories文件key=ApplicationContextInitializer对应的value并实例化
    private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
        ClassLoader classLoader = this.getClassLoader();
        Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
        List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
        AnnotationAwareOrderComparator.sort(instances);
        return instances;
    }
        //通过反射构造实例
            private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args, Set<String> names) {
        List<T> instances = new ArrayList(names.size());
                //遍历实例
        Iterator var7 = names.iterator();

        while(var7.hasNext()) {
            String name = (String)var7.next();

            try {
                //这个工具方法和Class.forName方法作用类似,但是他可以初始化数组和带 ;的Class对象
                Class<?> instanceClass = ClassUtils.forName(name, classLoader);
                //是否子类和父类关系 
                Assert.isAssignable(type, instanceClass);
                //通过类对象创建构造器
               
                Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
                //通过 BeanUtils.instantiateClass实例化对象
                T instance = BeanUtils.instantiateClass(constructor, args);
                //添加实例
                instances.add(instance);
            } catch (Throwable var12) {
                throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, var12);
            }
        }
/* 9. 1. 准备容器prepareContext()
 统一ApplicationContext和Application使用的environment
ApplicationContext的后置处理
执行Initializers
   DelegatingApplicationContextInitializer
*/
    private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
        //配置环境
        context.setEnvironment(environment);
        //后置处理ApplicationContext
        this.postProcessApplicationContext(context);
        //应用上下文初始化。即系统初始化器的调用
        this.applyInitializers(context);
        //监听上下文初始化
        listeners.contextPrepared(context);
        if (this.logStartupInfo) {
            this.logStartupInfo(context.getParent() == null);
            this.logStartupProfileInfo(context);
        }
        //后置处理ApplicationContext
            protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
        if (this.beanNameGenerator != null) {
            context.getBeanFactory().registerSingleton("org.springframework.context.annotation.internalConfigurationBeanNameGenerator", this.beanNameGenerator);
        }

        if (this.resourceLoader != null) {
            if (context instanceof GenericApplicationContext) {
                ((GenericApplicationContext)context).setResourceLoader(this.resourceLoader);
            }

            if (context instanceof DefaultResourceLoader) {
                ((DefaultResourceLoader)context).setClassLoader(this.resourceLoader.getClassLoader());
            }
        }

        if (this.addConversionService) {
            context.getBeanFactory().setConversionService(ApplicationConversionService.getSharedInstance());
        }

    }
// //监听上下文初始化
    protected void applyInitializers(ConfigurableApplicationContext context) {
        Iterator var2 = this.getInitializers().iterator();

        while(var2.hasNext()) {
            ApplicationContextInitializer initializer = (ApplicationContextInitializer)var2.next();
            Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(), ApplicationContextInitializer.class);
            Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
            initializer.initialize(context);
        }

    }
       //10.refresh方法主要是刷新应用程序上下文,这里主要涉及到准备刷新上下文,调用上下文注册为bean的工厂处理器,初始化上下文的消息源,初始化特定上下文子类中的其他特殊bean,检查监听器bean并注册,最后发布相应的事件并销毁已经创建的单例及重置active标志,整体的注解我都直接加在源码中了
            private void refreshContext(ConfigurableApplicationContext context) {
        if (this.registerShutdownHook) {
            try {
                context.registerShutdownHook();
            } catch (AccessControlException var3) {
            }
        }

        this.refresh((ApplicationContext)context);
    }
        //11.当前方法的代码是空的,可以做一些自定义的后置处理操作
            protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {
    }	
        //12.当应用程序启动时,我们可以让Grails记录一些额外的信息。 类似于应用程序的进程ID(PID)以及应用程序在哪台计算机上启动。 以及启动应用程序所需的时间。 GrailsApp类具有属性logStartupInfo ,默认情况下为true 。 如果属性为true,则在Application类的记录器的INFO和DEBUG级别记录一些额外的行
        private boolean logStartupInfo;

oid refreshContext(ConfigurableApplicationContext context) {
        if (this.registerShutdownHook) {
            try {
                context.registerShutdownHook();
            } catch (AccessControlException var3) {
            }
        }

        this.refresh((ApplicationContext)context);
    }
        //11.当前方法的代码是空的,可以做一些自定义的后置处理操作
            protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {
    }	
        //12.当应用程序启动时,我们可以让Grails记录一些额外的信息。 类似于应用程序的进程ID(PID)以及应用程序在哪台计算机上启动。 以及启动应用程序所需的时间。 GrailsApp类具有属性logStartupInfo ,默认情况下为true 。 如果属性为true,则在Application类的记录器的INFO和DEBUG级别记录一些额外的行
        private boolean logStartupInfo;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

rfos

谢谢您的支持!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值