spring boot容器启动流程

网友投稿 262 2023-02-25


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 attributeshttp:// = getAttributes(annotationMetadata);//2.获取注解属性

List configurations = getCandidateConfigurations(annotationMetadata,//3.获取97个自动配置类

attributes);

configurations = removeDuplicates(configurations);//4.移除重复的

configurations = sort(configurations, autoConfigurationMetadata);//5.排序

Set 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 getCandidateConfigurations(AnnotationMetadata metadata,

AnnotationAttributes attributes) {//话说这里2个入参没啥用啊...谁来给我解释一下...

List configurations = SpringFactoriesLoader.loadFactoryNames(

getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());

Assert.notEmpty(configurations,

"No auto configuration classes found in META-INF/spring.factories. If you "

+ "are using a custom packaging, make sure that file is correct.");

return configurations;

}

//返回的是EnableAutoConfiguration类

protected Class> getSpringFactoriesLoaderFactoryClass() {

return EnableAutoConfiguration.class;

}

实际获取了什么? 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.Chttp://ouchbaseAutoConfiguration,\

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 filter(List configurations,

AutoConfigurationMetadata autoConfigurationMetadata) {

long startTime = System.nanoTime();

String[] candidates = configurations.toArray(new String[configurations.size()]);

boolean[] skip = new boolean[candidates.length];

boolean skipped = false;

//获取需要过滤的自动配置导入拦截器,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 result = new ArrayList(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(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, listeners, 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 Collection extends T> getSpringFactoriesInstances(Class type) {

return getSpringFactoriesInstances(type, new Class>[] {});

}

private Collection extends T> getSpringFactoriesInstances(Class type,

Class>[] parameterTypes, Object... args) {

ClassLoader classLoader = Thread.currentThread().getContextClassLoader();

// 使用Set确保的字符串的唯一性

Set names = new LinkedHashSet(

SpringFactoriesLoader.loadFactoryNames(type, classLoader));// 1.载入工厂名称集合

List instances = createSpringFactoriesInstances(type, parameterTypes,// 2.创建工厂实例

classLoader, args, names);

AnnotationAwareOrderComparator.sort(instances);// 排序

return instances;

}

1.1 载入工厂名称(loadFactoryNames)

当前类的类加载器从 META-INF/spring.factories 文件中获取SpringApplicationRunListener类的配置

public static List loadFactoryNames(Class> factoryClass, ClassLoader classLoader) {

String factoryClassName = factoryClass.getName();

try {

Enumeration urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :

ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));

List result = new ArrayList();

while (urls.hasMoreElements()) {

URL url = urls.nextElement();

Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));

String factoryClassNames = properties.getProperty(factoryClassName);

result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));

}

return result;

}

catch (IOException ex) {

throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() +

"] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);

}

}

上图,获取到工厂类名后,下面来看看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 names(SpringApplicationRunListener的唯一实现类 EventPublishingRunListener )生成" 事件发布启动监听器 " 工厂实例

@SuppressWarnings("unchecked")

private List createSpringFactoriesInstances(Class type,

Class>[] parameterTypes, ClassLoader classLoader, Object[] args,

Set names) {

List instances = new ArrayList(names.size());

for (String name : names) {

try {

Class> instanceClass = ClassUtils.forName(name, classLoader);// 利用反射获取类

Assert.isAssignable(type, instanceClass);

Constructor> constructor = instanceClass

.getDeclaredConstructor(parameterTypes);// 得到构造器

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 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 runners = new ArrayList();

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(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 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这个接口,在容器启动完毕时最后一步listener.finished时,如果启动没有异常,就会执行!可以做一些数据初始化之类的操作。

总结

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


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:vue引入新版 vue
下一篇:软件开发接口标准(api接口开发规范)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~