中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

SpringBoot的啟動流程有哪些

發布時間:2021-06-18 14:58:10 來源:億速云 閱讀:177 作者:Leah 欄目:大數據

SpringBoot的啟動流程有哪些,針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。

1.SpringBoot項目啟動方式:

  1. 在IDE中啟動SpringBoot主類(XXXApplication)中的main方法

  2. 使用mvn spring-boot:run命令啟動

  3. 打成jar包之后使用java -jar xxx.jar運行

  4. 打成war包之后放在web容器中運行


2.SpringBoot啟動流程主要分為三步:

第一部分:SpringApplication初始化模塊,配置一些基本的環境變量,資源,監聽器,構造器;

第二部分:實現了應用具體的啟動方案,包括流程的監聽模塊,加載配置環境模塊以及創建上下文環境模塊

第三部分:自動化配置模塊,這個模塊是實現SpringBoot的自動配置


SpringBoot程序的主入口就是標注了@SpringBootApplication注解的類,該類中有一個main方法,在main方法中調用SpringApplication的run()方法,這個run()方法來啟動整個程序

@SpringBootApplication
public class CrmWebApiApplication extends SpringBootServletInitializer {

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

下面是@SpringBootApplication注解的頭部源碼

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
		@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

這是一個組合注解,其中標注的注解主要有以下作用

@EnableAutoConfiguration: 開啟SpringBoot自動配置,在程序啟動時會自動加載SpringBoot的默認配置,如果有對一些參數進行配置,則會在程序啟動時或調用時進行追加或者覆蓋

@SpringBootConfiguration: 這個注解和@Configuration注解的作用一樣,用來表示被標注的類是一個配置類,會將被標注的類中一個或多個被@Bean注解修飾的方法添加到Spring容器中,實例的名字默認是方法名

@ComponentScan: 包掃描注解,默認掃描主類包路徑下的類


進入run()方法后的代碼如下:

/**
	 * Static helper that can be used to run a {@link SpringApplication} from the
	 * specified sources using default settings and user supplied arguments.
	 * @param sources the sources to load
	 * @param args the application arguments (usually passed from a Java main method)
	 * @return the running {@link ApplicationContext}
	 */
	public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
		return new SpringApplication(sources).run(args);
	}

這里會創建一個SpringApplication類的實例,進入SpringApplication類中可以看到構造方法里調用了一個initialize(sources)方法

/**
	 * Create a new {@link SpringApplication} instance. The application context will load
	 * beans from the specified sources (see {@link SpringApplication class-level}
	 * documentation for details. The instance can be customized before calling
	 * {@link #run(String...)}.
	 * @param sources the bean sources
	 * @see #run(Object, String[])
	 * @see #SpringApplication(ResourceLoader, Object...)
	 */
	public SpringApplication(Object... sources) {
		initialize(sources);
	}

Initialize(sources)方法源碼如下:

@SuppressWarnings({ "unchecked", "rawtypes" })
private void initialize(Object[] sources) {
    if (sources != null && sources.length > 0) {
        //將sources設置到SpringApplication類的source屬性中,這時的source值只有主類
        this.sources.addAll(Arrays.asList(sources));
    }
    //判斷是不是web程序,
    this.webEnvironment = deduceWebEnvironment();
    //從spring.factories文件中找出key為ApplicationContextInitializer的類進行實例化,然后設置到SpringApplciation類的initializers屬性中,這個過程也是找出所有的應用程序初始化器
    setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class));
    //從spring.factories文件中找出key為ApplicationListener的類并實例化后設置到SpringApplication的listeners屬性中。這個過程就是找出所有的應用程序事件監聽器
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    //找出main類,也就是SpringBoot項目的主類
    this.mainApplicationClass = deduceMainApplicationClass();
}

2.1 run方法完整代碼

執行完初始化之后回到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) {
  StopWatch stopWatch = new StopWatch();
  stopWatch.start();
  ConfigurableApplicationContext context = null;
  FailureAnalyzers analyzers = null;
  configureHeadlessProperty();
   //創建應用監聽器
  SpringApplicationRunListeners listeners = getRunListeners(args);
  //開始監聽
  listeners.starting();
  
  try {
     ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
     //加載SpringBoot配置環境ConfigurableEnvironment,見2.2配置ConfigurableEnvironment
     ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);
     //打印banner
     Banner printedBanner = printBanner(environment);
     //創建應用程序上下文,見2.3 創建應用程序上下文
     context = createApplicationContext();
     analyzers = new FailureAnalyzers(context);
     prepareContext(context, environment, listeners, applicationArguments,printedBanner);
     refreshContext(context);
     afterRefresh(context, applicationArguments);
     listeners.finished(context, null);
     stopWatch.stop();
     if (this.logStartupInfo) {
      new StartupInfoLogger(this.mainApplicationClass)
            .logStarted(getApplicationLog(), stopWatch);
     }
     return context;
   }catch (Throwable ex) {
     handleRunFailure(context, listeners, analyzers, ex);
     throw new IllegalStateException(ex);
   }
}

2.2 配置ConfigurableEnvironment

加載SpringBoot配置環境ConfigurableEnvironment流程如下:

private ConfigurableEnvironment prepareEnvironment(
			SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments) {
		// Create and configure the environment
		ConfigurableEnvironment environment = getOrCreateEnvironment();
		configureEnvironment(environment, applicationArguments.getSourceArgs());
		listeners.environmentPrepared(environment);
		if (!this.webEnvironment) {
			environment = new EnvironmentConverter(getClassLoader())
					.convertToStandardEnvironmentIfNecessary(environment);
		}
		return environment;
	}

在加載配置環境的過程中會判斷是否是web容器啟動,如果是容器啟動會加載StandardServletEnvironment

private ConfigurableEnvironment getOrCreateEnvironment() {
		if (this.environment != null) {
			return this.environment;
		}
		if (this.webEnvironment) {
			return new StandardServletEnvironment();
		}
		return new StandardEnvironment();
	}

StandardServletEnvironment類的繼承關系如下,StandardServletEnvironment

SpringBoot的啟動流程有哪些

PropertyResolver接口是用于解析任何基礎源的屬性的接口,在加載完配置之后會將配置環境加入到監聽器對象SpringApplicationRunListeners中。

2.3 創建應用程序上下文

然后會創建應用上下文對象,具體代碼如下:

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);
	}

方法會先顯式的獲取應用上下文對象,如果對象為空,再加載默認的環境配置,通過是否是webEnvironment進行判斷,默認選擇的是AnnotationConfigApplicationContext(注解上下文,通過掃秒注解來加載bean),然后通過BeanUtils來實例化應用上下文對象然后返回,ConfigurableApplicationContext類繼承關系如下:

這里推薦一下我的另一篇博客,不太懂ConfigurableApplicationContext的可以去看一下,https://juejin.im/post/5d72055f5188256bab4c0b6d

SpringBoot的啟動流程有哪些

回到run()方法中,會調用prepareContext()方法將environment, listeners,applicationArguments, printedBanner等組件與上下文對象進行關聯

private void prepareContext(ConfigurableApplicationContext context,
			ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments, Banner printedBanner) {
		context.setEnvironment(environment);
		postProcessApplicationContext(context);
		applyInitializers(context);
		listeners.contextPrepared(context);
		if (this.logStartupInfo) {
			logStartupInfo(context.getParent() == null);
			logStartupProfileInfo(context);
		}

		// Add boot specific singleton beans
		context.getBeanFactory().registerSingleton("springApplicationArguments",
				applicationArguments);
		if (printedBanner != null) {
			context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
		}

		// Load the sources
		Set<Object> sources = getSources();
		Assert.notEmpty(sources, "Sources must not be empty");
		load(context, sources.toArray(new Object[sources.size()]));
		listeners.contextLoaded(context);
	}

然后會調用refreshContext()方法,實際調用org.springframework.context.support.AbstractApplicationContext.refresh()內的相關方法。這個方法里會進行redis,mybatis等的自動配置,包括spring.factories的加載,bean的實例化,BenFactoryPostProcessor接口的執行,BeanPostProcessor接口的執行,條件注解的解析,國際化功能的初始化等。

refreshContext()方法執行完畢之后會執行afterRefresh方法,當run()方法執行完之后Spring容器也就初始化完畢了

protected void afterRefresh(ConfigurableApplicationContext context,
			ApplicationArguments args) {
		callRunners(context, args);
	}

	private void callRunners(ApplicationContext context, ApplicationArguments args) {
		List<Object> runners = new ArrayList<Object>();
		runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
		runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
		AnnotationAwareOrderComparator.sort(runners);
		for (Object runner : new LinkedHashSet<Object>(runners)) {
			if (runner instanceof ApplicationRunner) {
				callRunner((ApplicationRunner) runner, args);
			}
			if (runner instanceof CommandLineRunner) {
				callRunner((CommandLineRunner) runner, args);
			}
		}
	}

	private void callRunner(ApplicationRunner runner, ApplicationArguments args) {
		try {
			(runner).run(args);
		}
		catch (Exception ex) {
			throw new IllegalStateException("Failed to execute ApplicationRunner", ex);
		}
	}

	private void callRunner(CommandLineRunner runner, ApplicationArguments args) {
		try {
			(runner).run(args.getSourceArgs());
		}
		catch (Exception ex) {
			throw new IllegalStateException("Failed to execute CommandLineRunner", ex);
		}
	}

關于SpringBoot的啟動流程有哪些問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業資訊頻道了解更多相關知識。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

东丰县| 通许县| 睢宁县| 汾阳市| 山阳县| 都兰县| 杭锦后旗| 克什克腾旗| 会东县| 定西市| 仁布县| 凤凰县| 论坛| 湘阴县| 大同县| 井研县| 新干县| 内江市| 敖汉旗| 拉孜县| 二连浩特市| 准格尔旗| 柏乡县| 东安县| 石家庄市| 延津县| 南漳县| 资阳市| 宁明县| 定兴县| 漳平市| 南通市| 泗阳县| 靖远县| 通渭县| 炎陵县| 衢州市| 左权县| 布尔津县| 中卫市| 清流县|