SpringBoot啟動(dòng)流程

springboot源碼解析(一):啟動(dòng)過程

1、springboot的入口程序

@SpringBootApplication
public class StartupApplication {

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

當(dāng)程序開始執(zhí)行之后,會(huì)調(diào)用SpringApplication的構(gòu)造方法,進(jìn)行某些初始參數(shù)的設(shè)置

//創(chuàng)建一個(gè)新的實(shí)例,這個(gè)應(yīng)用程序的上下文將要從指定的來源加載Bean
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    //資源初始化資源加載器,默認(rèn)為null
    this.resourceLoader = resourceLoader;
    //斷言主要加載資源類不能為 null,否則報(bào)錯(cuò)
    Assert.notNull(primarySources, "PrimarySources must not be null");
    //初始化主要加載資源類集合并去重
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    //推斷當(dāng)前 WEB 應(yīng)用類型,一共有三種:NONE,SERVLET,REACTIVE
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    //設(shè)置應(yīng)用上線文初始化器,從"META-INF/spring.factories"讀取ApplicationContextInitializer類的實(shí)例名稱集合并去重,并進(jìn)行set去重。(一共7個(gè))
    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    //設(shè)置監(jiān)聽器,從"META-INF/spring.factories"讀取ApplicationListener類的實(shí)例名稱集合并去重,并進(jìn)行set去重。(一共11個(gè))
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    //推斷主入口應(yīng)用類,通過當(dāng)前調(diào)用棧,獲取Main方法所在類,并賦值給mainApplicationClass
    this.mainApplicationClass = deduceMainApplicationClass();
    }

在上述構(gòu)造方法中,有一個(gè)判斷應(yīng)用類型的方法,用來判斷當(dāng)前應(yīng)用程序的類型:

    static WebApplicationType deduceFromClasspath() {
        if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
                && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
            return WebApplicationType.REACTIVE;
        }
        for (String className : SERVLET_INDICATOR_CLASSES) {
            if (!ClassUtils.isPresent(className, null)) {
                return WebApplicationType.NONE;
            }
        }
        return WebApplicationType.SERVLET;
    }
//WebApplicationType的類型
public enum WebApplicationType {

    /**
     * The application should not run as a web application and should not start an
     * embedded web server.
     * 非web項(xiàng)目
     */
    NONE,

    /**
     * The application should run as a servlet-based web application and should start an
     * embedded servlet web server.
     * servlet web 項(xiàng)目
     */
    SERVLET,

    /**
     * The application should run as a reactive web application and should start an
     * embedded reactive web server.
     * 響應(yīng)式 web 項(xiàng)目
     */
    REACTIVE;

springboot啟動(dòng)的運(yùn)行方法,可以看到主要是各種運(yùn)行環(huán)境的準(zhǔn)備工作

public ConfigurableApplicationContext run(String... args) {
    //1、創(chuàng)建并啟動(dòng)計(jì)時(shí)監(jiān)控類
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    //2、初始化應(yīng)用上下文和異常報(bào)告集合
    ConfigurableApplicationContext context = null;
    Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
    //3、設(shè)置系統(tǒng)屬性“java.awt.headless”的值,默認(rèn)為true,用于運(yùn)行headless服務(wù)器,進(jìn)行簡(jiǎn)單的圖像處理,多用于在缺少顯示屏、鍵盤或者鼠標(biāo)時(shí)的系統(tǒng)配置,很多監(jiān)控工具如jconsole 需要將該值設(shè)置為true
    configureHeadlessProperty();
    //4、創(chuàng)建所有spring運(yùn)行監(jiān)聽器并發(fā)布應(yīng)用啟動(dòng)事件,簡(jiǎn)單說的話就是獲取SpringApplicationRunListener類型的實(shí)例(EventPublishingRunListener對(duì)象),并封裝進(jìn)SpringApplicationRunListeners對(duì)象,然后返回這個(gè)SpringApplicationRunListeners對(duì)象。說的再簡(jiǎn)單點(diǎn),getRunListeners就是準(zhǔn)備好了運(yùn)行時(shí)監(jiān)聽器EventPublishingRunListener。
    SpringApplicationRunListeners listeners = getRunListeners(args);
    listeners.starting();
    try {
        //5、初始化默認(rèn)應(yīng)用參數(shù)類
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        //6、根據(jù)運(yùn)行監(jiān)聽器和應(yīng)用參數(shù)來準(zhǔn)備spring環(huán)境
        ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
        //將要忽略的bean的參數(shù)打開
        configureIgnoreBeanInfo(environment);
        //7、創(chuàng)建banner打印類
        Banner printedBanner = printBanner(environment);
        //8、創(chuàng)建應(yīng)用上下文,可以理解為創(chuàng)建一個(gè)容器
        context = createApplicationContext();
        //9、準(zhǔn)備異常報(bào)告器,用來支持報(bào)告關(guān)于啟動(dòng)的錯(cuò)誤
        exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
                    new Class[] { ConfigurableApplicationContext.class }, context);
        //10、準(zhǔn)備應(yīng)用上下文,該步驟包含一個(gè)非常關(guān)鍵的操作,將啟動(dòng)類注入容器,為后續(xù)開啟自動(dòng)化提供基礎(chǔ)
        prepareContext(context, environment, listeners, applicationArguments, printedBanner);
        //11、刷新應(yīng)用上下文
        refreshContext(context);
        //12、應(yīng)用上下文刷新后置處理,做一些擴(kuò)展功能
        afterRefresh(context, applicationArguments);
        //13、停止計(jì)時(shí)監(jiān)控類
        stopWatch.stop();
        //14、輸出日志記錄執(zhí)行主類名、時(shí)間信息
        if (this.logStartupInfo) {
                new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
        }
        //15、發(fā)布應(yīng)用上下文啟動(dòng)監(jiān)聽事件
        listeners.started(context);
        //16、執(zhí)行所有的Runner運(yùn)行器
        callRunners(context, applicationArguments);
    }catch (Throwable ex) {
        handleRunFailure(context, ex, exceptionReporters, listeners);
        throw new IllegalStateException(ex);
    }
    try {
        //17、發(fā)布應(yīng)用上下文就緒事件
        listeners.running(context);
    }catch (Throwable ex) {
        handleRunFailure(context, ex, exceptionReporters, null);
        throw new IllegalStateException(ex);
    }
    //18、返回應(yīng)用上下文
    return context;
}

下面詳細(xì)介紹各個(gè)啟動(dòng)的環(huán)節(jié):

1、創(chuàng)建并啟動(dòng)計(jì)時(shí)監(jiān)控類,可以看到記錄當(dāng)前任務(wù)的名稱,默認(rèn)是空字符串,然后記錄當(dāng)前springboot應(yīng)用啟動(dòng)的開始時(shí)間。

StopWatch stopWatch = new StopWatch();
stopWatch.start();
//詳細(xì)源代碼
public void start() throws IllegalStateException {
    start("");
}
public void start(String taskName) throws IllegalStateException {
    if (this.currentTaskName != null) {
        throw new IllegalStateException("Can't start StopWatch: it's already running");
    }
    this.currentTaskName = taskName;
    this.startTimeNanos = System.nanoTime();
}

2、初始化應(yīng)用上下文和異常報(bào)告集合

ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();

3、設(shè)置系統(tǒng)屬性java.awt.headless的值:

/*
java.awt.headless模式是在缺少顯示屏、鍵盤或者鼠標(biāo)的系統(tǒng)配置
當(dāng)配置了如下屬性之后,應(yīng)用程序可以執(zhí)行如下操作:
    1、創(chuàng)建輕量級(jí)組件
    2、收集關(guān)于可用的字體、字體指標(biāo)和字體設(shè)置的信息
    3、設(shè)置顏色來渲染準(zhǔn)備圖片
    4、創(chuàng)造和獲取圖像,為渲染準(zhǔn)備圖片
    5、使用java.awt.PrintJob,java.awt.print.*和javax.print.*類里的方法進(jìn)行打印
*/
private void configureHeadlessProperty() {
        System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS,
                System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
}

4、創(chuàng)建所有spring運(yùn)行監(jiān)聽器并發(fā)布應(yīng)用啟動(dòng)事件

SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();

//創(chuàng)建spring監(jiān)聽器
private SpringApplicationRunListeners getRunListeners(String[] args) {
    Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
    return new SpringApplicationRunListeners(logger,
                getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners) {
    this.log = log;
    this.listeners = new ArrayList<>(listeners);
}
//循環(huán)遍歷獲取監(jiān)聽器
void starting() {
    for (SpringApplicationRunListener listener : this.listeners) {
        listener.starting();
    }
}
//此處的監(jiān)聽器可以看出是事件發(fā)布監(jiān)聽器,主要用來發(fā)布啟動(dòng)事件
@Override
public void starting() {
    //這里是創(chuàng)建application事件‘a(chǎn)pplicationStartingEvent’
    this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}
//applicationStartingEvent是springboot框架最早執(zhí)行的監(jiān)聽器,在該監(jiān)聽器執(zhí)行started方法時(shí),會(huì)繼續(xù)發(fā)布事件,主要是基于spring的事件機(jī)制
    @Override
    public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
        ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
        //獲取線程池,如果為空則同步處理。這里線程池為空,還未初始化
        Executor executor = getTaskExecutor();
        for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
            if (executor != null) {
                //異步發(fā)送事件
                executor.execute(() -> invokeListener(listener, event));
            }
            else {
                //同步發(fā)送事件
                invokeListener(listener, event);
            }
        }
    }

5、初始化默認(rèn)應(yīng)用參數(shù)類

ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
public DefaultApplicationArguments(String... args) {
    Assert.notNull(args, "Args must not be null");
    this.source = new Source(args);
    this.args = args;
}

6、根據(jù)運(yùn)行監(jiān)聽器和應(yīng)用參數(shù)來準(zhǔn)備spring環(huán)境

ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
//詳細(xì)環(huán)境的準(zhǔn)備
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
    ApplicationArguments applicationArguments) {
    // 獲取或者創(chuàng)建應(yīng)用環(huán)境
    ConfigurableEnvironment environment = getOrCreateEnvironment();
    // 配置應(yīng)用環(huán)境,配置propertySource和activeProfiles
    configureEnvironment(environment, applicationArguments.getSourceArgs());
    //listeners環(huán)境準(zhǔn)備,廣播ApplicationEnvironmentPreparedEvent
    ConfigurationPropertySources.attach(environment);
    listeners.environmentPrepared(environment);
    //將環(huán)境綁定給當(dāng)前應(yīng)用程序
    bindToSpringApplication(environment);
    //對(duì)當(dāng)前的環(huán)境類型進(jìn)行判斷,如果不一致進(jìn)行轉(zhuǎn)換
    if (!this.isCustomEnvironment) {
        environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
                    deduceEnvironmentClass());
    }
    //配置propertySource對(duì)它自己的遞歸依賴
    ConfigurationPropertySources.attach(environment);
    return environment;
}
// 獲取或者創(chuàng)建應(yīng)用環(huán)境,根據(jù)應(yīng)用程序的類型可以分為servlet環(huán)境、標(biāo)準(zhǔn)環(huán)境(特殊的非web環(huán)境)和響應(yīng)式環(huán)境
private ConfigurableEnvironment getOrCreateEnvironment() {
    //存在則直接返回
        if (this.environment != null) {
            return this.environment;
        }
    //根據(jù)webApplicationType創(chuàng)建對(duì)應(yīng)的Environment
        switch (this.webApplicationType) {
        case SERVLET:
            return new StandardServletEnvironment();
        case REACTIVE:
            return new StandardReactiveWebEnvironment();
        default:
            return new StandardEnvironment();
        }
    }
//配置應(yīng)用環(huán)境
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
    if (this.addConversionService) {
        ConversionService conversionService = ApplicationConversionService.getSharedInstance();
        environment.setConversionService((ConfigurableConversionService) conversionService);
    }
    //配置property sources
    configurePropertySources(environment, args);
    //配置profiles
    configureProfiles(environment, args);
}

7、創(chuàng)建banner的打印類

Banner printedBanner = printBanner(environment);//打印類的詳細(xì)操作過程private Banner printBanner(ConfigurableEnvironment environment) {       if (this.bannerMode == Banner.Mode.OFF) {           return null;        }       ResourceLoader resourceLoader = (this.resourceLoader != null) ? this.resourceLoader             : new DefaultResourceLoader(getClassLoader());      SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, this.banner);     if (this.bannerMode == Mode.LOG) {          return bannerPrinter.print(environment, this.mainApplicationClass, logger);     }       return bannerPrinter.print(environment, this.mainApplicationClass, System.out); }

8、創(chuàng)建應(yīng)用的上下文:根據(jù)不同哦那個(gè)的應(yīng)用類型初始化不同的上下文應(yīng)用類

context = createApplicationContext();protected ConfigurableApplicationContext createApplicationContext() {      Class<?> contextClass = this.applicationContextClass;       if (contextClass == null) {         try {               switch (this.webApplicationType) {              case SERVLET:                   contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);                    break;              case REACTIVE:                  contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);                   break;              default:                    contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);                }           }           catch (ClassNotFoundException ex) {             throw new IllegalStateException(                        "Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);           }       }       return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);   }

9、準(zhǔn)備異常報(bào)告器

exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,                 new Class[] { ConfigurableApplicationContext.class }, context);private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {        ClassLoader classLoader = getClassLoader();     // Use names and ensure unique to protect against duplicates        Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));     List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);     AnnotationAwareOrderComparator.sort(instances);     return instances;   }

10、準(zhǔn)備應(yīng)用上下文

prepareContext(context, environment, listeners, applicationArguments, printedBanner);private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,           SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {     //應(yīng)用上下文的environment     context.setEnvironment(environment);        //應(yīng)用上下文后處理      postProcessApplicationContext(context);     //為上下文應(yīng)用所有初始化器,執(zhí)行容器中的applicationContextInitializer(spring.factories的實(shí)例),將所有的初始化對(duì)象放置到context對(duì)象中      applyInitializers(context);     //觸發(fā)所有SpringApplicationRunListener監(jiān)聽器的ContextPrepared事件方法。添加所有的事件監(jiān)聽器        listeners.contextPrepared(context);         //記錄啟動(dòng)日志        if (this.logStartupInfo) {          logStartupInfo(context.getParent() == null);            logStartupProfileInfo(context);     }       // 注冊(cè)啟動(dòng)參數(shù)bean,將容器指定的參數(shù)封裝成bean,注入容器      ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();     beanFactory.registerSingleton("springApplicationArguments", applicationArguments);      //設(shè)置banner      if (printedBanner != null) {            beanFactory.registerSingleton("springBootBanner", printedBanner);       }       if (beanFactory instanceof DefaultListableBeanFactory) {            ((DefaultListableBeanFactory) beanFactory)                  .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);      }       if (this.lazyInitialization) {          context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());      }       // 加載所有資源,指的是啟動(dòng)器指定的參數(shù)       Set<Object> sources = getAllSources();      Assert.notEmpty(sources, "Sources must not be empty");      //將bean加載到上下文中      load(context, sources.toArray(new Object[0]));      //觸發(fā)所有springapplicationRunListener監(jiān)聽器的contextLoaded事件方法,        listeners.contextLoaded(context);   }-------------------    //這里沒有做任何的處理過程,因?yàn)閎eanNameGenerator和resourceLoader默認(rèn)為空,可以方便后續(xù)做擴(kuò)展處理    protected void postProcessApplicationContext(ConfigurableApplicationContext context) {     if (this.beanNameGenerator != null) {           context.getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,                 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());        }   }---------------------    //將啟動(dòng)器類加載到spring容器中,為后續(xù)的自動(dòng)化配置奠定基礎(chǔ),之前看到的很多注解也與此相關(guān)    protected void load(ApplicationContext context, Object[] sources) {       if (logger.isDebugEnabled()) {          logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));     }       BeanDefinitionLoader loader = createBeanDefinitionLoader(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();  }---------------------    //springboot會(huì)優(yōu)先選擇groovy加載方式,找不到在選擇java方式    private int load(Class<?> source) {       if (isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {           // Any GroovyLoaders added in beans{} DSL can contribute beans here         GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class);           load(loader);       }       if (isComponent(source)) {          this.annotatedReader.register(source);          return 1;       }       return 0;   }

11、刷新應(yīng)用上下文

refreshContext(context);private void refreshContext(ConfigurableApplicationContext context) {       refresh(context);       if (this.registerShutdownHook) {            try {               context.registerShutdownHook();         }           catch (AccessControlException ex) {             // Not allowed in some environments.            }       }   }------------    public void refresh() throws BeansException, IllegalStateException {       synchronized (this.startupShutdownMonitor) {            // Prepare this context for refreshing.            //刷新上下文環(huán)境,初始化上下文環(huán)境,對(duì)系統(tǒng)的環(huán)境變量或者系統(tǒng)屬性進(jìn)行準(zhǔn)備和校驗(yàn)         prepareRefresh();           // Tell the subclass to refresh the internal bean factory.            //初始化beanfactory,解析xml,相當(dāng)于之前的xmlBeanfactory操作         ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();         // Prepare the bean factory for use in this context.            //為上下文準(zhǔn)備beanfactory,對(duì)beanFactory的各種功能進(jìn)行填充,如@autowired,設(shè)置spel表達(dá)式解析器,設(shè)置編輯注冊(cè)器,添加applicationContextAwareprocessor處理器等等          prepareBeanFactory(beanFactory);            try {               // Allows post-processing of the bean factory in context subclasses.                //提供子類覆蓋的額外處理,即子類處理自定義的beanfactorypostProcess               postProcessBeanFactory(beanFactory);                // Invoke factory processors registered as beans in the context.                //激活各種beanfactory處理器                invokeBeanFactoryPostProcessors(beanFactory);               // Register bean processors that intercept bean creation.                //注冊(cè)攔截bean創(chuàng)建的bean處理器,即注冊(cè)beanPostProcessor              registerBeanPostProcessors(beanFactory);                // Initialize message source for this context.                //初始化上下文中的資源文件如國(guó)際化文件的處理               initMessageSource();                // Initialize event multicaster for this context.                //初始化上下文事件廣播器              initApplicationEventMulticaster();              // Initialize other special beans in specific context subclasses.                //給子類擴(kuò)展初始化其他bean               onRefresh();                // Check for listener beans and register them.                //在所有的bean中查找listener bean,然后 注冊(cè)到廣播器中             registerListeners();                // Instantiate all remaining (non-lazy-init) singletons.                //初始化剩余的非懶惰的bean,即初始化非延遲加載的bean             finishBeanFactoryInitialization(beanFactory);               // Last step: publish corresponding event.                //發(fā)完成刷新過程,通知聲明周期處理器刷新過程,同時(shí)發(fā)出ContextRefreshEvent通知?jiǎng)e人               finishRefresh();            }           catch (BeansException ex) {             if (logger.isWarnEnabled()) {                   logger.warn("Exception encountered during context initialization - " +                          "cancelling refresh attempt: " + ex);               }               // Destroy already created singletons to avoid dangling resources.              destroyBeans();             // Reset 'active' flag.             cancelRefresh(ex);              // Propagate exception to caller.               throw ex;           }           finally {               // Reset common introspection caches in Spring's core, since we             // might not ever need metadata for singleton beans anymore...              resetCommonCaches();            }       }   }

12、應(yīng)用上下文刷新后置處理

afterRefresh(context, applicationArguments);//當(dāng)前方法的代碼是空的,可以做一些自定義的后置處理操作protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {    }

13、停止計(jì)時(shí)監(jiān)控類:計(jì)時(shí)監(jiān)聽器停止,并統(tǒng)計(jì)一些任務(wù)執(zhí)行信息

stopWatch.stop();public void stop() throws IllegalStateException {      if (this.currentTaskName == null) {         throw new IllegalStateException("Can't stop StopWatch: it's not running");      }       long lastTime = System.nanoTime() - this.startTimeNanos;        this.totalTimeNanos += lastTime;        this.lastTaskInfo = new TaskInfo(this.currentTaskName, lastTime);       if (this.keepTaskList) {            this.taskList.add(this.lastTaskInfo);       }       ++this.taskCount;       this.currentTaskName = null;    }

14、輸出日志記錄執(zhí)行主類名、時(shí)間信息

if (this.logStartupInfo) {  new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);}

15、發(fā)布應(yīng)用上下文啟動(dòng)完成事件:觸發(fā)所有SpringapplicationRunListener監(jiān)聽器的started事件方法

listeners.started(context); void started(ConfigurableApplicationContext context) {      for (SpringApplicationRunListener listener : this.listeners) {          listener.started(context);      }   }

16、執(zhí)行所有Runner執(zhí)行器:執(zhí)行所有applicationRunner和CommandLineRunner兩種運(yùn)行器

callRunners(context, applicationArguments);private void callRunners(ApplicationContext context, ApplicationArguments args) {        List<Object> runners = new ArrayList<>();       runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());       runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());       AnnotationAwareOrderComparator.sort(runners);       for (Object runner : new LinkedHashSet<>(runners)) {            if (runner instanceof ApplicationRunner) {              callRunner((ApplicationRunner) runner, args);           }           if (runner instanceof CommandLineRunner) {              callRunner((CommandLineRunner) runner, args);           }       }   }

17、發(fā)布應(yīng)用上下文就緒事件:觸發(fā)所有springapplicationRunnListener將挺起的running事件方法

listeners.running(context);void running(ConfigurableApplicationContext context) {       for (SpringApplicationRunListener listener : this.listeners) {          listener.running(context);      }   }

18、返回應(yīng)用上下文

return context;

注意:

整個(gè)springboot框架中獲取factorys文件的方式統(tǒng)一如下:

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {  return getSpringFactoriesInstances(type, new Class<?>[] {});}-------------------------------------private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {     ClassLoader classLoader = getClassLoader();     // Use names and ensure unique to protect against duplicates        Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));     List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);     AnnotationAwareOrderComparator.sort(instances);     return instances;}-----------------------------    public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {       String factoryTypeName = factoryType.getName();     return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList()); }   private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {       MultiValueMap<String, String> result = cache.get(classLoader);      if (result != null) {           return result;      }       try {           Enumeration<URL> urls = (classLoader != null ?                  classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :                 ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));           result = new LinkedMultiValueMap<>();           while (urls.hasMoreElements()) {                URL url = urls.nextElement();               UrlResource resource = new UrlResource(url);                Properties properties = PropertiesLoaderUtils.loadProperties(resource);             for (Map.Entry<?, ?> entry : properties.entrySet()) {                   String factoryTypeName = ((String) entry.getKey()).trim();                  for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {                       result.add(factoryTypeName, factoryImplementationName.trim());                  }               }           }           cache.put(classLoader, result);         return result;      }       catch (IOException ex) {            throw new IllegalArgumentException("Unable to load factories from location [" +                 FACTORIES_RESOURCE_LOCATION + "]", ex);     }   }-------------------------    private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,          ClassLoader classLoader, Object[] args, Set<String> names) {        List<T> instances = new ArrayList<>(names.size());      for (String name : names) {         try {                //裝載class文件到內(nèi)存             Class<?> instanceClass = ClassUtils.forName(name, classLoader);             Assert.isAssignable(type, instanceClass);               Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);                //通過反射創(chuàng)建實(shí)例                T instance = (T) BeanUtils.instantiateClass(constructor, args);             instances.add(instance);            }           catch (Throwable ex) {              throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);            }       }       return instances;   }

spring.factory文件中的類的作用:

# PropertySource Loaders 屬性文件加載器org.springframework.boot.env.PropertySourceLoader=\# properties文件加載器org.springframework.boot.env.PropertiesPropertySourceLoader,\# yaml文件加載器org.springframework.boot.env.YamlPropertySourceLoader# Run Listeners 運(yùn)行時(shí)的監(jiān)聽器org.springframework.boot.SpringApplicationRunListener=\# 程序運(yùn)行過程中所有監(jiān)聽通知都是通過此類來進(jìn)行回調(diào)org.springframework.boot.context.event.EventPublishingRunListener# Error Reporters 錯(cuò)誤報(bào)告器org.springframework.boot.SpringBootExceptionReporter=\org.springframework.boot.diagnostics.FailureAnalyzers# Application Context Initializersorg.springframework.context.ApplicationContextInitializer=\# 報(bào)告spring容器的一些常見的錯(cuò)誤配置org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\# 設(shè)置spring應(yīng)用上下文的IDorg.springframework.boot.context.ContextIdApplicationContextInitializer,\# 使用環(huán)境屬性context.initializer.classes指定初始化器進(jìn)行初始化規(guī)則org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer,\# 將內(nèi)置servlet容器實(shí)際使用的監(jiān)聽端口寫入到environment環(huán)境屬性中org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer# Application Listenersorg.springframework.context.ApplicationListener=\# 應(yīng)用上下文加載完成后對(duì)緩存做清除工作,響應(yīng)事件ContextRefreshEventorg.springframework.boot.ClearCachesApplicationListener,\# 監(jiān)聽雙親應(yīng)用上下文的關(guān)閉事件并往自己的孩子應(yīng)用上下文中傳播,相關(guān)事件ParentContextAvailableEvent/ContextClosedEventorg.springframework.boot.builder.ParentContextCloserApplicationListener,\org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\# 如果系統(tǒng)文件編碼和環(huán)境變量中指定的不同則終止應(yīng)用啟動(dòng)。具體的方法是比較系統(tǒng)屬性file.encoding和環(huán)境變量spring.mandatory-file-encoding是否相等(大小寫不敏感)。org.springframework.boot.context.FileEncodingApplicationListener,\# 根據(jù)spring.output.ansi.enabled參數(shù)配置AnsiOutputorg.springframework.boot.context.config.AnsiOutputApplicationListener,\# EnvironmentPostProcessor,從常見的那些約定的位置讀取配置文件,比如從以下目錄讀取#application.properties,application.yml等配置文件:# classpath:# file:.# classpath:config# file:./config/:# 也可以配置成從其他指定的位置讀取配置文件org.springframework.boot.context.config.ConfigFileApplicationListener,\# 監(jiān)聽到事件后轉(zhuǎn)發(fā)給環(huán)境變量context.listener.classes指定的那些事件監(jiān)聽器org.springframework.boot.context.config.DelegatingApplicationListener,\# 一個(gè)SmartApplicationListener,對(duì)環(huán)境就緒事件ApplicationEnvironmentPreparedEvent/應(yīng)用失敗事件ApplicationFailedEvent做出響應(yīng),往日志DEBUG級(jí)別輸出TCCL(thread context class loader)的classpath。org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\# 檢測(cè)正在使用的日志系統(tǒng),默認(rèn)時(shí)logback,,此時(shí)日志系統(tǒng)還沒有初始化org.springframework.boot.context.logging.LoggingApplicationListener,\# 使用一個(gè)可以和Spring Boot可執(zhí)行jar包配合工作的版本替換liquibase ServiceLocatororg.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener# Environment Post Processorsorg.springframework.boot.env.EnvironmentPostProcessor=\org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor,\org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProcessor,\org.springframework.boot.reactor.DebugAgentEnvironmentPostProcessor# Failure Analyzersorg.springframework.boot.diagnostics.FailureAnalyzer=\org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer,\org.springframework.boot.diagnostics.analyzer.BeanDefinitionOverrideFailureAnalyzer,\org.springframework.boot.diagnostics.analyzer.BeanNotOfRequiredTypeFailureAnalyzer,\org.springframework.boot.diagnostics.analyzer.BindFailureAnalyzer,\org.springframework.boot.diagnostics.analyzer.BindValidationFailureAnalyzer,\org.springframework.boot.diagnostics.analyzer.UnboundConfigurationPropertyFailureAnalyzer,\org.springframework.boot.diagnostics.analyzer.ConnectorStartFailureAnalyzer,\org.springframework.boot.diagnostics.analyzer.NoSuchMethodFailureAnalyzer,\org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnalyzer,\org.springframework.boot.diagnostics.analyzer.PortInUseFailureAnalyzer,\org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer,\org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyNameFailureAnalyzer,\org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyValueFailureAnalyzer# FailureAnalysisReportersorg.springframework.boot.diagnostics.FailureAnalysisReporter=\org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter# Initializersorg.springframework.context.ApplicationContextInitializer=\org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener# Application Listenersorg.springframework.context.ApplicationListener=\# 另外單獨(dú)啟動(dòng)一個(gè)線程實(shí)例化并調(diào)用run方法,包括驗(yàn)證器、消息轉(zhuǎn)換器等org.springframework.boot.autoconfigure.BackgroundPreinitializer# Auto Configuration Import Listenersorg.springframework.boot.autoconfigure.AutoConfigurationImportListener=\org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener# Auto Configuration Import Filtersorg.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\org.springframework.boot.autoconfigure.condition.OnBeanCondition,\org.springframework.boot.autoconfigure.condition.OnClassCondition,\org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition# Auto Configureorg.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.CloudServiceConnectorsAutoConfiguration,\org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration,\org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration,\org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration,\org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveRepositoriesAutoConfiguration,\org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration,\org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRepositoriesAutoConfiguration,\org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveRestClientAutoConfiguration,\org.springframework.boot.autoconfigure.data.jdbc.JdbcRepositoriesAutoConfiguration,\org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration,\org.springframework.boot.autoconfigure.data.mongo.MongoReactiveRepositoriesAutoConfiguration,\org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration,\org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,\org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\org.springframework.boot.autoconfigure.elasticsearch.jest.JestAutoConfiguration,\org.springframework.boot.autoconfigure.elasticsearch.rest.RestClientAutoConfiguration,\org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,\org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,\org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,\org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration,\org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration,\org.springframework.boot.autoconfigure.influx.InfluxDbAutoConfiguration,\org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,\org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,\org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration,\org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,\org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,\org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,\org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration,\org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\org.springframework.boot.autoconfigure.rsocket.RSocketMessagingAutoConfiguration,\org.springframework.boot.autoconfigure.rsocket.RSocketRequesterAutoConfiguration,\org.springframework.boot.autoconfigure.rsocket.RSocketServerAutoConfiguration,\org.springframework.boot.autoconfigure.rsocket.RSocketStrategiesAutoConfiguration,\org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,\org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,\org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration,\org.springframework.boot.autoconfigure.security.rsocket.RSocketSecurityAutoConfiguration,\org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyAutoConfiguration,\org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration,\org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration,\org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration,\org.springframework.boot.autoconfigure.security.oauth2.resource.reactive.ReactiveOAuth2ResourceServerAutoConfiguration,\org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration,\org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration,\org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration,\org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration,\org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration,\org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration,\org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration,\org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration,\org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration,\org.springframework.boot.autoconfigure.web.reactive.function.client.ClientHttpConnectorAutoConfiguration,\org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration,\org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,\org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration,\org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration,\org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration,\org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration,\org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration,\org.springframework.boot.autoconfigure.webservices.client.WebServiceTemplateAutoConfiguration# Failure analyzersorg.springframework.boot.diagnostics.FailureAnalyzer=\org.springframework.boot.autoconfigure.diagnostics.analyzer.NoSuchBeanDefinitionFailureAnalyzer,\org.springframework.boot.autoconfigure.flyway.FlywayMigrationScriptMissingFailureAnalyzer,\org.springframework.boot.autoconfigure.jdbc.DataSourceBeanCreationFailureAnalyzer,\org.springframework.boot.autoconfigure.jdbc.HikariDriverConfigurationFailureAnalyzer,\org.springframework.boot.autoconfigure.session.NonUniqueSessionRepositoryFailureAnalyzer# Template availability providersorg.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\org.springframework.boot.autoconfigure.freemarker.FreeMarkerTemplateAvailabilityProvider,\org.springframework.boot.autoconfigure.mustache.MustacheTemplateAvailabilityProvider,\org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAvailabilityProvider,\org.springframework.boot.autoconfigure.thymeleaf.ThymeleafTemplateAvailabilityProvider,\org.springframework.boot.autoconfigure.web.servlet.JspTemplateAvailabilityProvider

注意:

整個(gè)springboot框架中獲取factorys文件的方式統(tǒng)一如下:

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
    return getSpringFactoriesInstances(type, new Class<?>[] {});
}
-------------------------------------
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
        ClassLoader classLoader = getClassLoader();
        // Use names and ensure unique to protect against duplicates
        Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
        List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
        AnnotationAwareOrderComparator.sort(instances);
        return instances;
}
-----------------------------
    public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
        String factoryTypeName = factoryType.getName();
        return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
    }

    private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
        MultiValueMap<String, String> result = cache.get(classLoader);
        if (result != null) {
            return result;
        }

        try {
            Enumeration<URL> urls = (classLoader != null ?
                    classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
                    ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
            result = new LinkedMultiValueMap<>();
            while (urls.hasMoreElements()) {
                URL url = urls.nextElement();
                UrlResource resource = new UrlResource(url);
                Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                for (Map.Entry<?, ?> entry : properties.entrySet()) {
                    String factoryTypeName = ((String) entry.getKey()).trim();
                    for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
                        result.add(factoryTypeName, factoryImplementationName.trim());
                    }
                }
            }
            cache.put(classLoader, result);
            return result;
        }
        catch (IOException ex) {
            throw new IllegalArgumentException("Unable to load factories from location [" +
                    FACTORIES_RESOURCE_LOCATION + "]", ex);
        }
    }
-------------------------
    private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
            ClassLoader classLoader, Object[] args, Set<String> names) {
        List<T> instances = new ArrayList<>(names.size());
        for (String name : names) {
            try {
                //裝載class文件到內(nèi)存
                Class<?> instanceClass = ClassUtils.forName(name, classLoader);
                Assert.isAssignable(type, instanceClass);
                Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
                //通過反射創(chuàng)建實(shí)例
                T instance = (T) BeanUtils.instantiateClass(constructor, args);
                instances.add(instance);
            }
            catch (Throwable ex) {
                throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
            }
        }
        return instances;
    }

spring.factory文件中的類的作用:

# PropertySource Loaders 屬性文件加載器
org.springframework.boot.env.PropertySourceLoader=\
# properties文件加載器
org.springframework.boot.env.PropertiesPropertySourceLoader,\
# yaml文件加載器
org.springframework.boot.env.YamlPropertySourceLoader

# Run Listeners 運(yùn)行時(shí)的監(jiān)聽器
org.springframework.boot.SpringApplicationRunListener=\
# 程序運(yùn)行過程中所有監(jiān)聽通知都是通過此類來進(jìn)行回調(diào)
org.springframework.boot.context.event.EventPublishingRunListener

# Error Reporters   錯(cuò)誤報(bào)告器
org.springframework.boot.SpringBootExceptionReporter=\
org.springframework.boot.diagnostics.FailureAnalyzers

# Application Context Initializers
org.springframework.context.ApplicationContextInitializer=\
# 報(bào)告spring容器的一些常見的錯(cuò)誤配置
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
# 設(shè)置spring應(yīng)用上下文的ID
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
# 使用環(huán)境屬性context.initializer.classes指定初始化器進(jìn)行初始化規(guī)則
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer,\
# 將內(nèi)置servlet容器實(shí)際使用的監(jiān)聽端口寫入到environment環(huán)境屬性中
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer

# Application Listeners
org.springframework.context.ApplicationListener=\
# 應(yīng)用上下文加載完成后對(duì)緩存做清除工作,響應(yīng)事件ContextRefreshEvent
org.springframework.boot.ClearCachesApplicationListener,\
# 監(jiān)聽雙親應(yīng)用上下文的關(guān)閉事件并往自己的孩子應(yīng)用上下文中傳播,相關(guān)事件ParentContextAvailableEvent/ContextClosedEvent
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
# 如果系統(tǒng)文件編碼和環(huán)境變量中指定的不同則終止應(yīng)用啟動(dòng)。具體的方法是比較系統(tǒng)屬性file.encoding和環(huán)境變量spring.mandatory-file-encoding是否相等(大小寫不敏感)。
org.springframework.boot.context.FileEncodingApplicationListener,\
# 根據(jù)spring.output.ansi.enabled參數(shù)配置AnsiOutput
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
# EnvironmentPostProcessor,從常見的那些約定的位置讀取配置文件,比如從以下目錄讀取#application.properties,application.yml等配置文件:
# classpath:
# file:.
# classpath:config
# file:./config/:
# 也可以配置成從其他指定的位置讀取配置文件
org.springframework.boot.context.config.ConfigFileApplicationListener,\
# 監(jiān)聽到事件后轉(zhuǎn)發(fā)給環(huán)境變量context.listener.classes指定的那些事件監(jiān)聽器
org.springframework.boot.context.config.DelegatingApplicationListener,\
# 一個(gè)SmartApplicationListener,對(duì)環(huán)境就緒事件ApplicationEnvironmentPreparedEvent/應(yīng)用失敗事件ApplicationFailedEvent做出響應(yīng),往日志DEBUG級(jí)別輸出TCCL(thread context class loader)的classpath。
org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\
# 檢測(cè)正在使用的日志系統(tǒng),默認(rèn)時(shí)logback,,此時(shí)日志系統(tǒng)還沒有初始化
org.springframework.boot.context.logging.LoggingApplicationListener,\
# 使用一個(gè)可以和Spring Boot可執(zhí)行jar包配合工作的版本替換liquibase ServiceLocator
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener

# Environment Post Processors
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor,\
org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProcessor,\
org.springframework.boot.reactor.DebugAgentEnvironmentPostProcessor

# Failure Analyzers
org.springframework.boot.diagnostics.FailureAnalyzer=\
org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BeanDefinitionOverrideFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BeanNotOfRequiredTypeFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BindFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BindValidationFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.UnboundConfigurationPropertyFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.ConnectorStartFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.NoSuchMethodFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.PortInUseFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyNameFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyValueFailureAnalyzer

# FailureAnalysisReporters
org.springframework.boot.diagnostics.FailureAnalysisReporter=\
org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter

# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener

# Application Listeners
org.springframework.context.ApplicationListener=\
# 另外單獨(dú)啟動(dòng)一個(gè)線程實(shí)例化并調(diào)用run方法,包括驗(yàn)證器、消息轉(zhuǎn)換器等
org.springframework.boot.autoconfigure.BackgroundPreinitializer

# Auto Configuration Import Listeners
org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\
org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener

# Auto Configuration Import Filters
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
org.springframework.boot.autoconfigure.condition.OnClassCondition,\
org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition

# 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.CloudServiceConnectorsAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveRestClientAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jdbc.JdbcRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\
org.springframework.boot.autoconfigure.elasticsearch.jest.JestAutoConfiguration,\
org.springframework.boot.autoconfigure.elasticsearch.rest.RestClientAutoConfiguration,\
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\
org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\
org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,\
org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,\
org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration,\
org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration,\
org.springframework.boot.autoconfigure.influx.InfluxDbAutoConfiguration,\
org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,\
org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,\
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\
org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\
org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration,\
org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\
org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,\
org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,\
org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\
org.springframework.boot.autoconfigure.rsocket.RSocketMessagingAutoConfiguration,\
org.springframework.boot.autoconfigure.rsocket.RSocketRequesterAutoConfiguration,\
org.springframework.boot.autoconfigure.rsocket.RSocketServerAutoConfiguration,\
org.springframework.boot.autoconfigure.rsocket.RSocketStrategiesAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,\
org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration,\
org.springframework.boot.autoconfigure.security.rsocket.RSocketSecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyAutoConfiguration,\
org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\
org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.resource.reactive.ReactiveOAuth2ResourceServerAutoConfiguration,\
org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\
org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration,\
org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\
org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration,\
org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.function.client.ClientHttpConnectorAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration,\
org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration,\
org.springframework.boot.autoconfigure.webservices.client.WebServiceTemplateAutoConfiguration

# Failure analyzers
org.springframework.boot.diagnostics.FailureAnalyzer=\
org.springframework.boot.autoconfigure.diagnostics.analyzer.NoSuchBeanDefinitionFailureAnalyzer,\
org.springframework.boot.autoconfigure.flyway.FlywayMigrationScriptMissingFailureAnalyzer,\
org.springframework.boot.autoconfigure.jdbc.DataSourceBeanCreationFailureAnalyzer,\
org.springframework.boot.autoconfigure.jdbc.HikariDriverConfigurationFailureAnalyzer,\
org.springframework.boot.autoconfigure.session.NonUniqueSessionRepositoryFailureAnalyzer

# Template availability providers
org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.mustache.MustacheTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.web.servlet.JspTemplateAvailabilityProvider

springboot2.2.2啟動(dòng)過程流程.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容