欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

spring boot容器啟動流程

 更新時間:2018年01月25日 09:30:13   作者:只會一點java  
spring cloud是基于spring boot快速搭建的,今天咱們就看看spring boot容器啟動流程,需要的朋友跟隨腳本之家小編一起學習吧

一、前言

spring cloud大行其道的當下,如果不了解基本原理那么是很糾結(jié)的(看見的都是 約定大于配置 ,但是原理呢?為什么要這么做?)。spring cloud是基于spring boot快速搭建的,今天咱們就看看spring boot容器啟動流程。(本文不講解如何快速啟動spring boot,那些直接官方看即可, 官網(wǎng)文檔飛機票 )

二、容器啟動

spring boot一般是 指定容器啟動main方法,然后以命令行方式啟動Jar包 ,如下圖:

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

這里核心關(guān)注2個東西:

1.@SpringBootApplication注解

2. SpringApplication.run()靜態(tài)方法

下面我們就分別探究這兩塊內(nèi)容。

2.1 @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 {

核心注解:

@SpringBootConfiguration(實際就是個@Configuration):表示這是一個JavaConfig配置類,可以在這個類中自定義bean,依賴關(guān)系等。-》這個是spring-boot特有的注解,常用到。

@EnableAutoConfiguration:借助@Import的幫助,將所有符合自動配置條件的bean定義加載到IoC容器(建議放在根包路徑下,這樣可以掃描子包和類)。-》這個需要詳細深挖!

@ComponentScan:spring的自動掃描注解,可定義掃描范圍,加載到IOC容器。-》這個不多說,spring的注解大家肯定眼熟

其中@EnableAutoConfiguration這個注解的源碼:

 @SuppressWarnings("deprecation")
 @Target(ElementType.TYPE)
 @Retention(RetentionPolicy.RUNTIME)
 @Documented
 @Inherited
 @AutoConfigurationPackage
 @Import(EnableAutoConfigurationImportSelector.class)
 public @interface EnableAutoConfiguration {

核心是一個EnableAutoConfigurationImportSelector類圖如下:

 

核心方法在頂級接口 ImportSelector 的 selectImports() ,源碼如下:

 @Override
 public String[] selectImports(AnnotationMetadata annotationMetadata) {
 if (!isEnabled(annotationMetadata)) {
 return NO_IMPORTS;
 }
 try { //1.從META-INF/spring-autoconfigure-metadata.properties文件中載入483條配置屬性(有一些有默認值),
 AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
  .loadMetadata(this.beanClassLoader);
 AnnotationAttributes attributes = getAttributes(annotationMetadata);//2.獲取注解屬性
 List<String> configurations = getCandidateConfigurations(annotationMetadata,//3.獲取97個自動配置類
  attributes);
 configurations = removeDuplicates(configurations);//4.移除重復的
 configurations = sort(configurations, autoConfigurationMetadata);//5.排序
 Set<String> exclusions = getExclusions(annotationMetadata, attributes);//6.獲取需要排除的
 checkExcludedClasses(configurations, exclusions);//7.校驗排除類
 configurations.removeAll(exclusions);//8.刪除所有需要排除的
 configurations = filter(configurations, autoConfigurationMetadata);//9.過濾器OnClassCondition(注解中配置的當存在某類才生效)
 fireAutoConfigurationImportEvents(configurations, exclusions);//10.觸發(fā)自動配置導入監(jiān)聽事件
 return configurations.toArray(new String[configurations.size()]);
 }
 catch (IOException ex) {
 throw new IllegalStateException(ex);
 }
 }

這里注意3個核心方法:

1) loadMetadata 加載配置

其實就是用類加載器去加載: META-INF/spring-autoconfigure-metadata.properties (spring-boot-autoconfigure-1.5.9.RELEASE-sources.jar) 文件中定義的配置,返回PropertiesAutoConfigurationMetadata(實現(xiàn)了AutoConfigurationMetadata接口,封裝了屬性的get set方法)

2) getCandidateConfigurations 獲取默認支持的自動配置類名列表

自動配置靈魂方法, SpringFactoriesLoader.loadFactoryNames 從 META-INF/spring.factories (spring-boot-autoconfigure-1.5.9.RELEASE-sources.jar)文件中獲取自動配置類key=EnableAutoConfiguration.class的配置。 

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
 AnnotationAttributes attributes) {//話說這里2個入?yún)]啥用啊...誰來給我解釋一下...
 List<String> 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;
 }

實際獲取了什么? 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
# 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過濾器 根據(jù) OnClassCondition 注解把不滿足條件的過濾掉

 private List<String> filter(List<String> configurations,
 AutoConfigurationMetadata autoConfigurationMetadata) {
 long startTime = System.nanoTime();
 String[] candidates = configurations.toArray(new String[configurations.size()]);
 boolean[] skip = new boolean[candidates.length];
 boolean skipped = false;
 //獲取需要過濾的自動配置導入攔截器,spring.factories配置中就一個: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) {//多條件只要有一個不匹配->skipped = true,全部匹配-》skipped = false->直接返回
 return configurations;
 }
 List<String> result = new ArrayList<String>(candidates.length);
 for (int i = 0; i < candidates.length; i++) {
 if (!skip[i]) {//匹配-》不跳過-》添加進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<String>(result);
 }

2.2 SpringApplication .run()靜態(tài)方法

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();-->啟動!
 try {
 ApplicationArguments applicationArguments = new DefaultApplicationArguments(
  args);
 ConfigurableEnvironment environment = prepareEnvironment(listeners,//2.準備好環(huán)境,觸發(fā)ApplicationEnvironmentPreparedEvent事件
  applicationArguments);
 Banner printedBanner = printBanner(environment);//打印啟動提示字符,默認spring的字符圖
 context = createApplicationContext();//實例化一個可配置應(yīng)用上下文
 analyzers = new FailureAnalyzers(context);
 prepareContext(context, environment, listeners, applicationArguments,//3.準備上下文
  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 )

實際是 SpringApplicationRunListener 類

 private SpringApplicationRunListeners getRunListeners(String[] args) {
 Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
 return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
 SpringApplicationRunListener.class, types, this, args));
 }
 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();
 // 使用Set確保的字符串的唯一性
 Set<String> names = new LinkedHashSet<String>(
 SpringFactoriesLoader.loadFactoryNames(type, classLoader));// 1.載入工廠名稱集合
 List<T> instances = createSpringFactoriesInstances(type, parameterTypes,// 2.創(chuàng)建工廠實例
 classLoader, args, names);
 AnnotationAwareOrderComparator.sort(instances);// 排序
 return instances;
 }

1.1 載入工廠名稱(loadFactoryNames)

當前類的類加載器從 META-INF/spring.factories 文件中獲取SpringApplicationRunListener類的配置

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中定義了啥:

# 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都是實現(xiàn)類。我們根據(jù)key=“ org.springframework.boot.SpringApplicationRunListener ”查詢得到實現(xiàn)類value=" org.springframework.boot.context.event.EventPublishingRunListener" 事件發(fā)布啟動監(jiān)聽器 , 一猜也知道肯定要用” 反射 ”根據(jù)類名獲取類實例,下面很快得到驗證...

1.2 創(chuàng)建spring工廠實例(createSpringFactoriesInstances)

根據(jù)第一步得到的Set<String> names(SpringApplicationRunListener的唯一實現(xiàn)類 EventPublishingRunListener )生成" 事件發(fā)布啟動監(jiān)聽器 " 工廠實例

 @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
  .getDeclaredConstructor(parameterTypes);// 得到構(gòu)造器
  T instance = (T) BeanUtils.instantiateClass(constructor, args);// 根據(jù)構(gòu)造器和參數(shù)構(gòu)造實例
  instances.add(instance);
 }
 catch (Throwable ex) {
  throw new IllegalArgumentException(
  "Cannot instantiate " + type + " : " + name, ex);
 }
 }
 return instances;
 }

準備上下文

 private void prepareContext(ConfigurableApplicationContext context,
 ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
 ApplicationArguments applicationArguments, Banner printedBanner) {
 context.setEnvironment(environment);
 postProcessApplicationContext(context);//單例一個BeanNameGenerator,把ResourceLoader設(shè)置進應(yīng)用上下文
 applyInitializers(context);//執(zhí)行初始化器
 listeners.contextPrepared(context);// 監(jiān)聽器執(zhí)行上下文"已準備好"方法
 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<Object> sources = getSources();
 Assert.notEmpty(sources, "Sources must not be empty");
 load(context, sources.toArray(new Object[sources.size()]));
 listeners.contextLoaded(context);// 監(jiān)聽器執(zhí)行"上下文已加載"方法
 }

刷新上下文

 private void refreshContext(ConfigurableApplicationContext context) {
 refresh(context);//核心類
 if (this.registerShutdownHook) {
 try {
 context.registerShutdownHook();//注冊關(guān)閉鉤子,容器關(guān)閉時執(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) {
 //準備刷新的上下文環(huán)境,例如對系統(tǒng)屬性或者環(huán)境變量進行準備及驗證。
 prepareRefresh();
 //啟動子類的refreshBeanFactory方法.解析xml
 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
 //為BeanFactory配置容器特性,例如類加載器、事件處理器等.
 prepareBeanFactory(beanFactory);
 try {
  //設(shè)置BeanFactory的后置處理. 空方法,留給子類拓展用。 
  postProcessBeanFactory(beanFactory);
  //調(diào)用BeanFactory的后處理器, 這些后處理器是在Bean定義中向容器注冊的. 
  invokeBeanFactoryPostProcessors(beanFactory);
  //注冊Bean的后處理器, 在Bean創(chuàng)建過程中調(diào)用. 
  registerBeanPostProcessors(beanFactory);
  //初始化上下文中的消息源,即不同語言的消息體進行國際化處理 
  initMessageSource();
  //初始化ApplicationEventMulticaster bean,應(yīng)用事件廣播器
  initApplicationEventMulticaster();
  //初始化其它特殊的Bean, 空方法,留給子類拓展用。 
  onRefresh();
  //檢查并向容器注冊監(jiān)聽器Bean
  registerListeners();
  //實例化所有剩余的(non-lazy-init) 單例Bean.
  finishBeanFactoryInitialization(beanFactory);
  //發(fā)布容器事件, 結(jié)束refresh過程. 
  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標志. 
  cancelRefresh(ex);
  // Propagate exception to caller.
  throw ex;
 }
 finally {
  //重置Spring的核心緩存
  resetCommonCaches();
 }
 }
 }

刷新完上下文后

spring boot提供的2個供用戶自己拓展的接口: ApplicationRunner和 CommandLineRunner??梢栽谌萜鲉油戤吅螅ㄉ舷挛乃⑿潞螅﹫?zhí)行,做一些類似數(shù)據(jù)初始化的操作。

 private void callRunners(ApplicationContext context, ApplicationArguments args) {
 List<Object> runners = new ArrayList<Object>();
 runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());//從上下文中獲取ApplicationRunner類型的bean
 runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());//從上下文中獲取CommandLineRunner類型的bean
 AnnotationAwareOrderComparator.sort(runners);//排序
 for (Object runner : new LinkedHashSet<Object>(runners)) {
 if (runner instanceof ApplicationRunner) {
  callRunner((ApplicationRunner) runner, args);//執(zhí)行
 }
 if (runner instanceof CommandLineRunner) {
  callRunner((CommandLineRunner) runner, args);
 }
 }
 }

兩個區(qū)別在于入?yún)⒉煌鶕?jù)實際情況自己選擇。

 public interface CommandLineRunner {
 void run(String... args) throws Exception;
 }
 public interface ApplicationRunner {
 void run(ApplicationArguments args) throws Exception;
 }

CommandLineRunner中執(zhí)行參數(shù)是原始的 java啟動類main方法的String[] args字符串數(shù)組參數(shù); ApplicationRunner中的參數(shù)經(jīng)過處理提供一些方法例如:

 List<String> getOptionValues(String name);

根據(jù)名稱獲取值list,java 啟動命令中 --foo=bar --foo=baz,則根據(jù)foo參數(shù)名返回list ["bar", "baz"]

三、總結(jié)

 

按照前面的分析,Spring-boot容器啟動流程總體可劃分為2部分:

1) 執(zhí)行注解 :掃描指定范圍下的bean、載入自動配置類對應(yīng)的bean加載到IOC容器。

2)man方法中具體SpringAppliocation.run() ,全流程貫穿SpringApplicationEvent,有6個子類:

ApplicationFailedEvent.class
ApplicationPreparedEvent.class
ApplicationReadyEvent.class
ApplicationStartedEvent.class
ApplicationStartingEvent.class
SpringApplicationEvent.class

這里用到了很經(jīng)典的 spring事件驅(qū)動模型 ,飛機票: Spring事件驅(qū)動模型和觀察者模式

類圖如下:

 

如上圖,就是一個經(jīng)典spring 事件驅(qū)動模型,包含3種角色:事件發(fā)布者、事件、監(jiān)聽者。對應(yīng)到spring-boot中就是:

1 .EventPublishingRunListener 這個類封裝了 事件發(fā)布 ,

2. SpringApplicationEvent 是spring-boot中定義的事件(上面說的6種事件),繼承自 ApplicationEvent (spring中定義的)

3. 監(jiān)聽者 spring-boot并沒有實現(xiàn)針對上述6種事件的監(jiān)聽者(我沒找到...), 這里用戶可以自己實現(xiàn)監(jiān)聽者(上述6種事件)來注入spring boot容器啟動流程,觸發(fā)相應(yīng)的事件。

例如:實現(xiàn)ApplicationListener<ApplicationReadyEvent>這個接口,在容器啟動完畢時最后一步listener.finished時,如果啟動沒有異常,就會執(zhí)行!可以做一些數(shù)據(jù)初始化之類的操作。

總結(jié)

以上所述是小編給大家介紹的spring boot容器啟動的相關(guān)知識,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!

相關(guān)文章

  • idea本地merge如何合并代碼

    idea本地merge如何合并代碼

    這篇文章主要介紹了idea本地merge如何合并代碼問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-06-06
  • Java圖形化編程中的鍵盤事件設(shè)計簡介

    Java圖形化編程中的鍵盤事件設(shè)計簡介

    這篇文章主要介紹了Java圖形化編程中的鍵盤事件設(shè)計,是Java的GUI編程當中的基礎(chǔ)部分,需要的朋友可以參考下
    2015-10-10
  • 最新評論