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

SpringBoot應(yīng)用啟動過程分析

 更新時間:2017年08月04日 11:10:39   作者:loongshawn  
這篇文章主要介紹了SpringBoot應(yīng)用啟動過程分析,需要的朋友可以參考下

 SpringBoot項目通過SpringApplication.run(App.class, args)來啟動:

@Configuration
public class App {
 public static void main(String[] args) {
 SpringApplication.run(App.class, args);
 }
}

接下來,通過源碼來看看SpringApplication.run()方法的執(zhí)行過程。如果對源碼不感興趣,直接下拉到文章末尾,看啟動框圖。

1、調(diào)用SpringApplication類的靜態(tài)方法

 public static ConfigurableApplicationContext run(Object source, String... args) {
  return run(new Object[] { source }, args);
 }
 public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
  return new SpringApplication(sources).run(args);
 }

2、SpringApplication對象初始化

public SpringApplication(Object... sources) {
  initialize(sources);
 }
 @SuppressWarnings({ "unchecked", "rawtypes" })
 private void initialize(Object[] sources) {
  if (sources != null && sources.length > 0) {
   this.sources.addAll(Arrays.asList(sources));
  }
  // 判斷是否為WEB環(huán)境
  this.webEnvironment = deduceWebEnvironment();
  // 找到META-INF/spring.factories中ApplicationContextInitializer所有實現(xiàn)類,并將其實例化
  setInitializers((Collection) getSpringFactoriesInstances(
    ApplicationContextInitializer.class));
  // 找到META-INF/spring.factories中ApplicationListener所有實現(xiàn)類,并將其實例化
  setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
  // 獲取當(dāng)前main方法類對象,即測試類中的App實例
  this.mainApplicationClass = deduceMainApplicationClass();
 }

對象初始化過程中,使用到了getSpringFactoriesInstances方法:

 private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type) {
  return getSpringFactoriesInstances(type, new Class<?>[] {});
 }
 private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,
   Class<?>[] parameterTypes, Object... args) {
  ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
  // Use names and ensure unique to protect against duplicates
  // 讀取META-INF/spring.factories指定接口的實現(xiàn)類
  Set<String> names = new LinkedHashSet<String>(
    SpringFactoriesLoader.loadFactoryNames(type, classLoader));
  List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
    classLoader, args, names);
  AnnotationAwareOrderComparator.sort(instances);
  return instances;
 }
 @SuppressWarnings("unchecked")
 private <T> List<T> createSpringFactoriesInstances(Class<T> type,
   Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,
   Set<String> names) {
  List<T> instances = new ArrayList<T>(names.size());
  for (String name : names) {
   try {
    Class<?> instanceClass = ClassUtils.forName(name, classLoader);
    Assert.isAssignable(type, instanceClass);
    Constructor<?> constructor = instanceClass.getConstructor(parameterTypes);
    T instance = (T) constructor.newInstance(args);
    instances.add(instance);
   }
   catch (Throwable ex) {
    throw new IllegalArgumentException(
      "Cannot instantiate " + type + " : " + name, ex);
   }
  }
  return instances;
 }
 // 讀取META-INF/spring.factories文件
 public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
  String factoryClassName = factoryClass.getName();
  try {
   Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
     ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
   List<String> result = new ArrayList<String>();
   while (urls.hasMoreElements()) {
    URL url = urls.nextElement();
    Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
    String factoryClassNames = properties.getProperty(factoryClassName);
    result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
   }
   return result;
  }
  catch (IOException ex) {
   throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() +
     "] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);
  }
 }
META-INF/spring.factories文件內(nèi)容,spring boot版本1.3.6.RELEASE
# PropertySource Loaders
org.springframework.boot.env.PropertySourceLoader=\
org.springframework.boot.env.PropertiesPropertySourceLoader,\
org.springframework.boot.env.YamlPropertySourceLoader
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
# Application Context Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.context.web.ServerPortInfoApplicationContextInitializer
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.ConfigFileApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener,\
org.springframework.boot.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.logging.LoggingApplicationListener
# Environment Post Processors
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor

ApplicationListener接口是Spring框架的事件監(jiān)聽器,其作用可理解為SpringApplicationRunListener發(fā)布通知事件時,由ApplicationListener負(fù)責(zé)接收。SpringApplicationRunListener接口的實現(xiàn)類就是EventPublishingRunListener,其在SpringBoot啟動過程中,負(fù)責(zé)注冊ApplicationListener監(jiān)聽器,在不同時間節(jié)點發(fā)布不同事件類型,如果有ApplicationListener實現(xiàn)類監(jiān)聽了該事件,則接收處理。

public interface SpringApplicationRunListener {
 /**
  * 通知監(jiān)聽器,SpringBoot開始啟動
  */
 void started();
 /**
  * 通知監(jiān)聽器,環(huán)境配置完成
  */
 void environmentPrepared(ConfigurableEnvironment environment);
 /**
  * 通知監(jiān)聽器,ApplicationContext已創(chuàng)建并初始化完成
  */
 void contextPrepared(ConfigurableApplicationContext context);
 /**
  * 通知監(jiān)聽器,ApplicationContext已完成IOC配置
  */
 void contextLoaded(ConfigurableApplicationContext context);
 /**
  * 通知監(jiān)聽器,SpringBoot開始完畢
  */
 void finished(ConfigurableApplicationContext context, Throwable exception);
}

附圖為ApplicationListener監(jiān)聽接口實現(xiàn)類,每個類對應(yīng)了一種事件。

這里寫圖片描述

3、SpringApplication核心run方法

/**
  * Run the Spring application, creating and refreshing a new
  * {@link ApplicationContext}.
  * @param args the application arguments (usually passed from a Java main method)
  * @return a running {@link ApplicationContext}
  */
 public ConfigurableApplicationContext run(String... args) {
  // 任務(wù)執(zhí)行時間監(jiān)聽,記錄起止時間差
  StopWatch stopWatch = new StopWatch();
  stopWatch.start();
  ConfigurableApplicationContext context = null;
  configureHeadlessProperty();
  // 啟動SpringApplicationRunListener監(jiān)聽器
  SpringApplicationRunListeners listeners = getRunListeners(args);
  listeners.started();
  try {
   ApplicationArguments applicationArguments = new DefaultApplicationArguments(
     args);
   // 創(chuàng)建并刷新ApplicationContext
   context = createAndRefreshContext(listeners, applicationArguments);
   afterRefresh(context, applicationArguments);
   // 通知監(jiān)聽器,應(yīng)用啟動完畢
   listeners.finished(context, null);
   stopWatch.stop();
   if (this.logStartupInfo) {
    new StartupInfoLogger(this.mainApplicationClass)
      .logStarted(getApplicationLog(), stopWatch);
   }
   return context;
  }
  catch (Throwable ex) {
   handleRunFailure(context, listeners, ex);
   throw new IllegalStateException(ex);
  }
 }

這里,需要看看createAndRefreshContext()方法是如何創(chuàng)建并刷新ApplicationContext。

private ConfigurableApplicationContext createAndRefreshContext(
   SpringApplicationRunListeners listeners,
   ApplicationArguments applicationArguments) {
  ConfigurableApplicationContext context;
  // Create and configure the environment
  // 創(chuàng)建并配置運行環(huán)境,WebEnvironment與StandardEnvironment選其一
  ConfigurableEnvironment environment = getOrCreateEnvironment();
  configureEnvironment(environment, applicationArguments.getSourceArgs());
  listeners.environmentPrepared(environment);
  if (isWebEnvironment(environment) && !this.webEnvironment) {
   environment = convertToStandardEnvironment(environment);
  }
  // 是否打印Banner,就是啟動程序時出現(xiàn)的圖形
  if (this.bannerMode != Banner.Mode.OFF) {
   printBanner(environment);
  }
  // Create, load, refresh and run the ApplicationContext
  // 創(chuàng)建、裝置、刷新、運行ApplicationContext
  context = createApplicationContext();
  context.setEnvironment(environment);
  postProcessApplicationContext(context);
  applyInitializers(context);
  // 通知監(jiān)聽器,ApplicationContext創(chuàng)建完畢
  listeners.contextPrepared(context);
  if (this.logStartupInfo) {
   logStartupInfo(context.getParent() == null);
   logStartupProfileInfo(context);
  }
  // Add boot specific singleton beans
  context.getBeanFactory().registerSingleton("springApplicationArguments",
    applicationArguments);
  // Load the sources
  // 將beans載入到ApplicationContext容器中
  Set<Object> sources = getSources();
  Assert.notEmpty(sources, "Sources must not be empty");
  load(context, sources.toArray(new Object[sources.size()]));
  // 通知監(jiān)聽器,beans載入ApplicationContext完畢
  listeners.contextLoaded(context);
  // Refresh the context
  refresh(context);
  if (this.registerShutdownHook) {
   try {
    context.registerShutdownHook();
   }
   catch (AccessControlException ex) {
    // Not allowed in some environments.
   }
  }
  return context;
 }

其中利用createApplicationContext()來實例化ApplicationContext對象,即DEFAULT_WEB_CONTEXT_CLASS 、DEFAULT_CONTEXT_CLASS兩個對象其中一個。

protected ConfigurableApplicationContext createApplicationContext() {
  Class<?> contextClass = this.applicationContextClass;
  if (contextClass == null) {
   try {
    contextClass = Class.forName(this.webEnvironment
      ? DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS);
   }
   catch (ClassNotFoundException ex) {
    throw new IllegalStateException(
      "Unable create a default ApplicationContext, "
        + "please specify an ApplicationContextClass",
      ex);
   }
  }
  return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass);
 }

postProcessApplicationContext(context)、applyInitializers(context)均為初始化ApplicationContext工作。

SpringBoot啟動過程分析就先到這里,過程中關(guān)注幾個對象:

ApplicationContext:Spring高級容器,與BeanFactory類似。

SpringApplicationRunListener:SprintBoot啟動監(jiān)聽器,負(fù)責(zé)向ApplicationListener注冊各類事件。

Environment:運行環(huán)境。

4、啟動過程框圖

這里寫圖片描述

5、接口文檔

http://docs.spring.io/spring-framework/docs/current/javadoc-api/

總結(jié)

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

相關(guān)文章

  • Spring中@Value讀取properties作為map或list的操作

    Spring中@Value讀取properties作為map或list的操作

    這篇文章主要介紹了Spring中@Value讀取properties作為map或list的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • Java 數(shù)據(jù)庫連接池c3p0 介紹

    Java 數(shù)據(jù)庫連接池c3p0 介紹

    這篇文章主要介給大家分享了 Java 數(shù)據(jù)庫連接池c3p0 介紹,c3p0 是一個成熟的、高并發(fā)的 JDBC 連接池庫,支持緩存和 PreparedStatements 的重用。它以LGPL v.2.1或EPL v.1.0授權(quán),下面我們就一起來看看文章內(nèi)容的詳細(xì)介紹吧,需要的朋友也可以參考一下
    2021-11-11
  • Java多線程——基礎(chǔ)概念

    Java多線程——基礎(chǔ)概念

    這篇文章主要介紹了java多線程編程實例,分享了幾則多線程的實例代碼,具有一定參考價值,加深多線程編程的理解還是很有幫助的,需要的朋友可以參考下,希望可以幫到你
    2021-07-07
  • SpringBoot中LogBack日志配置與多環(huán)境實戰(zhàn)

    SpringBoot中LogBack日志配置與多環(huán)境實戰(zhàn)

    在現(xiàn)代軟件開發(fā)中,日志記錄是不可或缺的一部分,Spring Boot 提供了多種日志框架的支持,其中 Logback 是一個非常流行的選擇,因為它簡單、高效且功能強大,本文將介紹如何在 Spring Boot 項目中配置 Logback,并實現(xiàn)不同環(huán)境下的日志配置,需要的朋友可以參考下
    2025-01-01
  • java基礎(chǔ)之反射和泛型以及注解

    java基礎(chǔ)之反射和泛型以及注解

    這篇文章主要介紹了 java基礎(chǔ)之反射和泛型以及注解的相關(guān)資料,需要的朋友可以參考下
    2017-07-07
  • Java NIO深入分析

    Java NIO深入分析

    本篇技術(shù)文章主要對Java新api(New IO)做了詳細(xì)深入的講解,有助于程序?qū)IO有更加深入的理解。
    2017-12-12
  • 解讀nextLine().split(“[\\s]“)的意思

    解讀nextLine().split(“[\\s]“)的意思

    這篇文章主要介紹了解讀nextLine().split(“[\\s]“)的意思,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • java開發(fā)RocketMQ生產(chǎn)者高可用示例詳解

    java開發(fā)RocketMQ生產(chǎn)者高可用示例詳解

    這篇文章主要為大家介紹了java開發(fā)RocketMQ生產(chǎn)者高可用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • Java設(shè)計模式之java觀察者模式詳解

    Java設(shè)計模式之java觀察者模式詳解

    這篇文章主要介紹了Java經(jīng)典設(shè)計模式之觀察者模式,簡單分析了觀察者模式的概念、原理并結(jié)合實例形式給出了java觀察者模式的具體用法與相關(guān)注意事項,需要的朋友可以參考下
    2021-09-09
  • Spring?Boot?使用?Hutool-jwt?實現(xiàn)?token?驗證功能

    Spring?Boot?使用?Hutool-jwt?實現(xiàn)?token?驗證功能

    JWT?就是一種網(wǎng)絡(luò)身份認(rèn)證和信息交換格式,這篇文章主要介紹了Spring Boot使用Hutool-jwt實現(xiàn)token驗證,需要的朋友可以參考下
    2023-07-07

最新評論

区。| 济源市| 长治县| 镇安县| 江山市| 新晃| 临湘市| 高陵县| 屏南县| 德安县| 神木县| 温泉县| 富蕴县| 咸阳市| 肇源县| 家居| 屏山县| 灯塔市| 河源市| 繁昌县| 兰州市| 台安县| 兰州市| 伽师县| 开封县| 博罗县| 东港市| 田林县| 城口县| 尉犁县| 库车县| 兴安盟| 宿州市| 南岸区| 沛县| 阳西县| 仙桃市| 封丘县| 恩平市| 新宁县| 广灵县|