spring cloud大行其道的當(dāng)下,如果不了解基本原理那么是很糾結(jié)的(看見的都是 約定大于配置 ,但是原理呢?為什么要這么做?)。spring cloud是基于spring boot快速搭建的,今天咱們就看看spring boot容器啟動(dòng)流程。(本文不講解如何快速啟動(dòng)spring boot,那些直接官方看即可, 官網(wǎng)文檔飛機(jī)票 )
創(chuàng)新互聯(lián)是一家集網(wǎng)站建設(shè),安康企業(yè)網(wǎng)站建設(shè),安康品牌網(wǎng)站建設(shè),網(wǎng)站定制,安康網(wǎng)站建設(shè)報(bào)價(jià),網(wǎng)絡(luò)營(yíng)銷,網(wǎng)絡(luò)優(yōu)化,安康網(wǎng)站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強(qiáng)企業(yè)競(jìng)爭(zhēng)力??沙浞譂M足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時(shí)我們時(shí)刻保持專業(yè)、時(shí)尚、前沿,時(shí)刻以成就客戶成長(zhǎng)自我,堅(jiān)持不斷學(xué)習(xí)、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實(shí)用型網(wǎng)站。
spring boot一般是 指定容器啟動(dòng)main方法,然后以命令行方式啟動(dòng)Jar包 ,如下圖:
@SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
這里核心關(guān)注2個(gè)東西:
1.@SpringBootApplication注解
2. SpringApplication.run()靜態(tài)方法
下面我們就分別探究這兩塊內(nèi)容。
源碼如下:
@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 {
核心注解:
@SpringBootConfiguration(實(shí)際就是個(gè)@Configuration):表示這是一個(gè)JavaConfig配置類,可以在這個(gè)類中自定義bean,依賴關(guān)系等。-》這個(gè)是spring-boot特有的注解,常用到。
@EnableAutoConfiguration:借助@Import的幫助,將所有符合自動(dòng)配置條件的bean定義加載到IoC容器(建議放在根包路徑下,這樣可以掃描子包和類)。-》這個(gè)需要詳細(xì)深挖!
@ComponentScan:spring的自動(dòng)掃描注解,可定義掃描范圍,加載到IOC容器。-》這個(gè)不多說(shuō),spring的注解大家肯定眼熟
其中@EnableAutoConfiguration這個(gè)注解的源碼:
@SuppressWarnings("deprecation") @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(EnableAutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration {
核心是一個(gè)EnableAutoConfigurationImportSelector類圖如下:
核心方法在頂級(jí)接口 ImportSelector 的 selectImports() ,源碼如下:
@Override public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return NO_IMPORTS; } try { //1.從META-INF/spring-autoconfigure-metadata.properties文件中載入483條配置屬性(有一些有默認(rèn)值), AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader .loadMetadata(this.beanClassLoader); AnnotationAttributes attributes = getAttributes(annotationMetadata);//2.獲取注解屬性 Listconfigurations = getCandidateConfigurations(annotationMetadata,//3.獲取97個(gè)自動(dòng)配置類 attributes); configurations = removeDuplicates(configurations);//4.移除重復(fù)的 configurations = sort(configurations, autoConfigurationMetadata);//5.排序 Set exclusions = getExclusions(annotationMetadata, attributes);//6.獲取需要排除的 checkExcludedClasses(configurations, exclusions);//7.校驗(yàn)排除類 configurations.removeAll(exclusions);//8.刪除所有需要排除的 configurations = filter(configurations, autoConfigurationMetadata);//9.過(guò)濾器OnClassCondition(注解中配置的當(dāng)存在某類才生效) fireAutoConfigurationImportEvents(configurations, exclusions);//10.觸發(fā)自動(dòng)配置導(dǎo)入監(jiān)聽事件 return configurations.toArray(new String[configurations.size()]); } catch (IOException ex) { throw new IllegalStateException(ex); } }
這里注意3個(gè)核心方法:
1) loadMetadata 加載配置
其實(shí)就是用類加載器去加載: META-INF/spring-autoconfigure-metadata.properties (spring-boot-autoconfigure-1.5.9.RELEASE-sources.jar) 文件中定義的配置,返回PropertiesAutoConfigurationMetadata(實(shí)現(xiàn)了AutoConfigurationMetadata接口,封裝了屬性的get set方法)
2) getCandidateConfigurations 獲取默認(rèn)支持的自動(dòng)配置類名列表
自動(dòng)配置靈魂方法, SpringFactoriesLoader.loadFactoryNames 從 META-INF/spring.factories (spring-boot-autoconfigure-1.5.9.RELEASE-sources.jar)文件中獲取自動(dòng)配置類key=EnableAutoConfiguration.class的配置。
protected ListgetCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {//話說(shuō)這里2個(gè)入?yún)](méi)啥用啊...誰(shuí)來(lái)給我解釋一下... List configurations = SpringFactoriesLoader.loadFactoryNames( getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()); Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you " + "are using a custom packaging, make sure that file is correct."); return configurations; } //返回的是EnableAutoConfiguration類 protected Class<?> getSpringFactoriesLoaderFactoryClass() { return EnableAutoConfiguration.class; }
實(shí)際獲取了什么? spring.factories 文件如下,實(shí)際獲取了 # Auto Configure 自動(dòng)配置模塊的所有類。
# Initializers org.springframework.context.ApplicationContextInitializer=\ org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\ org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer # Application Listeners org.springframework.context.ApplicationListener=\ org.springframework.boot.autoconfigure.BackgroundPreinitializer # Auto Configuration Import Listeners org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\ org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener # Auto Configuration Import Filters org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\ org.springframework.boot.autoconfigure.condition.OnClassCondition # Auto Configure 這里就是全部的自動(dòng)配置類 org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\ org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\ org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\ org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\ org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\ org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\ org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\ org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\ org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\ org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\ org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\ org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\ org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration,\ org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.ldap.LdapDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\ org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\ org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\ org.springframework.boot.autoconfigure.elasticsearch.jest.JestAutoConfiguration,\ org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\ org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\ org.springframework.boot.autoconfigure.h3.H2ConsoleAutoConfiguration,\ org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\ org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,\ org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,\ org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,\ org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,\ org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\ org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\ org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\ org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\ org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\ org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\ org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\ org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\ org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\ org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\ org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\ org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\ org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\ org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\ org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\ org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\ org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,\ org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,\ org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\ org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\ org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,\ org.springframework.boot.autoconfigure.mobile.DeviceResolverAutoConfiguration,\ org.springframework.boot.autoconfigure.mobile.DeviceDelegatingViewResolverAutoConfiguration,\ org.springframework.boot.autoconfigure.mobile.SitePreferenceAutoConfiguration,\ org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\ org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\ org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\ org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\ org.springframework.boot.autoconfigure.reactor.ReactorAutoConfiguration,\ org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration,\ org.springframework.boot.autoconfigure.security.SecurityFilterAutoConfiguration,\ org.springframework.boot.autoconfigure.security.FallbackWebSecurityAutoConfiguration,\ org.springframework.boot.autoconfigure.security.oauth3.OAuth3AutoConfiguration,\ org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\ org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\ org.springframework.boot.autoconfigure.social.SocialWebAutoConfiguration,\ org.springframework.boot.autoconfigure.social.FacebookAutoConfiguration,\ org.springframework.boot.autoconfigure.social.LinkedInAutoConfiguration,\ org.springframework.boot.autoconfigure.social.TwitterAutoConfiguration,\ org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\ org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\ org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\ org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\ org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration,\ org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration,\ org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration,\ org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration,\ org.springframework.boot.autoconfigure.web.HttpEncodingAutoConfiguration,\ org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration,\ org.springframework.boot.autoconfigure.web.MultipartAutoConfiguration,\ org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration,\ org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration,\ org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration,\ org.springframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration,\ org.springframework.boot.autoconfigure.websocket.WebSocketMessagingAutoConfiguration,\ org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration # Failure analyzers org.springframework.boot.diagnostics.FailureAnalyzer=\ org.springframework.boot.autoconfigure.diagnostics.analyzer.NoSuchBeanDefinitionFailureAnalyzer,\ org.springframework.boot.autoconfigure.jdbc.DataSourceBeanCreationFailureAnalyzer,\ org.springframework.boot.autoconfigure.jdbc.HikariDriverConfigurationFailureAnalyzer # Template availability providers org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\ org.springframework.boot.autoconfigure.freemarker.FreeMarkerTemplateAvailabilityProvider,\ org.springframework.boot.autoconfigure.mustache.MustacheTemplateAvailabilityProvider,\ org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAvailabilityProvider,\ org.springframework.boot.autoconfigure.thymeleaf.ThymeleafTemplateAvailabilityProvider,\ org.springframework.boot.autoconfigure.web.JspTemplateAvailabilityProvider
3)filter過(guò)濾器 根據(jù) OnClassCondition 注解把不滿足條件的過(guò)濾掉
private Listfilter(List configurations, AutoConfigurationMetadata autoConfigurationMetadata) { long startTime = System.nanoTime(); String[] candidates = configurations.toArray(new String[configurations.size()]); boolean[] skip = new boolean[candidates.length]; boolean skipped = false; //獲取需要過(guò)濾的自動(dòng)配置導(dǎo)入攔截器,spring.factories配置中就一個(gè):org.springframework.boot.autoconfigure.condition.OnClassCondition for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) { invokeAwareMethods(filter); boolean[] match = filter.match(candidates, autoConfigurationMetadata); for (int i = 0; i < match.length; i++) { if (!match[i]) { skip[i] = true; skipped = true; } } } if (!skipped) {//多條件只要有一個(gè)不匹配->skipped = true,全部匹配-》skipped = false->直接返回 return configurations; } List result = new ArrayList (candidates.length); for (int i = 0; i < candidates.length; i++) { if (!skip[i]) {//匹配-》不跳過(guò)-》添加進(jìn)result result.add(candidates[i]); } } if (logger.isTraceEnabled()) { int numberFiltered = configurations.size() - result.size(); logger.trace("Filtered " + numberFiltered + " auto configuration class in " + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) + " ms"); } return new ArrayList (result); }
SpringApplication.run
public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; FailureAnalyzers analyzers = null; configureHeadlessProperty(); SpringApplicationRunListeners listeners = getRunListeners(args);//1.獲取監(jiān)聽器 listeners.starting();-->啟動(dòng)! try { ApplicationArguments applicationArguments = new DefaultApplicationArguments( args); ConfigurableEnvironment environment = prepareEnvironment(listeners,//2.準(zhǔn)備好環(huán)境,觸發(fā)ApplicationEnvironmentPreparedEvent事件 applicationArguments); Banner printedBanner = printBanner(environment);//打印啟動(dòng)提示字符,默認(rèn)spring的字符圖 context = createApplicationContext();//實(shí)例化一個(gè)可配置應(yīng)用上下文 analyzers = new FailureAnalyzers(context); prepareContext(context, environment, listeners, applicationArguments,//3.準(zhǔn)備上下文 printedBanner); refreshContext(context);//4.刷新上下文 afterRefresh(context, applicationArguments);//5.刷新上下文后 listeners.finished(context, null);--關(guān)閉! 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); } }
1. getRunListeners 獲取監(jiān)聽器( SpringApplicationRunListeners )
實(shí)際是 SpringApplicationRunListener 類
private SpringApplicationRunListeners getRunListeners(String[] args) { Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class }; return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances( SpringApplicationRunListener.class, types, this, args)); } privateCollection<? extends T> getSpringFactoriesInstances(Class type) { return getSpringFactoriesInstances(type, new Class<?>[] {}); } private Collection<? extends T> getSpringFactoriesInstances(Class type, Class<?>[] parameterTypes, Object... args) { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); // 使用Set確保的字符串的唯一性 Set names = new LinkedHashSet ( SpringFactoriesLoader.loadFactoryNames(type, classLoader));// 1.載入工廠名稱集合 List instances = createSpringFactoriesInstances(type, parameterTypes,// 2.創(chuàng)建工廠實(shí)例 classLoader, args, names); AnnotationAwareOrderComparator.sort(instances);// 排序 return instances; }
1.1 載入工廠名稱(loadFactoryNames)
當(dāng)前類的類加載器從 META-INF/spring.factories 文件中獲取SpringApplicationRunListener類的配置
public static ListloadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) { String factoryClassName = factoryClass.getName(); try { Enumeration urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); List result = new ArrayList (); 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); } }
上圖,獲取到工廠類名后,下面來(lái)看看META-INF/spring.factories中定義了啥:
# 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.embedded.ServerPortInfoApplicationContextInitializer # Application Listeners org.springframework.context.ApplicationListener=\ org.springframework.boot.ClearCachesApplicationListener,\ 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 # Failure Analyzers org.springframework.boot.diagnostics.FailureAnalyzer=\ org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.BeanNotOfRequiredTypeFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.BindFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.ConnectorStartFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.PortInUseFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer # FailureAnalysisReporters org.springframework.boot.diagnostics.FailureAnalysisReporter=\ org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter
哇,都是些類全名稱,且key都是接口,value都是實(shí)現(xiàn)類。我們根據(jù)key=“ org.springframework.boot.SpringApplicationRunListener ”查詢得到實(shí)現(xiàn)類value=" org.springframework.boot.context.event.EventPublishingRunListener" 事件發(fā)布啟動(dòng)監(jiān)聽器 , 一猜也知道肯定要用” 反射 ”根據(jù)類名獲取類實(shí)例,下面很快得到驗(yàn)證...
1.2 創(chuàng)建spring工廠實(shí)例(createSpringFactoriesInstances)
根據(jù)第一步得到的Set
@SuppressWarnings("unchecked") privateList createSpringFactoriesInstances(Class type, Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args, Set names) { List instances = new ArrayList (names.size()); for (String name : names) { try { Class<?> instanceClass = ClassUtils.forName(name, classLoader);// 利用反射獲取類 Assert.isAssignable(type, instanceClass); Constructor<?> constructor = instanceClass .getDeclaredConstructor(parameterTypes);// 得到構(gòu)造器 T instance = (T) BeanUtils.instantiateClass(constructor, args);// 根據(jù)構(gòu)造器和參數(shù)構(gòu)造實(shí)例 instances.add(instance); } catch (Throwable ex) { throw new IllegalArgumentException( "Cannot instantiate " + type + " : " + name, ex); } } return instances; }
準(zhǔn)備上下文
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { context.setEnvironment(environment); postProcessApplicationContext(context);//單例一個(gè)BeanNameGenerator,把ResourceLoader設(shè)置進(jìn)應(yīng)用上下文 applyInitializers(context);//執(zhí)行初始化器 listeners.contextPrepared(context);// 監(jiān)聽器執(zhí)行上下文"已準(zhǔn)備好"方法 if (this.logStartupInfo) { logStartupInfo(context.getParent() == null); logStartupProfileInfo(context); } // 添加spring boot特殊單例bean context.getBeanFactory().registerSingleton("springApplicationArguments", applicationArguments); if (printedBanner != null) { context.getBeanFactory().registerSingleton("springBootBanner", printedBanner); } // 載入資源 Set
刷新上下文
private void refreshContext(ConfigurableApplicationContext context) { refresh(context);//核心類 if (this.registerShutdownHook) { try { context.registerShutdownHook();//注冊(cè)關(guān)閉鉤子,容器關(guān)閉時(shí)執(zhí)行 } catch (AccessControlException ex) { // Not allowed in some environments. } } } protected void refresh(ApplicationContext applicationContext) { Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext); ((AbstractApplicationContext) applicationContext).refresh(); }
最終執(zhí)行的是AbstractApplicationContext抽象類的 refresh 方法。
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { //準(zhǔn)備刷新的上下文環(huán)境,例如對(duì)系統(tǒng)屬性或者環(huán)境變量進(jìn)行準(zhǔn)備及驗(yàn)證。 prepareRefresh(); //啟動(dòng)子類的refreshBeanFactory方法.解析xml ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); //為BeanFactory配置容器特性,例如類加載器、事件處理器等. prepareBeanFactory(beanFactory); try { //設(shè)置BeanFactory的后置處理. 空方法,留給子類拓展用。 postProcessBeanFactory(beanFactory); //調(diào)用BeanFactory的后處理器, 這些后處理器是在Bean定義中向容器注冊(cè)的. invokeBeanFactoryPostProcessors(beanFactory); //注冊(cè)Bean的后處理器, 在Bean創(chuàng)建過(guò)程中調(diào)用. registerBeanPostProcessors(beanFactory); //初始化上下文中的消息源,即不同語(yǔ)言的消息體進(jìn)行國(guó)際化處理 initMessageSource(); //初始化ApplicationEventMulticaster bean,應(yīng)用事件廣播器 initApplicationEventMulticaster(); //初始化其它特殊的Bean, 空方法,留給子類拓展用。 onRefresh(); //檢查并向容器注冊(cè)監(jiān)聽器Bean registerListeners(); //實(shí)例化所有剩余的(non-lazy-init) 單例Bean. finishBeanFactoryInitialization(beanFactory); //發(fā)布容器事件, 結(jié)束refresh過(guò)程. finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } //銷毀已經(jīng)創(chuàng)建的單例Bean, 以避免資源占用. destroyBeans(); //取消refresh操作, 重置active標(biāo)志. cancelRefresh(ex); // Propagate exception to caller. throw ex; } finally { //重置Spring的核心緩存 resetCommonCaches(); } } }
刷新完上下文后
spring boot提供的2個(gè)供用戶自己拓展的接口: ApplicationRunner和 CommandLineRunner。可以在容器啟動(dòng)完畢后(上下文刷新后)執(zhí)行,做一些類似數(shù)據(jù)初始化的操作。
private void callRunners(ApplicationContext context, ApplicationArguments args) { List
兩個(gè)區(qū)別在于入?yún)⒉煌?,根?jù)實(shí)際情況自己選擇。
public interface CommandLineRunner { void run(String... args) throws Exception; } public interface ApplicationRunner { void run(ApplicationArguments args) throws Exception; }
CommandLineRunner中執(zhí)行參數(shù)是原始的 java啟動(dòng)類main方法的String[] args字符串?dāng)?shù)組參數(shù); ApplicationRunner中的參數(shù)經(jīng)過(guò)處理提供一些方法例如:
ListgetOptionValues(String name);
根據(jù)名稱獲取值list,java 啟動(dòng)命令中 --foo=bar --foo=baz,則根據(jù)foo參數(shù)名返回list ["bar", "baz"]
按照前面的分析,Spring-boot容器啟動(dòng)流程總體可劃分為2部分:
1) 執(zhí)行注解 :掃描指定范圍下的bean、載入自動(dòng)配置類對(duì)應(yīng)的bean加載到IOC容器。
2)man方法中具體SpringAppliocation.run() ,全流程貫穿SpringApplicationEvent,有6個(gè)子類:
ApplicationFailedEvent.class ApplicationPreparedEvent.class ApplicationReadyEvent.class ApplicationStartedEvent.class ApplicationStartingEvent.class SpringApplicationEvent.class
這里用到了很經(jīng)典的 spring事件驅(qū)動(dòng)模型 ,飛機(jī)票: Spring事件驅(qū)動(dòng)模型和觀察者模式
類圖如下:
如上圖,就是一個(gè)經(jīng)典spring 事件驅(qū)動(dòng)模型,包含3種角色:事件發(fā)布者、事件、監(jiān)聽者。對(duì)應(yīng)到spring-boot中就是:
1 .EventPublishingRunListener 這個(gè)類封裝了 事件發(fā)布 ,
2. SpringApplicationEvent 是spring-boot中定義的事件(上面說(shuō)的6種事件),繼承自 ApplicationEvent (spring中定義的)
3. 監(jiān)聽者 spring-boot并沒(méi)有實(shí)現(xiàn)針對(duì)上述6種事件的監(jiān)聽者(我沒(méi)找到...), 這里用戶可以自己實(shí)現(xiàn)監(jiān)聽者(上述6種事件)來(lái)注入spring boot容器啟動(dòng)流程,觸發(fā)相應(yīng)的事件。
例如:實(shí)現(xiàn)ApplicationListener
總結(jié)
以上所述是小編給大家介紹的spring boot容器啟動(dòng)的相關(guān)知識(shí),希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)創(chuàng)新互聯(lián)網(wǎng)站的支持!