一、前言
spring cloud大行其道的当下,如果不了解基本原理那么是很纠结的(看见的都是 约定大于配置 ,但是原理呢?为什么要这么做?)。spring cloud是基于spring boot快速搭建的,今天咱们就看看spring boot容器启动流程。(本文不讲解如何快速启动spring boot,那些直接官方看即可,官网文档飞机票)
spring boot一般是 指定容器启动main方法,然后以命令行方式启动jar包 ,如下图:
|
1
2
3
4
5
6
|
@springbootapplication
public class application {
public static void main(string[] args) {
springapplication.run(application.class, args);
}
}
|
这里核心关注2个东西:
1.@springbootapplication注解
2. springapplication.run()静态方法
下面我们就分别探究这两块内容。
2.1 @springbootapplication注解
源码如下:
|
1
2
3
4
5
6
7
8
9
10
|
@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这个注解的源码:
|
1
2
3
4
5
6
7
8
|
@suppresswarnings("deprecation")
@target(elementtype.type)
@retention(retentionpolicy.runtime)
@documented
@inherited
@autoconfigurationpackage
@import(enableautoconfigurationimportselector.class)
public @interface enableautoconfiguration {
|
核心是一个enableautoconfigurationimportselector类图如下:
核心方法在顶级接口 importselector 的 selectimports() ,源码如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
@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的配置。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
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 自动配置模块的所有类。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
# 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 注解把不满足条件的过滤掉
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
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
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
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 类
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
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类的配置
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
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中定义了啥:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
# 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 )生成" 事件发布启动监听器 " 工厂实例
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
@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);// 得到构造器
t instance = (t) beanutils.instantiateclass(constructor, args);// 根据构造器和参数构造实例
instances.add(instance);
}
catch (throwable ex) {
throw new illegalargumentexception(
"cannot instantiate " + type + " : " + name, ex);
}
}
return instances;
}
|
准备上下文
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
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);// 监听器执行"上下文已加载"方法
}
|
刷新上下文
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
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 方法。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
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。可以在容器启动完毕后(上下文刷新后)执行,做一些类似数据初始化的操作。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
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);
}
}
}
|
两个区别在于入参不同,根据实际情况自己选择。
|
1
2
3
4
5
6
|
public interface commandlinerunner {
void run(string... args) throws exception;
}
public interface applicationrunner {
void run(applicationarguments args) throws exception;
}
|
commandlinerunner中执行参数是原始的 java启动类main方法的string[] args字符串数组参数; applicationrunner中的参数经过处理提供一些方法例如:
|
1
|
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个子类:
|
1
2
3
4
5
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容器启动的相关知识,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对快网idc网站的支持!
原文链接:http://www.cnblogs.com/dennyzhangdd/p/8028950.html
相关文章
- 64M VPS建站:如何选择最适合的网站建设平台? 2025-06-10
- ASP.NET本地开发时常见的配置错误及解决方法? 2025-06-10
- ASP.NET自助建站系统的数据库备份与恢复操作指南 2025-06-10
- 个人网站服务器域名解析设置指南:从购买到绑定全流程 2025-06-10
- 个人网站搭建:如何挑选具有弹性扩展能力的服务器? 2025-06-10
- 2025-07-10 怎样使用阿里云的安全工具进行服务器漏洞扫描和修复?
- 2025-07-10 怎样使用命令行工具优化Linux云服务器的Ping性能?
- 2025-07-10 怎样使用Xshell连接华为云服务器,实现高效远程管理?
- 2025-07-10 怎样利用云服务器D盘搭建稳定、高效的网站托管环境?
- 2025-07-10 怎样使用阿里云的安全组功能来增强服务器防火墙的安全性?
快网idc优惠网
QQ交流群
-
2025-05-25 21
-
2025-05-27 92
-
2025-05-27 38
-
2025-05-29 76
-
2025-06-04 47




