這篇文章將為大家詳細(xì)講解有關(guān)SpringBoot應(yīng)用是如何啟動的,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關(guān)知識有一定的了解。
創(chuàng)新互聯(lián)公司專注為客戶提供全方位的互聯(lián)網(wǎng)綜合服務(wù),包含不限于成都網(wǎng)站設(shè)計、成都做網(wǎng)站、外貿(mào)網(wǎng)站建設(shè)、尖草坪網(wǎng)絡(luò)推廣、重慶小程序開發(fā)公司、尖草坪網(wǎng)絡(luò)營銷、尖草坪企業(yè)策劃、尖草坪品牌公關(guān)、搜索引擎seo、人物專訪、企業(yè)宣傳片、企業(yè)代運(yùn)營等,從售前售中售后,我們都將竭誠為您服務(wù),您的肯定,是我們最大的嘉獎;創(chuàng)新互聯(lián)公司為所有大學(xué)生創(chuàng)業(yè)者提供尖草坪建站搭建服務(wù),24小時服務(wù)熱線:18982081108,官方網(wǎng)址:jinyejixie.com
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所有實(shí)現(xiàn)類,并將其實(shí)例化 setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class)); // 找到META-INF/spring.factories中ApplicationListener所有實(shí)現(xiàn)類,并將其實(shí)例化 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); // 獲取當(dāng)前main方法類對象,即測試類中的App實(shí)例 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指定接口的實(shí)現(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接口的實(shí)現(xiàn)類就是EventPublishingRunListener,其在SpringBoot啟動過程中,負(fù)責(zé)注冊ApplicationListener監(jiān)聽器,在不同時間節(jié)點(diǎn)發(fā)布不同事件類型,如果有ApplicationListener實(shí)現(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)聽接口實(shí)現(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)建并配置運(yùn)行環(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)建、裝置、刷新、運(yùn)行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()來實(shí)例化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:運(yùn)行環(huán)境。
4、啟動過程框圖
關(guān)于SpringBoot應(yīng)用是如何啟動的就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
當(dāng)前文章:SpringBoot應(yīng)用是如何啟動的
當(dāng)前地址:http://jinyejixie.com/article30/pshjpo.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供用戶體驗(yàn)、網(wǎng)站排名、電子商務(wù)、網(wǎng)站設(shè)計、商城網(wǎng)站、面包屑導(dǎo)航
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)