咱們學習技術的時代遇上了最好的時代,跳過了不少前人常常踩的坑,前人在踩坑的過程當中總結了不少經驗和教訓,而新時代的咱們只是繼承了前人的經驗和教訓,而忽略了這些採坑的過程,以致於咱們面對不少新技術都不知道他是什麼?他爲何存在?他爲何能夠解決這個問題?更不知道如何掌握其原理!雲裏霧裏一頭霧水!數據庫
交流羣的不少小夥伴,經常私聊我讓我推薦一下學習SSM框架的視頻和資料,我首先會打開他的資料卡看一下他的年齡,若是超過了他這個年齡應有的水平,我就會問他JSP+Servlet學了嗎?不少小夥伴的回答是簡單的學了一下,而後,我會給他一個關於JSP+Servlet的實戰項目,順便給他們找一些SSM的項目,而且建議他們首先看這個JSP+Servlet的實戰項目。編程
更有甚者,學了基礎以後就開始學習Spring Boot的,當問他們Spring Boot是什麼的時候,大體也能夠回答出來「約定大於配置」,「用起來很簡單」,可是在細究其原理,也是吱吱嗚嗚,只知其一;不知其二!若是咱們沒有經歷過Spring最開始繁瑣的配置、而後一步步精簡,根本體會不到爲何會有Spring Boot這個東西!後端
不先學習常見的設計模式直接看Spring、MyBatis等源碼,簡直就是一個找虐的過程!不掌握Servlet原理、基本的Tomcat容器技術上來就看Spring MVC源碼一樣也是一個打擊自信心的好地方!設計模式
學習是一個按部就班的過程,不能急於求成,但也不能過度鑽牛角尖!不能再一個技術上停滯不前,也不能如"走馬觀花"通常寥寥掠過!一樣,若是你尚未掌握好Servlet和簡單的設計模式我建議你先去查閱相關的資料進行系統的學習。瀏覽器
我也相信不少圖書或視頻等資料都忽略了講述爲何會有Spring的過程,要麼是簡單歸納而且痛斥EJB的各類弊端,要麼就是隻字不提,這是一種對讀者很不負責任的表現,知史能夠明鑑!所以,在進一步學習Spring核心原理以前,咱們有必要介紹一下整個Web發展的簡單歷史,一步步引出爲何會有Spring!bash
老一輩的軟件開發人員通常經歷了從Model1到Model2,而後到後來的三層模型,最後到如今的Spring Boot。若是從Model1到Model2提及到咱們如今使用的Spring Boot爲整個時間軸的話,大體能夠分爲4個階段:微信
(1)初級階段:使用Model1/Model2/三層模模型進行開發;網絡
(2)中級階段:使用EJB進行分佈式應用開發,忍受重量級框架帶來的種種麻煩;多線程
(3)高級階段:使用Spring春天帶給咱們的美好,可是還要忍受不少繁瑣的配置;架構
(4)骨灰級階段:使用Spring Boot,暢享「預約大於配置」帶給咱們的種種樂趣!
一、Model1開發模式:
Model1的開發模式是:JSP+JavaBean的模式,它的核心是Jsp頁面,在這個頁面中,Jsp頁面負責整合頁面和JavaBean(業務邏輯),並且渲染頁面,它的基本流程以下:
相信不少小夥伴在剛學習Web的時候,確定使用到了Model1開發模式,也就是咱們的業務代碼、持久化代碼直接寫在Jsp頁面裏邊,使用Jsp直接處理Web瀏覽器的請求,並使用JavaBean處理業務邏輯。
利用咱們如今熟悉的MVC模型的思想去看,雖然編寫代碼十分容易,但Jsp混淆了MVC模型中的視圖層和控制層,高度耦合的結果是Jsp代碼十分複雜,後期維護困難!
二、Model2開發模式:
Model1雖然在必定程度上解耦了,但JSP依舊即要負責頁面控制,又要負責邏輯處理,職責不單一!此時Model2應運而生,使得各個部分各司其職,Model2是基於MVC模式的。
Model2的開發模式是:Jsp+Servlet+JavaBean的模式,它和Model1不一樣的是,增長了Servlet,將調用頁面數據,調用業務邏輯等工做放到了Servlet中處理,從而減輕了Jsp的工做負擔!它的基本流程以下:
Model2開發模式將Servlet的概念引入架構體系中,使用它來分配視圖層Jsp的顯示頁面,同時調用模型層的JavaBean來控制業務邏輯。
三、Model1和Model2的區別:
Model1:簡單,適合小型項目的開發,可是Jsp的職責過於繁重,職責分工不明確。在後期的維護工做中,必將爲此付出代價!
Model2:相對於Model1來講,職責分工更爲明確,在Model1的基礎上,抽取了Servlet層,體現了一個分層的思想,適合大型的項目開發!(當時的評判標準是適合大型項目開發的,如今看起來已通過時了!)
Model2看起來已經盡善盡美了,儘管如此,他還不能稱之爲一個比較完善的MVC設計模式!
四、Model1和Model2與三層的對比:
在Model2中,咱們將Servlet抽取出單獨的一層,和Jsp協做完成用戶數據交互的工做,也就是表示層。那麼做爲三層結構來講,又作了什麼樣的改進呢?三層則是在此基礎上,將JavaBean再一次進行分割:業務邏輯、數據持久化,三層以下:
(1)表示層,JSP/Servlet; (2)業務邏輯層:業務規則; (3)持久化層:主要包裝持久化的邏輯 ;
各個的耦合性以下圖:
Model一、Model二、三層是在解耦的基礎上一步步進化而來,經過解耦咱們能夠進行進一步的抽象,以應對現實需求的變更。
這一小節彷佛有點應付,對於中級階段,由於我沒有用過EJB,在這裏不敢妄加評論,以避免誤導你們。可是相信每一位接觸過Spring的小夥伴,都應該知道Rod Johnson在2002年編寫的《Expert One-to-One J2EE Design and Development》一書,Rod 在本書中對J2EE正統框架臃腫、低效、脫離現實的種種學院派作法提出了質疑,並以此書爲指導思想,編寫了interface21框架,也就是後來的Spring。
對於高級階段和骨灰級階段是咱們後期一系列文章的重點,本篇只做爲一個階段劃分,不作過多的解釋,所以讓咱們從新回到Web發展的初級階段。
對EJB有興趣的能夠參考文章:www.uml.org.cn/j2ee/200911…
經歷過初級階段的小夥伴確定看得懂下邊的一個項目結構,一個簡單的MVC三層結構,使用JSP+Servlet+MySQL+JDBC技術,面向接口編程:
一、面向接口編程的實例化對象
以用戶管理模塊爲例,有一個UserDao接口,有一個接口的實現類UserDaoImpl,以下:
因爲是面向接口編程,所以咱們在每次使用UserDao的時候,都要進行實例化一次,實例化代碼以下:
UserDao userDao = new UserDaoImpl();
複製代碼
咱們在每次使用UserDao的時候都須要進行實例化,固然不只僅有UserDao須要進行實例化,還有不少須要進行實例化的,舉例以下:
能夠看出,每個方法中都須要進行實例化咱們須要用到的接口的實現類,這就會存在大量的實例化對象,而且他們的生命週期可能就是從方法的調用開始到方法的調用結束爲止,加大了GC回收的壓力!
二、使用單例模式的一次改進
瞭解設計模式的可能會想到使用單例模式的方式來解決這個問題,以此來避免大量重複的建立對象,可是咱們還要考慮到衆多的這種對象的建立都須要改爲單例模式的話,是一個耗時耗力的操做。
對於這個系統來講,若是都把這種面向接口的對象實現類轉換爲單例模式的方式的話,大概也要寫十幾個或者上百個這種單例模式代碼,而對於一個單例模式的寫法來講,每每是模板式的代碼,以靜態內部類的方式實現單例模式以下:
能夠看出,這種方式有兩個問題:
(1)業務代碼與單例模式的模板代碼放在一個類裏,耦合性較高; (2)大量重複的單例模式的模板代碼;
從上述能夠看出,使用的單例模式雖然從性能上有所提升,可是卻加劇了咱們的開發成本。所以只會小規模的使用,例如咱們操做JDBC的Utils對象等。
三、咱們開發中遇到的痛點
從上述代碼的演進過程咱們能夠看得出來,咱們即須要一個單例的對象來避免系統中大量重複對象的建立和銷燬,又不想由於使用單例模式形成大量重複無用的模板代碼和代碼的耦合!
(忽然想到一個段子,想和你們分享一下:產品經理在給甲方彙報方案的時候說了兩種方案:一種是實用的,一種是美觀的,問甲方但願選擇哪種?甲方說:有沒有即實用又美觀的!)
四、咱們還能怎麼作
做爲學院派的書生來講,咱們可能會聯想到「數據庫鏈接池」,咱們在獲取數據庫鏈接的時候會從這個池子中拿到一個鏈接的,假設這個數據庫鏈接池很特殊,有且只能有N個數據庫鏈接,而且每個鏈接對象都不一樣(假設),那麼這個不就至關於每個鏈接都是單例的了嗎?既能夠避免大量對象的建立,也能夠實現不會出現大量重複性的模板代碼。
所以,這裏應該有一個大膽的想法,咱們是否能夠創建一個池子,將咱們的接口實現類對象放入到這個池子中,咱們在使用的時候直接從這個池子裏邊取就好了!
五、這個池子
若是咱們要建立這個池子,首先要肯定須要把哪些對象放進這個池子,經過怎樣的方式放進去,放進去以後如何進行管理,如何進行獲取,池子中的每個對象的生命週期是怎麼樣的等等這些東西都是咱們須要考慮到的!
六、恭喜你
若是你已經瞭解了上述Web演進的過程,以及咱們想要建立的這個池子,那麼恭喜你!你已經打開了Spring核心原理的大門了!
上述咱們想要建立的池子其實就是Spring容器的雛形,將接口實現類的對象放進池子進行管理的過程其實也是Spring IOC依賴注入、控制反轉的雛形!
Spring的依賴注入/控制反轉就是從咱們的配置文件或註解中的獲得咱們須要進行注入到Spring容器的實現類的信息,Spring IOC經過這些配置信息建立一個個單例的對象並放入Spring容器中,Spring容器能夠看作是一個集合保存着咱們的這些對象。
七、小總結
上文中主要從一個切入點探討了一下爲何有Spring,以及介紹了一下Spring IOC和Spring容器的基本雛形概念,固然還能夠從其餘方面進行切入。這裏沒有進一步探討AOP的概念,對於新入門的小夥伴來講,這個確實有必要討論一下,也決定在後續文章中由淺入深的探討一下,而對於老手來講,其實我上邊寫的基本上是浪費你們時間的!
從歷史的角度來講,不一樣時期的大革命在爆發以前,都會有一個蓄謀已久的「導火線」!Spring的出現,一樣順應了歷史發展潮流,正是因爲那個時期J2EE開發標準的種種弊端造就了Spring的出現!即便不是Spring,一樣也會有其餘相似的產品出現,只不過歷史選擇了Spring,Spring順應了歷史!沒有切膚之痛,是不會體會到Spring帶給咱們的樂趣與快感!
一樣的,每一個時代都會有每個時代的問題,Spring也是!正如十年前咱們的計算機可能帶不動一款遊戲,今天咱們的計算機也有可能帶不動一款現在的遊戲,一樣十年後的計算機也會有一款他帶不動的遊戲出現!以一種發展的眼光去看Spring,就能夠很好的理解Spring Boot是以一種什麼樣的角色出如今咱們的面前了!
時代選擇了Spring,一樣Spring也被這個時代所選擇着!你我只有不停的進步,不停地學習才能跟上這個時代!