之前在排查一個線上問題時,不得不仔細跑了很多遍spring boot的代碼,于是整理一下,我用的是1.4.3.release。
首先,普通的入口,這沒什么好說的,我就隨便貼貼代碼了:
1
2
3
4
5
6
7
8
|
springapplication.run(application. class , args); --> public static configurableapplicationcontext run(object source, string... args) { return run( new object[] { source }, args); } public static configurableapplicationcontext run(object[] sources, string[] args) { return new springapplication(sources).run(args); } |
也就是一個靜態(tài)方法,調用了構造函數(shù)創(chuàng)建實例,構造的參數(shù)是object數(shù)組,這里new這個數(shù)組的時候傳入了一個元素就是啟動類的類對象實例(一般就是“new object[] { application.class” }),構造函數(shù)里調用了一個initialize方法。
springapplication的initialize方法,首先在object數(shù)組有值的情況下將數(shù)組放入一個final的類實例私有object的set集合中;然后用deducewebenvironment方法判斷當前應用環(huán)境是否是web環(huán)境,判斷邏輯是看classpath是否同時存在javax.servlet.servlet和org.springframework.web.context.configurablewebapplicationcontext,缺一就認為不是。然后,調用setinitializers方法,設置類實例的私有l(wèi)ist<applicationcontextinitializer<?>>類型變量initializers:
1
2
3
4
5
|
public void setinitializers( collection<? extends applicationcontextinitializer<?>> initializers) { this .initializers = new arraylist<applicationcontextinitializer<?>>(); this .initializers.addall(initializers); } |
設置的時候會先new,也就是說這方法每次都是整體更換,不會追加。這個方法的參數(shù)都是各個模塊中配置在meta-inf/spring.factories中的key為org.springframework.context.applicationcontextinitializer的值,這些類都是接口applicationcontextinitializer<c extends configurableapplicationcontext>的泛型實現(xiàn)。
1
2
3
4
5
6
7
8
9
10
11
|
private <t> collection<? extends t> getspringfactoriesinstances( class <t> type, class <?>[] parametertypes, object... args) { classloader classloader = thread.currentthread().getcontextclassloader(); // use names and ensure unique to protect against duplicates set<string> names = new linkedhashset<string>( springfactoriesloader.loadfactorynames(type, classloader)); list<t> instances = createspringfactoriesinstances(type, parametertypes, classloader, args, names); annotationawareordercomparator.sort(instances); return instances; } |
使用springfactoriesloader.loadfactorynames方法去取上面說的被配置的applicationcontextinitializer的名字放進set<string>中,并用反射創(chuàng)建這些名字的實例。
setinitializers方法之后又是setinitializers,參數(shù)同上都是getspringfactoriesinstances方法獲取,只不過這次參數(shù)class<t> type泛型類型是org.springframework.context.applicationlistener。
initialize方法的最后一個步是設置實例的class<?>類型私有屬性mainapplicationclass,獲取設置值的方法deducemainapplicationclass:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
private class <?> deducemainapplicationclass() { try { stacktraceelement[] stacktrace = new runtimeexception().getstacktrace(); for (stacktraceelement stacktraceelement : stacktrace) { if ( "main" .equals(stacktraceelement.getmethodname())) { return class .forname(stacktraceelement.getclassname()); } } } catch (classnotfoundexception ex) { // swallow and continue } return null ; } |
實例化springapplication后調用了它的run實例方法(注意不是上面的靜態(tài)方法)。一進run方法首先啟動了stopwatch,這個stopwatch的功能在類的注釋寫可,大概意思是這是個簡單的秒表,用于在開發(fā)過程中方便程序員調試性能等,非線程安全,不建議用于生產(chǎn)。configureheadlessproperty設置使用headless,對于只有遠程登錄使用的服務器來說這樣性能要好一些。接著是加載用于這個run方法啟動過程的監(jiān)聽器,依然是getspringfactoriesinstances方法,這次的類型是org.springframework.boot.springapplicationrunlistener:
1
2
3
4
|
# run listeners org.springframework.boot.springapplicationrunlistener=\ org.springframework.boot.context.event.eventpublishingrunlistener |
1
2
3
4
5
|
springapplicationrunlisteners(log log, collection<? extends springapplicationrunlistener> listeners) { this .log = log; this .listeners = new arraylist<springapplicationrunlistener>(listeners); } |
先是加載所有可用監(jiān)聽,然后初始化springapplicationrunlisteners對象,最后循環(huán)啟動所有springapplicationrunlistener監(jiān)聽。啟動監(jiān)聽的方法:
1
2
3
4
5
|
@override public void started() { this .initialmulticaster .multicastevent( new applicationstartedevent( this .application, this .args)); } |
applicationstartedevent實例化傳了兩個參數(shù),先看第一個參數(shù)this.application是怎么來的,實例的springapplication的run方法中,用于獲取springapplicationrunlistener,也就是前面說的getspringfactoriesinstances被調用時:
1
2
3
4
5
|
private springapplicationrunlisteners getrunlisteners(string[] args) { class <?>[] types = new class <?>[] { springapplication. class , string[]. class }; return new springapplicationrunlisteners(logger, getspringfactoriesinstances( springapplicationrunlistener. class , types, this , args)); } |
getspringfactoriesinstances方法的參數(shù)包含springapplication.class和this,這兩個參數(shù)被傳入createspringfactoriesinstances方法:
可以看到,是通過反射創(chuàng)建實例的時候,將springapplication中的this傳進來eventpublishingrunlistener構造的,然后eventpublishingrunlistener構造:
1
2
3
4
5
6
7
8
|
public eventpublishingrunlistener(springapplication application, string[] args) { this .application = application; this .args = args; this .initialmulticaster = new simpleapplicationeventmulticaster(); for (applicationlistener<?> listener : application.getlisteners()) { this .initialmulticaster.addapplicationlistener(listener); } } |
最后在構造applicationstartedevent時傳給它的基類eventobject的protected不可序列化屬性source。實例化applicationstartedevent后instance.getclass()并包裝為resolvabletype類型以保存類型信息,并將它和event作為參數(shù)傳入simpleapplicationeventmulticaster的multicastevent方法。multicastevent首先獲取applicationlistener,使用getapplicationlisteners方法,這個方法中拋開對listener做了一些緩存類工作外,主要就是將事件和對應的監(jiān)聽器做了下是否支持的驗證,返回通過了retrieveapplicationlisteners中通過了supportsevent驗證的監(jiān)聽器集合,這里就體現(xiàn)出了resolvabletype的作用,它保存了類型的信息同時對泛型類型也支持。
得到了這些匹配的監(jiān)聽器后,判斷當前executor是否被設置過,如果為null則同步循環(huán)執(zhí)行所有:invokelistener(listener, event);如果不為null則:
1
2
3
4
5
6
|
executor.execute( new runnable() { @override public void run() { invokelistener(listener, event); } }); |
監(jiān)聽器執(zhí)行的時候也會先判斷是否是該由自己處理的事件,例如:
1
2
3
4
5
6
7
8
9
10
|
@override public void onapplicationevent(applicationevent event) { if (event instanceof applicationenvironmentpreparedevent) { onapplicationenvironmentpreparedevent( (applicationenvironmentpreparedevent) event); } if (event instanceof applicationpreparedevent) { onapplicationpreparedevent(event); } } |
監(jiān)聽啟動后,只準備一些啟動參數(shù),和環(huán)境變量prepareenvironment方法先是讀取了應用的啟動參數(shù)和profile配置,然后用listeners.environmentprepared(environment)傳給監(jiān)聽器:
1
2
3
4
|
public void environmentprepared(configurableenvironment environment) { this .initialmulticaster.multicastevent( new applicationenvironmentpreparedevent( this .application, this .args, environment)); } |
接著判斷如果environment是org.springframework.web.context.configurablewebenvironment的實例,但webenvironment不是true,也就是說存在org.springframework.web.context.configurablewebenvironmen但不存在javax.servlet.servlet的情況,會多執(zhí)行一步environment = converttostandardenvironment(environment)轉換。
之后的printbanner就不細說了,如果你在resource下自定義了一個banner.txt文件,啟動時會輸出內容,否則輸出:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: spring boot :: (v1.4.3.release)
接著創(chuàng)建configurableapplicationcontext實例,方法也很簡單,如果是web環(huán)境就beanutils.instantiate一個org.springframework.boot.context.embedded. annotationconfigembeddedwebapplicationcontext的實例并強轉為configurableapplicationcontext,否則用org.springframework.context.annotation. annotationconfigapplicationcontext的實例強轉。
創(chuàng)建failureanalyzers實例,記錄了configurableapplicationcontext實例中需要關注的部分,如果啟動出錯了可以據(jù)此分析,可以配置,具體的邏輯依然是老方法spring.factories:
不同的analyzer關注不同的部分,自己可以擴展配置,最后preparefailureanalyzers方法給所有analyzer實例setbeanfactory(context.getbeanfactory()),一旦啟動過程進入catch,被注冊的analyzer實例的analyze方法就會被觸發(fā)執(zhí)行,分析結果會被loggedexceptions.add(exception)加入到拋出的異常中:
1
2
3
4
5
6
7
8
9
|
private failureanalysis analyze(throwable failure, list<failureanalyzer> analyzers) { for (failureanalyzer analyzer : analyzers) { failureanalysis analysis = analyzer.analyze(failure); if (analysis != null ) { return analysis; } } return null ; } |
例如:nosuchbeandefinitionfailureanalyzer
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
@override protected failureanalysis analyze(throwable rootfailure, nosuchbeandefinitionexception cause, string description) { if (cause.getnumberofbeansfound() != 0 ) { return null ; } list<autoconfigurationresult> autoconfigurationresults = getautoconfigurationresults( cause); stringbuilder message = new stringbuilder(); message.append(string.format( "%s required %s that could not be found.%n" , description == null ? "a component" : description, getbeandescription(cause))); if (!autoconfigurationresults.isempty()) { for (autoconfigurationresult provider : autoconfigurationresults) { message.append(string.format( "\t- %s%n" , provider)); } } string action = string.format( "consider %s %s in your configuration." , (!autoconfigurationresults.isempty() ? "revisiting the conditions above or defining" : "defining" ), getbeandescription(cause)); return new failureanalysis(message.tostring(), action, cause); } |
preparecontext方法中postprocessapplicationcontext會在this.beannamegenerator存在的情況下加載自定義命名策略,然后在this.resourceloader存在的情況下為context設置resourceloader和classloader。applyinitializers方法調用之前加載的initializer的實例并執(zhí)行其initialize方法,例如加載環(huán)境變量信息、注冊embeddedservletcontainerinitializedevent的監(jiān)聽、注冊cachingmetadatareaderfactorypostprocessor等。listeners.contextprepared(context)由于eventpublishingrunlistener的contextprepared是空的,先不說了。logstartupinfo部分初始化了logger,然后根據(jù)配置情況打印了啟動或運行以及profile是否配置的日志:
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
|
protected void logstartupinfo( boolean isroot) { if (isroot) { new startupinfologger( this .mainapplicationclass) .logstarting(getapplicationlog()); } } protected log getapplicationlog() { if ( this .mainapplicationclass == null ) { return logger; } return logfactory.getlog( this .mainapplicationclass); } public void logstarting(log log) { assert .notnull(log, "log must not be null" ); if (log.isinfoenabled()) { log.info(getstartupmessage()); } if (log.isdebugenabled()) { log.debug(getrunningmessage()); } } protected void logstartupprofileinfo(configurableapplicationcontext context) { log log = getapplicationlog(); if (log.isinfoenabled()) { string[] activeprofiles = context.getenvironment().getactiveprofiles(); if (objectutils.isempty(activeprofiles)) { string[] defaultprofiles = context.getenvironment().getdefaultprofiles(); log.info( "no active profile set, falling back to default profiles: " + stringutils.arraytocommadelimitedstring(defaultprofiles)); } else { log.info( "the following profiles are active: " + stringutils.arraytocommadelimitedstring(activeprofiles)); } } } |
接著preparecontext中注冊啟動參數(shù)(applicationarguments)到bean工廠,包括logger、commandlineargs等。然后加載bean定義的來源并根據(jù)其中配置加載bean,這里的sources就是初始化啟動類時傳進來的那個sources:
1
2
3
4
5
6
7
8
9
10
11
12
|
beandefinitionloader(beandefinitionregistry registry, object... sources) { assert .notnull(registry, "registry must not be null" ); assert .notempty(sources, "sources must not be empty" ); this .sources = sources; this .annotatedreader = new annotatedbeandefinitionreader(registry); this .xmlreader = new xmlbeandefinitionreader(registry); if (isgroovypresent()) { this .groovyreader = new groovybeandefinitionreader(registry); } this .scanner = new classpathbeandefinitionscanner(registry); this .scanner.addexcludefilter( new classexcludefilter(sources)); } |
注意下面的sources是待加載的,和上面這段不是同一個:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
public int load() { int count = 0 ; for (object source : this .sources) { count += load(source); } return count; } private int load(object source) { assert .notnull(source, "source must not be null" ); if (source instanceof class <?>) { return load(( class <?>) source); } if (source instanceof resource) { return load((resource) source); } if (source instanceof package ) { return load(( package ) source); } if (source instanceof charsequence) { return load((charsequence) source); } throw new illegalargumentexception( "invalid source type " + source.getclass()); } |
類型不同加載過程不同,其中class<?>加載過程大概是通過beandefinitionloader調用annotatedbeandefinitionreader的registerbean方法:
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
|
public void registerbean( class <?> annotatedclass, string name, class <? extends annotation>... qualifiers) { annotatedgenericbeandefinition abd = new annotatedgenericbeandefinition(annotatedclass); if ( this .conditionevaluator.shouldskip(abd.getmetadata())) { return ; } scopemetadata scopemetadata = this .scopemetadataresolver.resolvescopemetadata(abd); abd.setscope(scopemetadata.getscopename()); string beanname = (name != null ? name : this .beannamegenerator.generatebeanname(abd, this .registry)); annotationconfigutils.processcommondefinitionannotations(abd); if (qualifiers != null ) { for ( class <? extends annotation> qualifier : qualifiers) { if (primary. class == qualifier) { abd.setprimary( true ); } else if (lazy. class == qualifier) { abd.setlazyinit( true ); } else { abd.addqualifier( new autowirecandidatequalifier(qualifier)); } } } beandefinitionholder definitionholder = new beandefinitionholder(abd, beanname); definitionholder = annotationconfigutils.applyscopedproxymode(scopemetadata, definitionholder, this .registry); beandefinitionreaderutils.registerbeandefinition(definitionholder, this .registry); } |
可以看到有生成方法名,設置默認注入的實例、延遲以及過濾等等,注入的過程包括初始化一些信息,如構造、內部類、注解等:
1
2
3
4
5
6
7
8
9
|
protected abstractbeandefinition(constructorargumentvalues cargs, mutablepropertyvalues pvs) { setconstructorargumentvalues(cargs); setpropertyvalues(pvs); } public standardannotationmetadata( class <?> introspectedclass, boolean nestedannotationsasmap) { super (introspectedclass); this .annotations = introspectedclass.getannotations(); this .nestedannotationsasmap = nestedannotationsasmap; } |
其他三種比如有的有輸入流什么的就不細總結了,這部分介紹spring ioc的相關文章應該不少。
preparecontext方法最后listeners.contextloaded(context),加載監(jiān)聽器到context并廣播applicationpreparedevent事件。
咱最近用的github:https://github.com/saaavsaaa
以上所述是小編給大家介紹的spring boot啟動過程完全解析(一),希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對服務器之家網(wǎng)站的支持!
原文鏈接:http://www.cnblogs.com/saaav/p/6259405.html