<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      SpringApplication.run(xxx.class, args)背后的東東——實現(xiàn)原理

      現(xiàn)在springboot已經(jīng)成為web應(yīng)用開發(fā)的事實標準,所以為了能更好的應(yīng)用springboot特性,有必要深入研究下背后的實現(xiàn)原理。

       

      在分析之前,先拋出幾個問題,后續(xù)章節(jié)也是圍繞解決這幾個問題展開:

      1、springboot是如何依賴幾個注解就零配置啟動spring容器?

      2、springboot開發(fā)出來的jar,如何實現(xiàn)內(nèi)嵌tomcat?

      3、springboot開發(fā)經(jīng)常用到的springmvc中的dispathservlet是如何關(guān)聯(lián)到內(nèi)嵌tomcat?

       

      首先咱們直接從main方法上的  @SpringBootApplication 組合注解開始,里面實現(xiàn)零配置的注解就是  @EnableAutoConfiguration ,它利用 @Import 一個 AutoConfigurationImportSelector,該類主要利用類SPI的機制,獲取META-INFO下面需要自動裝配的 @Configuration,至于SPI后續(xù)將詳細介紹。

       

      說到這里,估計大家會有一個疑問,springboot如何一開始就知道這個重要 @Import  注解呢,肯定有個注解解析的地方,下面需要說的就是spring容器的啟動(跟著main方法走):

      context = this.createApplicationContext()
      

        這里是創(chuàng)建重要的ApplicationContext,其實就是BeanFactory,不過springboot會自動推斷創(chuàng)建針對servlet應(yīng)用的 AnnotationConfigServletWebServerApplicationContext。

      org.springframework.context.support.AbstractApplicationContext#refresh
      

        熟悉spring源碼的同學(xué)就會知道,這里就是刷新容器的地方,

      org.springframework.context.support.AbstractApplicationContext#invokeBeanFactoryPostProcessors
      org.springframework.context.annotation.ConfigurationClassParser#processImports
      

      這個方法里面就有對 @Import 注解做解析

        解析邏輯比較復(fù)雜,有興趣可以自己看下,說白了就是開頭講的找到需要自動裝配的 @Configuration 對應(yīng)的類,這里列出來三個重要的如下:

      @Configuration(proxyBeanMethods = false)
      @ConditionalOnWebApplication(type = Type.SERVLET)
      @ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
      @ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
      @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
      @AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
      		ValidationAutoConfiguration.class })
      public class WebMvcAutoConfiguration {
      

        

      @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
      @Configuration(proxyBeanMethods = false)
      @ConditionalOnWebApplication(type = Type.SERVLET)
      @ConditionalOnClass(DispatcherServlet.class)
      @AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class)
      public class DispatcherServletAutoConfiguration {
      

        

      @Configuration(proxyBeanMethods = false)
      @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
      @ConditionalOnClass(ServletRequest.class)
      @ConditionalOnWebApplication(type = Type.SERVLET)
      @EnableConfigurationProperties(ServerProperties.class)
      @Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
      		ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
      		ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
      		ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
      public class ServletWebServerFactoryAutoConfiguration {
      

        其實這三個都是通過 @AutoConfigureAfter 依賴關(guān)系加載的,加載這些的目的就是為了getBean時可以拿到具體的實例對象。

       

      咱們再回到刷新spring器中的方法中

      org.springframework.context.support.AbstractApplicationContext#onRefresh
      

        該方法對應(yīng)servlet的實現(xiàn)是

      org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#onRefresh
      

        里面就是創(chuàng)建WebServer,可以理解為就是咱們的tomcat,不過它是由工廠方法創(chuàng)建的

      protected ServletWebServerFactory getWebServerFactory() {
              String[] beanNames = this.getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class);
      

        核心代碼來了,這里就會觸發(fā)getBean,去拿到 ServletWebServerFactory的實例,也就會觸發(fā)Bean的生命周期調(diào)用,

      @Configuration(proxyBeanMethods = false)
      class ServletWebServerFactoryConfiguration {
      
      	@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) {
      			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;
      		}
      
      	}
      

        其實就是到這里來獲取 TomcatServletWebServerFactory 實例,這個也就是前面自動配置 @Import掃描出來的 ServletWebServerFactoryAutoConfiguration 導(dǎo)入的beandefinition

      這個工廠實現(xiàn)了 ErrorPageRegistry 接口

      org.springframework.boot.web.server.ErrorPageRegistry
      

        而ServletWebServerFactory在getBean的生命周期中會觸發(fā)BeanPostProcessor實現(xiàn)類的調(diào)用

      public class ErrorPageRegistrarBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {
      
      	private ListableBeanFactory beanFactory;
      
      	private List<ErrorPageRegistrar> registrars;
      
      	@Override
      	public void setBeanFactory(BeanFactory beanFactory) {
      		Assert.isInstanceOf(ListableBeanFactory.class, beanFactory,
      				"ErrorPageRegistrarBeanPostProcessor can only be used with a ListableBeanFactory");
      		this.beanFactory = (ListableBeanFactory) beanFactory;
      	}
      
      	@Override
      	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
      		if (bean instanceof ErrorPageRegistry) {
      			postProcessBeforeInitialization((ErrorPageRegistry) bean);
      		}
      		return bean;
      	}
      

        也就是實例化 TomcatServletWebServerFactory 之前,會去先實例化 ErrorPageRegistrar

      	private Collection<ErrorPageRegistrar> getRegistrars() {
      		if (this.registrars == null) {
      			// Look up does not include the parent context
      			this.registrars = new ArrayList<>(
      					this.beanFactory.getBeansOfType(ErrorPageRegistrar.class, false, false).values());
      			this.registrars.sort(AnnotationAwareOrderComparator.INSTANCE);
      			this.registrars = Collections.unmodifiableList(this.registrars);
      		}
      		return this.registrars;
      	}
      

        跟著代碼,實例化 ErrorPageRegistrar 又會先去實例化  DispatcherServletPath,它只有一個實現(xiàn)類 DispatcherServletRegistrationBean

      protected ErrorPageCustomizer(ServerProperties properties, DispatcherServletPath dispatcherServletPath) {
      			this.properties = properties;
      			this.dispatcherServletPath = dispatcherServletPath;
      		}
      

        

      public DispatcherServletRegistrationBean(DispatcherServlet servlet, String path) {
      		super(servlet);
      		Assert.notNull(path, "Path must not be null");
      		this.path = path;
      		super.addUrlMappings(getServletUrlMapping());
      	}
      

        這里就看到熟悉的 DispatcherServlet了,有人可能會問,DispatcherServlet哪里來的?其實又要回到前面掃描處理的三個自動裝配類中的 DispatcherServletAutoConfiguration

       

      至此,我們終于通過spring容器的啟動,將DispatcherServlet實例化出來了,同理負責創(chuàng)建tomcat容器的TomcatServletWebServerFactory也實例化出來了。

       

      下面就是負責創(chuàng)建內(nèi)嵌tomcat了,以及建立tomcat與DispatcherServlet實例的關(guān)聯(lián)

      org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory#getWebServer
      

        

      tomcat容器啟動后,因為它實現(xiàn)了servlet規(guī)范,內(nèi)部會回調(diào)實現(xiàn)了所有實現(xiàn)了ServletContainerInitializer類的onStartup方法

      javax.servlet.ServletContainerInitializer#onStartup
      

        具體代碼需要關(guān)聯(lián)tomcat源碼,這里只是簡單記錄下,后續(xù)再深入分析tomcat實現(xiàn)原理

      org.apache.catalina.core.StandardContext#startInternal
      
      while(var27.hasNext()) {
                      Entry entry = (Entry)var27.next();
      
                      try {
                          ((ServletContainerInitializer)entry.getKey()).onStartup((Set)entry.getValue(), this.getServletContext());
                      } catch (ServletException var22) {
                          log.error(sm.getString("standardContext.sciFail"), var22);
                          ok = false;
                          break;
                      }
                  }
      

       

            而TomcatStarter正好實現(xiàn)了ServletContainerInitializer接口,所以tomcat啟動會觸發(fā)這個方法的調(diào)用  

      org.springframework.boot.web.embedded.tomcat.TomcatStarter#onStartup
      

        方法內(nèi)部調(diào)用了spring中實現(xiàn)了ServletContextInitializer接口的類的onStartup方法,恰好又是DispatcherServletRegistrationBean,而它的父類RegistrationBean就將DispatcherServlet綁定到tomcat容器的ServletContext上了

      org.springframework.boot.autoconfigure.web.servlet.DispatcherServletRegistrationBean
      org.springframework.boot.web.servlet.RegistrationBean#onStartup
      

        

      最后,tomcat容器啟動了,spring容器也啟動了,訪問tomcat的請求也可以通過關(guān)聯(lián)的DispatcherServlet進行分發(fā)處理了,咱們前面的三個問題也應(yīng)該有答案了。

       

      posted @ 2022-01-23 12:50  abingtech  閱讀(473)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 久久精品丝袜高跟鞋| 亚洲熟妇自偷自拍另欧美| 天堂国产一区二区三区| 国产国语一级毛片| 国产av一区二区亚洲精品| 久久无码高潮喷水| 国产伦子沙发午休系列资源曝光 | 国产精品国产亚洲看不卡| 威远县| 亚洲精品一二三在线观看| 日韩精品中文字幕有码| 免费吃奶摸下激烈视频| 亚洲中文字幕av天堂| 五月综合婷婷久久网站| 免费观看激色视频网站| 国产日韩精品一区在线不卡| 亚洲sm另类一区二区三区| 襄城县| 在线视频中文字幕二区| 插入中文字幕在线一区二区三区| 免费看黄色片| 国产精品老熟女露脸视频| 精品久久久久久无码专区不卡| 熟女精品国产一区二区三区| 99精品热在线在线观看视| 亚洲人成网线在线播放VA| 人妻少妇精品系列一区二区| 日本真人添下面视频免费| 国产成人高清精品免费软件| 免费观看日本污污ww网站| 亚洲国产精品日韩av专区| 国产精品一区中文字幕| 亚洲欧美激情在线一区| 人妻少妇精品中文字幕| 国产亚洲精品97在线视频一| 国产区二区三区在线观看| 夜夜添狠狠添高潮出水| 不卡一区二区三区四区视频| 久久视频这里只精品| 中文字幕国产精品av| 久久精品一偷一偷国产|