spring boot 啓動tomcat過程

  1. 從SpringApplication run方法開始
public ConfigurableApplicationContext run(String... args) {
		、、、
		try {
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
			ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
			configureIgnoreBeanInfo(environment);
			Banner printedBanner = printBanner(environment);
			// 創建 ServletWebServerApplicationContext  
			context = createApplicationContext();
			exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);
			prepareContext(context, environment, listeners, applicationArguments, printedBanner);
			//tomcat 是真的在這裏面啓動的
			refreshContext(context);
			afterRefresh(context, applicationArguments);
			stopWatch.stop();
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
			}
			listeners.started(context);
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, listeners);
			throw new IllegalStateException(ex);
		}

		、、、
	}
  1. 查看 SpringApplication refreshContext 方法
private void refreshContext(ConfigurableApplicationContext context) {
		refresh(context);
		if (this.registerShutdownHook) {
			try {
				context.registerShutdownHook();
			}
			catch (AccessControlException ex) {
				// Not allowed in some environments.
			}
		}
	}


protected void refresh(ApplicationContext applicationContext) {
		Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
		((AbstractApplicationContext) applicationContext).refresh();
	}
  1. ServletWebServerApplicationContext 的refresh 方法
    public final void refresh() throws BeansException, IllegalStateException {
		try {
		    // 啓動AbstractApplicationContext   spring  容器
			super.refresh();
		}
		catch (RuntimeException ex) {
			stopAndReleaseWebServer();
			throw ex;
		}
	}

   // AbstractApplicationContext  的refresh方法在創建容器後會回調子類的onRefresh方法
	@Override
	protected void onRefresh() {
		super.onRefresh();
		try {
		    //  真的開始創建tomcat 容器了
			createWebServer();
		}
		catch (Throwable ex) {
			throw new ApplicationContextException("Unable to start web server", ex);
		}
	}
  1. 創建tomcat 容器
private void createWebServer() {
		WebServer webServer = this.webServer;
		ServletContext servletContext = getServletContext();
		if (webServer == null && servletContext == null) {
		// 工廠在ServletWebServerFactoryConfiguration  配置類中配置
			ServletWebServerFactory factory = getWebServerFactory();
    // getSelfInitializer 獲取初始化器,其中就有DispatcherServletRegistrationBean對
    // DispatcherServlet  進行初始化
    // getWebServer 創建tomcat 服務器
			this.webServer = factory.getWebServer(getSelfInitializer());
		}
		else if (servletContext != null) {
			try {
				getSelfInitializer().onStartup(servletContext);
			}
			catch (ServletException ex) {
				throw new ApplicationContextException("Cannot initialize servlet context", ex);
			}
		}
		initPropertySources();
	}
  1. 創建tomcat 服務器的過程
public WebServer getWebServer(ServletContextInitializer... initializers) {
		if (this.disableMBeanRegistry) {
			Registry.disableRegistry();
		}
		Tomcat tomcat = new Tomcat();
		File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
		tomcat.setBaseDir(baseDir.getAbsolutePath());
		// 創建連接器
		Connector connector = new Connector(this.protocol);
		connector.setThrowOnFailure(true);
		// 創建StandardServer 並添加connector
		tomcat.getService().addConnector(connector);
		customizeConnector(connector);
		tomcat.setConnector(connector);
		// 創建並獲取StandardEngine
		// 創建並獲取StandardHost 
		tomcat.getHost().setAutoDeploy(false);
		configureEngine(tomcat.getEngine());
		for (Connector additionalConnector : this.additionalTomcatConnectors) {
			tomcat.getService().addConnector(additionalConnector);
		}
		// 創建TomcatEmbeddedContext
		prepareContext(tomcat.getHost(), initializers);
		// tomcat StandardServer  初始化
		return getTomcatWebServer(tomcat);
	}
  1. org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#finishRefresh啓動tomcat 服務器
protected void finishRefresh() {
		super.finishRefresh();
		 // 啓動web服務器
		WebServer webServer = startWebServer();
		if (webServer != null) {
			publishEvent(new ServletWebServerInitializedEvent(webServer, this));
		}
	}


private WebServer startWebServer() {
		WebServer webServer = this.webServer;
		if (webServer != null) {
		// 啓動
			webServer.start();
		}
		return webServer;
	}



	public void start() throws WebServerException {
		synchronized (this.monitor) {
			if (this.started) {
				return;
			}
			try {
			    // 啓動connector ,及connector使用的線程池
				addPreviouslyRemovedConnectors();
				Connector connector = this.tomcat.getConnector();
				if (connector != null && this.autoStart) {
				  //  初始化servlet, 例如DispatcherServlet
					performDeferredLoadOnStartup();
				}
				checkThatConnectorsHaveStarted();
				this.started = true;
				logger.info("Tomcat started on port(s): " + getPortsDescription(true) + " with context path '"
						+ getContextPath() + "'");
			}
			catch (ConnectorStartFailedException ex) {
				stopSilently();
				throw ex;
			}
			catch (Exception ex) {
				if (findBindException(ex) != null) {
					throw new PortInUseException(this.tomcat.getConnector().getPort());
				}
				throw new WebServerException("Unable to start embedded Tomcat server", ex);
			}
			finally {
				Context context = findContext();
				ContextBindings.unbindClassLoader(context, context.getNamingToken(), getClass().getClassLoader());
			}
		}
	}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章