接第二篇 第二篇裡面, 看到容器創建的是 AnnotationConfigServletWebServerApplicationContext 類型. 一 .類圖 二. 構造 public GenericApplicationContext() { //創建 bean 工廠 this.beanFac ...
第二篇裡面, 看到容器創建的是 AnnotationConfigServletWebServerApplicationContext 類型.
一 .類圖
二. 構造
public GenericApplicationContext() {
//創建 bean 工廠 this.beanFactory = new DefaultListableBeanFactory(); } public AnnotationConfigServletWebServerApplicationContext() {
//創建讀取器 this.reader = new AnnotatedBeanDefinitionReader(this);
//創建掃描器 this.scanner = new ClassPathBeanDefinitionScanner(this); }
構造函數中, 創建了三個類, 並賦值給相應的屬性.
三. 啟動 tomcat
@Override 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(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); } } }
這裡我主要是想要瞭解tomcat啟動, 所以一些方法, 就先不看.
1. onRefresh()
onRefresh() 方法執行的是 ServletWebServerApplicationContext 的方法.
@Override protected void onRefresh() { super.onRefresh(); try { createWebServer(); } catch (Throwable ex) { throw new ApplicationContextException("Unable to start web server", ex); } }
createWebServer() 方法中, 會創建 Tomcat 類.
private void createWebServer() { WebServer webServer = this.webServer;
//當前進來, servletContext 為null ServletContext servletContext = getServletContext(); if (webServer == null && servletContext == null) {
//創建了 TomcatServletWebServerFactory 類 ServletWebServerFactory factory = getWebServerFactory();
//創建 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(); }
getWebServer方法裡面, 就創建了 Tomcat 類, 並對其進行一些配置操作.
@Override public WebServer getWebServer(ServletContextInitializer... initializers) {
//創建 Tomcat Tomcat tomcat = new Tomcat(); File baseDir = (this.baseDirectory != null ? this.baseDirectory : createTempDir("tomcat")); tomcat.setBaseDir(baseDir.getAbsolutePath()); Connector connector = new Connector(this.protocol); tomcat.getService().addConnector(connector); 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);
//這裡會創建 TomcatWebServer 實例, 並返回 return getTomcatWebServer(tomcat); }
這裡的 protocol 是有一個預設值的:
public static final String DEFAULT_PROTOCOL = "org.apache.coyote.http11.Http11NioProtocol"; private String protocol = DEFAULT_PROTOCOL;
可以看到, 這裡預設使用的是 同步非阻塞io協議. 需要註意的是, 在 new Connector() 的時候 對 Http11NioProtocol 進行了反射實例化.
public Http11NioProtocol() { super(new NioEndpoint()); }
在實例化的時候, new 了一個 NioEndpoint. 這個東西很重要, 後面會看到.
getTomcatWebServer()
protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) { return new TomcatWebServer(tomcat, getPort() >= 0); }
在創建 TomcatWebServer 的時候, 就會啟動 Tomcat
public TomcatWebServer(Tomcat tomcat, boolean autoStart) { Assert.notNull(tomcat, "Tomcat Server must not be null"); this.tomcat = tomcat; this.autoStart = autoStart; initialize(); } private void initialize() throws WebServerException { TomcatWebServer.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 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(); throw new WebServerException("Unable to start embedded Tomcat", ex); } } }
2. finishRefresh()
ServletWebServerApplicationContext 重寫了該方法.
@Override protected void finishRefresh() {
//調用父類的 finishedRefresh 方法, 保證處理完整性 super.finishRefresh();
//啟動 TomcatWebServer WebServer webServer = startWebServer(); if (webServer != null) { publishEvent(new ServletWebServerInitializedEvent(webServer, this)); } }
startWebServer()
private WebServer startWebServer() { WebServer webServer = this.webServer; if (webServer != null) { webServer.start(); } return webServer; } @Override public void start() throws WebServerException { synchronized (this.monitor) { if (this.started) { return; } try {
//遍歷service, 拿到service, 然後綁定 Connector addPreviouslyRemovedConnectors(); Connector connector = this.tomcat.getConnector(); if (connector != null && this.autoStart) { performDeferredLoadOnStartup(); } checkThatConnectorsHaveStarted(); this.started = true; TomcatWebServer.logger .info("Tomcat started on port(s): " + getPortsDescription(true) + " with context path '" + getContextPath() + "'"); ...... }
addPreviouslyRemovedConnectors()
private void addPreviouslyRemovedConnectors() { Service[] services = this.tomcat.getServer().findServices(); for (Service service : services) { Connector[] connectors = this.serviceConnectors.get(service); if (connectors != null) { for (Connector connector : connectors) { service.addConnector(connector); if (!this.autoStart) { stopProtocolHandler(connector); } } this.serviceConnectors.remove(service); } } }
service 在綁定 Connector 的時候, 會啟動 Connector
@Override public void addConnector(Connector connector) { synchronized (connectorsLock) { connector.setService(this); Connector results[] = new Connector[connectors.length + 1]; System.arraycopy(connectors, 0, results, 0, connectors.length); results[connectors.length] = connector; connectors = results; if (getState().isAvailable()) { try { connector.start(); } catch (LifecycleException e) { log.error(sm.getString( "standardService.connector.startFailed", connector), e); } } // Report this property change to interested listeners support.firePropertyChange("connector", null, connector); } }
看一下 connector.start() 方法.
@Override public final synchronized void start() throws LifecycleException { ......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. ExceptionUtils.handleThrowable(t); setStateInternal(LifecycleState.FAILED, null, false); throw new LifecycleException(sm.getString("lifecycleBase.startFail", toString()), t); } }
startInternal() 是一個抽象方法, 其中的一個實現類 Connector
@Override protected void startInternal() throws LifecycleException { // Validate settings before starting if (getPort() < 0) { throw new LifecycleException(sm.getString( "coyoteConnector.invalidPort", Integer.valueOf(getPort()))); } setState(LifecycleState.STARTING); try { protocolHandler.start(); } catch (Exception e) { throw new LifecycleException( sm.getString("coyoteConnector.protocolHandlerStartFailed"), e); } }
接著進 start() 方法
@Override public void start() throws Exception { if (getLog().isInfoEnabled()) { getLog().info(sm.getString("abstractProtocolHandler.start", getName())); } endpoint.start(); // Start async timeout thread asyncTimeout = new AsyncTimeout(); Thread timeoutThread = new Thread(asyncTimeout, getNameInternal() + "-AsyncTimeout"); int priority = endpoint.getThreadPriority(); if (priority < Thread.MIN_PRIORITY || priority > Thread.MAX_PRIORITY) { priority = Thread.NORM_PRIORITY; } timeoutThread.setPriority(priority); timeoutThread.setDaemon(true); timeoutThread.start(); }
endPoint.start() 方法:
public final void start() throws Exception { if (bindState == BindState.UNBOUND) { bind(); bindState = BindState.BOUND_ON_START; } startInternal(); }
這個bind() 執行的是NioEndpoint 中的方法, 進行埠綁定監聽.
@Override public void bind() throws Exception { serverSock = ServerSocketChannel.open(); socketProperties.setProperties(serverSock.socket()); InetSocketAddress addr = (getAddress()!=null?new InetSocketAddress(getAddress(),getPort()):new InetSocketAddress(getPort())); serverSock.socket().bind(addr,getAcceptCount()); serverSock.configureBlocking(true); //mimic APR behavior // Initialize thread count defaults for acceptor, poller if (acceptorThreadCount == 0) { // FIXME: Doesn't seem to work that well with multiple accept threads acceptorThreadCount = 1; } if (pollerThreadCount <= 0) { //minimum one poller thread pollerThreadCount = 1; } setStopLatch(new CountDownLatch(pollerThreadCount)); // Initialize SSL if needed initialiseSsl(); selectorPool.open(); }
總結:
從執行流程上來看,
1. 在onRefresh() 中, 啟動Tomcat
2. 在 finishBeanFactoryInitialization() 中進行了後臺方法的路由映射(待續)
3. 在finishRefresh()中進行了埠綁定監聽