1. 程式人生 > >SpringBoot系列之嵌入式servlet容器啟動原理

SpringBoot系列之嵌入式servlet容器啟動原理

嵌入式servlet容器啟動原理

本文將探討以下問題:
什麼時候建立嵌入式的Servlet容器工廠?什麼時候獲取嵌入式的Servlet容器並啟動Tomcat;


1)、SpringBoot應用啟動執行run方法
2)、refreshContext(context);SpringBoot重新整理IOC容器【建立IOC容器物件,並初始化容器,建立容器中的每一
個元件】;如果是web應用建立:AnnotationConfigEmbeddedWebApplicationContext,否則建立:AnnotationConfigApplicationContext

public ConfigurableApplicationContext run(String... args) {
	StopWatch stopWatch = new StopWatch();
	stopWatch.start();
	ConfigurableApplicationContext context = null;
	FailureAnalyzers analyzers = null;
	configureHeadlessProperty();
	SpringApplicationRunListeners listeners = getRunListeners(args);
	listeners.starting();
	try {
		ApplicationArguments applicationArguments = new DefaultApplicationArguments(
				args);
		ConfigurableEnvironment environment = prepareEnvironment(listeners,
				applicationArguments);
		Banner printedBanner = printBanner(environment);
		// 建立IOC容器,如果是web應用建立AnnotationConfigEmbeddedWebApplicationContext
		// 否則建立AnnotationConfigApplicationContext
		context = createApplicationContext();
		analyzers = new FailureAnalyzers(context);
		prepareContext(context, environment, listeners, applicationArguments,
				printedBanner);
		// 重新整理IOC容器,即建立並初始化容器
		refreshContext(context);
		afterRefresh(context, applicationArguments);
		listeners.finished(context, null);
		stopWatch.stop();
		if (this.logStartupInfo) {
			new StartupInfoLogger(this.mainApplicationClass)
					.logStarted(getApplicationLog(), stopWatch);
		}
		return context;
	}
	catch (Throwable ex) {
		handleRunFailure(context, listeners, analyzers, ex);
		throw new IllegalStateException(ex);
	}
}

3)、refresh(context);重新整理剛才建立好的ioc容器;

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // Prepare this context for refreshing.
        prepareRefresh();
        // Tell the subclass to refresh the internal bean factory.
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        // Prepare the bean factory for use in this context.
        prepareBeanFactory(beanFactory);
        try {
            // Allows post-processing of the bean factory in context subclasses.
            postProcessBeanFactory(beanFactory);
            // Invoke factory processors registered as beans in the context.
            invokeBeanFactoryPostProcessors(beanFactory);
            // Register bean processors that intercept bean creation.
            registerBeanPostProcessors(beanFactory);
            // Initialize message source for this context.
            initMessageSource();
            // Initialize event multicaster for this context.
            initApplicationEventMulticaster();

            // SpringBoot web的ioc容器重寫了onRefresh方法.
            onRefresh();
            // Check for listener beans and register them.
            registerListeners();
            // Instantiate all remaining (non-lazy-init) singletons.
            finishBeanFactoryInitialization(beanFactory);

            // Last step: publish corresponding event.
            finishRefresh();
        } catch (BeansException ex) {
           // 原始碼省略 ...                
        } 
    }
}

4)、onRefresh(); web的ioc容器重寫了onRefresh方法
5)、webIOC容器會建立嵌入式的Servlet容器;createEmbeddedServletContainer();
6)、獲取嵌入式的Servlet容器工廠:
    EmbeddedServletContainerFactory containerFactory = getEmbeddedServletContainerFactory();
從ioc容器中獲取EmbeddedServletContainerFactory 元件;TomcatEmbeddedServletContainerFactory建立
物件,後置處理器一看是這個物件,就獲取所有的定製器來先定製Servlet容器的相關配置;(注:參考

《SpringBoot系列之嵌入式servlet容器自動配置原理》
7)、使用容器工廠獲取嵌入式的Servlet容器:
    this.embeddedServletContainer = containerFactory.getEmbeddedServletContainer(getSelfInitializer());
8)、嵌入式的Servlet容器建立物件並啟動Servlet容器;
    先啟動嵌入式的Servlet容器,再將IOC容器中剩下沒有創建出的物件獲取出來;IOC容器啟動建立嵌入式的Servlet容器

嵌入式的Servlet容器在企業級應用中可能存在一定的侷限性,使用嵌入式Servlet容器:應用需打成可執行的jar
優點:簡單、便攜;
缺點:預設不支援JSP、
    優化定製比較複雜(使用定製器【ServerProperties、自定義EmbeddedServletContainerCustomizer】,自己編寫嵌入式Servlet容器的建立工廠【EmbeddedServletContainerFactory】);

在大部分的企業應用中我們可能將專案打成war包,容器的一些引數配置到外接容器上,接下來的文章將探討《外部Servlet容器啟動SpringBoot應用》