最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring Boot啟動過程完全解析(二)

 更新時間:2017年04月21日 16:57:10   作者:draculav  
這篇文章主要介紹了Spring Boot啟動過程完全解析(二),需要的朋友可以參考下

上篇給大家介紹了Spring Boot啟動過程完全解析(一),大家可以點擊參考下

  該說refreshContext(context)了,首先是判斷context是否是AbstractApplicationContext派生類的實例,之后調用了強轉為AbstractApplicationContext類型并調用它的refresh方法。由于AnnotationConfigEmbeddedWebApplicationContext繼承自EmbeddedWebApplicationContext,所以會執(zhí)行EmbeddedWebApplicationContext的refresh方法,繼而執(zhí)行其中的super.refresh。這個refresh也就是AbstractApplicationContext的refresh方法了,它內部是一個synchronized鎖全局的代碼塊,同樣的加鎖方法還有這個類里的close和registerShutdownHook方法。

  同步代碼塊中第一個方法prepareRefresh,首先會執(zhí)行AnnotationConfigEmbeddedWebApplicationContext的prepareRefresh方法:

 protected void prepareRefresh() {
  this.scanner.clearCache();
  super.prepareRefresh();
 }

  這個super也就是AbstractApplicationContext,它的prepareRefresh方法邏輯是:生成啟動時間;設置closed狀態(tài)為false;active狀態(tài)為true;initPropertySources方法主要是調用了AbstractEnvironment的getPropertySources方法獲取了之前SpringApplication的prepareEnvironment方法中getOrCreateEnvironment方法準備的各種環(huán)境變量及配置并用于初始化ServletPropertySources。具體的servletContextInitParams這些是在環(huán)境對象初始化時由各集成級別Environment的customizePropertySources方法中初始化的。

   接著的getEnvironment().validateRequiredProperties()方法實際執(zhí)行了AbstractEnvironment中的this.propertyResolver.validateRequiredProperties(),主要是驗證了被占位的key如果是required的值不能為null。prepareRefresh的最后是初始化this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>()。*****

  只夠是獲取BeanFactory實例的方法obtainFreshBeanFactory(),首先在refreshBeanFactory方法中用原子布爾類型判斷是否刷新過,BeanFactory實例是在createApplicationContext創(chuàng)建Context實例時被創(chuàng)建的,如果沒有刷新則設置一個用于序列化的id,id是ContextIdApplicationContextInitializer初始化設置的(如未配置該初始化器,是有一個默認ObjectUtils.identityToString(this)生成的),這個id的生成規(guī)則是spring.config.name截取的+":"+server.port的占位截取。設置序列化id時,同時保存了一個id和弱引用DefaultListableBeanFactory實例映射。

  得到了beanFactory后就是prepareBeanFactory(beanFactory)了,邏輯是注冊了BeanClassLoader用于注入的bean實例的創(chuàng)建;StandardBeanExpressionResolver用于EL表達式,比如配置文件或者@Value("#{...}")等使用;用ResourceEditorRegistrar注冊屬性轉換器,比如xml配置的bean屬性都是用的字符串配置的要轉成真正的屬性類型;addBeanPostProcessor(new ApplicationContextAwareProcessor(this))注冊ApplicationContextAwareProcessor,它的invokeAwareInterfaces方法會對實現(xiàn)指定接口的bean調用指定的set方法;ignoreDependencyInterface忽略對這些接口的自動裝配,比如Aware這些是要做獨立處理的,不適合通用的方法;然后是有幾個類型直接手動注冊,比如BeanFactory,這個很好理解;接著注冊一個后置處理器ApplicationListenerDetector的實例,addBeanPostProcessor注冊的會按照注冊先后順序執(zhí)行;這個方法的最后判斷了特定的4個bean名字,如果存在會做相應注冊,包括loadTimeWeaver、environment、systemProperties和systemEnvironment。補充一點,在最開始創(chuàng)建實例的時候還執(zhí)行過ignoreDependencyInterface(BeanNameAware.class);ignoreDependencyInterface(BeanFactoryAware.class);ignoreDependencyInterface(BeanClassLoaderAware.class)。

 protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
  // Tell the internal bean factory to use the context's class loader etc.
  beanFactory.setBeanClassLoader(getClassLoader());
  beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
  beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
  // Configure the bean factory with context callbacks.
  beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
  beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
  beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
  beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
  beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
  beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
  beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
  // BeanFactory interface not registered as resolvable type in a plain factory.
  // MessageSource registered (and found for autowiring) as a bean.
  beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
  beanFactory.registerResolvableDependency(ResourceLoader.class, this);
  beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
  beanFactory.registerResolvableDependency(ApplicationContext.class, this);
  // Register early post-processor for detecting inner beans as ApplicationListeners.
  beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
  // Detect a LoadTimeWeaver and prepare for weaving, if found.
  if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
   beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
   // Set a temporary ClassLoader for type matching.
   beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
  }
  // Register default environment beans.
  if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
   beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
  }
  if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
   beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
  }
  if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
   beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
  }
 }

   之后到了refresh的postProcessBeanFactory方法,首先是會走到AnnotationConfigEmbeddedWebApplicationContext的Override,需要注意的一點是,這是web環(huán)境,如果不是是不會加載這個上下文的,也就不會這么走。它重寫的第一步是先走super也就是EmbeddedWebApplicationContext的postProcessBeanFactory,這里又注冊了個后置處理器WebApplicationContextServletContextAwareProcessor的實例,構造參數(shù)是this,也就是當前上下文,同時忽略ServletContextAware接口,這個接口是用于獲取ServletContext的,為什么要忽略呢,我猜應該是因為我們既然有了web應用并且內嵌servlet的上下文實例,還要ServletContext的實現(xiàn)就沒什么用了,還有可能出現(xiàn)沖突的問題,有空我再確認下。然后是配置的basePackages和annotatedClasses:

@Override
 protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
  super.postProcessBeanFactory(beanFactory);
  if (this.basePackages != null && this.basePackages.length > 0) {
   this.scanner.scan(this.basePackages);
  }
  if (this.annotatedClasses != null && this.annotatedClasses.length > 0) {
   this.reader.register(this.annotatedClasses);
  }
 }

  到了invokeBeanFactoryPostProcessors方法,這個方法就是執(zhí)行之前注冊的BeanFactory后置處理器的地方。代碼一目了然,PostProcessorRegistrationDelegate的invokeBeanFactoryPostProcessors中只是有些排序的邏輯,我就不說了:

 /**
  * Instantiate and invoke all registered BeanFactoryPostProcessor beans,
  * respecting explicit order if given.
  * <p>Must be called before singleton instantiation.
  */
 protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
  PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
  // Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
  // (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
  if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
   beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
   beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
  }
 }

   BeanFactory后置處理器執(zhí)行之后是注冊Bean的后置處理器方法registerBeanPostProcessors。例如new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount)會在Bean沒有合適的后置處理器時記條info級日志。ApplicationListenerDetector也注冊了一個。

  initMessageSource這個方法在我這沒什么用,都說是國際化的,隨便百度一下一堆一堆的,而且其實嚴格來說這篇多數(shù)不屬于spring boot的部分,這方法我就不細寫了。

  initApplicationEventMulticaster方法主要也就是初始化并注冊applicationEventMulticaster的這兩句代碼:          

this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
   beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);

   onRefresh也是根據(jù)環(huán)境不同加載的上下文不同而不同的,用于支持子類擴展出來的上下文特定的邏輯的。EmbeddedWebApplicationContext的onRefresh首先依然是super.onRefresh,邏輯就是初始化了主題;

createEmbeddedServletContainer方法名我就不翻譯了,一般情況下是使用getBeanFactory .getBeanNamesForType方法找到EmbeddedServletContainerFactory類型的實例,這也就是我之前那個問題解決過程中,為什么只要排除掉tomcat引用,引入jetty引用就可以自動換成jetty的原因。創(chuàng)建容器的過程中初始化方法selfInitialize注冊了filter和MappingForUrlPatterns等,代碼在AbstractFilterRegistrationBean等onStartup,這里就不細說了,如果能抽出時間說說之前查問題的時候查的容器代碼再說。然后初始化PropertySources,servletContextInitParams和servletConfigInitParams:

 public static void initServletPropertySources(
   MutablePropertySources propertySources, ServletContext servletContext, ServletConfig servletConfig) {
  Assert.notNull(propertySources, "'propertySources' must not be null");
  if (servletContext != null && propertySources.contains(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME) &&
    propertySources.get(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME) instanceof StubPropertySource) {
   propertySources.replace(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME,
     new ServletContextPropertySource(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME, servletContext));
  }
  if (servletConfig != null && propertySources.contains(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME) &&
    propertySources.get(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME) instanceof StubPropertySource) {
   propertySources.replace(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME,
     new ServletConfigPropertySource(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME, servletConfig));
  }
 }

  registerListeners首先注冊靜態(tài)監(jiān)聽:

 @Override
 public void addApplicationListener(ApplicationListener<?> listener) {
  synchronized (this.retrievalMutex) {
   this.defaultRetriever.applicationListeners.add(listener);
   this.retrieverCache.clear();
  }
 }

  接著是:

 

 registerListeners的最后,初始化過的earlyApplicationEvents如果有事件,這時候會被發(fā)布。

  finishBeanFactoryInitialization結束BeanFactory的初始化并初始化所有非延遲加載的單例。事實上我們自定義的單例Bean都是在這里getBean方法初始化的,所以如果注冊的Bean特別多的話,這個過程就是啟動過程中最慢的。初始化開始前先設置configurationFrozen為true,并this.frozenBeanDefinitionNames = StringUtils.toStringArray ( this. beanDefinitionNames )。如果有bean實例實現(xiàn)了SmartInitializingSingleton會有后置處理觸發(fā),不包括延遲加載的。例如:org.springframework.context.event. internalEventListenerProcessor會觸發(fā)EventListenerMethodProcessor的afterSingletonsInstantiated方法對所有對象(Object的子類)處理。

  finishRefresh:Refresh的最后一步,發(fā)布相應事件。同樣先執(zhí)行EmbeddedWebApplicationContext中對應方法的super(EmbeddedWebApplicationContext)的對應方法:

 /**
  * Finish the refresh of this context, invoking the LifecycleProcessor's
  * onRefresh() method and publishing the
  * {@link org.springframework.context.event.ContextRefreshedEvent}.
  */
 protected void finishRefresh() {
  // Initialize lifecycle processor for this context.
  initLifecycleProcessor();
  // Propagate refresh to lifecycle processor first.
  getLifecycleProcessor().onRefresh();
  // Publish the final event.
  publishEvent(new ContextRefreshedEvent(this));
  // Participate in LiveBeansView MBean, if active.
  LiveBeansView.registerApplicationContext(this);
 }

   初始化生命周期處理器,邏輯是判斷beanFactory中是否已經(jīng)注冊了lifecycleProcessor,沒有就new一個DefaultLifecycleProcessor并setBeanFactory(beanFactory),然后將它賦值給私有LifecycleProcessor類型的this變量。然后執(zhí)行生命周期處理器的onRefresh,其中先startBeans,被start的beans是通過getBeanNamesForType(Lifecycle.class, false, false)從beanFactory中取出來的,例如endpointMBeanExporter和lifecycleProcessor,會去調用bean的start方法,endpointMBeanExporter的start中執(zhí)行 locateAndRegisterEndpoints方法并設置running屬性為true,這個過程加了ReentrantLock鎖。bean都啟動完會設置處理器的running為true。刷新完會發(fā)布ContextRefreshedEvent事件,這個事件除了都有的記錄時間還執(zhí)行了ConfigurationPropertiesBindingPostProcessor的freeLocalValidator方法,我這的邏輯是實際上執(zhí)行了ValidatorFactoryImpl的close方法。這個邏輯的最后會檢查一個配置spring.liveBeansView.mbeanDomain是否存在,有就會創(chuàng)建一個MBeanServer:

static void registerApplicationContext(ConfigurableApplicationContext applicationContext) {
  String mbeanDomain = applicationContext.getEnvironment().getProperty(MBEAN_DOMAIN_PROPERTY_NAME);
  if (mbeanDomain != null) {
   synchronized (applicationContexts) {
    if (applicationContexts.isEmpty()) {
     try {
      MBeanServer server = ManagementFactory.getPlatformMBeanServer();
      applicationName = applicationContext.getApplicationName();
      server.registerMBean(new LiveBeansView(),
        new ObjectName(mbeanDomain, MBEAN_APPLICATION_KEY, applicationName));
     }
     catch (Throwable ex) {
      throw new ApplicationContextException("Failed to register LiveBeansView MBean", ex);
     }
    }
    applicationContexts.add(applicationContext);
   }
  }
 }

  finishRefresh最后會啟動前面創(chuàng)建的內嵌容器,并發(fā)布EmbeddedServletContainerInitializedEvent事件,啟動這一部分算是容器的邏輯了,有機會整理容器邏輯再細寫,我這里是Tomcat的:

@Override
 public void start() throws EmbeddedServletContainerException {
  try {
   addPreviouslyRemovedConnectors();
   Connector connector = this.tomcat.getConnector();
   if (connector != null && this.autoStart) {
    startConnector(connector);
   }
   checkThatConnectorsHaveStarted();
   TomcatEmbeddedServletContainer.logger
     .info("Tomcat started on port(s): " + getPortsDescription(true));
  }
  catch (ConnectorStartFailedException ex) {
   stopSilently();
   throw ex;
  }
  catch (Exception ex) {
   throw new EmbeddedServletContainerException(
     "Unable to start embedded Tomcat servlet container", ex);
  }
  finally {
   Context context = findContext();
   ContextBindings.unbindClassLoader(context, getNamingToken(context),
     getClass().getClassLoader());
  }
 }

  然后是resetCommonCaches:

 /**
  * Reset Spring's common core caches, in particular the {@link ReflectionUtils},
  * {@link ResolvableType} and {@link CachedIntrospectionResults} caches.
  * @since 4.2
  * @see ReflectionUtils#clearCache()
  * @see ResolvableType#clearCache()
  * @see CachedIntrospectionResults#clearClassLoader(ClassLoader)
  */
 protected void resetCommonCaches() {
  ReflectionUtils.clearCache();
  ResolvableType.clearCache();
  CachedIntrospectionResults.clearClassLoader(getClassLoader());
 }

  refreshContext的最后是注冊shutdown的鉤子:

 if (this.registerShutdownHook) {
   try {
    context.registerShutdownHook();
   }
   catch (AccessControlException ex) {
    // Not allowed in some environments.
   }
  }

 /**
  * Register a shutdown hook with the JVM runtime, closing this context
  * on JVM shutdown unless it has already been closed at that time.
  * <p>Delegates to {@code doClose()} for the actual closing procedure.
  * @see Runtime#addShutdownHook
  * @see #close()
  * @see #doClose()
  */
 @Override
 public void registerShutdownHook() {
  if (this.shutdownHook == null) {
   // No shutdown hook registered yet.
   this.shutdownHook = new Thread() {
    @Override
    public void run() {
     synchronized (startupShutdownMonitor) {
      doClose();
     }
    }
   };
   Runtime.getRuntime().addShutdownHook(this.shutdownHook);
  }
 }

咱最近用的github:https://github.com/saaavsaaa

以上所述是小編給大家介紹的Spring Boot啟動過程完全解析(二),希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!

相關文章

  • Java初學者入門之繼承和多態(tài)

    Java初學者入門之繼承和多態(tài)

    Java 面向對象編程有三大特性:封裝、繼承、多態(tài),學好繼承和多態(tài)是面向對象開發(fā)語言中非常重要的一個環(huán)節(jié),這篇文章主要給大家介紹了關于Java初學者入門之繼承和多態(tài)的相關資料,需要的朋友可以參考下
    2021-07-07
  • Springboot apollo原理及使用方法詳解

    Springboot apollo原理及使用方法詳解

    這篇文章主要介紹了Springboot apollo原理及使用方法詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-06-06
  • Java多線程下載文件實現(xiàn)案例詳解

    Java多線程下載文件實現(xiàn)案例詳解

    這篇文章主要介紹了Java多線程下載文件實現(xiàn)案例詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-05-05
  • Mybatis-plus使用selectList查詢數(shù)據(jù)為null的問題及解決辦法

    Mybatis-plus使用selectList查詢數(shù)據(jù)為null的問題及解決辦法

    這篇文章主要介紹了Mybatis-plus使用selectList查詢數(shù)據(jù)為null的問題及解決方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-07-07
  • Java與Node.js利用AES加密解密出相同結果的方法示例

    Java與Node.js利用AES加密解密出相同結果的方法示例

    這篇文章主要介紹了Java與Node.js利用AES加密解密出相同結果的方法,文中給出了詳細的示例代碼,相信對大家的學習或者工作能帶來一定的幫助,需要的朋友們下面來一起看看吧。
    2017-02-02
  • spring mvc中@RequestBody注解的作用說明

    spring mvc中@RequestBody注解的作用說明

    這篇文章主要介紹了spring mvc中@RequestBody注解的作用說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • Java設計模式之策略模式的使用(Strategy?Pattern)

    Java設計模式之策略模式的使用(Strategy?Pattern)

    策略模式是一種行為型設計模式,用于定義一系列算法并將每個算法封裝起來,使它們可以互相替換,從而實現(xiàn)代碼的可維護性和靈活性,策略模式包含策略接口、具體策略類和上下文類,并通過將算法的選擇與使用分離,使得算法可以獨立變化
    2025-03-03
  • 如何解決SpringBoot定時任務報錯Unexpected error occurred in scheduled task問題

    如何解決SpringBoot定時任務報錯Unexpected error occurred 

    這篇文章主要介紹了如何解決SpringBoot定時任務報錯Unexpected error occurred in scheduled task問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • Java以struts2為例介紹如何實現(xiàn)圖片上傳

    Java以struts2為例介紹如何實現(xiàn)圖片上傳

    這篇文章主要介紹了Java struts2中如何實現(xiàn)圖片上傳的相關資料,需要的朋友可以參考下
    2015-11-11
  • Java調用dll文件的實現(xiàn)解析

    Java調用dll文件的實現(xiàn)解析

    這篇文章主要介紹了Java調用dll文件的實現(xiàn)解析,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-02-02

最新評論

苏州市| 织金县| 玛纳斯县| 东平县| 沅江市| 乐陵市| 衡山县| 柞水县| 云和县| 阜新市| 汤原县| 黄梅县| 达拉特旗| 都安| 三明市| 沙湾县| 垫江县| 阜康市| 雷山县| 福建省| 海口市| 阿勒泰市| 旬邑县| 瑞昌市| 阳信县| 个旧市| 邢台市| 通州市| 什邡市| 报价| 青海省| 定安县| 平罗县| 黄平县| 佛教| 葫芦岛市| 临安市| 菏泽市| 仙桃市| 长子县| 调兵山市|