上一节咱们次要剖析了refreshContext中,次要有3个逻辑,如下图:
上一节重点解析了invokeBeanFactoryPostProcessors执行容器扩大点,实现了主动配备配置、第三方执行扩大的执行。
明天咱们持续剖析refreshContext另一个重要的逻辑onRefresh()逻辑,让咱们开始吧!
疾速概览: onRefresh启动内嵌tomcat前的操作
refreshContext中onRefresh之前还有一些逻辑,咱们先来疾速看下它们次要做了什么。首先来看下代码:
@Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { //省略 // 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(); //省略 }
下面次要波及了3个办法,从名字行就能猜出来它们做了什么:
1)registerBeanPostProcessors 通过扫描到BeanDefination中找出BeanPostProcessor,减少几个Bean的扩大点BeanPostProcessor 按4类程序一一减少。
回顾术语BeanPostProcessor是什么?
之前BeanFactoryPostProcessor是对容器的扩大,次要有一个办法,能够给容器设置属性,补充一些单例对象,补充一些BeanDefinition。那BeanPostProcessor是对bean的扩大,有before和after两类办法,对Bean如何做扩大,在bean的创立前后,给bean补充一些属性等。
2)initMessageSource 注册音讯M essageSource对象到容器 DelegatingMessageSource 国际化相干反对,默认的没有。
3)initApplicationEventMulticaster 注册播送对象到容器 这个对象就是之前触发listener扩大点的播送对象。
相熟了onRefresh办法之前的大体逻辑后,目前为止,整个rereshConext()执行的逻辑次要如下:
onRefresh的外围脉络
相熟了onRefresh办法之前的大体逻辑后,接下来咱们就先钻研下onRefresh的外围脉络在做什么了。
//ServletWebServerApplicationContext.java @Override protected void onRefresh() { super.onRefresh(); try { createWebServer(); } catch (Throwable ex) { throw new ApplicationContextException("Unable to start web server", ex); } } //父类GenericWebApplicationContext.java @Override protected void onRefresh() { this.themeSource = UiApplicationContextUtils.initThemeSource(this); }
这个onRefresh办法的脉络其实很简略,父类没有什么逻辑,外围应该就是createWebServer了,咱们持续来看下:
private void createWebServer() { WebServer webServer = this.webServer; ServletContext servletContext = getServletContext(); if (webServer == null && servletContext == null) { ServletWebServerFactory factory = getWebServerFactory(); 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(); }
这个逻辑其实很有意思,次要的外围脉络是if-else-if
1)如果webServer和servletContext为空,就创立一个WebServer,之后执行initPropertySources。
2)否则就应用getSelfInitializer,执行onStartup办法,之后执行initPropertySources。
能够默认状况webServer和servletContext为空的,这个咱们在之前剖析的整个流程中没看到过任何对于这两个组件的逻辑,或者你本人断点也能显著的找到代码执行的门路。
这里其实你会发现,判断走哪个分支的办法可能不止一种,你能够连蒙带猜,也能够断点走一下,也能够依据教训剖析等等。办法有很多,大家千万剖析原理或者源码的时候不要陷入追寻有哪些办法上。办法不是最重要的,适宜你本人的就好。这个思维很要害,你能够模拟,但不能齐全照搬,肯定要联合本人状况思考,最终能力成为你本人的。本人悟到的才是本人的,这些也是思维,也是最要害的。所以不要总问我有哪些办法,有时候是你本人悟出来的,我只能揭示或者倡议。
好了,言归正传,这里理论走的门路就是第一条了。如下图所示:
最终,你会发现onRefresh波及的外围组件ServletWebServerFactory、WebServer、ServletContext。
SpringBoot对web容器的形象封装和设计
既然之前波及到了几个组件ServletWebServerFactory、WebServer、ServletContext。 那它们是别离是什么货色呢?
其实从名字就能猜出很多货色,不难想到:
ServletContext,这个是指解决整个web申请是的上下文对象,在Tocmat中通常是整个申请的上下文参数都封装在这个对象中了,十分要害的对象。
ServletWebServerFactory和WebServer是什么?很显著ServletWebServerFactory是个工厂,用来创立WebServer。
而WebServer从接口中定义的办法就可以看进去,封装了web容器的启动和进行,获取端口的外围操作,也就是说WebServer是web容器的一个形象封装。
@FunctionalInterfacepublic interface ServletWebServerFactory { /** * Gets a new fully configured but paused {@link WebServer} instance. Clients should * not be able to connect to the returned server until {@link WebServer#start()} is * called (which happens when the {@code ApplicationContext} has been fully * refreshed). * @param initializers {@link ServletContextInitializer}s that should be applied as * the server starts * @return a fully configured and started {@link WebServer} * @see WebServer#stop() */ WebServer getWebServer(ServletContextInitializer... initializers);}
public interface WebServer { /** * Starts the web server. Calling this method on an already started server has no * effect. * @throws WebServerException if the server cannot be started */ void start() throws WebServerException; /** * Stops the web server. Calling this method on an already stopped server has no * effect. * @throws WebServerException if the server cannot be stopped */ void stop() throws WebServerException; /** * Return the port this server is listening on. * @return the port (or -1 if none) */ int getPort();}
从下面两个接口的设计和正文看
首先ServletWebServerFactory的getWebServer正文翻译: 获取一个新的齐全配置但暂停的 {@link WebServer} 实例。 客户应无奈连贯到返回的服务器,直到 {@link WebServer#start()} 是调用(当 {@code ApplicationContext} 已齐全刷新)。
也就是说,这个办法意思就是获取到一个配置好的webServer容器,在调用start办法时启动容器,启动时候ApplicationContext,也就是Spring容器曾经实现了刷新。
而WebServer接口封装了web容器的常见操作,如启动、进行,获取端口号之类的。
也就是说ServletWebServerFactory能够取得一个web容器,WebServer能够操作一个容器。
并且从上面的图中能够看出,它们有很多不同web容器的实现。整体如下图所示:
综上,最终你能够了解为WebServer和ServletWebServerFactory,这一套,其实就是SpringBoot对web容器的形象封装,WebServer能够代表了整个容器。
理解了onRefesh的整体脉络和要害的组件之后,咱们来看下如何创立webServer的。
默认状况咱们获取到的是TomcatServletWebServerFactory,通过它来创立
//TomcatServletWebServerFactory.javapublic 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); 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); return getTomcatWebServer(tomcat); }
整个办法脉络如下:
1)入参是一个java8定义的函数表达式,也就是参数传递进来了一个办法,应用的是函数式接口ServletContextInitializer。这个办法在前面应该会被执行的。
2)创立了外围组件Tomcat,一会能够看下它的外围脉络,外面封装了Server
3)创立和配置组件Connector, new Connector()、customizeConnector这个是Tomcat的Connector组件相干
4)创立和配置组件Engine getEngine、 configureEngine tomcat的Engine组件相干设置
5)prepareContext 筹备tomcat的context相干
6)getTomcatWebServer 真正启动tomcat
画成图如下所示:
看完这个办法后,你可能对这里波及的很多组件比拟生疏,因为波及到了很多tomcat的组件。不过没有关系,你能够通过之前学习的办法来梳理这些组件的关系。就算不晓得每个组件是干嘛的,也能够连蒙带猜下。
new Tomcat外围组件和脉络剖析
这里我就来带教大家一起用之前的办法和思路剖析一下它们的外围脉络吧。
首先第一个组件就是Tomcat这个类的创立。老办法,能够看下这个类脉络、构造方法之后,画一个图。
首先看下构造方法
public Tomcat() { ExceptionUtils.preload(); }
你会发现什么都么有,只有一个异样工具预加载的解决。一看就不是重点。
那就再看下这个类的整体脉络吧:
看完这个类的脉络,能够看进去Tomcat这个类次要有
1)对Wrapper相干的操作方法,比方addServelt办法就是返回一个Wrapper。
2)有Context相干一些办法,createContext、addWebapp之类的
3)有一堆组件的get办法,比方Connector、Engine、Service、Server、Host
4)最初就是一些属性了,比方Server对象、端口号、hostname、用户权限相干Userpass/UserRole之类的。
尽管咱们不晓得这个类外面的那些组件是干嘛的。然而起码咱们有了一个印象。能够感触到这个Tomcat类,封装了简直Tomcat所有的外围组件,是一个对tomcat容器的一个形象对象,代表了整个tomcat。
最初咱们能够画图先列举下看完Tomcat这个类的构造函数和类脉络中,次要波及概念或者说是组件,如下图所示:
不晓得你们目前是什么感触,感觉有好多新的概念。如果你不理解tomcat的原理的话,第一次看到这一大堆组件,必定有点懵的。
不过没关系,你其实能够连蒙带猜,或者抓大放小,因为咱们次要还是看SpringBoot如何启动内嵌tomcat,如何和tomcat整合Spring容器的。
所以你没必要非要弄清楚这些组件,等之后咱们Tomcat成长记,钻研tomcat的原理和源码时候再来认真弄清楚。
这里咱们还是找到关注的重点就能够了。
好,咱们接着向下剖析。
Connector根本创立和扩大设计
最高层的形象封装Tomcat对象创立实现后,下一个外围创立的就是Connector了。创立它的代码如下:
public static final String DEFAULT_PROTOCOL = "org.apache.coyote.http11.Http11NioProtocol";private String protocol = DEFAULT_PROTOCOL; public WebServer getWebServer(ServletContextInitializer... initializers) { //其余 Tomcat tomcat = new Tomcat(); tomcat.setBaseDir(baseDir.getAbsolutePath()); Connector connector = new Connector(this.protocol); connector.setThrowOnFailure(true); tomcat.getService().addConnector(connector); customizeConnector(connector); //其余 }
能够看到Connector创立默认传入了一个Http11NioProtocol类的全名,当然你能够通过set办法批改这个protocol的默认值,只有获取到TomcatServletWebServerFactory就能够批改对吧?
至于为啥传递了类的全名,你猜测下都晓得,它外部可能是通过反射创立了这个类,并把这个组件设置给了Connector。咱们来看下是不是:
public Connector(String protocol) { boolean aprConnector = AprLifecycleListener.isAprAvailable() && AprLifecycleListener.getUseAprConnector(); if ("HTTP/1.1".equals(protocol) || protocol == null) { if (aprConnector) { protocolHandlerClassName = "org.apache.coyote.http11.Http11AprProtocol"; } else { protocolHandlerClassName = "org.apache.coyote.http11.Http11NioProtocol"; } } else if ("AJP/1.3".equals(protocol)) { if (aprConnector) { protocolHandlerClassName = "org.apache.coyote.ajp.AjpAprProtocol"; } else { protocolHandlerClassName = "org.apache.coyote.ajp.AjpNioProtocol"; } } else { protocolHandlerClassName = protocol; } // Instantiate protocol handler ProtocolHandler p = null; try { Class<?> clazz = Class.forName(protocolHandlerClassName); p = (ProtocolHandler) clazz.getConstructor().newInstance(); } catch (Exception e) { log.error(sm.getString( "coyoteConnector.protocolHandlerInstantiationFailed"), e); } finally { this.protocolHandler = p; } // Default for Connector depends on this system property setThrowOnFailure(Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE"));}
这个构造函数最要害的就是3行代码:
public Connector(String protocol) { Class<?> clazz = Class.forName(protocolHandlerClassName); p = (ProtocolHandler) clazz.getConstructor().newInstance(); this.protocolHandler = p; }
也就是说其实new Connector外围就做了一件事件:创立了一个Http11NioProtocol组件。
这个从名字上看就是一个NIO相干的通信组件,外部应该会有Selector、Channel、Bytebuffer等NIO外围组件的。
至于Http11NioProtocol如何创立的这里我就不带大家深究了,你能够剖析它的构造函数、类脉络、画一个组件图剖析下它的创立过程,或者之后咱们Tomcat成长记会详细分析的,可之后带大家一起剖析下。
到这里先画个图小结下:
new Connector之后就是十分要害的扩大点执行了customizeConnector()办法。
这个办法理论是SpringBoot对Connector扩大设计的接入,能够批改Connector中很多配置和属性,让咱们来一起看下。
private Set<TomcatConnectorCustomizer> tomcatConnectorCustomizers = new LinkedHashSet<>();private Set<TomcatProtocolHandlerCustomizer<?>> tomcatProtocolHandlerCustomizers = new LinkedHashSet<>();protected void customizeConnector(Connector connector) { int port = Math.max(getPort(), 0); connector.setPort(port); if (StringUtils.hasText(this.getServerHeader())) { connector.setAttribute("server", this.getServerHeader()); } if (connector.getProtocolHandler() instanceof AbstractProtocol) { customizeProtocol((AbstractProtocol<?>) connector.getProtocolHandler()); } invokeProtocolHandlerCustomizers(connector.getProtocolHandler()); if (getUriEncoding() != null) { connector.setURIEncoding(getUriEncoding().name()); } // Don't bind to the socket prematurely if ApplicationContext is slow to start connector.setProperty("bindOnInit", "false"); if (getSsl() != null && getSsl().isEnabled()) { customizeSsl(connector); } TomcatConnectorCustomizer compression = new CompressionConnectorCustomizer(getCompression()); compression.customize(connector); for (TomcatConnectorCustomizer customizer : this.tomcatConnectorCustomizers) { customizer.customize(connector); }}
这个扩大办法外围的逻辑就是在给connector进行一些属性设置,外围通过了两个扩大进行调用。
1)invokeProtocolHandlerCustomizers 执行对ProtocolHandler扩大
2)customizer.customize(connector); 执行对Connector的扩大
其实能够看到触发的都是tomcatConnectorCustomizers、tomcatProtocolHandlerCustomizers这两个汇合中的扩大类。、
整体如下图所示:
咱们先不焦急看这些扩大类做了什么,首先的得思考下,tomcatConnectorCustomizers、tomcatProtocolHandlerCustomizers这两个汇合中的扩大类什么时候设置的值呢?
其实你想下,这两个属性属于谁呢?没错,属于TomcatServletWebServerFactory。而这个类是不是之前通过ServletWebServerApplicationContext执行onRefresh脉络时候获取到的呢?如下图:
对应获取的代码如下:
//ServletWebServerApplicationContext.javaprotected ServletWebServerFactory getWebServerFactory() { // Use bean names so that we don't consider the hierarchy String[] beanNames = getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class); if (beanNames.length == 0) { throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to missing " + "ServletWebServerFactory bean."); } if (beanNames.length > 1) { throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to multiple " + "ServletWebServerFactory beans : " + StringUtils.arrayToCommaDelimitedString(beanNames)); } return getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);}
能够看到的是,这个办法外围就是通过getBean从容器获取一个对象。然而其实容器中并没有ServletWebServerFactory这个对象,只有它的BeanDefinition。
为什么呢?因为之前咱们执行ConfigurationClassPostProcessor时候,只是加载了Bean对应的BeanDefinition而已。
不过没关系,getBean中的逻辑是,如果容器没有然而有对应的BeanDefinition,它会进行Bean实例化,Bean的实例化咱们下一节会具体讲,这里只是简略提下。
那这个bean,ServletWebServerFactory实例化的时候会做什么呢?除了根本构造函数外,其实Bean实例化的过程有很多扩大点,能够为bean设置属性。
好,那要害的就来了,tomcatConnectorCustomizers、tomcatProtocolHandlerCustomizers既然是ServletWebServerFactory的两个属性,必定就能够通过Bean实例化时候的扩大点,给这两个属性设置进去值。
最终,我给大家详情如下图所示:
至于Connector中每个customizer做了哪些事件,这里咱们不去详细分析了
大体就是初始化protocol相干的配置,比方setMaxThreads默认200、minSpareThreads默认10、maxHttpHeaderSize默认8192byte 、maxSwallowSize 2097152等等。
相熟了这个扩大点的逻辑后,其实最要害的是如何应用它,你能够通过ServerProperties扩大配置值,也能够自定义tomcatConnectorCustomizers或者tomcatProtocolHandlerCustomizers,只有实现对应的接口就能够了。这个才是领悟了SpringBoot的设计思路后最要害的。
术语遍及:Tomcat的Engine、Context、Host、Wrapper关系
剖析完了Connector的创立之后,其余的组件其实就是一般的创立,建设关联关系而已。它们的关系其实不简单,属于tomcat的基本知识,这里我通过一个tomcat流程执行图给大家介绍下它们的关系即可。它们之间的关系如下图所示:
这些组件每个都有本人的职责,你大体理解上述组件的关系就能够了,咱们就不开展剖析了。
当然SpringBoot也有一些对它们的扩大,比方对Engine、Context阀门的扩大。也是通过engineValves、contextValves两个list属性进行扩大。
//TomcatServletWebServerFactory.javaprivate List<Valve> engineValves = new ArrayList<>();private List<Valve> contextValves = new ArrayList<>();
只不过这两个汇合默认是空的,你能够通过TomcatServletWebServerFactory对他们进行设置和扩大。
这里我也不开展了。
记住,只有你了解了SpringBoot围绕TomcatServletWebServerFactory对tomcat做封装和扩大是要害,就能够了。
prepareContext 中的扩大点ServletContextInitializer
后面一堆组件创立实现后,还有一个比拟有意思的操作就是prepareContext 。
让咱们来看下吧!它的代码如下:
protected void prepareContext(Host host, ServletContextInitializer[] initializers) { File documentRoot = getValidDocumentRoot(); TomcatEmbeddedContext context = new TomcatEmbeddedContext(); if (documentRoot != null) { context.setResources(new LoaderHidingResourceRoot(context)); } context.setName(getContextPath()); context.setDisplayName(getDisplayName()); context.setPath(getContextPath()); File docBase = (documentRoot != null) ? documentRoot : createTempDir("tomcat-docbase"); context.setDocBase(docBase.getAbsolutePath()); context.addLifecycleListener(new FixContextListener()); context.setParentClassLoader((this.resourceLoader != null) ? this.resourceLoader.getClassLoader() : ClassUtils.getDefaultClassLoader()); resetDefaultLocaleMapping(context); addLocaleMappings(context); context.setUseRelativeRedirects(false); try { context.setCreateUploadTargets(true); } catch (NoSuchMethodError ex) { // Tomcat is < 8.5.39. Continue. } configureTldSkipPatterns(context); WebappLoader loader = new WebappLoader(context.getParentClassLoader()); loader.setLoaderClass(TomcatEmbeddedWebappClassLoader.class.getName()); loader.setDelegate(true); context.setLoader(loader); if (isRegisterDefaultServlet()) { addDefaultServlet(context); } if (shouldRegisterJspServlet()) { addJspServlet(context); addJasperInitializer(context); } context.addLifecycleListener(new StaticResourceConfigurer(context)); ServletContextInitializer[] initializersToUse = mergeInitializers(initializers); host.addChild(context); configureContext(context, initializersToUse); postProcessContext(context);}
整个办法的脉络其实不简单,次要就是:
1)new TomcatEmbeddedContext
2)为tomcat的这个Context设置了很多值
3)执行了一个扩大点ServletContextInitializer
整体如下图所示:
至于扩大点,ServletContextInitializer执行了什么?
其实能够看下它的逻辑。它是应用了java8的个性,通过一个函数式接口传入过去的办法,也就是说,通过办法参数传递过去了一个行为,而不是一个变量。
咱们能够找到传入的地位:
//ServletWebServerApplicationContext.java private void selfInitialize(ServletContext servletContext) throws ServletException { prepareWebApplicationContext(servletContext); registerApplicationScope(servletContext); WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(), servletContext); for (ServletContextInitializer beans : getServletContextInitializerBeans()) { beans.onStartup(servletContext); } }
办法其实不简单,外围就是触发了ServletContextInitializer的所有实现,执行了扩大办法onStartup。
默认次要有4个实现:
result = {ServletContextInitializerBeans@6345} size = 4 0 = {DispatcherServletRegistrationBean@6339} "dispatcherServlet urls=[/]" 1 = {FilterRegistrationBean@6350} "characterEncodingFilter urls=[/*] order=-2147483648" 2 = {FilterRegistrationBean@6351} "formContentFilter urls=[/*] order=-9900" 3 = {FilterRegistrationBean@6352} "requestContextFilter urls=[/*] order=-105"
其实从名字就看进去了,它的含意是往ServletContext中注册一堆Servelt、Filter等等。
这个扩大点还是比拟要害的。
整体如下图所示:
思考:tomcat和SpringBoot怎么整合的?
剖析完了整个WebServer的创立后,其实你就会发现:
最终是Spring的容器ServletWebServerApplicationContext创立了WebServer,它持有了这对象,也就有了Tomcat整个形象封装。
天然它们就整合到了一起了。
内嵌Tomcat最终的启动
之前剖析的整个逻辑都是webServer这个对象的创立,之前从正文咱们就晓得,创立的webServer只是一个配置实现,进行的web容器,web容器并没有启动。只有调用webServer#start()这个办法,容器才会真正启动。
所以,最初咱们来剖析下tomcat是如何启动的。启动的代码就是getWebServer的最初一行,代码如下:
//TomcatServletWebServerFactory.java @Override public WebServer getWebServer(ServletContextInitializer... initializers) { //省略 Tomcat的创立、connector的创立和扩大、其余组件的创立、prepareContext的执行和扩大 return getTomcatWebServer(tomcat); } protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) { return new TomcatWebServer(tomcat, getPort() >= 0); } public TomcatWebServer(Tomcat tomcat, boolean autoStart) { Assert.notNull(tomcat, "Tomcat Server must not be null"); this.tomcat = tomcat; this.autoStart = autoStart; initialize(); }
能够看到下面的代码脉络是:通过一系列的办法调用最终将创立的tomcat对象,有封装了一下,封装为了TomcatWebServer对象,之后执行了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 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.start();
这个start办法执行的流程很有意思。它是相似一个链式调用。
其实你从之前tomcat的组件图就能够猜到,它们组件层级关系很多,每个组件都会触发下一层组件的逻辑。
每个组件都有生命周期,比方init办法-->start()-->destory()之类的。
那么也就说tomcat会以链的形式逐级调用各个模块的init()办法进行初始化, 待各个模块都初始化后, 又会逐级调用各个模块的start()办法启动各个模块。
整体大略如下图所示:
小结
最初咱们小结下,明天咱们次要剖析了SpringBoot在onRefresh办法中如何启动的tomcat:
1)疾速该来了 onRefresh启动内嵌tomcat前的操作
2)剖析了onRefresh的外围脉络
3)思考了SpringBoot对web容器的形象封装和设计
4)对new Tomcat进行了外围组件和脉络剖析
5)剖析了Connector根本创立和扩大设计
6)术语遍及:Tomcat的Engine、Context、Host、Wrapper关系
7)prepareContext 中的扩大点ServletContextInitializer
8)思考了:tomcat和SpringBoot怎么整合的?
9)内嵌Tomcat最终的启动
最初补充一点思维:
整个过程中有的是知识点,有的是一些设计的思考、扩大点的思考。大家肯定要学会抓重点。这个能力十分要害。
这就是波及到了一个能力模型的档次,能够有这样一种划分
第一个档次:常识、技术根本的应用,也就是说咱们从理解常识到应用它做好一件事是一个档次。这个能够体现在你学习技术上,率领团队做我的项目,或者学习任何新事物上。
第二个档次:通过思考和总结,形象和提炼出事件的关键点。比方一个提炼设计思维,发现我的项目的要害节点、门路等。
最初一个档次:站在肯定高度和视角,掌控和推动整体。这个就须要很多教训和像比你胜利的人学习了,因为把握力是能够练习的,然而视线和思维的高度,尽管能够教训积攒,然而最快的形式就是像比你优良的人学习,如果有一个导师的话那就更好了。
本文由博客一文多发平台 OpenWrite 公布!