目錄html
正文java
1、前言
spring cloud大行其道的當下,若是不瞭解基本原理那麼是很糾結的(看見的都是約定大於配置,可是原理呢?爲何要這麼作?如何串聯起來的?)。spring cloud是基於spring boot快速搭建的,今天我們就看看spring boot容器啓動流程(全文基於1.5.9版本)。(本文不講解如何快速啓動spring boot,那些直接官方看便可,官網文檔飛機票)react
2、容器啓動
spring boot通常是指定容器啓動main方法,而後以命令行方式啓動Jar包,以下圖:web
1 @SpringBootApplication 2 public class Application { 3 public static void main(String[] args) { 4 SpringApplication.run(Application.class, args); 5 } 6 }
這裏核心關注2個東西:redis
1.@SpringBootApplication註解
spring
2.SpringApplication.run()靜態方法數組
下面咱們就分別探究這兩塊內容。緩存
2.1 @SpringBootApplication註解
源碼以下:websocket
1 @Target(ElementType.TYPE) 2 @Retention(RetentionPolicy.RUNTIME) 3 @Documented 4 @Inherited 5 @SpringBootConfiguration 6 @EnableAutoConfiguration 7 @ComponentScan(excludeFilters = { 8 @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), 9 @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) 10 public @interface SpringBootApplication {
核心註解:session
@SpringBootConfiguration(實際就是個@Configuration):表示這是一個JavaConfig配置類,能夠在這個類中自定義bean,依賴關係等。-》這個是spring-boot特有的註解,經常使用到。
@EnableAutoConfiguration:藉助@Import的幫助,將全部符合自動配置條件的bean定義加載到IoC容器(建議放在根包路徑下,這樣能夠掃描子包和類)。-》這個須要詳細深挖!
@ComponentScan:spring的自動掃描註解,可定義掃描範圍,加載到IOC容器。-》這個很少說,spring的註解你們確定眼熟
其中@EnableAutoConfiguration這個註解的源碼:
1 @SuppressWarnings("deprecation") 2 @Target(ElementType.TYPE) 3 @Retention(RetentionPolicy.RUNTIME) 4 @Documented 5 @Inherited 6 @AutoConfigurationPackage 7 @Import(EnableAutoConfigurationImportSelector.class) 8 public @interface EnableAutoConfiguration {
核心是一個EnableAutoConfigurationImportSelector類圖以下:
核心方法在頂級接口ImportSelector的selectImports(),源碼以下:
1 @Override 2 public String[] selectImports(AnnotationMetadata annotationMetadata) { 3 if (!isEnabled(annotationMetadata)) { 4 return NO_IMPORTS; 5 } 6 try { //1.從META-INF/spring-autoconfigure-metadata.properties文件中載入483條配置屬性(有一些有默認值), 7 AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader 8 .loadMetadata(this.beanClassLoader); 9 AnnotationAttributes attributes = getAttributes(annotationMetadata);//2.獲取註解屬性 10 List<String> configurations = getCandidateConfigurations(annotationMetadata,//3.獲取97個自動配置類 11 attributes); 12 configurations = removeDuplicates(configurations);//4.移除重複的 13 configurations = sort(configurations, autoConfigurationMetadata);//5.排序 14 Set<String> exclusions = getExclusions(annotationMetadata, attributes);//6.獲取須要排除的 15 checkExcludedClasses(configurations, exclusions);//7.校驗排除類 16 configurations.removeAll(exclusions);//8.刪除全部須要排除的 17 configurations = filter(configurations, autoConfigurationMetadata);//9.過濾器OnClassCondition(註解中配置的當存在某類才生效) 18 fireAutoConfigurationImportEvents(configurations, exclusions);//10.觸發自動配置導入監聽事件 19 return configurations.toArray(new String[configurations.size()]); 20 } 21 catch (IOException ex) { 22 throw new IllegalStateException(ex); 23 } 24 }
這裏注意3個核心方法:
1)loadMetadata 加載配置
其實就是用類加載器去加載:META-INF/spring-autoconfigure-metadata.properties(spring-boot-autoconfigure-1.5.9.RELEASE-sources.jar)文件中定義的配置,返回PropertiesAutoConfigurationMetadata(實現了AutoConfigurationMetadata接口,封裝了屬性的get set方法)
2)getCandidateConfigurations獲取默認支持的自動配置類名列表
自動配置靈魂方法,SpringFactoriesLoader.loadFactoryNames 從META-INF/spring.factories(spring-boot-autoconfigure-1.5.9.RELEASE-sources.jar)文件中獲取自動配置類key=EnableAutoConfiguration.class的配置。
1 protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, 2 AnnotationAttributes attributes) {//話說這裏2個入參沒啥用啊...誰來給我解釋一下... 3 List<String> configurations = SpringFactoriesLoader.loadFactoryNames( 4 getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()); 5 Assert.notEmpty(configurations, 6 "No auto configuration classes found in META-INF/spring.factories. If you " 7 + "are using a custom packaging, make sure that file is correct."); 8 return configurations; 9 } 10 //返回的是EnableAutoConfiguration類 11 protected Class<?> getSpringFactoriesLoaderFactoryClass() { 12 return EnableAutoConfiguration.class; 13 }
實際獲取了什麼?spring.factories文件以下,實際獲取了# Auto Configure自動配置模塊的全部類。
# 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 ===========這裏就是所有的自動配置類=============================== 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.h2.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.oauth2.OAuth2AutoConfiguration,\ 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 ============================================end================================================ # 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過濾器 根據OnClassCondition註解把不知足條件的過濾掉
1 private List<String> filter(List<String> configurations, 2 AutoConfigurationMetadata autoConfigurationMetadata) { 3 long startTime = System.nanoTime(); 4 String[] candidates = configurations.toArray(new String[configurations.size()]); 5 boolean[] skip = new boolean[candidates.length]; 6 boolean skipped = false;
//獲取須要過濾的自動配置導入攔截器,spring.factories配置中就一個:org.springframework.boot.autoconfigure.condition.OnClassCondition 7 for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) { 8 invokeAwareMethods(filter); 9 boolean[] match = filter.match(candidates, autoConfigurationMetadata); 10 for (int i = 0; i < match.length; i++) { 11 if (!match[i]) { 12 skip[i] = true; 13 skipped = true; 14 } 15 } 16 } 17 if (!skipped) {//多條件只要有一個不匹配->skipped = true,所有匹配-》skipped = false->直接返回 18 return configurations; 19 } 20 List<String> result = new ArrayList<String>(candidates.length); 21 for (int i = 0; i < candidates.length; i++) { 22 if (!skip[i]) {//匹配-》不跳過-》添加進result 23 result.add(candidates[i]); 24 } 25 } 26 if (logger.isTraceEnabled()) { 27 int numberFiltered = configurations.size() - result.size(); 28 logger.trace("Filtered " + numberFiltered + " auto configuration class in " 29 + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) 30 + " ms"); 31 } 32 return new ArrayList<String>(result); 33 }
2.2 SpringApplication.run()靜態方法
SpringApplication.run
1 public ConfigurableApplicationContext run(String... args) { 2 StopWatch stopWatch = new StopWatch(); 3 stopWatch.start(); 4 ConfigurableApplicationContext context = null; 5 FailureAnalyzers analyzers = null; 6 configureHeadlessProperty(); 7 SpringApplicationRunListeners listeners = getRunListeners(args);//1.獲取監聽器 8 listeners.starting();-->啓動! 9 try { 10 ApplicationArguments applicationArguments = new DefaultApplicationArguments( 11 args); 12 ConfigurableEnvironment environment = prepareEnvironment(listeners,//2.準備好環境,觸發ApplicationEnvironmentPreparedEvent事件 13 applicationArguments); 14 Banner printedBanner = printBanner(environment);//打印啓動提示字符,默認spring的字符圖 15 context = createApplicationContext();//實例化一個可配置應用上下文 16 analyzers = new FailureAnalyzers(context); 17 prepareContext(context, environment, listeners, applicationArguments,//3.準備上下文 18 printedBanner); 19 refreshContext(context);//4.刷新上下文 20 afterRefresh(context, applicationArguments);//5.刷新上下文後 21 listeners.finished(context, null);--關閉! 22 stopWatch.stop(); 23 if (this.logStartupInfo) { 24 new StartupInfoLogger(this.mainApplicationClass) 25 .logStarted(getApplicationLog(), stopWatch); 26 } 27 return context; 28 } 29 catch (Throwable ex) { 30 handleRunFailure(context, listeners, analyzers, ex); 31 throw new IllegalStateException(ex); 32 } 33 }
如上圖,容器啓動流程能夠分爲5個主要步驟:
1.getRunListeners獲取監聽器(SpringApplicationRunListeners )
實際是SpringApplicationRunListener類
1 private SpringApplicationRunListeners getRunListeners(String[] args) { 2 Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class }; 3 return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances( 4 SpringApplicationRunListener.class, types, this, args)); 5 } 6 7 private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type) { 8 return getSpringFactoriesInstances(type, new Class<?>[] {}); 9 } 10 11 private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type, 12 Class<?>[] parameterTypes, Object... args) { 13 ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); 14 // 使用Set確保的字符串的惟一性 15 Set<String> names = new LinkedHashSet<String>( 16 SpringFactoriesLoader.loadFactoryNames(type, classLoader));// 1.載入工廠名稱集合 17 List<T> instances = createSpringFactoriesInstances(type, parameterTypes,// 2.建立工廠實例 18 classLoader, args, names); 19 AnnotationAwareOrderComparator.sort(instances);// 排序 20 return instances; 21 }
載入工廠名稱(loadFactoryNames)
當前類的類加載器從META-INF/spring.factories文件中獲取SpringApplicationRunListener類的配置
1 public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) { 2 String factoryClassName = factoryClass.getName(); 3 try { 4 Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : 5 ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); 6 List<String> result = new ArrayList<String>(); 7 while (urls.hasMoreElements()) { 8 URL url = urls.nextElement(); 9 Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url)); 10 String factoryClassNames = properties.getProperty(factoryClassName); 11 result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames))); 12 } 13 return result; 14 } 15 catch (IOException ex) { 16 throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + 17 "] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex); 18 } 19 }
上圖,獲取到工廠類名後,下面來看看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都是實現類。咱們根據key=「org.springframework.boot.SpringApplicationRunListener」查詢獲得實現類value="org.springframework.boot.context.event.EventPublishingRunListener"事件發佈啓動監聽器,一猜也知道確定要用」反射」根據類名獲取類實例,下面很快獲得驗證...
建立spring工廠實例(createSpringFactoriesInstances)
根據第一步獲得的Set<String> names(SpringApplicationRunListener的惟一實現類EventPublishingRunListener)生成"事件發佈啓動監聽器"工廠實例
1 @SuppressWarnings("unchecked") 2 private <T> List<T> createSpringFactoriesInstances(Class<T> type, 3 Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args, 4 Set<String> names) { 5 List<T> instances = new ArrayList<T>(names.size()); 6 for (String name : names) { 7 try { 8 Class<?> instanceClass = ClassUtils.forName(name, classLoader);// 利用反射獲取類 9 Assert.isAssignable(type, instanceClass); 10 Constructor<?> constructor = instanceClass 11 .getDeclaredConstructor(parameterTypes);// 獲得構造器 12 T instance = (T) BeanUtils.instantiateClass(constructor, args);// 根據構造器和參數構造實例 13 instances.add(instance); 14 } 15 catch (Throwable ex) { 16 throw new IllegalArgumentException( 17 "Cannot instantiate " + type + " : " + name, ex); 18 } 19 } 20 return instances; 21 }
2.準備好環境
構造一個ConfigurableEnvironment,這裏很少說。
3.準備上下文
1 private void prepareContext(ConfigurableApplicationContext context, 2 ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, 3 ApplicationArguments applicationArguments, Banner printedBanner) { 4 context.setEnvironment(environment); 5 postProcessApplicationContext(context);//單例一個BeanNameGenerator,把ResourceLoader設置進應用上下文 6 applyInitializers(context);//執行初始化器 7 listeners.contextPrepared(context);// 監聽器執行上下文"已準備好"方法 8 if (this.logStartupInfo) { 9 logStartupInfo(context.getParent() == null); 10 logStartupProfileInfo(context); 11 } 12 13 // 添加spring boot特殊單例bean 14 context.getBeanFactory().registerSingleton("springApplicationArguments", 15 applicationArguments); 16 if (printedBanner != null) { 17 context.getBeanFactory().registerSingleton("springBootBanner", printedBanner); 18 } 19 20 // 載入資源 21 Set<Object> sources = getSources(); 22 Assert.notEmpty(sources, "Sources must not be empty"); 23 load(context, sources.toArray(new Object[sources.size()])); 24 listeners.contextLoaded(context);// 監聽器執行"上下文已加載"方法 25 }
4.刷新上下文
1 private void refreshContext(ConfigurableApplicationContext context) { 2 refresh(context);//核心類 3 if (this.registerShutdownHook) { 4 try { 5 context.registerShutdownHook();//註冊關閉鉤子,容器關閉時執行 6 } 7 catch (AccessControlException ex) { 8 // Not allowed in some environments. 9 } 10 } 11 } 12 13 protected void refresh(ApplicationContext applicationContext) { 14 Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext); 15 ((AbstractApplicationContext) applicationContext).refresh(); 16 }
最終執行的是AbstractApplicationContext抽象類的refresh方法。
1 public void refresh() throws BeansException, IllegalStateException { 2 synchronized (this.startupShutdownMonitor) { 3 //準備刷新的上下文環境,例如對系統屬性或者環境變量進行準備及驗證。 4 prepareRefresh(); 5 6 //啓動子類的refreshBeanFactory方法.解析xml 7 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); 8 9 //爲BeanFactory配置容器特性,例如類加載器、事件處理器等. 10 prepareBeanFactory(beanFactory); 11 12 try { 13 //設置BeanFactory的後置處理. 空方法,留給子類拓展用。 14 postProcessBeanFactory(beanFactory); 15 16 //調用BeanFactory的後處理器, 這些後處理器是在Bean定義中向容器註冊的. 17 invokeBeanFactoryPostProcessors(beanFactory); 18 19 //註冊Bean的後處理器, 在Bean建立過程當中調用. 20 registerBeanPostProcessors(beanFactory); 21 22 //初始化上下文中的消息源,即不一樣語言的消息體進行國際化處理 23 initMessageSource(); 24 25 //初始化ApplicationEventMulticaster bean,應用事件廣播器 26 initApplicationEventMulticaster(); 27 28 //初始化其它特殊的Bean, 空方法,留給子類拓展用。 29 onRefresh(); 30 31 //檢查並向容器註冊監聽器Bean 32 registerListeners(); 33 34 //實例化全部剩餘的(non-lazy-init) 單例Bean. 35 finishBeanFactoryInitialization(beanFactory); 36 37 //發佈容器事件, 結束refresh過程. 38 finishRefresh(); 39 } 40 41 catch (BeansException ex) { 42 if (logger.isWarnEnabled()) { 43 logger.warn("Exception encountered during context initialization - " + 44 "cancelling refresh attempt: " + ex); 45 } 46 47 //銷燬已經建立的單例Bean, 以免資源佔用. 48 destroyBeans(); 49 50 //取消refresh操做, 重置active標誌. 51 cancelRefresh(ex); 52 53 // Propagate exception to caller. 54 throw ex; 55 } 56 57 finally { 58 //重置Spring的核心緩存 59 resetCommonCaches(); 60 } 61 } 62 }
5.刷新完上下文後
spring boot提供的2個供用戶本身拓展的接口:ApplicationRunner和CommandLineRunner。能夠在容器啓動完畢後(上下文刷新後)執行,作一些相似數據初始化的操做。
1 private void callRunners(ApplicationContext context, ApplicationArguments args) { 2 List<Object> runners = new ArrayList<Object>(); 3 runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());//從上下文中獲取ApplicationRunner類型的bean 4 runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());//從上下文中獲取CommandLineRunner類型的bean 5 AnnotationAwareOrderComparator.sort(runners);//排序 6 for (Object runner : new LinkedHashSet<Object>(runners)) { 7 if (runner instanceof ApplicationRunner) { 8 callRunner((ApplicationRunner) runner, args);//執行 9 } 10 if (runner instanceof CommandLineRunner) { 11 callRunner((CommandLineRunner) runner, args); 12 } 13 } 14 }
兩個區別在於入參不一樣,根據實際狀況本身選擇。
1 public interface CommandLineRunner { 8 void run(String... args) throws Exception; 10 } 11 12 public interface ApplicationRunner { 19 void run(ApplicationArguments args) throws Exception; 20 21 }
CommandLineRunner中執行參數是原始的java啓動類main方法的String[] args字符串數組參數;ApplicationRunner中的參數通過處理提供一些方法例如:
1 List<String> getOptionValues(String name);
根據名稱獲取值list,java 啓動命令中 --foo=bar --foo=baz,則根據foo參數名返回list["bar", "baz"]
3、總結
按照前面的分析,Spring-boot容器啓動流程整體可劃分爲2部分:
1)執行註解:掃描指定範圍下的bean、載入自動配置類對應的bean加載到IOC容器。
2)man方法中具體SpringAppliocation.run(),全流程貫穿SpringApplicationEvent,有6個子類:
ApplicationFailedEvent.class
ApplicationPreparedEvent.class
ApplicationReadyEvent.class
ApplicationStartedEvent.class
ApplicationStartingEvent.class
SpringApplicationEvent.class
這裏用到了很經典的spring事件驅動模型,飛機票:Spring事件驅動模型和觀察者模式
類圖以下:
如上圖,就是一個經典spring 事件驅動模型,包含3種角色:事件發佈者、事件、監聽者。對應到spring-boot中就是:
1.EventPublishingRunListener這個類封裝了事件發佈,
2.SpringApplicationEvent是spring-boot中定義的事件(上面說的6種事件),繼承自ApplicationEvent(spring中定義的)
3.監聽者 spring-boot並無實現針對上述6種事件的監聽者(我沒找到...),這裏用戶能夠本身實現監聽者(上述6種事件)來注入spring boot容器啓動流程,觸發相應的事件。
例如:實現ApplicationListener<ApplicationReadyEvent>這個接口,在容器啓動完畢時最後一步listener.finished時,若是啓動沒有異常,就會執行!能夠作一些數據初始化之類的操做。