SpringBoot啟動(dòng)過程的實(shí)現(xiàn)
SpringBoot啟動(dòng)過程分析,首先打開SpringBoot的啟用入口Main類:
@SpringBootApplication public class ApplicationMain{ public static void main(String[] args) { SpringApplication.run(ApplicationMain.class, args); } }
可以看到main方法里面只有一行核心啟用類:SpringApplication.run(ApplicationMain.class, args);這個(gè)是關(guān)鍵,在改行打上斷點(diǎn),debug模式啟動(dòng)該main類。點(diǎn)擊下一步進(jìn)入SpringApplication的源碼對(duì)應(yīng)的run方法:
public static ConfigurableApplicationContext run(Object[] sources, String[] args) { return (new SpringApplication(sources)).run(args); }
初始化SpringApplication
SpringApplication實(shí)例化之前會(huì)調(diào)用構(gòu)造方法進(jìn)行初始化:
public SpringApplication(Object... sources) { this.bannerMode = Mode.CONSOLE; this.logStartupInfo = true; this.addCommandLineProperties = true; this.headless = true; this.registerShutdownHook = true; this.additionalProfiles = new HashSet(); this.initialize(sources); }
而SpringApplication構(gòu)造方法的核心是:this.initialize(sources);初始化方法,SpringApplication通過調(diào)用該方法來初始化。
private void initialize(Object[] sources) { if (sources != null && sources.length > 0) { this.sources.addAll(Arrays.asList(sources)); } this.webEnvironment = deduceWebEnvironment(); setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class)); setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = deduceMainApplicationClass(); }
1.deduceWebEnvironment方法是用來判斷當(dāng)前應(yīng)用的環(huán)境,該方法通過獲取這兩個(gè)類來判斷當(dāng)前環(huán)境是否是web環(huán)境,如果能獲得這兩個(gè)類說明是web環(huán)境,否則不是。
javax.servlet.Servlet org.springframework.web.context.ConfigurableWebApplicationContext
2.getSpringFactoriesInstances方法主要用來從spring.factories文件中找出key為ApplicationContextInitializer的類并實(shí)例化,然后調(diào)用setInitializers方法設(shè)置到SpringApplication的initializers屬性中。這個(gè)過程就是找出所有的應(yīng)用程序初始化器。
private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader)); List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); AnnotationAwareOrderComparator.sort(instances); return instances; }
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) { String factoryClassName = factoryClass.getName(); try { //從spring.factories文件中找出key為ApplicationContextInitializer的類 Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories"); ArrayList result = new ArrayList(); while(urls.hasMoreElements()) { URL 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 var8) { throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + "] factories from location [" + "META-INF/spring.factories" + "]", var8); } }
當(dāng)前的初始化器有如下幾個(gè):
3.同理調(diào)用getSpringFactoriesInstances從spring.factories文件中找出key為ApplicationListener的類并實(shí)例化,然后調(diào)用setListeners方法設(shè)置到SpringApplication的listeners屬性中。這個(gè)過程就是找出所有的應(yīng)用程序事件監(jiān)聽器。
當(dāng)前的事件監(jiān)聽器有如下幾個(gè):
4.調(diào)用deduceMainApplicationClass方法找出main類,就是這里的ApplicationMain類。
運(yùn)行SpringApplication
初始化SpringApplication完成之后,調(diào)用run方法運(yùn)行:
public ConfigurableApplicationContext run(String... args) { //計(jì)時(shí)器,統(tǒng)計(jì)任務(wù)的執(zhí)行時(shí)間 StopWatch stopWatch = new StopWatch(); //開始執(zhí)行 stopWatch.start(); ConfigurableApplicationContext context = null; FailureAnalyzers analyzers = null; this.configureHeadlessProperty(); // 獲取SpringApplicationRunListeners啟動(dòng)事件監(jiān)聽器,這里只有一個(gè)EventPublishingRunListener SpringApplicationRunListeners listeners = this.getRunListeners(args); // 封裝成SpringApplicationEvent事件然后廣播出去給SpringApplication中的listeners所監(jiān)聽 listeners.starting(); try { // 構(gòu)造一個(gè)應(yīng)用程序參數(shù)持有類 ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); // 準(zhǔn)備并配置環(huán)境 ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments); // 打印banner圖形 Banner printedBanner = this.printBanner(environment); // 創(chuàng)建Spring容器 context = this.createApplicationContext(); new FailureAnalyzers(context); // 配置Spring容器 this.prepareContext(context, environment, listeners, applicationArguments, printedBanner); // 容器上下文刷新 this.refreshContext(context); // 容器創(chuàng)建完成之后調(diào)用afterRefresh方法 this.afterRefresh(context, applicationArguments); // 調(diào)用監(jiān)聽器,廣播Spring啟動(dòng)結(jié)束的事件 listeners.finished(context, (Throwable)null); // 停止計(jì)時(shí)器 stopWatch.stop(); if (this.logStartupInfo) { (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch); } return context; } catch (Throwable var9) { this.handleRunFailure(context, listeners, (FailureAnalyzers)analyzers, var9); throw new IllegalStateException(var9); } }
SpringApplicationRunListeners
1.獲取啟動(dòng)事件監(jiān)聽器,可以看看該方法:
SpringApplicationRunListeners listeners = this.getRunListeners(args);
private SpringApplicationRunListeners getRunListeners(String[] args) { Class<?>[] types = new Class[]{SpringApplication.class, String[].class}; return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args)); }
同樣的通過調(diào)用getSpringFactoriesInstances方法去META-INF/spring.factories文件中拿到SpringApplicationRunListener監(jiān)聽器,當(dāng)前的SpringApplicationRunListener事件監(jiān)聽器只有一個(gè)EventPublishingRunListener廣播事件監(jiān)聽器:
SpringApplicationRunListeners內(nèi)部持有SpringApplicationRunListener集合和1個(gè)Log日志類。用于SpringApplicationRunListener監(jiān)聽器的批量執(zhí)行。
SpringApplicationRunListener用于監(jiān)聽SpringApplication的run方法的執(zhí)行,它定義了5個(gè)步驟:
1.starting:run方法執(zhí)行的時(shí)候立馬執(zhí)行,對(duì)應(yīng)的事件類型是ApplicationStartedEvent
2.environmentPrepared:ApplicationContext創(chuàng)建之前并且環(huán)境信息準(zhǔn)備好的時(shí)候調(diào)用,對(duì)應(yīng)的事件類型是ApplicationEnvironmentPreparedEvent
3.contextPrepared:ApplicationContext創(chuàng)建好并且在source加載之前調(diào)用一次,沒有具體的對(duì)應(yīng)事件
4.contextLoaded:ApplicationContext創(chuàng)建并加載之后并在refresh之前調(diào)用,對(duì)應(yīng)的事件類型是ApplicationPreparedEvent
5.finished:run方法結(jié)束之前調(diào)用,對(duì)應(yīng)事件的類型是ApplicationReadyEvent或ApplicationFailedEvent
SpringApplicationRunListener目前只有一個(gè)實(shí)現(xiàn)類EventPublishingRunListener,詳見獲取SpringApplicationRunListeners。它把監(jiān)聽的過程封裝成了SpringApplicationEvent事件并讓內(nèi)部屬性ApplicationEventMulticaster接口的實(shí)現(xiàn)類SimpleApplicationEventMulticaster廣播出去,廣播出去的事件對(duì)象會(huì)被SpringApplication中的listeners屬性進(jìn)行處理。
所以說SpringApplicationRunListener和ApplicationListener之間的關(guān)系是通過ApplicationEventMulticaster廣播出去的SpringApplicationEvent所聯(lián)系起來的
2.啟動(dòng)事件監(jiān)聽器
通過listeners.starting()可以啟動(dòng)事件監(jiān)聽器SpringApplicationRunListener ,SpringApplicationRunListener 是一個(gè)啟動(dòng)事件監(jiān)聽器接口:
public interface SpringApplicationRunListener { void starting(); void environmentPrepared(ConfigurableEnvironment var1); void contextPrepared(ConfigurableApplicationContext var1); void contextLoaded(ConfigurableApplicationContext var1); void finished(ConfigurableApplicationContext var1, Throwable var2); }
SpringApplicationRunListener 接口的具體實(shí)現(xiàn)就是EventPublishingRunListener類,我們主要來看一下它的startting方法,該方法會(huì)封裝成SpringApplicationEvent事件然后廣播出去給SpringApplication中的listeners所監(jiān)聽。
public void starting() { this.initialMulticaster.multicastEvent(new ApplicationStartedEvent(this.application, this.args)); }
配置并準(zhǔn)備環(huán)境
private ConfigurableEnvironment prepareEnvironment( SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) { // 創(chuàng)建應(yīng)用程序的環(huán)境信息。如果是web程序,創(chuàng)建StandardServletEnvironment;否則,創(chuàng)建StandardEnvironment ConfigurableEnvironment environment = getOrCreateEnvironment(); // 配置環(huán)境信息。比如profile,命令行參數(shù) configureEnvironment(environment, applicationArguments.getSourceArgs()); // 廣播出ApplicationEnvironmentPreparedEvent事件給相應(yīng)的監(jiān)聽器執(zhí)行 listeners.environmentPrepared(environment); // 環(huán)境信息的校對(duì) if (!this.webEnvironment) { environment = new EnvironmentConverter(getClassLoader()) .convertToStandardEnvironmentIfNecessary(environment); } return environment; }
判斷環(huán)境,如果是web程序,創(chuàng)建StandardServletEnvironment;否則,創(chuàng)建StandardEnvironment。
private ConfigurableEnvironment getOrCreateEnvironment() { if (this.environment != null) { return this.environment; } else { return (ConfigurableEnvironment)(this.webEnvironment ? new StandardServletEnvironment() : new StandardEnvironment()); } }
創(chuàng)建Spring容器上下文
protected ConfigurableApplicationContext createApplicationContext() { Class<?> contextClass = this.applicationContextClass; if (contextClass == null) { try { // 判斷是否是web應(yīng)用, // 如果是則創(chuàng)建AnnotationConfigEmbeddedWebApplicationContext,否則創(chuàng)建AnnotationConfigApplicationContext 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); }
配置Spring容器上下文
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { // 設(shè)置Spring容器上下文的環(huán)境信息 context.setEnvironment(environment); // Spring容器創(chuàng)建之后做一些額外的事 postProcessApplicationContext(context); // SpringApplication的初始化器開始工作 applyInitializers(context); // 遍歷調(diào)用SpringApplicationRunListener的contextPrepared方法。目前只是將這個(gè)事件廣播器注冊(cè)到Spring容器中 listeners.contextPrepared(context); if (this.logStartupInfo) { logStartupInfo(context.getParent() == null); logStartupProfileInfo(context); } // 把應(yīng)用程序參數(shù)持有類注冊(cè)到Spring容器中,并且是一個(gè)單例 context.getBeanFactory().registerSingleton("springApplicationArguments", applicationArguments); if (printedBanner != null) { context.getBeanFactory().registerSingleton("springBootBanner", printedBanner); } // 加載sources,sources是main方法所在的類 Set<Object> sources = getSources(); Assert.notEmpty(sources, "Sources must not be empty"); // 將sources加載到應(yīng)用上下文中。最終調(diào)用的是AnnotatedBeanDefinitionReader.registerBean方法 load(context, sources.toArray(new Object[sources.size()])); // 廣播出ApplicationPreparedEvent事件給相應(yīng)的監(jiān)聽器執(zhí)行 // 執(zhí)行EventPublishingRunListener.contextLoaded方法 listeners.contextLoaded(context); }
Spring容器創(chuàng)建之后回調(diào)方法postProcessApplicationContext
protected void postProcessApplicationContext(ConfigurableApplicationContext context) { // 如果SpringApplication設(shè)置了實(shí)例命名生成器,則注冊(cè)到Spring容器中 if (this.beanNameGenerator != null) { context.getBeanFactory().registerSingleton( AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, this.beanNameGenerator); } // 如果SpringApplication設(shè)置了資源加載器,設(shè)置到Spring容器中 if (this.resourceLoader != null) { if (context instanceof GenericApplicationContext) { ((GenericApplicationContext) context) .setResourceLoader(this.resourceLoader); } if (context instanceof DefaultResourceLoader) { ((DefaultResourceLoader) context) .setClassLoader(this.resourceLoader.getClassLoader()); } } }
初始化器開始工作
protected void applyInitializers(ConfigurableApplicationContext context) { // 遍歷每個(gè)初始化器,調(diào)用對(duì)應(yīng)的initialize方法 for (ApplicationContextInitializer initializer : getInitializers()) { Class<?> requiredType = GenericTypeResolver.resolveTypeArgument( initializer.getClass(), ApplicationContextInitializer.class); Assert.isInstanceOf(requiredType, context, "Unable to call initializer."); initializer.initialize(context); } }
Spring容器創(chuàng)建完成之后會(huì)調(diào)用afterRefresh方法
ApplicationRunner、CommandLineRunner類都是在在afterRefresh方法中調(diào)用的,也就是說在Spring容器創(chuàng)建之后執(zhí)行的。
protected void applyInitializers(ConfigurableApplicationContext context) { // 遍歷每個(gè)初始化器,調(diào)用對(duì)應(yīng)的initialize方法 for (ApplicationContextInitializer initializer : getInitializers()) { Class<?> requiredType = GenericTypeResolver.resolveTypeArgument( initializer.getClass(), ApplicationContextInitializer.class); Assert.isInstanceOf(requiredType, context, "Unable to call initializer."); initializer.initialize(context); } }
參考:https://blog.wangqi.love/articles/Spring/SpringBoot啟動(dòng)過程.html
到此這篇關(guān)于SpringBoot啟動(dòng)過程的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)SpringBoot啟動(dòng)過程內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java中Caffeine本地緩存項(xiàng)目實(shí)例
這篇文章主要介紹了Java中Caffeine本地緩存項(xiàng)目實(shí)例,Caffeine是一個(gè)高性能Java 緩存庫(kù),使用Java8對(duì)Guava緩存重寫版本,在Spring Boot 2.0中將取代Guava,使用spring.cache.cache-names屬性可以在啟動(dòng)時(shí)創(chuàng)建緩存,需要的朋友可以參考下2023-10-10Java8通過CompletableFuture實(shí)現(xiàn)異步回調(diào)
這篇文章主要介紹了Java8通過CompletableFuture實(shí)現(xiàn)異步回調(diào),CompletableFuture是Java?8?中新增的一個(gè)類,它是對(duì)Future接口的擴(kuò)展,下文關(guān)于其更多相關(guān)詳細(xì)介紹需要的小伙伴可以參考一下2022-04-04Java數(shù)據(jù)庫(kù)連接池c3p0過程解析
這篇文章主要介紹了Java數(shù)據(jù)庫(kù)連接池c3p0過程解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-07-07SpringBoot異常處理器的使用與添加員工功能實(shí)現(xiàn)流程介紹
設(shè)計(jì)完了登錄與退出功能還只完成了冰山一角,經(jīng)過測(cè)試發(fā)現(xiàn),我們以u(píng)rl的方式來訪問網(wǎng)站時(shí)可以直接跳過登陸頁(yè)面進(jìn)入后臺(tái)頁(yè)面,這樣顯然是不合理的,下面我們通過異常攔截器+boot來做到訪問限制,以及實(shí)現(xiàn)新增員工功能,制作全局異常處理器2022-10-10