我们SpringBoot应用都是通过SpringApplication.run()这一行代码启动起来的,那么我们有理由怀疑实现逻辑就在这个里面
应用跑起来-run()
public ConfigurableApplicationContext run(String... args) {
// 省略代码
...
ConfigurableApplicationContext context = null;
// 省略代码
...
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 准备上下文环境
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
// 配置忽略的Bean信息
configureIgnoreBeanInfo(environment);
// 打印Banner信息
Banner printedBanner = printBanner(environment);
// 创建ioc容器
context = createApplicationContext();
// 准备ioc容器【核心】
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// 刷新ioc容器
refreshContext(context);
// 省略代码
...
}
// 省略代码
...
return context;
}
刷新ioc容器-refreshContext()
private void refreshContext(ConfigurableApplicationContext context) {
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
}
catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
// 进一步调用 refresh()
refresh((ApplicationContext) context);
}
protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(ConfigurableApplicationContext.class, applicationContext);
// 进一步调用 refresh()
refresh((ConfigurableApplicationContext) applicationContext);
}
// 调用 ConfigurableApplicationContext 的refresh()
protected void refresh(ConfigurableApplicationContext applicationContext) {
applicationContext.refresh();
}
我们可以发现最终调用了ConfigurableApplicationContext 的refresh()来完成刷新容器的操作
ServletWebServerApplicationContext
public final void refresh() throws BeansException, IllegalStateException {
try {
// 调用父类的 refresh()
super.refresh();
}
catch (RuntimeException ex) {
// 如果出现异常,并且web服务器创建好了,就会停止当前web服务器
WebServer webServer = this.webServer;
if (webServer != null) {
webServer.stop();
}
throw ex;
}
}
AbstractApplicationContext
Spring容器刷新经典12大步
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
// 1、准备刷新
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
// 2、获取一个BeanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
// 3、准备BeanFactory
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
// 4、BeanFactory的后置处理【留给子类的扩展】
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
// 5、执行BeanFactory的后置处理器
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
// 6、注册Bean的后置处理器
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
// 7、初始化MessageSource【国际化相关】
initMessageSource();
// Initialize event multicaster for this context.
// 8、初始化事件派发工具
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
// 9、刷新【留给子类的扩展点,重点关注】
onRefresh();
// Check for listener beans and register them.
// 10、注册监听器
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
// 11、完成BeanFactory的初始化工作【实例化剩下的单实例Bean】
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
// 12、刷新完成【发布事件】
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
// 重置缓存
resetCommonCaches();
}
}
}
我们重点关注第9步 onRefresh(),因为这是留给子类的扩展点
子类ioc容器的扩展点-onRefresh()
ServletWebServerApplicationContext
protected void onRefresh() {
// 1、调用父类的 onRefresh()
super.onRefresh();
try {
// 2、创建Web服务器
createWebServer();
}
catch (Throwable ex) {
throw new ApplicationContextException("Unable to start web server", ex);
}
}
创建Web服务器-createWebServer()
这里拿到的服务器工厂默认是Tomcat的,所以会创建出Tomcat服务器的实例然后启动
因为我们引入的starter-web里默认引入的就是Tomcat的jar包
private void createWebServer() {
// 1、拿到Web服务器【刚开始肯定是null,因为我们还没创建呢】
WebServer webServer = this.webServer;
// 2、拿到ServletContext【刚开始也是null】
ServletContext servletContext = getServletContext();
if (webServer == null && servletContext == null) {
// 3、从容器中得到一个Web服务器的工厂【ServletWebServerFactory】
ServletWebServerFactory factory = getWebServerFactory();
// 4、使用工厂来创建Web服务器
this.webServer = factory.getWebServer(getSelfInitializer());
getBeanFactory().registerSingleton("webServerGracefulShutdown",
new WebServerGracefulShutdownLifecycle(this.webServer));
getBeanFactory().registerSingleton("webServerStartStop",
new WebServerStartStopLifecycle(this, this.webServer));
}
else if (servletContext != null) {
try {
// 遍历所有的ServletContextInitializer调用其onStartup()来启动
getSelfInitializer().onStartup(servletContext);
}
catch (ServletException ex) {
throw new ApplicationContextException("Cannot initialize servlet context", ex);
}
}
initPropertySources();
}
getWebServer()
public WebServer getWebServer(ServletContextInitializer... initializers) {
if (this.disableMBeanRegistry) {
Registry.disableRegistry();
}
// 1、直接创建一个Tomcat服务器
Tomcat tomcat = new Tomcat();
// 2、设置一些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);
// 3、得到一个Tomcat服务器【会启动Tomcat服务器】
return getTomcatWebServer(tomcat);
}
protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
return new TomcatWebServer(tomcat, getPort() >= 0, getShutdown());
}
创建一个TomcatWebServer,用来封装Tomat实例
public TomcatWebServer(Tomcat tomcat, boolean autoStart, Shutdown shutdown) {
Assert.notNull(tomcat, "Tomcat Server must not be null");
this.tomcat = tomcat;
this.autoStart = autoStart;
this.gracefulShutdown = (shutdown == Shutdown.GRACEFUL) ? new GracefulShutdown(tomcat) : null;
// 初始化:启动Tomcat
initialize();
}
private void initialize() throws WebServerException {
logger.info("Tomcat initialized with port(s): " + getPortsDescription(false));
synchronized (this.monitor) {
try {
// 省略代码
...
// 启动tomcat
this.tomcat.start();
// 省略代码
...
}
catch (Exception ex) {
// 出现异常就停止、销毁Tomcat
stopSilently();
destroySilently();
throw new WebServerException("Unable to start embedded Tomcat", ex);
}
}
}
到这里Tomcat就创建并启动成功了。
如何切换Web服务器
案例:切换Web服务器为Jetty。
我们知道了内嵌服务器的原理,它是通过不同的Web服务器工厂来创建出不同的Web服务器实例,然后启动。
Web服务器工厂通过条件注解进行注册到容器中,然后从容器中拿到Web服务器工厂,也就是导入不同的jar包就会注册不同的Web服务器工厂。所以我们只需要把tomcat的jar包替换为jetty的jar包即可完成切换。
Tomcat的jar包是在starter-web中引入的:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>2.3.12.RELEASE</version>
<scope>compile</scope>
</dependency>
我们只需要把这个jar包排除,然后加上jetty的jar包即可实现,SpringBoot帮我们把一切都在底层配置好了
<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>
再次启动,会发现已经切换成功了:
这里从容器中拿到的Web服务器工厂就是Jetty的了:
总结
我们发现内嵌Tomcat服务器的本质其实是:通过Web服务器工厂创建一个Tomcat实例,然后调用其start()来启动。
其它服务器也是一样的道理
// 1、web服务器工厂创建服务器实例
factory.getWebServer(getSelfInitializer())
// 2、创建
Tomcat tomcat = new Tomcat();
// 启动
tomcat.start();
Web服务器工厂如何被注册到容器中的?
使用ServletWebServerFactoryAutoConfiguration自动配置类
利用@Import()机制给容器中导入组件,然后通过@ConditonalOnxxx()条件注解给容器中导入不同的Web服务器工厂
@Configuration(proxyBeanMethods = false)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnClass(ServletRequest.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(ServerProperties.class)
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {
}
// 嵌入式的Tomcat
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
static class EmbeddedTomcat {
// Tomcat Web服务器工厂
@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;
}
}
// 嵌入式的Jetty
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Servlet.class, Server.class, Loader.class, WebAppContext.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
static class EmbeddedJetty {
// Jetty Web服务器工厂
@Bean
JettyServletWebServerFactory JettyServletWebServerFactory(
ObjectProvider<JettyServerCustomizer> serverCustomizers) {
JettyServletWebServerFactory factory = new JettyServletWebServerFactory();
factory.getServerCustomizers().addAll(serverCustomizers.orderedStream().collect(Collectors.toList()));
return factory;
}
}
// 嵌入式的Undertow
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Servlet.class, Undertow.class, SslClientAuthMode.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
static class EmbeddedUndertow {
// Undertow Web服务器工厂
@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;
}
}
WebServerFactory
用来创建Web服务器的工厂
WebServer
Web服务器
WebServer实际是调用具体的服务器实例来做的:Tomcat、Jetty、Undertow
public class Tomcat {}
public class Jetty {}
ioc容器