Detailed explanation of Spring Boot container startup

I. Introduction

Now that spring cloud is so popular, if you don’t understand the basic principles, it will be very tangled (what you see is that the convention is greater than the configuration, but what is the principle? Why do you do this? How to connect it?). Spring cloud is quickly built based on spring boot. Today we will take a look at the spring boot container startup process (the full text is based on version 1.5.9, and springboot2 is basically the same). (This article does not explain how to quickly start spring boot, just look directly at the official

2. Container startup

Spring boot generally specifies the container to start the main method, and then starts the Jar package with the command line , as shown in the following figure:

 
 

typescript

copy code

1 @SpringBootApplication 2 public class Application { 3 public static void main(String[] args) { 4 SpringApplication.run(Application.class, args); 5 } 6 }

Focus on 2 things here:

2.1  @SpringBootApplication annotation

The source code is as follows:

copy code

 
 

java

copy code

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 {

copy code

Core Notes:

 
 

less

copy code

@SpringBootConfiguration(实际就是个@Configuration):表示这是一个JavaConfig配置类,可以在这个类中自定义bean,依赖关系等。-》这个是spring-boot特有的注解,常用到。 @EnableAutoConfiguration:借助@Import的帮助,将所有符合自动配置条件的bean定义加载到IoC容器(建议放在根包路径下,这样可以扫描子包和类)。-》这个需要详细深挖! @ComponentScan:spring的自动扫描注解,可定义扫描范围,加载到IOC容器。-》这个不多说,spring的注解大家肯定眼熟 其中@EnableAutoConfiguration这个注解的源码:

copy code

 
 

kotlin

copy code

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 {

copy code

 
 

copy code

The core is an EnableAutoConfigurationImportSelector class diagram as follows:

The core method is selectImports() of the top-level interface ImportSelector , and the source code is as follows:

copy code

 
 

scss

copy code

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 }

copy code

 Pay attention to 3 core methods here:

1) loadMetadata load configuration

In fact, it uses the class loader to load: the configuration defined in the META-INF/spring-autoconfigure-metadata.properties (spring-boot-autoconfigure-1.5.9.RELEASE-sources.jar) file, returns PropertiesAutoConfigurationMetadata (implements the AutoConfigurationMetadata interface , encapsulates the get set method of the attribute)

2) getCandidateConfigurations gets the list of auto-configuration class names supported by default

The automatic configuration soul method, SpringFactoriesLoader.loadFactoryNames obtains the configuration of the automatic configuration class key=EnableAutoConfiguration.class from the META-INF/spring.factories (spring-boot-autoconfigure-1.5.9.RELEASE-sources.jar) file.

copy code

 
 

typescript

copy code

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 }

copy code

What is actually gained? The spring.factories file is as follows, which actually gets all the classes of the # Auto Configure automatic configuration module.

copy code

 
 

This

copy code

# 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

copy code

 3) filter filters out those that do not meet the conditions according to the OnClassCondition annotation

copy code

 
 

This

copy code

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 }

copy code

2.2 SpringApplication.run() static method

SpringApplication.run

copy code

 
 

scss

copy code

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 }

copy code

As shown above, the container startup process can be divided into 5 main steps:

1. getRunListeners get listener (SpringApplicationRunListeners)

Actually the SpringApplicationRunListener class

copy code

 
 

typescript

copy code

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 }

copy code

Load Factory Names (loadFactoryNames)

The class loader of the current class obtains the configuration of the SpringApplicationRunListener class from the META-INF/spring.factories file

copy code

 
 

This

copy code

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 }

copy code

In the picture above, after obtaining the factory class name, let’s take a look at what is defined in META-INF/spring.factories:

copy code

 
 

This

copy code

# 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

copy code

Wow, they are all full names of classes, and the keys are all interfaces, and the values ​​are all implementation classes. We get the implementation class value="org.springframework.boot.context.event.EventPublishingRunListener" event publishing start listener according to the key="org.springframework.boot.SpringApplicationRunListener" query, and we must use "reflection" according to the class Get the class instance by name, and the following will be verified soon...

Create a spring factory instance (createSpringFactoriesInstances)

According to the Set names obtained in the first step (the only implementation class of SpringApplicationRunListener, EventPublishingRunListener), a factory instance of "Event Publishing Start Listener" is generated

copy code

 
 

typescript

copy code

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 }

copy code

2. Prepare the environment

 
 

copy code

构造一个ConfigurableEnvironment,这里不多说。

3. Prepare the context

copy code

 
 

scss

copy code

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 }

copy code

4. Refresh the context

copy code

 
 

scss

copy code

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 }

copy code

The final execution is the refresh method of the AbstractApplicationContext abstract class.

copy code

 
 

scss

copy code

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 }

copy code

5. After refreshing the context

Spring boot provides two interfaces for users to expand themselves: ApplicationRunner and CommandLineRunner. It can be executed after the container is started (after the context is refreshed) to do some operations similar to data initialization.

copy code

 
 

scss

copy code

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 }

copy code

 
 

copy code

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

copy code

 
 

java

copy code

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 }

copy code

 The execution parameter in CommandLineRunner is the String[] args string array parameter of the original java startup class main method; the parameters in ApplicationRunner are processed to provide some methods such as:``

 1 List getOptionValues(String name); 

 Get the value list according to the name, in the java startup command --foo=bar --foo=baz, return the list according to the foo parameter name["bar", "baz"]

back to the top

3. Summary

 

According to the previous analysis, the Spring-boot container startup process can be divided into two parts:

1) Execute annotations : Scan the beans under the specified range, load the beans corresponding to the automatic configuration class and load them into the IOC container.

2) The specific SpringApplication.run() in the man method, the whole process runs through the SpringApplicationEvent, and there are 6 subclasses:

ApplicationEnvironmentPreparedEvent

ApplicationFailedEvent.class

ApplicationPreparedEvent.class

ApplicationReadyEvent.class

ApplicationStartedEvent.class

ApplicationStartingEvent.class

A very classic spring event-driven model is used here , the plane ticket: Spring event-driven model and observer mode

The class diagram is as follows:

As shown above, it is a classic spring event-driven model, which includes three roles: event publisher, event, and listener. Corresponding to spring-boot is:

1. The EventPublishingRunListener class encapsulates event publishing ,

2. SpringApplicationEvent is an event defined in spring-boot (the 6 events mentioned above), inherited from ApplicationEvent (defined in spring)

3. ApplicationListener is spring-boot's listener for the above 6 events . Here, users can also implement the listener (the above 6 events) to inject the spring boot container startup process and trigger corresponding events.

For example: to implement the ApplicationListener interface, when the last step listener.finished when the container is started, if there is no abnormality in the startup, it will be executed! You can do some operations such as data initialization.

Guess you like

Origin blog.csdn.net/wdj_yyds/article/details/131940876