想必大家都体验过springboot的便捷,以前想要运行web项目,我们首先需要将项目打成war包,然后再运行Tomcat启动项目,不过自从有了springboot,我们可以像启动jar包一样简单的启动一个web项目,今天我们就来分析下springboot启动web项目整个流程。
分析springboot,万变不离其中,一样从启动方法作为入口
public ConfigurableApplicationContext run(String... args) {
context = createApplicationContext();//创建上下文
... 略
refreshContext(context);//上下文刷新
afterRefresh(context, applicationArguments);
... 略
}
这里我们引出了启动相关的两个核心方法 createApplicationContext 和 refreshContext
首先看下createApplicationContext实现:
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
contextClass = Class.forName(this.webEnvironment
? DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS);
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, "
+ "please specify an ApplicationContextClass",
ex);
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass);
}
我们可以看到context的类型判断逻辑,本文我们分析web容器,所以contextClass 为 DEFAULT_WEB_CONTEXT_CLASS
public static final String DEFAULT_WEB_CONTEXT_CLASS = "org.springframework."
+ "boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext";
故springboot 的web环境context类 为 AnnotationConfigEmbeddedWebApplicationContext
接着看refreshContext方法:
private void refreshContext(ConfigurableApplicationContext context) {
refresh(context);
... 略
}
AbstractApplicationContext的refresh方法
protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
((AbstractApplicationContext) applicationContext).refresh();
}
可以看到这里最终会调用到context的refresh方法,而我们的AnnotationConfigEmbeddedWebApplicationContext的集成关系图如下:
PS:集成关系过于复杂,这里截取了部分重点关系
而context的refresh则在AbstractApplicationContext中:
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
// 具体的刷新逻辑 交由子类实现
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();//容器刷新完成之后 启动容器
}
}
而onRefresh的具体实现在 EmbeddedWebApplicationContext中:
protected void onRefresh() {
super.onRefresh();
try {
//创建内嵌的servlet容器
createEmbeddedServletContainer();
}
catch (Throwable ex) {
throw new ApplicationContextException("Unable to start embedded container",
ex);
}
}
private void createEmbeddedServletContainer() {
EmbeddedServletContainer localContainer = this.embeddedServletContainer;
ServletContext localServletContext = getServletContext();
// 首次启动 容器为空
if (localContainer == null && localServletContext == null) {
EmbeddedServletContainerFactory containerFactory = getEmbeddedServletContainerFactory();//获取创建容器工厂类
this.embeddedServletContainer = containerFactory
.getEmbeddedServletContainer(getSelfInitializer());//创建容器
}
else if (localServletContext != null) {
try {
getSelfInitializer().onStartup(localServletContext);
}
catch (ServletException ex) {
throw new ApplicationContextException("Cannot initialize servlet context",
ex);
}
}
initPropertySources();
}
容器创建getEmbeddedServletContainer方法实现如下:
public EmbeddedServletContainer getEmbeddedServletContainer(
ServletContextInitializer... initializers) {
Tomcat tomcat = new Tomcat();//新建tomcat
File baseDir = (this.baseDirectory != null ? this.baseDirectory
: createTempDir("tomcat"));
tomcat.setBaseDir(baseDir.getAbsolutePath());
Connector connector = new Connector(this.protocol);//新建tomcat容器连接器
tomcat.getService().addConnector(connector);//将connector添加至tomcat
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 getTomcatEmbeddedServletContainer(tomcat);//返回tomcat内嵌容器
}
可以看出 通过onRefresh方法最终创建了类型为TomcatEmbeddedServletContainer的web容器,接着我们再来看容器的启动
finishRefresh由EmbeddedWebApplicationContext重载实现:
protected void finishRefresh() {
super.finishRefresh();
EmbeddedServletContainer localContainer = startEmbeddedServletContainer();//启动内嵌servlet容器
if (localContainer != null) {
publishEvent(
new EmbeddedServletContainerInitializedEvent(this, localContainer));
}
}
private EmbeddedServletContainer startEmbeddedServletContainer() {
EmbeddedServletContainer localContainer = this.embeddedServletContainer;
if (localContainer != null) {
localContainer.start();
}
return localContainer;
}
到此,springboot启动web容器流程,下一篇我们将分析tomcat的启动流程
敬请期待...