共计 8640 个字符,预计需要花费 22 分钟才能阅读完成。
一、前言
- Springboot 源码解析是一件大工程,逐行逐句的去钻研代码,会很干燥,也不容易坚持下去。
- 咱们不谋求大而全,而是试着每次去钻研一个小知识点,最终聚沙成塔,这就是咱们的 springboot 源码管中窥豹系列。
二、web 服务器
- 以前的的 spring 我的项目或者 springmvc 我的项目都须要一个 web 服务器,tomcat, 或者其它的
- 应用 springboot 之后,咱们不再须要配置 web 服务器,因为 springboot 帮咱们集成了
- 明天咱们来剖析一下源码,看看在哪里实现的,知其然知其所以然
三、源码剖析
- 还是从 SpringApplication 的 run 办法开始看
- 不相熟的能够看之前的文章:springboot 源码解析 - 管中窥豹系列之总体构造(一)
SpringApplication.java
public ConfigurableApplicationContext run(String... args) {
...
try {
...
refreshContext(context);
...
}
catch (Throwable ex) {...}
...
return context;
}
- 接着进入到 refreshContext(context) 外面
AbstractApplicationContext.java
@Override
public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {
...
try {
...
// Initialize other special beans in specific context subclasses.
onRefresh();
...
}
catch (BeansException ex) {...}
finally {...}
}
}
- 进入到 onRefresh() 办法
protected void onRefresh() throws BeansException {// For subclasses: do nothing by default.}
- 留神这个是一个 protected 办法,咱们进入到子实现外面
- 具体用的哪个 context,请看之前的文章:springboot 源码解析 - 管中窥豹系列之我的项目类型(二)
public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context."
+ "annotation.AnnotationConfigApplicationContext";
public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot."
+ "web.servlet.context.AnnotationConfigServletWebServerApplicationContext";
public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework."
+ "boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {switch (this.webApplicationType) {
case SERVLET:
contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
break;
case REACTIVE:
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
default:
contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException("Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
- 最罕用的就是一般 web 我的项目,咱们看这一个
- 咱们到 org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext 外面找 onRefresh() 办法
- 没找到,在父类 ServletWebServerApplicationContext 外面找到了
ServletWebServerApplicationContext.java
@Override
protected void onRefresh() {super.onRefresh();
try {createWebServer();
}
catch (Throwable ex) {throw new ApplicationContextException("Unable to start web server", ex);
}
}
- 咱们到 createWebServer() 办法外面
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();}
- 用的工厂模式,先找到工厂 getWebServerFactory()
- 再用工厂生成 webServer, factory.getWebServer(getSelfInitializer())
- 先看看 getWebServerFactory() 这个办法
protected ServletWebServerFactory getWebServerFactory() {
// Use bean names so that we don't consider the hierarchy
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);
}
- 获取惟一的工厂:ServletWebServerFactory,多了少了都不行
- 在哪加载进 springboot 的呢?
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<scope>compile</scope>
</dependency>
- spring-boot-starter-web 外面是蕴含了 spring-boot-starter 依赖的
- spring-boot-starter 外面蕴含了 spring-boot-autoconfigure 依赖
- spring-boot-autoconfigure 外面有一个类:ServletWebServerFactoryConfiguration
- 这个类外面有一个动态类: EmbeddedTomcat
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({Servlet.class, Tomcat.class, UpgradeProtocol.class})
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
static class EmbeddedTomcat {
@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;
}
}
- ConditionOnClass : 它依赖 Servlet.class, Tomcat.class, UpgradeProtocol.class
- ConditionalOnMissingBean:避免反复加载
- 至此,factory 怎么加载进 spring 就找到了
- 咱们多看一点,这个类 ServletWebServerFactoryConfiguration 还有两个动态类
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({Servlet.class, Server.class, Loader.class, WebAppContext.class})
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
static class EmbeddedJetty {
@Bean
JettyServletWebServerFactory JettyServletWebServerFactory(ObjectProvider<JettyServerCustomizer> serverCustomizers) {JettyServletWebServerFactory factory = new JettyServletWebServerFactory();
factory.getServerCustomizers().addAll(serverCustomizers.orderedStream().collect(Collectors.toList()));
return factory;
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({Servlet.class, Undertow.class, SslClientAuthMode.class})
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
static class EmbeddedUndertow {
@Bean
UndertowServletWebServerFactory undertowServletWebServerFactory(
ObjectProvider<UndertowDeploymentInfoCustomizer> deploymentInfoCustomizers,
ObjectProvider<UndertowBuilderCustomizer> builderCustomizers) {UndertowServletWebServerFactory factory = new UndertowServletWebServerFactory();
factory.getDeploymentInfoCustomizers()
.addAll(deploymentInfoCustomizers.orderedStream().collect(Collectors.toList()));
factory.getBuilderCustomizers().addAll(builderCustomizers.orderedStream().collect(Collectors.toList()));
return factory;
}
}
- 一个是生成 jetty 服务器工厂,一个是生成 undertow 服务器工厂
- 它们的加载,取决于依赖的 class 是否存在
- tomcat: Servlet.class, Tomcat.class, UpgradeProtocol.class
- jetty: Servlet.class, Server.class, Loader.class, WebAppContext.class
- undertow: Servlet.class, Undertow.class, SslClientAuthMode.class
如果咱们想换成 undertow 服务器,依赖改了就行了
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
如果咱们想换成 jetty 服务器,同理
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
- 思维拉回来,工厂有了,咱们看看工厂怎么生成的 webServer
TomcatServletWebServerFactory.java
@Override
public WebServer getWebServer(ServletContextInitializer... initializers) {if (this.disableMBeanRegistry) {Registry.disableRegistry();
}
Tomcat tomcat = new Tomcat();
File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
tomcat.setBaseDir(baseDir.getAbsolutePath());
Connector connector = new Connector(this.protocol);
connector.setThrowOnFailure(true);
tomcat.getService().addConnector(connector);
customizeConnector(connector);
tomcat.setConnector(connector);
tomcat.getHost().setAutoDeploy(false);
configureEngine(tomcat.getEngine());
for (Connector additionalConnector : this.additionalTomcatConnectors) {tomcat.getService().addConnector(additionalConnector);
}
prepareContext(tomcat.getHost(), initializers);
return getTomcatWebServer(tomcat);
}
- 这个办法咱们就不剖析了,就是生成 tomcat 服务器,和 spring 关联不大,改天咱们专门剖析 tomcat 源码
- 至此,整个 springboot 的加载 web 服务器过程就完了
欢送关注微信公众号:丰极,更多技术学习分享。
正文完