1. 程式人生 > 實用技巧 >SpringBoot2.3.1嵌入式Servlet啟動配置原理

SpringBoot2.3.1嵌入式Servlet啟動配置原理

從SpringBoot啟動類開始看起

@SpringBootApplication
public class DemoApplication {

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

}

進入run方法

    /**
     * Static helper that can be used to run a {@link SpringApplication} from the
     * specified sources using default settings and user supplied arguments.
     * 
@param primarySources the primary sources to load * @param args the application arguments (usually passed from a Java main method) * @return the running {@link ApplicationContext} */ public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
//首先建立一個Spring應用,然後執行run方法。
return new SpringApplication(primarySources).run(args); }

進入new SpringApplication(primarySources)

/**
     * Create a new {@link SpringApplication} instance. The application context will load
     * beans from the specified primary sources (see {@link SpringApplication class-level}
     * documentation for details. The instance can be customized before calling
     * {
@link #run(String...)}. * @param resourceLoader the resource loader to use * @param primarySources the primary bean sources * @see #run(Class, String[]) * @see #setSources(Set) */ @SuppressWarnings({ "unchecked", "rawtypes" }) public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//判斷是不是web應用
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//得到所有的META_INF下的spring.factories裡面配置的
ApplicationContextInitializer
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
        //得到所有的META_INF下的spring.factories裡面配置的ApplicationListener
         setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); 
//得到主類
this.mainApplicationClass = deduceMainApplicationClass(); }

然後再進入ru/**

     * Run the Spring application, creating and refreshing a new
     * {@link ApplicationContext}.
     * @param args the application arguments (usually passed from a Java main method)
     * @return a running {@link ApplicationContext}
     */
    public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
        configureHeadlessProperty();
//得到META_INF下的spring.factoies下的SpringApplicationRunListeners SpringApplicationRunListeners listeners
= getRunListeners(args);
//執行每一個SpringApplicationRunListener的starting方法 listeners.starting();
try {
//封裝命令列引數 ApplicationArguments applicationArguments
= new DefaultApplicationArguments(args);
//準備環境 ConfigurableEnvironment environment
= prepareEnvironment(listeners, applicationArguments);
/**

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,ApplicationArguments applicationArguments) {
   // Create and configure the environment
ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, applicationArguments.getSourceArgs());
ConfigurationPropertySources.attach(environment);
//這裡會呼叫SpringApplicationRunListener的environmentPrepared方法
  listeners.environmentPrepared(environment);
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
deduceEnvironmentClass());
}
ConfigurationPropertySources.attach(environment);
return environment;
}*/

            configureIgnoreBeanInfo(environment);
            Banner printedBanner = printBanner(environment);
//建立ioc容器 context
= createApplicationContext(); exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context);

prepareContext(context, environment, listeners, applicationArguments, printedBanner);

/**

private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
postProcessApplicationContext(context);
//執行ApplicationContextInitializer的initializers方法
   applyInitializers(context);
//執行SpringApplicationRunListener的contextPrepared方法

listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
// Load the sources
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[0]));
//執行SpringApplicationRunListener的contextLoaded方法
   listeners.contextLoaded(context);
}
*/
        //掃描,建立,載入所有元件的地方;(配置類,元件,自動配置),嵌入式sevlet容易在此建立   
refreshContext(context);
//回撥ApplicationRunner和CommandLineRunner,這兩個類不需要配置在spring.factoies中,直接放在ioc容器中就可以 afterRefresh(context, applicationArguments); stopWatch.stop();
if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch); }
//執行SpringApplicaitonRunListener的started方法 listeners.started(context); callRunners(context, applicationArguments); }
catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); } try {
//執行SpringApplicationRunListener的running方法 listeners.running(context); }
catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, null); throw new IllegalStateException(ex); }
//返回已經啟動的ioc容器
return context; }