1. 程式人生 > >25 Servlet容器啟動原理

25 Servlet容器啟動原理

1 SpringBoot專案啟動

1.1 SpringBoot應用啟動執行run方法

  • Springboot21Application
@SpringBootApplication
public class Springboot21Application {

    public static void main(String[] args) {
        SpringApplication.run(Springboot21Application.class, args);
    }
}
  • SpringApplication
public
static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) { return (new SpringApplication(primarySources)).run(args); } public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context =
null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList(); this.configureHeadlessProperty(); SpringApplicationRunListeners listeners = this.getRunListeners(args); listeners.starting(); Collection exceptionReporters; try { ApplicationArguments applicationArguments =
new DefaultApplicationArguments(args); ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments); this.configureIgnoreBeanInfo(environment); Banner printedBanner = this.printBanner(environment); // 建立IOC容器 context = this.createApplicationContext(); exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context); this.prepareContext(context, environment, listeners, applicationArguments, printedBanner); /* SpringBoot重新整理IOC容器 建立IOC容器物件,並初始化容器 初始化容器: 建立容器中的每一個元件 */ 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); } ...... } 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); } } return (ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass); }
  • this.refreshContext(context) --> AbstractApplicationContext
public void refresh() throws BeansException, IllegalStateException {
	synchronized(this.startupShutdownMonitor) {
		this.prepareRefresh();
		ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
		this.prepareBeanFactory(beanFactory);

		try {
			this.postProcessBeanFactory(beanFactory);
			this.invokeBeanFactoryPostProcessors(beanFactory);
			this.registerBeanPostProcessors(beanFactory);
			this.initMessageSource();
			this.initApplicationEventMulticaster();
			
			// web的ioc容器重寫了onRefresh方法
			this.onRefresh();
			
			this.registerListeners();
			
			// 初始化IOC容器中剩餘的單例項元件,eg:@Controller ,@Service
			this.finishBeanFactoryInitialization(beanFactory);
			this.finishRefresh();
		} catch (BeansException var9) {
			if (this.logger.isWarnEnabled()) {
				this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
			}

			this.destroyBeans();
			this.cancelRefresh(var9);
			throw var9;
		} finally {
			this.resetCommonCaches();
		}
	}
}
  • 重寫onRefresh方法的容器
    重寫onRefresh方法的容器

1.2 web的IOC容器會建立嵌入式的Servlet容器;createWebServer();

protected void onRefresh() {
	super.onRefresh();

	try {
		this.createWebServer();
	} catch (Throwable var2) {
		throw new ApplicationContextException("Unable to start web server", var2);
	}
}

1.3 獲取嵌入式的Servlet容器工廠

private void createWebServer() {
	WebServer webServer = this.webServer;
	ServletContext servletContext = this.getServletContext();
	if (webServer == null && servletContext == null) {
	
		// 獲取嵌入式的Servlet容器工廠
		ServletWebServerFactory factory = this.getWebServerFactory();
		this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()});
	} else if (servletContext != null) {
		try {
			this.getSelfInitializer().onStartup(servletContext);
		} catch (ServletException var4) {
			throw new ApplicationContextException("Cannot initialize servlet context", var4);
		}
	}

	this.initPropertySources();
}
  • getWebServerFactory()
protected ServletWebServerFactory getWebServerFactory() {
	String[] beanNames = this.getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class);
	if (beanNames.length == 0) {
		throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean.");
	} else if (beanNames.length > 1) {
		throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to multiple ServletWebServerFactory beans : " + StringUtils.arrayToCommaDelimitedString(beanNames));
	} else {
		return (ServletWebServerFactory)this.getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);
	}
}

在這裡插入圖片描述

​從ioc容器中獲取TomcatServletWebServerFactory 並建立物件,後置處理器識別物件,然後獲取所有的定製器來先定製Servlet容器的相關配置,詳見24 Servlet容器配置原理

1.4 使用容器工廠獲取嵌入式的Servlet容器

1.5 嵌入式的Servlet容器建立物件並啟動Servlet容器;

1.6 先啟動嵌入式的Servlet容器,再將ioc容器中剩下沒有創建出的物件獲取出來

1.7 IOC容器啟動建立嵌入式的Servlet容器