激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|編程技術(shù)|正則表達式|

服務(wù)器之家 - 編程語言 - JAVA教程 - Spring Boot啟動過程完全解析(二)

Spring Boot啟動過程完全解析(二)

2020-09-16 14:21draculav JAVA教程

這篇文章主要介紹了Spring Boot啟動過程完全解析(二),需要的朋友可以參考下

上篇給大家介紹了spring boot啟動過程完全解析(一),大家可以點擊參考下

  該說refreshcontext(context)了,首先是判斷context是否是abstractapplicationcontext派生類的實例,之后調(diào)用了強轉(zhuǎn)為abstractapplicationcontext類型并調(diào)用它的refresh方法。由于annotationconfigembeddedwebapplicationcontext繼承自embeddedwebapplicationcontext,所以會執(zhí)行embeddedwebapplicationcontext的refresh方法,繼而執(zhí)行其中的super.refresh。這個refresh也就是abstractapplicationcontext的refresh方法了,它內(nèi)部是一個synchronized鎖全局的代碼塊,同樣的加鎖方法還有這個類里的close和registershutdownhook方法。

  同步代碼塊中第一個方法preparerefresh,首先會執(zhí)行annotationconfigembeddedwebapplicationcontext的preparerefresh方法:

?
1
2
3
4
protected void preparerefresh() {
 this.scanner.clearcache();
 super.preparerefresh();
}

  這個super也就是abstractapplicationcontext,它的preparerefresh方法邏輯是:生成啟動時間;設(shè)置closed狀態(tài)為false;active狀態(tài)為true;initpropertysources方法主要是調(diào)用了abstractenvironment的getpropertysources方法獲取了之前springapplication的prepareenvironment方法中g(shù)etorcreateenvironment方法準(zhǔn)備的各種環(huán)境變量及配置并用于初始化servletpropertysources。具體的servletcontextinitparams這些是在環(huán)境對象初始化時由各集成級別environment的customizepropertysources方法中初始化的。

Spring Boot啟動過程完全解析(二)

   接著的getenvironment().validaterequiredproperties()方法實際執(zhí)行了abstractenvironment中的this.propertyresolver.validaterequiredproperties(),主要是驗證了被占位的key如果是required的值不能為null。preparerefresh的最后是初始化this.earlyapplicationevents = new linkedhashset<applicationevent>()。*****

  只夠是獲取beanfactory實例的方法obtainfreshbeanfactory(),首先在refreshbeanfactory方法中用原子布爾類型判斷是否刷新過,beanfactory實例是在createapplicationcontext創(chuàng)建context實例時被創(chuàng)建的,如果沒有刷新則設(shè)置一個用于序列化的id,id是contextidapplicationcontextinitializer初始化設(shè)置的(如未配置該初始化器,是有一個默認(rèn)objectutils.identitytostring(this)生成的),這個id的生成規(guī)則是spring.config.name截取的+":"+server.port的占位截取。設(shè)置序列化id時,同時保存了一個id和弱引用defaultlistablebeanfactory實例映射。

  得到了beanfactory后就是preparebeanfactory(beanfactory)了,邏輯是注冊了beanclassloader用于注入的bean實例的創(chuàng)建;standardbeanexpressionresolver用于el表達式,比如配置文件或者@value("#{...}")等使用;用resourceeditorregistrar注冊屬性轉(zhuǎn)換器,比如xml配置的bean屬性都是用的字符串配置的要轉(zhuǎn)成真正的屬性類型;addbeanpostprocessor(new applicationcontextawareprocessor(this))注冊applicationcontextawareprocessor,它的invokeawareinterfaces方法會對實現(xiàn)指定接口的bean調(diào)用指定的set方法;ignoredependencyinterface忽略對這些接口的自動裝配,比如aware這些是要做獨立處理的,不適合通用的方法;然后是有幾個類型直接手動注冊,比如beanfactory,這個很好理解;接著注冊一個后置處理器applicationlistenerdetector的實例,addbeanpostprocessor注冊的會按照注冊先后順序執(zhí)行;這個方法的最后判斷了特定的4個bean名字,如果存在會做相應(yīng)注冊,包括loadtimeweaver、environment、systemproperties和systemenvironment。補充一點,在最開始創(chuàng)建實例的時候還執(zhí)行過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環(huán)境,如果不是是不會加載這個上下文的,也就不會這么走。它重寫的第一步是先走super也就是embeddedwebapplicationcontext的postprocessbeanfactory,這里又注冊了個后置處理器webapplicationcontextservletcontextawareprocessor的實例,構(gòu)造參數(shù)是this,也就是當(dāng)前上下文,同時忽略servletcontextaware接口,這個接口是用于獲取servletcontext的,為什么要忽略呢,我猜應(yīng)該是因為我們既然有了web應(yīng)用并且內(nèi)嵌servlet的上下文實例,還要servletcontext的實現(xiàn)就沒什么用了,還有可能出現(xiàn)沖突的問題,有空我再確認(rèn)下。然后是配置的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方法,這個方法就是執(zhí)行之前注冊的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后置處理器執(zhí)行之后是注冊bean的后置處理器方法registerbeanpostprocessors。例如new beanpostprocessorchecker(beanfactory, beanprocessortargetcount)會在bean沒有合適的后置處理器時記條info級日志。applicationlistenerdetector也注冊了一個。

  initmessagesource這個方法在我這沒什么用,都說是國際化的,隨便百度一下一堆一堆的,而且其實嚴(yán)格來說這篇多數(shù)不屬于spring boot的部分,這方法我就不細(xì)寫了。

  initapplicationeventmulticaster方法主要也就是初始化并注冊applicationeventmulticaster的這兩句代碼:          

?
1
2
this.applicationeventmulticaster = new simpleapplicationeventmulticaster(beanfactory);
   beanfactory.registersingleton(application_event_multicaster_bean_name, this.applicationeventmulticaster);

   onrefresh也是根據(jù)環(huán)境不同加載的上下文不同而不同的,用于支持子類擴展出來的上下文特定的邏輯的。embeddedwebapplicationcontext的onrefresh首先依然是super.onrefresh,邏輯就是初始化了主題;

createembeddedservletcontainer方法名我就不翻譯了,一般情況下是使用getbeanfactory .getbeannamesfortype方法找到embeddedservletcontainerfactory類型的實例,這也就是我之前那個問題解決過程中,為什么只要排除掉tomcat引用,引入jetty引用就可以自動換成jetty的原因。創(chuàng)建容器的過程中初始化方法selfinitialize注冊了filter和mappingforurlpatterns等,代碼在abstractfilterregistrationbean等onstartup,這里就不細(xì)說了,如果能抽出時間說說之前查問題的時候查的容器代碼再說。然后初始化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首先注冊靜態(tài)監(jiān)聽:

?
1
2
3
4
5
6
7
@override
public void addapplicationlistener(applicationlistener<?> listener) {
 synchronized (this.retrievalmutex) {
  this.defaultretriever.applicationlisteners.add(listener);
  this.retrievercache.clear();
 }
}

Spring Boot啟動過程完全解析(二)

  接著是:

Spring Boot啟動過程完全解析(二) 

 registerlisteners的最后,初始化過的earlyapplicationevents如果有事件,這時候會被發(fā)布。

  finishbeanfactoryinitialization結(jié)束beanfactory的初始化并初始化所有非延遲加載的單例。事實上我們自定義的單例bean都是在這里getbean方法初始化的,所以如果注冊的bean特別多的話,這個過程就是啟動過程中最慢的。初始化開始前先設(shè)置configurationfrozen為true,并this.frozenbeandefinitionnames = stringutils.tostringarray ( this. beandefinitionnames )。如果有bean實例實現(xiàn)了smartinitializingsingleton會有后置處理觸發(fā),不包括延遲加載的。例如:org.springframework.context.event. internaleventlistenerprocessor會觸發(fā)eventlistenermethodprocessor的aftersingletonsinstantiated方法對所有對象(object的子類)處理。

  finishrefresh:refresh的最后一步,發(fā)布相應(yīng)事件。同樣先執(zhí)行embeddedwebapplicationcontext中對應(yīng)方法的super(embeddedwebapplicationcontext)的對應(yīng)方法:

?
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中是否已經(jīng)注冊了lifecycleprocessor,沒有就new一個defaultlifecycleprocessor并setbeanfactory(beanfactory),然后將它賦值給私有l(wèi)ifecycleprocessor類型的this變量。然后執(zhí)行生命周期處理器的onrefresh,其中先startbeans,被start的beans是通過getbeannamesfortype(lifecycle.class, false, false)從beanfactory中取出來的,例如endpointmbeanexporter和lifecycleprocessor,會去調(diào)用bean的start方法,endpointmbeanexporter的start中執(zhí)行 locateandregisterendpoints方法并設(shè)置running屬性為true,這個過程加了reentrantlock鎖。bean都啟動完會設(shè)置處理器的running為true。刷新完會發(fā)布contextrefreshedevent事件,這個事件除了都有的記錄時間還執(zhí)行了configurationpropertiesbindingpostprocessor的freelocalvalidator方法,我這的邏輯是實際上執(zhí)行了validatorfactoryimpl的close方法。這個邏輯的最后會檢查一個配置spring.livebeansview.mbeandomain是否存在,有就會創(chuàng)建一個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最后會啟動前面創(chuàng)建的內(nèi)嵌容器,并發(fā)布embeddedservletcontainerinitializedevent事件,啟動這一部分算是容器的邏輯了,有機會整理容器邏輯再細(xì)寫,我這里是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啟動過程完全解析(二),希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對服務(wù)器之家網(wǎng)站的支持!

原文鏈接:http://www.cnblogs.com/saaav/p/6292524.html

延伸 · 閱讀

精彩推薦
  • JAVA教程解析Java設(shè)計模式編程中命令模式的使用

    解析Java設(shè)計模式編程中命令模式的使用

    這篇文章主要介紹了Java設(shè)計模式編程中命令模式的使用,在一些處理請求響應(yīng)的場合經(jīng)常可以用到命令模式的編程思路,需要的朋友可以參考下 ...

    卡奴達摩4992020-03-31
  • JAVA教程Java設(shè)計模式之Strategy模式

    Java設(shè)計模式之Strategy模式

    Strategy模式即策略模式,就是將一個算法的不同實現(xiàn)封裝成一個個單獨的類,這些類實現(xiàn)同一個接口,使用者直接使用該接口來訪問具體的算法。這個樣子...

    java教程網(wǎng)3652020-05-29
  • JAVA教程淺談java Collection中的排序問題

    淺談java Collection中的排序問題

    下面小編就為大家?guī)硪黄獪\談java Collection中的排序問題。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧 ...

    jingxian2462020-07-12
  • JAVA教程java調(diào)用回調(diào)機制詳解

    java調(diào)用回調(diào)機制詳解

    這篇文章主要介紹了java調(diào)用回調(diào)機制詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小...

    帶妳心菲4182020-08-01
  • JAVA教程Windows下Java+MyBatis框架+MySQL的開發(fā)環(huán)境搭建教程

    Windows下Java+MyBatis框架+MySQL的開發(fā)環(huán)境搭建教程

    這篇文章主要介紹了Windows下Java+MyBatis框架+MySQL的開發(fā)環(huán)境搭建教程,Mybatis對普通SQL語句的支持非常好,需要的朋友可以參考下 ...

    紅燒獅子頭5162020-04-15
  • JAVA教程Springboot web項目打包實現(xiàn)過程解析

    Springboot web項目打包實現(xiàn)過程解析

    這篇文章主要介紹了Springboot web項目打包實現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以...

    Auler4712020-08-31
  • JAVA教程Java基礎(chǔ)之如何學(xué)好Java

    Java基礎(chǔ)之如何學(xué)好Java

    這篇文章已經(jīng)是有數(shù)年“網(wǎng)齡”的老文,不過在今天看來仍然經(jīng)典。如何學(xué)習(xí)java?本篇文章可以說也是面對編程初學(xué)者的一篇指導(dǎo)文章,其中對于如何學(xué)習(xí)...

    hebedich4962019-12-03
  • JAVA教程java書店系統(tǒng)畢業(yè)設(shè)計 用戶模塊(3)

    java書店系統(tǒng)畢業(yè)設(shè)計 用戶模塊(3)

    這篇文章主要介紹了java書店系統(tǒng)畢業(yè)設(shè)計,第三步系統(tǒng)總體設(shè)計,具有一定的參考價值,感興趣的小伙伴們可以參考一下 ...

    xanlv3372020-06-22
主站蜘蛛池模板: 黄色成人在线 | 麻豆国产网站 | 成人性爱视频在线观看 | 成人午夜免费网站 | 亚洲最大av网站 | 1级片在线观看 | 伊人成人免费视频 | 国产成人av在线 | 伊人成人免费视频 | 九九热精品在线视频 | 免费毛片免费看 | 一级做受大片免费视频 | 亚洲欧美日韩中文在线 | 中文字幕一区二区三区四区 | 99欧美精品 | 蜜桃精品视频 | 国产一级αv片免费观看 | 一级成人欧美一区在线观看 | 国产精品久久久久av | 久久久成人免费视频 | 久久精品日产高清版的功能介绍 | 日韩精品一区不卡 | 久久超| 亚洲午夜精品视频 | 红杏网站永久免费视频入口 | 中国美女一级黄色大片 | 欧美18—19sex性hd按摩 | 欧美韩国一区 | av在线高清观看 | 日本精品免费观看 | 日韩视频在线不卡 | 日韩色电影 | 午夜免费一区 | 91网页在线观看 | 黄色特级片黄色特级片 | 久久国产一级片 | 国产一区二区三区色淫影院 | 国产黄色一区二区 | 成年人免费高清视频 | 草草在线视频 | 国产一区二区三区在线视频 |