springboot中如何嵌入servlet容器以及容器啓動過程

  最近在學習springboot,抽空記錄一下,加強記憶。

springboot兼容Tomcat,jetty,undertow容器,默認兼容Tomcat容器,因爲spring-boot-starter-web包含tomcat,因此需要使用的時候,需要先把tomcat排除,再引入其他容器,如下:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
	<exclusions>
		<exclusion>
			<artifactId>spring-boot-starter-tomcat</artifactId>
			<groupId>org.springframework.boot</groupId>
		</exclusion>
	</exclusions>
</dependency>
<dependency>
	<artifactId>spring-boot-starter-jetty</artifactId>
	<groupId>org.springframework.boot</groupId>
</dependency>

 現在分成2部分,容器注入方式和容器使用

  1. ServletWebServerFactoryConfiguration是配置類,裏面的@Bean會被自動注入到spring容器中,通過@ConditionalOnClass來判斷應該注入哪個servlet容器
    @Configuration(proxyBeanMethods = false)
    @ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })//如果系統中存在tomcat相關類,引入tomcat內嵌servlet容器
    @ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
    static class EmbeddedTomcat {
    //自動注入TomcatServletWebServerFactory
    @Bean
    TomcatServletWebServerFactory tomcatServletWebServerFactory(ObjectProvider<TomcatConnectorCustomizer> connectorCustomizers,ObjectProvider<TomcatContextCustomizer> contextCustomizers,
    		ObjectProvider<TomcatProtocolHandlerCustomizer<?>> protocolHandlerCustomizers) {
    	TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
    	factory.getTomcatConnectorCustomizers().addAll(connectorCustomizers.orderedStream().collect(Collectors.toList()));
    	factory.getTomcatContextCustomizers().addAll(contextCustomizers.orderedStream().collect(Collectors.toList()));
    	factory.getTomcatProtocolHandlerCustomizers().addAll(protocolHandlerCustomizers.orderedStream().collect(Collectors.toList()));
    	return factory;
    }
    
    
    @Configuration(proxyBeanMethods = false)
    @ConditionalOnClass({ Servlet.class, Server.class, Loader.class, WebAppContext.class })//如果系統中存在Jetty相關類,引入Jetty內嵌servlet容器
    @ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
    static class EmbeddedJetty {

    2.springBoot啓動時通過SpringApplication.run方法,最終調用onRefresh()方法,取得TomcatServletWebServerFactory,啓動容器

    @Override
    protected void onRefresh() {
    	super.onRefresh();
    	try {
    		createWebServer();//創建servlet容器
    	}
    	catch (Throwable ex) {
    		throw new ApplicationContextException("Unable to start web server", ex);
    	}
    }
    
    private void createWebServer() {
    	WebServer webServer = this.webServer;
    	ServletContext servletContext = getServletContext();
    	if (webServer == null && servletContext == null) {
    		ServletWebServerFactory factory = getWebServerFactory();
    		this.webServer = factory.getWebServer(getSelfInitializer());
    	}
    	else if (servletContext != null) {
    		try {
    			getSelfInitializer().onStartup(servletContext);
    		}
    		catch (ServletException ex) {
    			throw new ApplicationContextException("Cannot initialize servlet context", ex);
    		}
    	}
    	initPropertySources();
    }
    
    protected ServletWebServerFactory getWebServerFactory() {
    	// Use bean names so that we don't consider the hierarchy
    	//ServletWebServerFactory.class的實現類正是:TomcatServletWebServerFactory,JettyServletWebServerFactory,UndertowServletWebServerFactory
    	String[] beanNames = getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class);
    	if (beanNames.length == 0) {
    		throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to missing "
    				+ "ServletWebServerFactory bean.");
    	}
    	if (beanNames.length > 1) {
    		throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to multiple "
    				+ "ServletWebServerFactory beans : " + StringUtils.arrayToCommaDelimitedString(beanNames));
    	}
    	return getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);
    }

     

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章