springboot启动的时候,怎么勾起tomcat启动?
springboot加载工程,到底是怎么启动的,我知道springboot中加了一个tomcat的源码,可是这个tomcat是怎么启动的呢?
spring的启动是从一个java类的main函数开始的,这个应该没有异议:
public static void main(String[] args) {
SpringApplication application = new SpringApplication(App.class);
application.run(args);
}
A: 首先是初始化
启动新建的类
public SpringApplication(Object... sources) {
initialize(sources);
}
private final Set<Object> sources = new LinkedHashSet<Object>();
@SuppressWarnings({ "unchecked", "rawtypes" })
private void initialize(Object[] sources) {
if (sources != null && sources.length > 0) {
this.sources.addAll(Arrays.asList(sources));
}
//推断是否是WEB环境
this.webEnvironment = deduceWebEnvironment();
//应用上下文初始化实例 的加载
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
//监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//推断出启动类
this.mainApplicationClass = deduceMainApplicationClass();
}
推断是否是WEB环境的判断就是,看看能否加出来:
private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet",
"org.springframework.web.context.ConfigurableWebApplicationContext" };
这里的类。
然后就是初始化监听器和初始化工厂,这部分不关心。
4 ******** 非常精彩的代码*********
根据运行的堆栈,查找到启动的类!
private Class<?> deduceMainApplicationClass() {
try {
StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
for (StackTraceElement stackTraceElement : stackTrace) {
if ("main".equals(stackTraceElement.getMethodName())) {
return Class.forName(stackTraceElement.getClassName());
}
}
}
catch (ClassNotFoundException ex) {
// Swallow and continue
}
return null;
}
B: 找到具体的main方法所在的类,然后就是run方法了:
/**
* Run the Spring application, creating and refreshing a new
* {@link ApplicationContext}.
* @param args the application arguments (usually passed from a Java main method)
* @return a running {@link ApplicationContext}
*/
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
configureHeadlessProperty();
// listeners 发不的是application启动的event
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.started();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
// 创建执行的上下文环境
context = createAndRefreshContext(listeners, applicationArguments);
afterRefresh(context, applicationArguments);
listeners.finished(context, null);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
return context;
}
catch (Throwable ex) {
handleRunFailure(context, listeners, ex);
throw new IllegalStateException(ex);
}
}
————————————————————————————————————
- 创建并且刷新配置上下文:
private ConfigurableApplicationContext createAndRefreshContext(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
ConfigurableApplicationContext context;
// Create and configure the environment
ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, applicationArguments.getSourceArgs());
listeners.environmentPrepared(environment);
if (isWebEnvironment(environment) && !this.webEnvironment) {
environment = convertToStandardEnvironment(environment);
}
//打印Spring boot的流程
if (this.bannerMode != Banner.Mode.OFF) {
printBanner(environment);
}
// Create, load, refresh and run the ApplicationContext
context = createApplicationContext();
context.setEnvironment(environment);
postProcessApplicationContext(context);
applyInitializers(context);
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
context.getBeanFactory().registerSingleton("springApplicationArguments",
applicationArguments);
// Load the sources
Set<Object> sources = getSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[sources.size()]));
listeners.contextLoaded(context);
// Refresh the context
refresh(context);
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
}
catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
return context;
}
2.3 // refresh(context);
最主要的调用的方法
protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
((AbstractApplicationContext) applicationContext).refresh();
}
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
。。。。。。。。。。
try {
。。。。。。。。。。。。。。。
// Initialize other special beans in specific context subclasses.
onRefresh(); //启动tomcat开始
。。。。。。。。。。。。。
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
。。。。。。。。。。。。
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
创建servlet容器的过程:
@Override
protected void onRefresh() {
super.onRefresh();
try {
createEmbeddedServletContainer();//创建servlet的容器
}
catch (Throwable ex) {
throw new ApplicationContextException("Unable to start embedded container",
ex);
}
}
// 创建servlet的容器
private void createEmbeddedServletContainer() {
EmbeddedServletContainer localContainer = this.embeddedServletContainer; //servlet的容器的具有的特征:start,stop,getport
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();
}
具体运行的过程中的servlet的容器建造类:
新建tomcat servlet 容器的时候,直接的把tomcat启动!!
public TomcatEmbeddedServletContainer(Tomcat tomcat, boolean autoStart) {
Assert.notNull(tomcat, "Tomcat Server must not be null");
this.tomcat = tomcat;
this.autoStart = autoStart;
initialize();
}
private synchronized void initialize() throws EmbeddedServletContainerException {
TomcatEmbeddedServletContainer.logger
.info("Tomcat initialized with port(s): " + getPortsDescription(false));
try {
addInstanceIdToEngineName();
// Remove service connectors to that protocol binding doesn't happen yet
removeServiceConnectors();
// Start the server to trigger initialization listeners
this.tomcat.start();
// We can re-throw failure exception directly in the main thread
rethrowDeferredStartupExceptions();
// Unlike Jetty, all Tomcat threads are daemon threads. We create a
// blocking non-daemon to stop immediate shutdown
startDaemonAwaitThread();
}
catch (Exception ex) {
throw new EmbeddedServletContainerException("Unable to start embedded Tomcat",
ex);
}
}
this.tomcat.start() 这个算是将tomcat启动:
2018-01-02 19:06:05.426 [main] INFO o.s.b.c.e.tomcat.TomcatEmbeddedServletContainer - Tomcat initialized with port(s): 20011 (http)
2018-01-02 19:06:07.534 [main] INFO org.apache.catalina.core.StandardService - Starting service Tomcat
2018-01-02 19:06:07.542 [main] INFO org.apache.catalina.core.StandardEngine - Starting Servlet Engine: Apache Tomcat/8.0.32
2018-01-02 19:06:07.721 [localhost-startStop-1] INFO o.a.c.core.ContainerBase.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext
2018-01-02 19:06:07.722 [localhost-startStop-1] INFO org.springframework.web.context.ContextLoader - Root WebApplicationContext: initialization completed in 11890 ms
2018-01-02 19:06:07.982 [localhost-startStop-1] INFO o.s.boot.context.embedded.ServletRegistrationBean - Mapping servlet: 'dispatcherServlet' to [/]
2018-01-02 19:06:07.987 [localhost-startStop-1] INFO o.s.boot.context.embedded.FilterRegistrationBean - Mapping filter: 'characterEncodingFilter' to: [/*]
2018-01-02 19:06:07.988 [localhost-startStop-1] INFO o.s.boot.context.embedded.FilterRegistrationBean - Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2018-01-02 19:06:07.988 [localhost-startStop-1] INFO o.s.boot.context.embedded.FilterRegistrationBean - Mapping filter: 'httpPutFormContentFilter' to: [/*]
2018-01-02 19:06:07.988 [localhost-startStop-1] INFO o.s.boot.context.embedded.FilterRegistrationBean - Mapping filter: 'requestContextFilter' to: [/*]
总结来说:springboot在运行的过程中,确定是web体系,找到main类的run方法,执行的过程中 确定了:org.springframework.boot.context.embedded.EmbeddedWebApplicationContext 上下文环境,在创建Servlet容器的时候,新建Tomcat对象,初始化的时候,直接启动tomcat。
- 上一篇 问题总结(一)
- 下一篇 netty in action 读书笔记