SpringBoot-嵌入式Servlet容器原理
WebServerFactory自动配置
@Configuration
@AutoConfigureOrder(-2147483648)
@ConditionalOnClass({ServletRequest.class})
@ConditionalOnWebApplication(
type = Type.SERVLET
)
@EnableConfigurationProperties({ServerProperties.class})
@Import({ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class, EmbeddedTomcat.class, EmbeddedJetty.class, EmbeddedUndertow.class})
public class ServletWebServerFactoryAutoConfiguration {
// Servlet Web Server 通用配置,将ServerProperties注入到定制器中,实现application.properties中的配置信息配置 Servlet Web Server
@Bean
public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties) {
return new ServletWebServerFactoryCustomizer(serverProperties);
}
// Tomcat Servlet Web Server 配置信息
@Bean
@ConditionalOnClass(
name = {"org.apache.catalina.startup.Tomcat"}
)
public TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer(ServerProperties serverProperties) {
return new TomcatServletWebServerFactoryCustomizer(serverProperties);
}
}
EmbeddedTomcat 嵌入式Tomcat
@Configuration
// 判断当前是否引入了 org.apache.catalina.startup.Tomcat 依赖
@ConditionalOnClass({Servlet.class, Tomcat.class, UpgradeProtocol.class})
// 当没有 ServletWebServerFactory 类型的Bean时才注入该组件
@ConditionalOnMissingBean(
value = {ServletWebServerFactory.class},
search = SearchStrategy.CURRENT
)
public static class EmbeddedTomcat {
public EmbeddedTomcat() {
}
// 创建Tomcat容器工厂
@Bean
public TomcatServletWebServerFactory tomcatServletWebServerFactory() {
return new TomcatServletWebServerFactory();
}
}
ServletWebServerFactory(Servlet容器工厂) 继承关系

@FunctionalInterface
public interface ServletWebServerFactory {
// 创建WebServer即Servlet容器
WebServer getWebServer(ServletContextInitializer... initializers);
}
WebServer (Servlet容器) 继承关系

public interface WebServer {
void start() throws WebServerException;
void stop() throws WebServerException;
int getPort();
}
TomcatServletWebServerFactory 获得Tomcat Servlet 容器(即org.apache.catalina.startup.Tomcat)
public WebServer getWebServer(ServletContextInitializer... initializers) {
// 创建Tomcat容器
Tomcat tomcat = new Tomcat();
// 配置Tomcat运行环境
File baseDir = this.baseDirectory != null ? this.baseDirectory : this.createTempDir("tomcat");
tomcat.setBaseDir(baseDir.getAbsolutePath());
Connector connector = new Connector(this.protocol);
tomcat.getService().addConnector(connector);
this.customizeConnector(connector);
tomcat.setConnector(connector);
tomcat.getHost().setAutoDeploy(false);
this.configureEngine(tomcat.getEngine());
Iterator var5 = this.additionalTomcatConnectors.iterator();
while(var5.hasNext()) {
Connector additionalConnector = (Connector)var5.next();
tomcat.getService().addConnector(additionalConnector);
}
this.prepareContext(tomcat.getHost(), initializers);
// 调用 tomcat.start(); 启动容器
return this.getTomcatWebServer(tomcat);
}
修改Servlet容器配置信息的方式
1)修改application.properties
server.port=8888
2) 添加定制器
package com.wjz.config;
import org.springframework.boot.web.server.ConfigurableWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.stereotype.Component;
@Component
public class WebServerConfig implements WebServerFactoryCustomizer<ConfigurableWebServerFactory> {
@Override
public void customize(ConfigurableWebServerFactory factory) {
factory.setPort(8888);
}
}
定制器后置处理器
public class WebServerFactoryCustomizerBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof WebServerFactory) {
this.postProcessBeforeInitialization((WebServerFactory)bean);
}
return bean;
}
private void postProcessBeforeInitialization(WebServerFactory webServerFactory) {
((Callbacks)LambdaSafe.callbacks(WebServerFactoryCustomizer.class, this.getCustomizers(), webServerFactory, new Object[0]).withLogger(WebServerFactoryCustomizerBeanPostProcessor.class)).invoke((customizer) -> {
customizer.customize(webServerFactory);
});
}
private Collection<WebServerFactoryCustomizer<?>> getCustomizers() {
if (this.customizers == null) {
this.customizers = new ArrayList(this.getWebServerFactoryCustomizerBeans());
this.customizers.sort(AnnotationAwareOrderComparator.INSTANCE);
this.customizers = Collections.unmodifiableList(this.customizers);
}
return this.customizers;
}
private Collection<WebServerFactoryCustomizer<?>> getWebServerFactoryCustomizerBeans() {
return this.beanFactory.getBeansOfType(WebServerFactoryCustomizer.class, false, false).values();
}
}
Servlet容器启动流程
什么时候创建ServletWebServerFactory(Servlet容器工厂),什么时候创建 WebServer (Servlet容器)并启动?
1)EmbeddedTomcat.TomcatServletWebServerFactory处和TomcatServletWebServerFactory#getWebServer()处打断点,debug方式启动系统
2)创建SpringApplication对象并执行run()方法
3)context = this.createApplicationContext(); this.refreshContext(context); SpringBoot刷新IOC容器即创建IOC容器对象并初始化容器,创建容器中的每一个组件
如果是Web环境创建AnnotationConfigServletWebServerApplicationContext,否则创建默认的IOC容器AnnotationConfigApplicationContext
4)this.refresh(context); 刷新刚创建好的IOC容器即执行IOC容器的refresh()方法
5)this.onRefresh(); Web容器会创建嵌入式Servlet Web Server容器(参见ServletWebServerApplicationContext)
6)ServletWebServerFactory factory = this.getWebServerFactory(); 创建ServletWebServerFactory(Servlet容器工厂),后置处理器工作获取所有的定制器定制Servlet容器的相关配置
7)this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()}); 创建 WebServer (Servlet容器)并启动
外部Servlet容器&支持JSP
1)创建一个war项目
2)嵌入式Tomcat依赖指定为provided
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
3)编写一个SpringBootServletInitializer的子类并复写configure方法
package com.wjz.springboot;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
public class ServletInitializer extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(SpringBootJspApplication.class);
}
}
4)启动外部Tomcat
外部Servlet容器启动流程
1)Servlet3.0的一个规范,容器启动时会创建每一个应用实现了javax.servlet.ServletContainerInitializer的实例
2)寻找各个应用每个jar包路径 META-INF/services/ 路径下的文件,文件名为 javax.servlet.ServletContainerInitializer,内容是实现类的全类名,参考 spring-web jar包下对应的路径文件
org.springframework.web.SpringServletContainerInitializer
3)还可以使用@HandlesTypes注解,在容器启动时传入类
4)SpringServletContainerInitializer将@HandlesTypes({WebApplicationInitializer.class})标注的这个类型的所有类传入到onStartup方法的Set<Class<?>>中,
将这些类型创建实例且调用各自的onStartup方法

相当于SpringBootServletInitializer类会创建对象并调用onStartup方法,该方法中会创建IOC容器
public void onStartup(ServletContext servletContext) throws ServletException {
this.logger = LogFactory.getLog(this.getClass());
// 创建IOC容器
WebApplicationContext rootAppContext = this.createRootApplicationContext(servletContext);
if (rootAppContext != null) {
servletContext.addListener(new ContextLoaderListener(rootAppContext) {
public void contextInitialized(ServletContextEvent event) {
}
});
} else {
this.logger.debug("No ContextLoaderListener registered, as createRootApplicationContext() did not return an application context");
}
}

浙公网安备 33010602011771号