spring boot容器启动流程

一、前言

spring cloud大行其道的当下,如果不了解基本原理那么是很纠结的(看见的都是 约定大于配置 ,但是原理呢?为什么要这么做?)。spring cloud是基于spring boot快速搭建的,今天咱们就看看spring boot容器启动流程。(本文不讲解如何快速启动spring boot,那些直接官方看即可, 官网文档飞机票 )

二、容器启动

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

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

这里核心关注2个东西:

1.@SpringBootApplication注解

2. SpringApplication.run()静态方法

下面我们就分别探究这两块内容。

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,依赖关系等。-》这个是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.触发自动配置导入监听事件
 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(实现了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个入参没啥用啊...谁来给我解释一下...
 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过滤器 根据 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()静态方法

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.获取监听器
 listeners.starting();-->启动!
 try {
 ApplicationArguments applicationArguments = new DefaultApplicationArguments(
  args);
 ConfigurableEnvironment environment = prepareEnvironment(listeners,//2.准备好环境,触发ApplicationEnvironmentPreparedEvent事件
  applicationArguments);
 Banner printedBanner = printBanner(environment);//打印启动提示字符,默认spring的字符图
 context = createApplicationContext();//实例化一个可配置应用上下文
 analyzers = new FailureAnalyzers(context);
 prepareContext(context,environment,listeners,applicationArguments,//3.准备上下文
  printedBanner);
 refreshContext(context);//4.刷新上下文
 afterRefresh(context,applicationArguments);//5.刷新上下文后
 listeners.finished(context,null);--关闭!
 stopWatch.stop();
 if (this.logStartupInfo) {
  new StartupInfoLogger(this.mainApplicationClass)
  .logStarted(getApplicationLog(),stopWatch);
 }
 return context;
 }
 catch (Throwable ex) {
 handleRunFailure(context,analyzers,ex);
 throw new IllegalStateException(ex);
 }
 }

1. getRunListeners 获取监听器( 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.创建工厂实例
 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都是实现类。我们根据key=“ org.springframework.boot.SpringApplicationRunListener ”查询得到实现类value=" org.springframework.boot.context.event.EventPublishingRunListener" 事件发布启动监听器 , 一猜也知道肯定要用” 反射 ”根据类名获取类实例,下面很快得到验证...

1.2 创建spring工厂实例(createSpringFactoriesInstances)

根据第一步得到的Set<String> names(SpringApplicationRunListener的唯一实现类 EventPublishingRunListener )生成" 事件发布启动监听器 " 工厂实例

 @SuppressWarnings("unchecked")
 private <T> List<T> createSpringFactoriesInstances(Class<T> type,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);// 得到构造器
  T instance = (T) BeanUtils.instantiateClass(constructor,args);// 根据构造器和参数构造实例
  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设置进应用上下文
 applyInitializers(context);//执行初始化器
 listeners.contextPrepared(context);// 监听器执行上下文"已准备好"方法
 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);// 监听器执行"上下文已加载"方法
 }

刷新上下文

 private void refreshContext(ConfigurableApplicationContext context) {
 refresh(context);//核心类
 if (this.registerShutdownHook) {
 try {
 context.registerShutdownHook();//注册关闭钩子,容器关闭时执行
 }
 catch (AccessControlException ex) {
 // Not allowed in some environments.
 }
 }
 }
 protected void refresh(ApplicationContext applicationContext) {
 Assert.isInstanceOf(AbstractApplicationContext.class,applicationContext);
 ((AbstractApplicationContext) applicationContext).refresh();
 }

最终执行的是AbstractApplicationContext抽象类的 refresh 方法。

 public void refresh() throws BeansException,IllegalStateException {
 synchronized (this.startupShutdownMonitor) {
 //准备刷新的上下文环境,例如对系统属性或者环境变量进行准备及验证。
 prepareRefresh();
 //启动子类的refreshBeanFactory方法.解析xml
 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
 //为BeanFactory配置容器特性,例如类加载器、事件处理器等.
 prepareBeanFactory(beanFactory);
 try {
  //设置BeanFactory的后置处理. 空方法,留给子类拓展用。 
  postProcessBeanFactory(beanFactory);
  //调用BeanFactory的后处理器,这些后处理器是在Bean定义中向容器注册的. 
  invokeBeanFactoryPostProcessors(beanFactory);
  //注册Bean的后处理器,在Bean创建过程中调用. 
  registerBeanPostProcessors(beanFactory);
  //初始化上下文中的消息源,即不同语言的消息体进行国际化处理 
  initMessageSource();
  //初始化ApplicationEventMulticaster bean,应用事件广播器
  initApplicationEventMulticaster();
  //初始化其它特殊的Bean, 空方法,留给子类拓展用。 
  onRefresh();
  //检查并向容器注册监听器Bean
  registerListeners();
  //实例化所有剩余的(non-lazy-init) 单例Bean.
  finishBeanFactoryInitialization(beanFactory);
  //发布容器事件,结束refresh过程. 
  finishRefresh();
 }
 catch (BeansException ex) {
  if (logger.isWarnEnabled()) {
  logger.warn("Exception encountered during context initialization - " +
  "cancelling refresh attempt: " + ex);
  }
  //销毁已经创建的单例Bean,以避免资源占用.
  destroyBeans();
  //取消refresh操作,重置active标志. 
  cancelRefresh(ex);
  // Propagate exception to caller.
  throw ex;
 }
 finally {
  //重置Spring的核心缓存
  resetCommonCaches();
 }
 }
 }

刷新完上下文后

spring boot提供的2个供用户自己拓展的接口: ApplicationRunner和 CommandLineRunner。可以在容器启动完毕后(上下文刷新后)执行,做一些类似数据初始化的操作。

 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);//执行
 }
 if (runner instanceof CommandLineRunner) {
  callRunner((CommandLineRunner) runner,args);
 }
 }
 }

两个区别在于入参不同,根据实际情况自己选择。

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

CommandLineRunner中执行参数是原始的 java启动类main方法的String[] args字符串数组参数; ApplicationRunner中的参数经过处理提供一些方法例如:

 List<String> getOptionValues(String name);

根据名称获取值list,java 启动命令中 --foo=bar --foo=baz,则根据foo参数名返回list ["bar","baz"]

三、总结

 

按照前面的分析,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时,如果启动没有异常,就会执行!可以做一些数据初始化之类的操作。

总结

以上所述是小编给大家介绍的spring boot容器启动的相关知识,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对编程小技巧网站的支持!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习编程?其实不难,不过在学习编程之前你得先了解你的目的是什么?这个很重要,因为目的决定你的发展方向、决定你的发展速度。
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面设计类、前端与移动、开发与测试、营销推广类、数据运营类、运营维护类、游戏相关类等,根据不同的分类下面有细分了不同的岗位。
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生学习Java开发,但要结合自身的情况,先了解自己适不适合去学习Java,不要盲目的选择不适合自己的Java培训班进行学习。只要肯下功夫钻研,多看、多想、多练
Can’t connect to local MySQL server through socket \'/var/lib/mysql/mysql.sock问题 1.进入mysql路径
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 sqlplus / as sysdba 2.普通用户登录
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服务器有时候会断掉,所以写个shell脚本每五分钟去判断是否连接,于是就有下面的shell脚本。
BETWEEN 操作符选取介于两个值之间的数据范围内的值。这些值可以是数值、文本或者日期。
假如你已经使用过苹果开发者中心上架app,你肯定知道在苹果开发者中心的web界面,无法直接提交ipa文件,而是需要使用第三方工具,将ipa文件上传到构建版本,开...
下面的 SQL 语句指定了两个别名,一个是 name 列的别名,一个是 country 列的别名。**提示:**如果列名称包含空格,要求使用双引号或方括号:
在使用H5混合开发的app打包后,需要将ipa文件上传到appstore进行发布,就需要去苹果开发者中心进行发布。​
+----+--------------+---------------------------+-------+---------+
数组的声明并不是声明一个个单独的变量,比如 number0、number1、...、number99,而是声明一个数组变量,比如 numbers,然后使用 nu...
第一步:到appuploader官网下载辅助工具和iCloud驱动,使用前面创建的AppID登录。
如需删除表中的列,请使用下面的语法(请注意,某些数据库系统不允许这种在数据库表中删除列的方式):
前不久在制作win11pe,制作了一版,1.26GB,太大了,不满意,想再裁剪下,发现这次dism mount正常,commit或discard巨慢,以前都很快...
赛门铁克各个版本概览:https://knowledge.broadcom.com/external/article?legacyId=tech163829
实测Python 3.6.6用pip 21.3.1,再高就报错了,Python 3.10.7用pip 22.3.1是可以的
Broadcom Corporation (博通公司,股票代号AVGO)是全球领先的有线和无线通信半导体公司。其产品实现向家庭、 办公室和移动环境以及在这些环境...
发现个问题,server2016上安装了c4d这些版本,低版本的正常显示窗格,但红色圈出的高版本c4d打开后不显示窗格,
TAT:https://cloud.tencent.com/document/product/1340