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-启动原理 - sun丶牧羊人 - 博客园
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工厂
【SpringBoot内置Tomcat启动原理源码分析】
@Configuration(proxyBeanMethods = false)@ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })@ConditionalOnMissingBean(value = https://www.isolves.com/it/cxkf/jiagou/2022-02-22/ServletWebServerFactory.class, search = SearchStrategy.CURRENT)static class EmbeddedTomcat {@BeanTomcatServletWebServerFactory tomcatServletWebServerFactory(ObjectProvider connectorCustomizers,ObjectProvider contextCustomizers,ObjectProvider> 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 = https://www.isolves.com/it/cxkf/jiagou/2022-02-22/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并启动tomcatthis.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 类中@Overridepublic WebServer getWebServer(ServletContextInitializer... initializers) {if (this.disableMBeanRegistry) {Registry.disableRegistry();}// 实例化tomcatTomcat tomcat = new Tomcat();File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");// 设置tomcat临时工作目录tomcat.setBaseDir(baseDir.getAbsolutePath());// 默认使用 org.Apache.coyote.http11.Http11NioProtocol 实例化ConnectorConnector connector = new Connector(this.protocol);connector.setThrowOnFailure(true);// 给service添加Connectortomcat.getService().addConnector(connector);customizeConnector(connector);tomcat.setConnector(connector);// 关闭热部署tomcat.getHost().setAutoDeploy(false);// 配置 EngineconfigureEngine(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等事件给相应的监听器// 本方法并没有启动tomcatthis.tomcat.start();// We can re-throw failure exception directly in the main threadrethrowDeferredStartupExceptions();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 shutdownstartDaemonAwaitThread();}catch (Exception ex) {stopSilently();destroySilently();throw new WebServerException("Unable to start embedded Tomcat", ex);}}}// Tomcat类public void start() throws LifecycleException {getServer();server.start();}// LifecycleBasepublic 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());}}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 国外服务器部署springboot 项目 出现时区问题
- JavaScript 内置对象之——Date,看完你会更清晰
- 效率这不就提上来了嘛!SpringBoot+flowable快速实现工作流
- SpringBoot 如何使用同步锁
- Springboot使用OkHttp实现微信支付API-V3签名、证书的管理和使用
- 不用某度搜索和 XX 管家,这些应用在 Windows 内置商店就能下载到
- python初学者必须吃透的这些内置函数
- 开源的springboot+thymeleaf后台架构,程序员用了都点赞
- 68 个 Python 内置函数详解
- 快速打造属于自己的 PE 系统,内置大量插件包