SpringBoot内置Tomcat启动原理源码分析
1、获取SpringBoot内置Tomcat自动配置类:
在SpringBoot项目中引入spring-boot-starter-web依赖,就默认使用Tomcat容器,该依赖中引入spring-boot-starter-tomcat、spring-webmvc,就引入了tomtcat核心依赖和springMvc相关jar包,这样就间接地引入了tomcat。
在执行SpringBoot项目启动类的main()方法,启动SpringBoot项目的过程中会加载各个jar包下META-INF/spring.factories的文件,在该文件中包含着自动配置的子路径,在refresh()方法中的invokeBeanFactoryPostProcessors()中首先会对启动类上的 @SpringBootApplication 注解进行解析,最终调用 AutoConfigurationImportSelector类中的 getAutoConfigurationEntry() 加载 META-INF/spring.factories 文件中的自动配置类,得到自动配置类的全路径,其中 org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration 为tomcat自动配置类。
具体加载流程见: springBoot-启动原理
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } AnnotationAttributes attributes = getAttributes(annotationMetadata); // 1、得到META-INF/spring.factories文件中配置的所有自动配置类 List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); // 移除重复的配置类 configurations = removeDuplicates(configurations); // 获取需要排除的自动配置类,eg:注解属性中的exculde的配置类 Set<String> exclusions = getExclusions(annotationMetadata, attributes); // 检查需要被排除的配置类,因为有些不是自动配置类,需要抛异常 checkExcludedClasses(configurations, exclusions); // 移除需要排除的配置类 configurations.removeAll(exclusions); // 根据 META-INF/spring-autoconfigure-metadata.properties 中配置的规则过虑掉一部分配置类(根据@ConditionalOnXXX注解进行过滤) configurations = getConfigurationClassFilter().filter(configurations); // 获取符合条件的配置类后,触发 AutoConfigurationImportEvent 事件 fireAutoConfigurationImportEvents(configurations, exclusions); // 将符合条件和需要排除的配置类封装进 AutoConfigurationEntry 对象中返回 return new AutoConfigurationEntry(configurations, exclusions); }
2、ServletWebServerFactoryAutoConfiguration - tomcat自动配置类分析
3、创建tomcat工厂
@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) { // 创建生产tomcat的工厂 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; } }
4、创建tomcat容器
在SpringBoot启动过程中会调用 AbstractApplicationContext.refresh() 方法,在该方法会调用onRefresh()方法,这个方法是个模板方法,最终会交给子类实现,在使用内置tomcat的SpringBoot项目中,最终会调用 ServletWebServerApplicationContext 实现(AbstractApplicationContext是GenericWebApplicationContext,ServletWebServerApplicationContext 是GenericWebApplicationContext),最终调用ServletWebServerApplicationContext 的createWebServer()方法创建 webServer。
@Configuration(proxyBeanMethods = false) @ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class }) @ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT) protected void onRefresh() { // 调用 GenericWebApplicationContext类的 onRefresh() 方法, super.onRefresh(); try { // 获取嵌入式的Servlet容器工厂(TomcatServletWebServerFactory),并通过工厂来获取Servlet容器 createWebServer(); } catch (Throwable ex) { throw new ApplicationContextException("Unable to start web server", ex); } } private void createWebServer() { WebServer webServer = this.webServer; ServletContext servletContext = getServletContext(); if (webServer == null && servletContext == null) { StartupStep createWebServer = this.getApplicationStartup().start("spring.boot.webserver.create"); // 获取 Servlet容器工厂 ServletWebServerFactory factory = getWebServerFactory(); createWebServer.tag("factory", factory.getClass().toString()); // 通过Servlet容器工厂加载tomcat并启动tomcat this.webServer = factory.getWebServer(getSelfInitializer()); createWebServer.end(); getBeanFactory().registerSingleton("webServerGracefulShutdown", new WebServerGracefulShutdownLifecycle(this.webServer)); getBeanFactory().registerSingleton("webServerStartStop", new WebServerStartStopLifecycle(this, this.webServer)); } else if (servletContext != null) { try { getSelfInitializer().onStartup(servletContext); } catch (ServletException ex) { throw new ApplicationContextException("Cannot initialize servlet context", ex); } } initPropertySources(); } 在 TomcatServletWebServerFactory 类中 @Override public WebServer getWebServer(ServletContextInitializer... initializers) { if (this.disableMBeanRegistry) { Registry.disableRegistry(); } // 实例化tomcat Tomcat tomcat = new Tomcat(); File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat"); // 设置tomcat临时工作目录 tomcat.setBaseDir(baseDir.getAbsolutePath()); // 默认使用 org.apache.coyote.http11.Http11NioProtocol 实例化Connector Connector connector = new Connector(this.protocol); connector.setThrowOnFailure(true); // 给service添加Connector tomcat.getService().addConnector(connector); customizeConnector(connector); tomcat.setConnector(connector); // 关闭热部署 tomcat.getHost().setAutoDeploy(false); // 配置 Engine configureEngine(tomcat.getEngine()); for (Connector additionalConnector : this.additionalTomcatConnectors) { tomcat.getService().addConnector(additionalConnector); } prepareContext(tomcat.getHost(), initializers); // 实例化 TomcatWebServer,将 DispatcherServlet 以及一些Filter添加到Tomcat中 return getTomcatWebServer(tomcat); } protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) { return new TomcatWebServer(tomcat, getPort() >= 0, getShutdown()); } //TomcatWebServer类的构造方法 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; initialize(); } private void initialize() throws WebServerException { logger.info("Tomcat initialized with port(s): " + getPortsDescription(false)); synchronized (this.monitor) { try { addInstanceIdToEngineName(); Context context = findContext(); context.addLifecycleListener((event) -> { if (context.equals(event.getSource()) && Lifecycle.START_EVENT.equals(event.getType())) { // Remove service connectors so that protocol binding doesn't // happen when the service is started. removeServiceConnectors(); } }); // Start the server to trigger initialization listeners //利用LifecycleBase对这一套容器(engine,host,context及wrapper)进行启动并发布configure_start、 // before_init、after_start的lifecycleEvent等事件给相应的监听器 // 本方法并没有启动tomcat this.tomcat.start(); // We can re-throw failure exception directly in the main thread rethrowDeferredStartupExceptions(); try { ContextBindings.bindClassLoader(context, context.getNamingToken(), getClass().getClassLoader()); } catch (NamingException ex) { // Naming is not enabled. Continue } // Unlike Jetty, all Tomcat threads are daemon threads. We create a // blocking non-daemon to stop immediate shutdown startDaemonAwaitThread(); } catch (Exception ex) { stopSilently(); destroySilently(); throw new WebServerException("Unable to start embedded Tomcat", ex); } } } // Tomcat类 public void start() throws LifecycleException { getServer(); server.start(); } // LifecycleBase public final synchronized void start() throws LifecycleException { if (LifecycleState.STARTING_PREP.equals(state) || LifecycleState.STARTING.equals(state) || LifecycleState.STARTED.equals(state)) { if (log.isDebugEnabled()) { Exception e = new LifecycleException(); log.debug(sm.getString("lifecycleBase.alreadyStarted", toString()), e); } else if (log.isInfoEnabled()) { log.info(sm.getString("lifecycleBase.alreadyStarted", toString())); } return; } if (state.equals(LifecycleState.NEW)) { init(); } else if (state.equals(LifecycleState.FAILED)) { stop(); } else if (!state.equals(LifecycleState.INITIALIZED) && !state.equals(LifecycleState.STOPPED)) { invalidTransition(Lifecycle.BEFORE_START_EVENT); } try { setStateInternal(LifecycleState.STARTING_PREP, null, false); startInternal(); if (state.equals(LifecycleState.FAILED)) { // This is a 'controlled' failure. The component put itself into the // FAILED state so call stop() to complete the clean-up. stop(); } else if (!state.equals(LifecycleState.STARTING)) { // Shouldn't be necessary but acts as a check that sub-classes are // doing what they are supposed to. invalidTransition(Lifecycle.AFTER_START_EVENT); } else { setStateInternal(LifecycleState.STARTED, null, false); } } catch (Throwable t) { // This is an 'uncontrolled' failure so put the component into the // FAILED state and throw an exception. handleSubClassException(t, "lifecycleBase.startFail", toString()); } } createWebServer
5、启动tomcat容器
创建webServer后在refresh()方法中的finishRefresh()完成tomcat的启动。
最终会调用 TomcatWebServer中的start()方法启动tomcat容器。
1 protected void finishRefresh() { 2 // Clear context-level resource caches (such as ASM metadata from scanning). 3 clearResourceCaches(); 4 5 // Initialize lifecycle processor for this context. 6 initLifecycleProcessor(); 7 8 // Propagate refresh to lifecycle processor first. 9 // 启动tomcat 10 getLifecycleProcessor().onRefresh(); 11 12 // Publish the final event. 13 publishEvent(new ContextRefreshedEvent(this)); 14 15 // Participate in LiveBeansView MBean, if active. 16 if (!NativeDetector.inNativeImage()) { 17 LiveBeansView.registerApplicationContext(this); 18 } 19 } 20 21 @Override 22 public void onRefresh() { 23 startBeans(true); 24 this.running = true; 25 } 26 27 private void startBeans(boolean autoStartupOnly) { 28 Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans(); 29 Map<Integer, LifecycleGroup> phases = new TreeMap<>(); 30 31 lifecycleBeans.forEach((beanName, bean) -> { 32 if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) { 33 int phase = getPhase(bean); 34 phases.computeIfAbsent( 35 phase, 36 p -> new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly) 37 ).add(beanName, bean); 38 } 39 }); 40 if (!phases.isEmpty()) { 41 // 遍历启动 42 phases.values().forEach(LifecycleGroup::start); 43 } 44 } 45 46 public void start() { 47 if (this.members.isEmpty()) { 48 return; 49 } 50 if (logger.isDebugEnabled()) { 51 logger.debug("Starting beans in phase " + this.phase); 52 } 53 Collections.sort(this.members); 54 for (LifecycleGroupMember member : this.members) { 55 doStart(this.lifecycleBeans, member.name, this.autoStartupOnly); 56 } 57 } 58 59 private void doStart(Map<String, ? extends Lifecycle> lifecycleBeans, String beanName, boolean autoStartupOnly) { 60 Lifecycle bean = lifecycleBeans.remove(beanName); 61 if (bean != null && bean != this) { 62 String[] dependenciesForBean = getBeanFactory().getDependenciesForBean(beanName); 63 for (String dependency : dependenciesForBean) { 64 doStart(lifecycleBeans, dependency, autoStartupOnly); 65 } 66 if (!bean.isRunning() && 67 (!autoStartupOnly || !(bean instanceof SmartLifecycle) || ((SmartLifecycle) bean).isAutoStartup())) { 68 if (logger.isTraceEnabled()) { 69 logger.trace("Starting bean '" + beanName + "' of type [" + bean.getClass().getName() + "]"); 70 } 71 try { 72 bean.start(); 73 } 74 catch (Throwable ex) { 75 throw new ApplicationContextException("Failed to start bean '" + beanName + "'", ex); 76 } 77 if (logger.isDebugEnabled()) { 78 logger.debug("Successfully started bean '" + beanName + "'"); 79 } 80 } 81 } 82 } 83 84 //WebServerStartStopLifecycle 中start() 方法的实现 85 public void start() { 86 this.weServerManager.start(); 87 this.running = true; 88 } 89 90 void start() { 91 this.handler.initializeHandler(); 92 this.webServer.start(); 93 this.applicationContext 94 .publishEvent(new ReactiveWebServerInitializedEvent(this.webServer, this.applicationContext)); 95 } 96 // 完成对tomcat的启动 97 @Override 98 public void start() throws WebServerException { 99 synchronized (this.monitor) { 100 if (this.started) { 101 return; 102 } 103 try { 104 addPreviouslyRemovedConnectors(); 105 Connector connector = this.tomcat.getConnector(); 106 if (connector != null && this.autoStart) { 107 performDeferredLoadOnStartup(); 108 } 109 checkThatConnectorsHaveStarted(); 110 this.started = true; 111 logger.info("Tomcat started on port(s): " + getPortsDescription(true) + " with context path '" 112 + getContextPath() + "'"); 113 } 114 catch (ConnectorStartFailedException ex) { 115 stopSilently(); 116 throw ex; 117 } 118 catch (Exception ex) { 119 PortInUseException.throwIfPortBindingException(ex, () -> this.tomcat.getConnector().getPort()); 120 throw new WebServerException("Unable to start embedded Tomcat server", ex); 121 } 122 finally { 123 Context context = findContext(); 124 ContextBindings.unbindClassLoader(context, context.getNamingToken(), getClass().getClassLoader()); 125 } 126 } 127 } 128 129 finishRefresh