一、前言
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容器啟動的相關知識,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對服務器之家網站的支持!
原文鏈接:http://www.cnblogs.com/dennyzhangdd/p/8028950.html