從一個簡單的例子看spring ApplicationContext上下文隔離

前言html


 

  某天,瀏覽博客園的時候,對首頁上面的一篇文章,標題爲:<<一個普通類就能幹趴你的springboot,你信嗎?>>,文章連接:http://www.javashuo.com/article/p-ntjljexb-do.html 非常感興趣。點進去以後,大體看一下。該篇博文主要說的是在使用spring boot環境下想建立一個名爲Environment的bean,結果發現建立不了,因而不斷調試終於找到了「真理」。java

 

  說真的。這篇博文的內容很是長,主要也是記錄調試過程的「流水帳」。我也只看到了看頭,就迅速拉到文章結尾看一下。比較讓我感到震驚的是,博主提到爲了寫這篇文章花費了很長的時間,從該博主的這篇文章中摘錄了一句話:週五晚上從下班回家一邊一步步斷點一遍寫這篇博客。能夠看出該博主非常用心,調試程序是一件很費心,耗時的事。因而評論區送上一個大大的贊。git

 

  不管是調試仍是閱讀Spring源碼,真的是一件很枯燥的事,很是考驗人的耐心,由其是spring發展了這麼多年,已經造成了生態圈。其代碼也是高度抽象。曾經對spring進行過一番折騰,也是爲了給本身所在小團隊提供一個基於spring封裝的迷你型的小框架。spring

 

  因爲有折騰過spring的經歷,我一眼就看出了問題的所在。根本緣由就在於spring框架自身也有一個Environment類,在應用程序啓動時也會向spring ApplicationContext中注入名爲environment的bean,這樣就會跟博主命名Environment類注入名爲environment的bean產生衝突,由於這兩個bean的名稱同樣。springboot

 

  像BAT這樣級別的公司每每內部或多或少都會有本身的框架,這些框架每每都是由一個相似於基礎架構部的團隊來負責提供的,這樣應用開發小組會基於這個框架快速的開發應用。應用開發者通常只會關心如何使用框架,通常都由專門的人來折騰框架。雖然我沒有在這樣體量的公司裏面工做過,鑑於以前折騰框架經驗來看。框架不管多麼的高大上,有一點是能夠確定的時,框架所使用的資源跟應用所使用的資源確定會進行隔離。架構

 

  爲何會這樣說呢,打個比方。封裝框架的過程當中確定會引入一些第三方的jar,應用在開發的過程也會引用第三方jar,假設框架和應用同時引用一個jar可是兩者的版本不一樣?那可能會致使程序在運行的過程當中搞很差就會出現 java.lang.NoSuchMethodException異常,包衝突了。這時該怎麼辦?若是要框架jar跟應用的jar保持一致,那就不得了,這麼多應用都使用框架進行開發,牽一髮而動全身,風險即大。若是應用使用跟框架同樣的jar,可是這個jar又沒有相應的方法,使用不了。能夠想象同樣,若是框架和應用沒有分別定義自身的類加載器來加載各自的所引用的jar,遇到這樣的場景,解決起來將會很是棘手。app

 

  因此在封裝框架的過程當中,都會對框架所引用的資源跟應用所使用的資源都要進行相應的隔離,若是不隔離的話,框架三天兩天就要改動,對應用開發者來講就會認爲框架很是的不穩定。由其在BAT這樣大致量的公司,開發人員如此衆多,對框架提供技術支撐的人不會不少,框架若是不夠穩定的話,搞很差那麼那些提供技術支撐人員的電話,天天都會響個不停,會處處去解決問題,疲於奔命。就像那篇文章提到定義Envrionment bean時候,應用就會跑起不來,打電話給技術支撐的人,人家一過來搗鼓一番對像你說,老兄,對不住啊,命名衝突了,換這個名字吧。也許從新命個名字了事,可是有些場景這個類的名字改不了,別人的代碼已經固定了要使用這個名字來調用你的bean,更名字別人就調不了。從新命名也許能夠解決問題,但心裏深處,你會對這個框架失去信心了。什麼框架,還限制別人bean的名字。框架

 

  像spring框架就提供了對ApplicationContext進行隔離的功能,能夠輕鬆解決這個問題。在spring官網的文檔中我也沒有看到有提到,不容許應用程序注入一個命名爲Environment的Bean。ide

 

程序出錯spa


我已經將復現一樣錯誤的示例程序代碼上傳到了gitee上面。你們能夠把代碼拉下來,跑起來會出現跟那篇文章中提所到的如出一轍錯誤。 出現這樣錯誤的緣由就是因爲兩個同名的類注入到同一個ApplicationContext中致使的。

示例代碼連接:https://gitee.com/fiercetiger/laboratory/tree/master/applicationcontext-test

致使程序出錯,Bean的源碼以下所示:

1 @Component
2 public class Environment {
3 }

ApplicationContext隔離


  spring ApplicationContext是能夠設置成上下級關係的,查找bean的時候若是在當前的ApplicationContext中沒有找到的話,就會到本身的父級的ApplicationContext中去查找,一直向上回溯,若是找到就會返回。這樣一來的話,咱們能夠這樣處理。讓應用的ApplicationContext做爲spring框架的ApplicationContext的父級。示例程序,我也提交到了gitee上面,能夠把代碼拉下來,跑一下就會發現沒有報錯。

示例代碼連接:https://gitee.com/fiercetiger/laboratory/tree/master/applicationcontext-test2

  關鍵代碼以下所示,定義一個類繼承spring boot的SpringApplication類,覆蓋其createApplicationContext方法,在方法中首先建立應用的ApplicationContext,並注入應用所定義的Environment Bean,隨後將其設置爲spring boot ApplicationContext的父級。爲了更好的演示向上回溯查找Bean的效果,特地定義了一個MyService Bean,這個Bean注入到spring boot ApplicationContext中,而且在MyService Bean中自動注入對應用所定義的Environment Bean的依賴。當應用程序啓動以後,沒有報錯。說明了MyService Bean成功注入了父級的application context中所定義的Environment Bean

 1 import org.springframework.boot.SpringApplication;
 2 import org.springframework.context.ConfigurableApplicationContext;
 3 import org.springframework.context.support.StaticApplicationContext;
 4 
 5 public class MySpringApplication extends SpringApplication {
 6 
 7     public MySpringApplication(Class<?>[] classes){
 8         super(classes);
 9     }
10 
11     @Override
12     protected ConfigurableApplicationContext createApplicationContext(){
13         
14         StaticApplicationContext parent=new StaticApplicationContext();
15         parent.registerBean(Environment.class);
16         parent.refresh();
17         
18         ConfigurableApplicationContext child=super.createApplicationContext();
19         child.setParent(parent);
20 
21         return child;
22     }    
23 }

 結尾


  寫這篇文章的旨在分享有關spring ApplicationContext 一個小小的知識點,Spring所涉及到的知識點很是龐雜。那篇文章的博主爲了弄清楚問題的真相,花費大量的程序來調試程序,還花了大篇幅的文章記錄下來,能夠看到出該博主是一個對技術有着執着追求的人。這篇文章也完整呈現了我在那篇文章評論區中所提到,能夠採用對applicationcontext進行分層來解決這一問題。

相關文章
相關標籤/搜索