上篇給大家介紹了spring boot啟動過程完全解析(一),大家可以點擊參考下
該說refreshcontext(context)了,首先是判斷context是否是abstractapplicationcontext派生類的實例,之后調用了強轉為abstractapplicationcontext類型并調用它的refresh方法。由于annotationconfigembeddedwebapplicationcontext繼承自embeddedwebapplicationcontext,所以會執行embeddedwebapplicationcontext的refresh方法,繼而執行其中的super.refresh。這個refresh也就是abstractapplicationcontext的refresh方法了,它內部是一個synchronized鎖全局的代碼塊,同樣的加鎖方法還有這個類里的close和registershutdownhook方法。
同步代碼塊中第一個方法preparerefresh,首先會執行annotationconfigembeddedwebapplicationcontext的preparerefresh方法:
1
2
3
4
|
protected void preparerefresh() { this .scanner.clearcache(); super .preparerefresh(); } |
這個super也就是abstractapplicationcontext,它的preparerefresh方法邏輯是:生成啟動時間;設置closed狀態為false;active狀態為true;initpropertysources方法主要是調用了abstractenvironment的getpropertysources方法獲取了之前springapplication的prepareenvironment方法中getorcreateenvironment方法準備的各種環境變量及配置并用于初始化servletpropertysources。具體的servletcontextinitparams這些是在環境對象初始化時由各集成級別environment的customizepropertysources方法中初始化的。
接著的getenvironment().validaterequiredproperties()方法實際執行了abstractenvironment中的this.propertyresolver.validaterequiredproperties(),主要是驗證了被占位的key如果是required的值不能為null。preparerefresh的最后是初始化this.earlyapplicationevents = new linkedhashset<applicationevent>()。*****
只夠是獲取beanfactory實例的方法obtainfreshbeanfactory(),首先在refreshbeanfactory方法中用原子布爾類型判斷是否刷新過,beanfactory實例是在createapplicationcontext創建context實例時被創建的,如果沒有刷新則設置一個用于序列化的id,id是contextidapplicationcontextinitializer初始化設置的(如未配置該初始化器,是有一個默認objectutils.identitytostring(this)生成的),這個id的生成規則是spring.config.name截取的+":"+server.port的占位截取。設置序列化id時,同時保存了一個id和弱引用defaultlistablebeanfactory實例映射。
得到了beanfactory后就是preparebeanfactory(beanfactory)了,邏輯是注冊了beanclassloader用于注入的bean實例的創建;standardbeanexpressionresolver用于el表達式,比如配置文件或者@value("#{...}")等使用;用resourceeditorregistrar注冊屬性轉換器,比如xml配置的bean屬性都是用的字符串配置的要轉成真正的屬性類型;addbeanpostprocessor(new applicationcontextawareprocessor(this))注冊applicationcontextawareprocessor,它的invokeawareinterfaces方法會對實現指定接口的bean調用指定的set方法;ignoredependencyinterface忽略對這些接口的自動裝配,比如aware這些是要做獨立處理的,不適合通用的方法;然后是有幾個類型直接手動注冊,比如beanfactory,這個很好理解;接著注冊一個后置處理器applicationlistenerdetector的實例,addbeanpostprocessor注冊的會按照注冊先后順序執行;這個方法的最后判斷了特定的4個bean名字,如果存在會做相應注冊,包括loadtimeweaver、environment、systemproperties和systemenvironment。補充一點,在最開始創建實例的時候還執行過ignoredependencyinterface(beannameaware.class);ignoredependencyinterface(beanfactoryaware.class);ignoredependencyinterface(beanclassloaderaware.class)。
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
|
protected void preparebeanfactory(configurablelistablebeanfactory beanfactory) { // tell the internal bean factory to use the context's class loader etc. beanfactory.setbeanclassloader(getclassloader()); beanfactory.setbeanexpressionresolver( new standardbeanexpressionresolver(beanfactory.getbeanclassloader())); beanfactory.addpropertyeditorregistrar( new resourceeditorregistrar( this , getenvironment())); // configure the bean factory with context callbacks. beanfactory.addbeanpostprocessor( new applicationcontextawareprocessor( this )); beanfactory.ignoredependencyinterface(environmentaware. class ); beanfactory.ignoredependencyinterface(embeddedvalueresolveraware. class ); beanfactory.ignoredependencyinterface(resourceloaderaware. class ); beanfactory.ignoredependencyinterface(applicationeventpublisheraware. class ); beanfactory.ignoredependencyinterface(messagesourceaware. class ); beanfactory.ignoredependencyinterface(applicationcontextaware. class ); // beanfactory interface not registered as resolvable type in a plain factory. // messagesource registered (and found for autowiring) as a bean. beanfactory.registerresolvabledependency(beanfactory. class , beanfactory); beanfactory.registerresolvabledependency(resourceloader. class , this ); beanfactory.registerresolvabledependency(applicationeventpublisher. class , this ); beanfactory.registerresolvabledependency(applicationcontext. class , this ); // register early post-processor for detecting inner beans as applicationlisteners. beanfactory.addbeanpostprocessor( new applicationlistenerdetector( this )); // detect a loadtimeweaver and prepare for weaving, if found. if (beanfactory.containsbean(load_time_weaver_bean_name)) { beanfactory.addbeanpostprocessor( new loadtimeweaverawareprocessor(beanfactory)); // set a temporary classloader for type matching. beanfactory.settempclassloader( new contexttypematchclassloader(beanfactory.getbeanclassloader())); } // register default environment beans. if (!beanfactory.containslocalbean(environment_bean_name)) { beanfactory.registersingleton(environment_bean_name, getenvironment()); } if (!beanfactory.containslocalbean(system_properties_bean_name)) { beanfactory.registersingleton(system_properties_bean_name, getenvironment().getsystemproperties()); } if (!beanfactory.containslocalbean(system_environment_bean_name)) { beanfactory.registersingleton(system_environment_bean_name, getenvironment().getsystemenvironment()); } } |
之后到了refresh的postprocessbeanfactory方法,首先是會走到annotationconfigembeddedwebapplicationcontext的override,需要注意的一點是,這是web環境,如果不是是不會加載這個上下文的,也就不會這么走。它重寫的第一步是先走super也就是embeddedwebapplicationcontext的postprocessbeanfactory,這里又注冊了個后置處理器webapplicationcontextservletcontextawareprocessor的實例,構造參數是this,也就是當前上下文,同時忽略servletcontextaware接口,這個接口是用于獲取servletcontext的,為什么要忽略呢,我猜應該是因為我們既然有了web應用并且內嵌servlet的上下文實例,還要servletcontext的實現就沒什么用了,還有可能出現沖突的問題,有空我再確認下。然后是配置的basepackages和annotatedclasses:
1
2
3
4
5
6
7
8
9
10
|
@override protected void postprocessbeanfactory(configurablelistablebeanfactory beanfactory) { super .postprocessbeanfactory(beanfactory); if ( this .basepackages != null && this .basepackages.length > 0 ) { this .scanner.scan( this .basepackages); } if ( this .annotatedclasses != null && this .annotatedclasses.length > 0 ) { this .reader.register( this .annotatedclasses); } } |
到了invokebeanfactorypostprocessors方法,這個方法就是執行之前注冊的beanfactory后置處理器的地方。代碼一目了然,postprocessorregistrationdelegate的invokebeanfactorypostprocessors中只是有些排序的邏輯,我就不說了:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
/** * instantiate and invoke all registered beanfactorypostprocessor beans, * respecting explicit order if given. * <p>must be called before singleton instantiation. */ protected void invokebeanfactorypostprocessors(configurablelistablebeanfactory beanfactory) { postprocessorregistrationdelegate.invokebeanfactorypostprocessors(beanfactory, getbeanfactorypostprocessors()); // detect a loadtimeweaver and prepare for weaving, if found in the meantime // (e.g. through an @bean method registered by configurationclasspostprocessor) if (beanfactory.gettempclassloader() == null && beanfactory.containsbean(load_time_weaver_bean_name)) { beanfactory.addbeanpostprocessor( new loadtimeweaverawareprocessor(beanfactory)); beanfactory.settempclassloader( new contexttypematchclassloader(beanfactory.getbeanclassloader())); } } |
beanfactory后置處理器執行之后是注冊bean的后置處理器方法registerbeanpostprocessors。例如new beanpostprocessorchecker(beanfactory, beanprocessortargetcount)會在bean沒有合適的后置處理器時記條info級日志。applicationlistenerdetector也注冊了一個。
initmessagesource這個方法在我這沒什么用,都說是國際化的,隨便百度一下一堆一堆的,而且其實嚴格來說這篇多數不屬于spring boot的部分,這方法我就不細寫了。
initapplicationeventmulticaster方法主要也就是初始化并注冊applicationeventmulticaster的這兩句代碼:
1
2
|
this .applicationeventmulticaster = new simpleapplicationeventmulticaster(beanfactory); beanfactory.registersingleton(application_event_multicaster_bean_name, this .applicationeventmulticaster); |
onrefresh也是根據環境不同加載的上下文不同而不同的,用于支持子類擴展出來的上下文特定的邏輯的。embeddedwebapplicationcontext的onrefresh首先依然是super.onrefresh,邏輯就是初始化了主題;
createembeddedservletcontainer方法名我就不翻譯了,一般情況下是使用getbeanfactory .getbeannamesfortype方法找到embeddedservletcontainerfactory類型的實例,這也就是我之前那個問題解決過程中,為什么只要排除掉tomcat引用,引入jetty引用就可以自動換成jetty的原因。創建容器的過程中初始化方法selfinitialize注冊了filter和mappingforurlpatterns等,代碼在abstractfilterregistrationbean等onstartup,這里就不細說了,如果能抽出時間說說之前查問題的時候查的容器代碼再說。然后初始化propertysources,servletcontextinitparams和servletconfiginitparams:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public static void initservletpropertysources( mutablepropertysources propertysources, servletcontext servletcontext, servletconfig servletconfig) { assert .notnull(propertysources, "'propertysources' must not be null" ); if (servletcontext != null && propertysources.contains(standardservletenvironment.servlet_context_property_source_name) && propertysources.get(standardservletenvironment.servlet_context_property_source_name) instanceof stubpropertysource) { propertysources.replace(standardservletenvironment.servlet_context_property_source_name, new servletcontextpropertysource(standardservletenvironment.servlet_context_property_source_name, servletcontext)); } if (servletconfig != null && propertysources.contains(standardservletenvironment.servlet_config_property_source_name) && propertysources.get(standardservletenvironment.servlet_config_property_source_name) instanceof stubpropertysource) { propertysources.replace(standardservletenvironment.servlet_config_property_source_name, new servletconfigpropertysource(standardservletenvironment.servlet_config_property_source_name, servletconfig)); } } |
registerlisteners首先注冊靜態監聽:
1
2
3
4
5
6
7
|
@override public void addapplicationlistener(applicationlistener<?> listener) { synchronized ( this .retrievalmutex) { this .defaultretriever.applicationlisteners.add(listener); this .retrievercache.clear(); } } |
接著是:
registerlisteners的最后,初始化過的earlyapplicationevents如果有事件,這時候會被發布。
finishbeanfactoryinitialization結束beanfactory的初始化并初始化所有非延遲加載的單例。事實上我們自定義的單例bean都是在這里getbean方法初始化的,所以如果注冊的bean特別多的話,這個過程就是啟動過程中最慢的。初始化開始前先設置configurationfrozen為true,并this.frozenbeandefinitionnames = stringutils.tostringarray ( this. beandefinitionnames )。如果有bean實例實現了smartinitializingsingleton會有后置處理觸發,不包括延遲加載的。例如:org.springframework.context.event. internaleventlistenerprocessor會觸發eventlistenermethodprocessor的aftersingletonsinstantiated方法對所有對象(object的子類)處理。
finishrefresh:refresh的最后一步,發布相應事件。同樣先執行embeddedwebapplicationcontext中對應方法的super(embeddedwebapplicationcontext)的對應方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
/** * finish the refresh of this context, invoking the lifecycleprocessor's * onrefresh() method and publishing the * {@link org.springframework.context.event.contextrefreshedevent}. */ protected void finishrefresh() { // initialize lifecycle processor for this context. initlifecycleprocessor(); // propagate refresh to lifecycle processor first. getlifecycleprocessor().onrefresh(); // publish the final event. publishevent( new contextrefreshedevent( this )); // participate in livebeansview mbean, if active. livebeansview.registerapplicationcontext( this ); } |
初始化生命周期處理器,邏輯是判斷beanfactory中是否已經注冊了lifecycleprocessor,沒有就new一個defaultlifecycleprocessor并setbeanfactory(beanfactory),然后將它賦值給私有lifecycleprocessor類型的this變量。然后執行生命周期處理器的onrefresh,其中先startbeans,被start的beans是通過getbeannamesfortype(lifecycle.class, false, false)從beanfactory中取出來的,例如endpointmbeanexporter和lifecycleprocessor,會去調用bean的start方法,endpointmbeanexporter的start中執行 locateandregisterendpoints方法并設置running屬性為true,這個過程加了reentrantlock鎖。bean都啟動完會設置處理器的running為true。刷新完會發布contextrefreshedevent事件,這個事件除了都有的記錄時間還執行了configurationpropertiesbindingpostprocessor的freelocalvalidator方法,我這的邏輯是實際上執行了validatorfactoryimpl的close方法。這個邏輯的最后會檢查一個配置spring.livebeansview.mbeandomain是否存在,有就會創建一個mbeanserver:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
static void registerapplicationcontext(configurableapplicationcontext applicationcontext) { string mbeandomain = applicationcontext.getenvironment().getproperty(mbean_domain_property_name); if (mbeandomain != null ) { synchronized (applicationcontexts) { if (applicationcontexts.isempty()) { try { mbeanserver server = managementfactory.getplatformmbeanserver(); applicationname = applicationcontext.getapplicationname(); server.registermbean( new livebeansview(), new objectname(mbeandomain, mbean_application_key, applicationname)); } catch (throwable ex) { throw new applicationcontextexception( "failed to register livebeansview mbean" , ex); } } applicationcontexts.add(applicationcontext); } } } |
finishrefresh最后會啟動前面創建的內嵌容器,并發布embeddedservletcontainerinitializedevent事件,啟動這一部分算是容器的邏輯了,有機會整理容器邏輯再細寫,我這里是tomcat的:
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
|
@override public void start() throws embeddedservletcontainerexception { try { addpreviouslyremovedconnectors(); connector connector = this .tomcat.getconnector(); if (connector != null && this .autostart) { startconnector(connector); } checkthatconnectorshavestarted(); tomcatembeddedservletcontainer.logger .info( "tomcat started on port(s): " + getportsdescription( true )); } catch (connectorstartfailedexception ex) { stopsilently(); throw ex; } catch (exception ex) { throw new embeddedservletcontainerexception( "unable to start embedded tomcat servlet container" , ex); } finally { context context = findcontext(); contextbindings.unbindclassloader(context, getnamingtoken(context), getclass().getclassloader()); } } |
然后是resetcommoncaches:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
/** * reset spring's common core caches, in particular the {@link reflectionutils}, * {@link resolvabletype} and {@link cachedintrospectionresults} caches. * @since 4.2 * @see reflectionutils#clearcache() * @see resolvabletype#clearcache() * @see cachedintrospectionresults#clearclassloader(classloader) */ protected void resetcommoncaches() { reflectionutils.clearcache(); resolvabletype.clearcache(); cachedintrospectionresults.clearclassloader(getclassloader()); } |
refreshcontext的最后是注冊shutdown的鉤子:
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
|
if ( this .registershutdownhook) { try { context.registershutdownhook(); } catch (accesscontrolexception ex) { // not allowed in some environments. } } /** * register a shutdown hook with the jvm runtime, closing this context * on jvm shutdown unless it has already been closed at that time. * <p>delegates to {@code doclose()} for the actual closing procedure. * @see runtime#addshutdownhook * @see #close() * @see #doclose() */ @override public void registershutdownhook() { if ( this .shutdownhook == null ) { // no shutdown hook registered yet. this .shutdownhook = new thread() { @override public void run() { synchronized (startupshutdownmonitor) { doclose(); } } }; runtime.getruntime().addshutdownhook( this .shutdownhook); } } |
咱最近用的github:https://github.com/saaavsaaa
以上所述是小編給大家介紹的spring boot啟動過程完全解析(二),希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對服務器之家網站的支持!
原文鏈接:http://www.cnblogs.com/saaav/p/6292524.html