第1章 Spring Boot史前簡(jiǎn)述
很久以前呢簸,老一代的系統(tǒng)都是使用EJB技術(shù)開(kāi)發(fā)。到后來(lái)集成 struts, spring, hibernate等框架開(kāi)發(fā)哼凯。在這些開(kāi)發(fā)過(guò)程中锉屈,基本都是開(kāi)發(fā)者自己手動(dòng)拉jar到/lib目錄地下,手動(dòng)管理jar版本之間的依賴露筒,需要編寫(xiě)大量的xml配置。
大約20年前敌卓,程序員們使用“企業(yè)級(jí)Java Bean”(EJB)開(kāi)發(fā)企業(yè)應(yīng)用慎式,需要配置復(fù)雜的XML。
在二十世紀(jì)初期趟径,新興Java技術(shù)——Spring瘪吏,橫空出世。使用極簡(jiǎn)XML和POJO(普通Java對(duì)象)蜗巧,結(jié)合EJB的替代品(如Hibernate)掌眠,Spring在企業(yè)級(jí)Java開(kāi)發(fā)上占據(jù)了絕對(duì)領(lǐng)先地位。
但是幕屹,隨著Spring的不斷發(fā)展蓝丙,當(dāng)初的XML配置逐漸變得復(fù)雜龐大,成了累贅望拖,遭眾多程序員“詬病”渺尘。后來(lái)扒秸,Spring推出了JavaConfig項(xiàng)目昌抠,使用聲明式的注解,大量減少了顯式的XML配置秋忙。
然而盔沫,問(wèn)題到這里医咨,并沒(méi)有結(jié)束。
1.1 J2EE(Java 2 Platform Enterprise Edition)簡(jiǎn)介
J2EE 的四層模型
J2EE使用多層的分布式應(yīng)用模型架诞,如下圖所示:
應(yīng)用邏輯按功能劃分為組件拟淮,各個(gè)應(yīng)用組件根據(jù)他們所在的層分布在不同的機(jī)器上。事實(shí)上侈贷,sun設(shè)計(jì)J2EE的初衷正是為了解決兩層模式(client/server)的弊端惩歉,在傳統(tǒng)模式中等脂,客戶端擔(dān)當(dāng)了過(guò)多的角色而顯得臃腫。
J2EE平臺(tái)由一整套服務(wù)(Services)撑蚌、應(yīng)用程序接口(APIs)和協(xié)議構(gòu)成上遥,它對(duì)開(kāi)發(fā)基于Web的多層應(yīng)用提供了功能支持。
如下是對(duì)J2EE中的13種技術(shù)規(guī)范進(jìn)行簡(jiǎn)單的描述[3]:
JDBC(Java Database Connectivity): JDBC API為訪問(wèn)不同的數(shù)據(jù)庫(kù)提供了一種統(tǒng)一的途徑争涌,象ODBC一樣粉楚,JDBC對(duì)開(kāi)發(fā)者屏蔽了一些細(xì)節(jié)問(wèn)題,另外亮垫,JDCB對(duì)數(shù)據(jù)庫(kù)的訪問(wèn)也具有平臺(tái)無(wú)關(guān)性模软。
JNDI(Java Name and Directory Interface): JNDI API被用于執(zhí)行名字和目錄服務(wù)。它提供了一致的模型來(lái)存取和操作企業(yè)級(jí)的資源如DNS和LDAP饮潦,本地文件系統(tǒng)燃异,或應(yīng)用服務(wù)器中的對(duì)象。
EJB(Enterprise JavaBean): J2EE技術(shù)之所以贏得某體廣泛重視的原因之一就是EJB继蜡。它們提供了一個(gè)框架來(lái)開(kāi)發(fā)和實(shí)施分布式商務(wù)邏輯回俐,由此很顯著地簡(jiǎn)化了具有可伸縮性和高度復(fù)雜的企業(yè)級(jí)應(yīng)用的開(kāi)發(fā)。EJB規(guī)范定義了EJB組件在何時(shí)如何與它們的容器進(jìn)行交互作用稀并。容器負(fù)責(zé)提供公用的服務(wù)仅颇,例如目錄服務(wù)、事務(wù)管理碘举、安全性忘瓦、資源緩沖池以及容錯(cuò)性。但這里值得注意的是引颈,EJB并不是實(shí)現(xiàn)J2EE的唯一途徑耕皮。正是由于J2EE的開(kāi)放性,使得有的廠商能夠以一種和EJB平行的方式來(lái)達(dá)到同樣的目的线欲。
RMI(Remote Method Invoke): 正如其名字所表示的那樣明场,RMI協(xié)議調(diào)用遠(yuǎn)程對(duì)象上方法。它使用了序列化方式在客戶端和服務(wù)器端傳遞數(shù)據(jù)李丰。RMI是一種被EJB使用的更底層的協(xié)議苦锨。
Java IDL/CORBA: 在Java IDL的支持下,開(kāi)發(fā)人員可以將Java和CORBA集成在一起趴泌。 他們可以創(chuàng)建Java對(duì)象并使之可在CORBA ORB中展開(kāi), 或者他們還可以創(chuàng)建Java類并作為和其它ORB一起展開(kāi)的CORBA對(duì)象的客戶舟舒。后一種方法提供了另外一種途徑,通過(guò)它Java可以被用于將你的新的應(yīng)用和舊的系統(tǒng)相集成嗜憔。
JSP(Java Server Pages): JSP頁(yè)面由HTML代碼和嵌入其中的Java代碼所組成秃励。服務(wù)器在頁(yè)面被客戶端所請(qǐng)求以后對(duì)這些Java代碼進(jìn)行處理,然后將生成的HTML頁(yè)面返回給客戶端的瀏覽器吉捶。
Java Servlet: Servlet是一種小型的Java程序夺鲜,它擴(kuò)展了Web服務(wù)器的功能皆尔。作為一種服務(wù)器端的應(yīng)用,當(dāng)被請(qǐng)求時(shí)開(kāi)始執(zhí)行币励,這和CGI Perl腳本很相似慷蠕。Servlet提供的功能大多與JSP類似,不過(guò)實(shí)現(xiàn)的方式不同食呻。JSP通常是大多數(shù)HTML代碼中嵌入少量的Java代碼流炕,而servlets全部由Java寫(xiě)成并且生成HTML。
XML(Extensible Markup Language): XML是一種可以用來(lái)定義其它標(biāo)記語(yǔ)言的語(yǔ)言仅胞。它被用來(lái)在不同的商務(wù)過(guò)程中共享數(shù)據(jù)每辟。XML的發(fā)展和Java是相互獨(dú)立的,但是干旧,它和Java具有的相同目標(biāo)正是平臺(tái)獨(dú)立性渠欺。通過(guò)將Java和XML的組合,您可以得到一個(gè)完美的具有平臺(tái)獨(dú)立性的解決方案莱革。
JMS(Java Message Service): MS是用于和面向消息的中間件相互通信的應(yīng)用程序接口(API)峻堰。它既支持點(diǎn)對(duì)點(diǎn)的域,有支持發(fā)布/訂閱(publish/subscribe)類型的域盅视,并且提供對(duì)下列類型的支持:經(jīng)認(rèn)可的消息傳遞,事務(wù)型消息的傳遞,一致性消息和具有持久性的訂閱者支持旦万。JMS還提供了另一種方式來(lái)對(duì)您的應(yīng)用與舊的后臺(tái)系統(tǒng)相集成闹击。
JTA(Java Transaction Architecture): JTA定義了一種標(biāo)準(zhǔn)的API,應(yīng)用系統(tǒng)由此可以訪問(wèn)各種事務(wù)監(jiān)控成艘。
JTS(Java Transaction Service): JTS是CORBA OTS事務(wù)監(jiān)控的基本的實(shí)現(xiàn)赏半。JTS規(guī)定了事務(wù)管理器的實(shí)現(xiàn)方式。該事務(wù)管理器是在高層支持Java
Transaction API (JTA)規(guī)范淆两,并且在較底層實(shí)現(xiàn)OMG OTS specification的Java映像断箫。JTS事務(wù)管理器為應(yīng)用服務(wù)器、資源管理器秋冰、獨(dú)立的應(yīng)用以及通信資源管理器提供了事務(wù)服務(wù)仲义。JavaMail: JavaMail是用于存取郵件服務(wù)器的API,它提供了一套郵件服務(wù)器的抽象類剑勾。不僅支持SMTP服務(wù)器埃撵,也支持IMAP服務(wù)器。
JTA(JavaBeans Activation Framework): JavaMail利用JAF來(lái)處理MIME編碼的郵件附件虽另。MIME的字節(jié)流可以被轉(zhuǎn)換成Java對(duì)象暂刘,或者轉(zhuǎn)換自Java對(duì)象。大多數(shù)應(yīng)用都可以不需要直接使用JAF捂刺。
J2EE提供了"編寫(xiě)一次谣拣、隨處運(yùn)行"的特性募寨、方便存取數(shù)據(jù)庫(kù)的JDBC API、CORBA技術(shù)以及能夠在Internet應(yīng)用中保護(hù)數(shù)據(jù)的安全模式等等森缠,同時(shí)還提供了對(duì) EJB(Enterprise JavaBeans)拔鹰、Java Servlets API、JSP(Java Server Pages)以及XML(標(biāo)準(zhǔn)通用標(biāo)記語(yǔ)言的子集)技術(shù)的全面支持辅鲸。
1.2 Java企業(yè)級(jí)開(kāi)發(fā)框架概述
EJB(Enterprise Java Bean)
曾幾何時(shí)格郁,EJB被人們當(dāng)做J2EE的核心而頂禮膜拜。
EJB就是把原來(lái)放到客戶端實(shí)現(xiàn)的代碼放到服務(wù)器端独悴,并依靠RMI(Remote Method Invocation例书,是EJB的 技術(shù)基礎(chǔ))進(jìn)行通信。而客戶端就單純負(fù)責(zé)發(fā)送調(diào)用請(qǐng)求和顯示處理結(jié)果刻炒。
在J2EE 中决采,這個(gè)運(yùn)行在一個(gè)獨(dú)立的服務(wù)器上,并封裝了業(yè)務(wù)邏輯的組件就EJB組件坟奥。
回顧EJB出現(xiàn)以前的Java應(yīng)用開(kāi)發(fā)树瞭,大部分開(kāi)發(fā)者直接用JSP頁(yè)面,再加上少量Java Bean就可以完成整個(gè)應(yīng)用爱谁,所有的業(yè)務(wù)邏輯晒喷、數(shù)據(jù)庫(kù)訪問(wèn)邏輯都直接寫(xiě)在JSP頁(yè)面中。系統(tǒng)開(kāi)發(fā)前期访敌,開(kāi)發(fā)者不會(huì)意識(shí)到有什么問(wèn)題凉敲,但隨著開(kāi)發(fā)進(jìn)行到后期,應(yīng)用越來(lái)越大寺旺,開(kāi)發(fā)者需要花費(fèi)大量時(shí)間去解決非常常見(jiàn)的系統(tǒng)級(jí)問(wèn)題爷抓,反而無(wú)暇顧及真正需要解決的業(yè)務(wù)邏輯問(wèn)題。
對(duì)于EJB來(lái)說(shuō)阻塑,它提供了一種良好的組件封裝蓝撇,EJB容器負(fù)責(zé)處理如事務(wù)、訪問(wèn)控制等系統(tǒng)級(jí)問(wèn)題陈莽,而EJB開(kāi)發(fā)者則集中精力去實(shí)現(xiàn)業(yè)務(wù)邏輯渤昌;對(duì)頁(yè)面開(kāi)發(fā)者而言,EJB的存在無(wú)須關(guān)心传透,EJB的實(shí)現(xiàn)無(wú)須關(guān)心耘沼,他們只要調(diào)用EJB的方法即可。
基于EJB的程序架構(gòu)總體有一個(gè)非常優(yōu)秀的思想:業(yè)務(wù)邏輯相關(guān)的實(shí)現(xiàn)集中在EJB中完成朱盐,而EJB容器則負(fù)責(zé)提供帶有重復(fù)性質(zhì)的群嗤、系統(tǒng)級(jí)的功能,這樣EJB組件就可對(duì)外提供完整的業(yè)務(wù)服務(wù)兵琳。
但是狂秘,由于EJB開(kāi)發(fā)的復(fù)雜性骇径,導(dǎo)致許多開(kāi)發(fā)者的批評(píng),以致后來(lái)直接催生了spring框架者春。Spring容器管理的不再是復(fù)雜的EJB組件破衔,而是POJO(Plain Old Java Object) Bean。Spring容器取代了原有的EJB容器钱烟,以Spring框架為核心的應(yīng)用無(wú)須EJB容器支持晰筛,可以直接在Web容器中運(yùn)行。
現(xiàn)在SSH(Spring + Struts + Hibernate)是越來(lái)越少了拴袭,現(xiàn)在比較通用的是SSM(Spring + SpringMVC + Mybatis)读第。
在SSH框架中,Spring負(fù)責(zé)容器管理拥刻,對(duì)象生命周期的管理以及對(duì)象關(guān)系的維護(hù)怜瞒。Hibernate負(fù)責(zé)持久層,它將JDBC做了一個(gè)良好的封裝般哼,程序員在與數(shù)據(jù)庫(kù)進(jìn)行交互時(shí)可以不用書(shū)寫(xiě)大量的SQL語(yǔ)句吴汪。Struts是在應(yīng)用層,它負(fù)責(zé)調(diào)用serivce業(yè)務(wù)邏輯層蒸眠。
Struts
為了解決這些問(wèn)題漾橙,出現(xiàn)了Struts框架,它是一個(gè)完美的MVC實(shí)現(xiàn)楞卡,它有一個(gè)中央控制類(一個(gè)Servlet)近刘,針對(duì)不同的業(yè)務(wù),我們需要一個(gè)Action類負(fù)責(zé)頁(yè)面跳轉(zhuǎn)和后臺(tái)邏輯運(yùn)算臀晃,一個(gè)或幾個(gè)JSP頁(yè)面負(fù)責(zé)數(shù)據(jù)的輸入和輸出顯示,還有一個(gè)Form類負(fù)責(zé)傳遞Action和JSP中間的數(shù)據(jù)介劫。JSP中可以使用Struts框架提供的一組標(biāo)簽徽惋,就像使用HTML標(biāo)簽一樣簡(jiǎn)單,但是可以完成非常復(fù)雜的邏輯座韵。從此JSP頁(yè)面中不需要出現(xiàn)一行<%%>包圍的Java代碼了险绘。
可是所有的運(yùn)算邏輯都放在Struts的Action里將使得Action類復(fù)用度低和邏輯混亂,所以通常人們會(huì)把整個(gè)Web應(yīng)用程序分為三層誉碴,Struts負(fù)責(zé)顯示層宦棺,它調(diào)用業(yè)務(wù)層完成運(yùn)算邏輯,業(yè)務(wù)層再調(diào)用持久層完成數(shù)據(jù)庫(kù)的讀寫(xiě)黔帕。
使用JDBC連接來(lái)讀寫(xiě)數(shù)據(jù)庫(kù)代咸,我們最常見(jiàn)的就是打開(kāi)數(shù)據(jù)庫(kù)連接、使用復(fù)雜的SQL語(yǔ)句進(jìn)行讀寫(xiě)成黄、關(guān)閉連接呐芥,獲得的數(shù)據(jù)又需要轉(zhuǎn)換或封裝后往外傳逻杖,這是一個(gè)非常煩瑣的過(guò)程。
Hibernate
這時(shí)出現(xiàn)了Hibernate框架思瘟。它對(duì)JDBC提供了封裝荸百。Hibernate的O/R Mapping實(shí)現(xiàn)了POJO 和數(shù)據(jù)庫(kù)表之間的映射,以及SQL的自動(dòng)生成和執(zhí)行滨攻。
Hibernate是一個(gè)開(kāi)放源代碼的對(duì)象關(guān)系映射框架够话,它對(duì)JDBC進(jìn)行了非常輕量級(jí)的對(duì)象封裝,它將POJO與數(shù)據(jù)庫(kù)表建立映射關(guān)系光绕,是一個(gè)全自動(dòng)的orm框架女嘲,hibernate可以自動(dòng)生成SQL語(yǔ)句,自動(dòng)執(zhí)行奇钞,使得Java程序員可以隨心所欲的使用對(duì)象編程思維來(lái)操縱數(shù)據(jù)庫(kù)澡为。 Hibernate可以應(yīng)用在任何使用JDBC的場(chǎng)合,既可以在Java的客戶端程序使用景埃,也可以在Servlet/JSP的Web應(yīng)用中使用媒至,最具革命意義的是,Hibernate可以在應(yīng)用EJB的J2EE架構(gòu)中取代CMP谷徙,完成數(shù)據(jù)持久化的重任拒啰。[8]
現(xiàn)在我們有三個(gè)層了,可是每層之間的調(diào)用是怎樣的呢?比如顯示層的Struts需要調(diào)用一個(gè)業(yè)務(wù)類完慧,就需要new一個(gè)業(yè)務(wù)類出來(lái)谋旦,然后使用;業(yè)務(wù)層需要調(diào)用持久層的類,也需要new一個(gè)持久層類出來(lái)用屈尼。通過(guò)這種new的方式互相調(diào)用就是軟件開(kāi)發(fā)中最糟糕設(shè)計(jì)的體現(xiàn)册着。簡(jiǎn)單的說(shuō),就是調(diào)用者依賴被調(diào)用者脾歧,它們之間形成了強(qiáng)耦合甲捏,如果我想在其他地方復(fù)用某個(gè)類,則這個(gè)類依賴的其他類也需要包含鞭执。程序就變得很混亂司顿,每個(gè)類互相依賴互相調(diào)用,復(fù)用度極低兄纺。如果一個(gè)類做了修改大溜,則依賴它的很多類都會(huì)受到牽連。 為此估脆,出現(xiàn)了Spring框架钦奋。
Mybatis
MyBatis是另外一個(gè)廣泛使用的ORM框架。原本是Apache的一個(gè)開(kāi)源項(xiàng)目iBatis, 后改名為MyBatis 。MyBatis的核心在于管理 POJO 與 SQL 之間的映射關(guān)系锨苏。MyBatis 使用簡(jiǎn)單的 XML或注解用于配置和原始映射疙教,將接口和 Java 的POJOs(Plain Old Java Objects,普通的 Java對(duì)象)映射成數(shù)據(jù)庫(kù)中的記錄伞租。
Mybatis框架的架構(gòu)如下圖:
MyBatis相對(duì)于Hibernate贞谓,主要優(yōu)勢(shì)是可以進(jìn)行更為細(xì)致的SQL優(yōu)化。
關(guān)于MyBatis葵诈,詳細(xì)了解可參考:http://www.mybatis.org/mybatis-3/zh/index.html
Spring框架
Spring Framework:
Core support for dependency injection, transaction management, web applications, data access, messaging, testing and more.
Spring是一個(gè)開(kāi)源框架裸弦,Spring是于2003 年興起的一個(gè)輕量級(jí)的Java 開(kāi)發(fā)框架,由Rod Johnson創(chuàng)建作喘。簡(jiǎn)單來(lái)說(shuō)理疙,Spring是一個(gè)分層的JavaSE/EE full-stack(全棧式) 輕量級(jí)開(kāi)源框架。
循證架構(gòu)(Evidence-Based Architecture)
Rod Johnson在2002年編著的《Expert one on one J2EE design and development》一書(shū)中泞坦,對(duì)Java EE 系統(tǒng)框架臃腫窖贤、低效、脫離現(xiàn)實(shí)的種種現(xiàn)狀提出了質(zhì)疑贰锁,并積極尋求探索革新之道赃梧。以此書(shū)為指導(dǎo)思想,他編寫(xiě)了interface21框架豌熄,這是一個(gè)力圖沖破J2EE傳統(tǒng)開(kāi)發(fā)的困境授嘀,從實(shí)際需求出發(fā),著眼于輕便锣险、靈巧蹄皱,易于開(kāi)發(fā)、測(cè)試和部署的輕量級(jí)開(kāi)發(fā)框架芯肤。
Spring框架即以interface21框架為基礎(chǔ)巷折,經(jīng)過(guò)重新設(shè)計(jì),并不斷豐富其內(nèi)涵崖咨,于2004年3月24日盔几,發(fā)布了1.0正式版。同年他又推出了一部堪稱經(jīng)典的力作《Expert one-on-one J2EE Development without EJB》掩幢,該書(shū)在Java世界掀起了軒然大波,不斷改變著Java開(kāi)發(fā)者程序設(shè)計(jì)和開(kāi)發(fā)的思考方式上鞠。
沒(méi)有最好的架構(gòu)际邻,只有最合適的架構(gòu)。循證架構(gòu)是《Expert One-on-One J2EE Development without EJB》(Rod Johnson芍阎,)一書(shū)中推崇的架構(gòu)思路世曾,用俺們的話說(shuō)就是摸著石頭過(guò)河,找最適合自己的架構(gòu)。
我們?cè)?jīng)在無(wú)數(shù)的書(shū)籍和文章中看到轮听,EJB是J2EE的核心技術(shù)之一骗露。而Rod Johnson竟然宣稱,絕大多數(shù)的J2EE應(yīng)用根本不需要EJB血巍。
Rod Johnson引領(lǐng)了一場(chǎng)J2EE領(lǐng)域影響深遠(yuǎn)的變革萧锉。Spring和Hibernate,IoC和AOP,輕量級(jí)架構(gòu)等等。還有更重要的一點(diǎn)述寡,是遵循一切實(shí)事求是的“循證架構(gòu)”的問(wèn)題解決的方法論哲學(xué)柿隙。
Rod Johnson認(rèn)為,應(yīng)該是基于實(shí)踐的證據(jù)鲫凶、來(lái)自歷史項(xiàng)目或親自試驗(yàn)的經(jīng)驗(yàn)禀崖,而不是任何形式的偶像崇拜或者門(mén)戶之見(jiàn)。[10]
“循證哲學(xué)”(基于實(shí)踐的證據(jù)螟炫、來(lái)自歷史項(xiàng)目或親自試驗(yàn)的經(jīng)驗(yàn))波附、“實(shí)事求是”的工作方式——這原本就應(yīng)該是程序員的工作方式。
“認(rèn)識(shí)來(lái)源于實(shí)踐昼钻,而又運(yùn)用于實(shí)踐”掸屡。
——馬克思
人的認(rèn)識(shí)來(lái)源于實(shí)踐,是隨著實(shí)踐的發(fā)展而發(fā)展的。通過(guò)實(shí)踐得出的認(rèn)識(shí)换吧,只有作用于實(shí)踐并通過(guò)實(shí)踐的檢驗(yàn)折晦,才能夠確定認(rèn)識(shí)的正確與否。
循證架構(gòu)思想來(lái)源于”循證實(shí)踐“沾瓦。任何涉及模式满着,架構(gòu)模式,編程范式(過(guò)程式贯莺,面向?qū)ο笫椒缋瘮?shù)式,邏輯式缕探,面向服務(wù)式)的問(wèn)題魂莫,都是基于解決某個(gè)實(shí)際業(yè)務(wù)場(chǎng)景才有其實(shí)質(zhì)存在的意義。
循證實(shí)踐(Evidence-Based Practise)爹耗,亦為循證學(xué)耙考。本意是"基于證據(jù)的實(shí)踐",其理念始于20世紀(jì)末發(fā)展起來(lái)的循證醫(yī)學(xué)潭兽。最初意指醫(yī)生"將當(dāng)前所能獲得的最佳研究證據(jù)與自身的專業(yè)技能及患者的價(jià)值觀整合起來(lái)進(jìn)行治療"倦始。此后,它便以迅雷不及掩耳之勢(shì)席卷了整個(gè)醫(yī)療衛(wèi)生領(lǐng)域山卦,并不斷向鄰近學(xué)科滲透鞋邑,形成了循證心理治療、循證教育學(xué)、循證社會(huì)學(xué)等數(shù)十個(gè)新的學(xué)科領(lǐng)域枚碗。
在程序開(kāi)發(fā)里不同模塊之間信息的溝通是通過(guò)對(duì)象傳遞完成的逾一,而對(duì)象能否順利傳遞就是要合理的構(gòu)建好對(duì)象,而管理好對(duì)象的構(gòu)建方式就能管理好對(duì)象傳遞肮雨,spring主要就是解決這個(gè)問(wèn)題的遵堵。spring提供一個(gè)容器,我們?cè)趚ml文件里酷含,或者通過(guò)注解的方式(注解的方式是通過(guò)反射機(jī)制實(shí)現(xiàn))定義各個(gè)對(duì)象的依賴關(guān)系鄙早,由容器完成對(duì)象的生命周期的管理(創(chuàng)建,運(yùn)行椅亚,銷毀)限番。
Spring框架建立在IOC和AOP技術(shù)之上。
IOC: Inversion of Control呀舔,控制反轉(zhuǎn)弥虐,就是由容器控制程序之間的(依賴)關(guān)系,而非傳統(tǒng)實(shí)現(xiàn)中媚赖,由程序代碼直接操控霜瘪。 當(dāng)我們的代碼里需要使用某個(gè)實(shí)例的時(shí)候就可以直接從容器里獲取。對(duì)象的實(shí)例化由spring容器負(fù)責(zé)搞定惧磺,所以它被稱為控制反轉(zhuǎn)颖对,控制反轉(zhuǎn)的意思就是本來(lái)屬于java程序里構(gòu)建對(duì)象的功能交由容器接管,依賴注入(DI)就是當(dāng)程序要使用某個(gè)對(duì)象時(shí)候磨隘,容器會(huì)把它注入到程序里缤底。Spring IOC有三種注入方式:接口注入、setter注入番捂、構(gòu)造器注入个唧。
AOP: Aspect Oriented Programming,面向切面編程设预,就是把可重用的功能提取出來(lái)徙歼,然后將這些通用功能在合適的時(shí)候織入到應(yīng)用程序中,比如事務(wù)管理鳖枕、權(quán)限控制魄梯、日志記錄、性能統(tǒng)計(jì)等宾符。通過(guò)預(yù)編譯方式和運(yùn)行期動(dòng)態(tài)代理實(shí)現(xiàn)業(yè)務(wù)邏輯模塊之間的隔離画恰,使業(yè)務(wù)邏輯模塊間的耦合度極大化地降低,提高程序可重用性和開(kāi)發(fā)的效率吸奴。使用 AOP 后,公共服務(wù) (比 如日志、持久性则奥、事務(wù)等)就可以分解成方面并應(yīng)用到域?qū)ο笊峡既螅瑫r(shí)不會(huì)增加域?qū)ο蟮膶?duì)象模型的復(fù)雜性。AOP的工作模式如下圖所示:
1.3 Spring生態(tài)系統(tǒng)
Spring的整體架構(gòu)
Spring框架至今已集成了20多個(gè)模塊读处。這些模塊主要被分如下圖所示的核心容器糊治、數(shù)據(jù)訪問(wèn)/集成,、Web罚舱、AOP(面向切面編程)井辜、工具、消息和測(cè)試模塊[5]:
Core Container
核心部分分為4大塊管闷,spring-core, spring-beans, spring-context, spring-expression. 其中core和bean是整個(gè)框架的核心粥脚,提供了基礎(chǔ)的DI和IoC功能。 Context建立在core和beans模塊之上包个,提供一種類似JNDI且以框架的方式來(lái)操作對(duì)象的方式刷允。Context模塊從beans模塊繼承它的功能同時(shí)增加了國(guó)際化支持,如資源綁定等碧囊,同時(shí)树灶,Context模塊也支持JavaEE功能,如EJB糯而,JMX和基本的遠(yuǎn)程調(diào)用天通。ApplicationContext接口是context模塊的焦點(diǎn)。expression是一種很強(qiáng)大的expression language熄驼,支持在運(yùn)行時(shí)查詢和操作對(duì)象的屬性像寒,我們會(huì)在后面的文章中舉些例子來(lái)說(shuō)明spring expression language的用法。
AOP and instrumentation
Aop模塊提供了面向切面編程的實(shí)現(xiàn)谜洽,和AspectJ集成萝映。
Messaging
Messaging是spring4新增加的模塊,包含了一部分主要的基于message的應(yīng)用的實(shí)現(xiàn)阐虚。
Data Access/Integration
Data access顧名思義序臂,是spring對(duì)數(shù)據(jù)層提供的支持,是功能比較豐富的模塊实束。提供了包括JDBC奥秆,事物,ORM咸灿,JMS等一系列實(shí)現(xiàn)构订。
Web
Web模塊主要提供面向web的一些實(shí)現(xiàn),例如多文件上傳避矢,servlet監(jiān)聽(tīng)器以及spring mvc方面的支持悼瘾。
Test
Test模塊主要是針對(duì)spring的各個(gè)模塊做各種各樣的測(cè)試囊榜,包括單元測(cè)試、集成測(cè)試等等亥宿。
1.4 Spring JavaConfig
Java元編程 (meta-programming)
一般代碼的操作對(duì)象是數(shù)據(jù)卸勺。元編程操作的對(duì)象是代碼。
元編程一言以蔽之烫扼,就是用代碼生成(操縱)代碼曙求。在運(yùn)行時(shí)創(chuàng)建和修改代碼而非編程時(shí),這種程序叫做元程序映企。而編寫(xiě)這種程序就叫做元編程悟狱。元編程是用代碼在編譯期或運(yùn)行期生成/改變代碼。元編程是現(xiàn)實(shí)世界的抽象的利器堰氓。
元編程技術(shù)在多種編程語(yǔ)言中都可以使用挤渐,但更多的還是被應(yīng)用于動(dòng)態(tài)語(yǔ)言中,因?yàn)閯?dòng)態(tài)語(yǔ)言提供了更多的在運(yùn)行時(shí)將代碼視為數(shù)據(jù)進(jìn)行操縱的能力豆赏。
Java 5中提供了Annotations挣菲,它是Java的metadata。Java應(yīng)用中的元數(shù)據(jù)在早期Java版本中掷邦,一般使用屬性文件白胀、XML,后來(lái)注解出現(xiàn)了抚岗,就都用注解了或杠。
Java通過(guò)反射機(jī)制實(shí)現(xiàn)元編程。反射是促進(jìn)元編程的一種很有價(jià)值的語(yǔ)言特性宣蔚。
常見(jiàn)的開(kāi)發(fā)語(yǔ)言均能做到元編程向抢,Lisp就不用多說(shuō)了,C的Marco胚委,C++的Template挟鸠,Java的Annotation,C#的Attribute亩冬、Reflection艘希、CodeDom和IL Emitter,各種腳本語(yǔ)言(如js硅急、python)的eval覆享,甚至連Unix/Linux的shell腳本也能。
元編程常見(jiàn)的應(yīng)用場(chǎng)景很多营袜,擴(kuò)展語(yǔ)法撒顿、開(kāi)發(fā)DSL、生成代碼荚板、根據(jù)特定場(chǎng)景自動(dòng)選擇代碼優(yōu)化凤壁、解決一些正交的架構(gòu)設(shè)計(jì)問(wèn)題吩屹、AOP等等。
元編程拧抖,是對(duì)語(yǔ)言自身再向上一層抽象祟峦。
JavaConfig簡(jiǎn)介
Spring IOC有一個(gè)非常核心的概念——Bean。由Spring容器來(lái)負(fù)責(zé)對(duì)Bean的實(shí)例化徙鱼,裝配和管理。XML是用來(lái)描述Bean最為流行的配置方式针姿。Spring可以從XML配置文件中讀取任何類型的元數(shù)據(jù)并自動(dòng)轉(zhuǎn)換成相應(yīng)的Java代碼袱吆。Spring改變了java的編程模式。
隨著Spring的日益發(fā)展距淫,越來(lái)越多的人對(duì)Spring提出了批評(píng)绞绒。“Spring項(xiàng)目大量的爛用XML”就是最為嚴(yán)勵(lì)的一個(gè)批評(píng)榕暇。由于Spring會(huì)把幾乎所有的業(yè)務(wù)類都以Bean的形式配置在XML文件中蓬衡,造成了大量的XML文件。使用XML來(lái)配置Bean失去了編譯時(shí)的類型安全檢查彤枢。大量的XML配置使得整個(gè)項(xiàng)目變得更加復(fù)雜狰晚。Rod Johnson也注意到了這個(gè)非常嚴(yán)重的問(wèn)題。
當(dāng)隨著Java EE 5.0的發(fā)布缴啡,其中引入了一個(gè)非常重要的特性——Annotations(注解)壁晒。注解是源代碼的標(biāo)簽,這些標(biāo)簽可以在源代碼層進(jìn)行處理或通過(guò)編譯器把它熔入到class文件中业栅。在Java EE 5以后的版本中秒咐,注釋成為了一個(gè)主要的配置選項(xiàng)。Spring使用注釋來(lái)描述Bean的配置與采用XML相比碘裕,因類注釋是在一個(gè)類源代碼中携取,可以獲得類型安全檢查的好處“锟祝可以良好的支持重構(gòu)雷滋。
JavaConfig就是使用注釋來(lái)描述Bean配置的組件。JavaConfig 是Spring的一個(gè)子項(xiàng)目(詳細(xì)了解可參考:http://docs.spring.io/spring-javaconfig/docs/).
JavaConfig與注解驅(qū)動(dòng)配置( Annotation-Driven Configuration)
后來(lái)你弦,當(dāng)@Annotation出現(xiàn)了惊豺,大部分技術(shù)、框架就紛紛放棄了XML配置文件禽作,改為使用Annotation來(lái)管理配置信息尸昧。
Spring有2種常用的配置方式:
- 基于XML文件的配置
- 基于@Annotation的配置
Spring的XML配置方式是使用被Spring命名空間的所支持的一系列的XML標(biāo)簽來(lái)實(shí)現(xiàn)的。Spring有以下主要的命名空間:context旷偿、beans烹俗、jdbc爆侣、tx、aop幢妄、mvc等兔仰。
使用XML來(lái)配置Bean所能實(shí)現(xiàn)的功能,通過(guò)JavaConfig同樣可以很好的實(shí)現(xiàn)蕉鸳。之前我們都是在xml文件中定義bean的乎赴,比如:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="helloBean" class="com.hello.impl.HelloWorldImpl">
</beans>
其實(shí)我們可以使用注解來(lái)完成這些事情,例如下面的代碼潮尝,完成的功能和上面的xml配置的功能是一樣的:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.hello.HelloWorld;
import com.hello.impl.HelloWorldImpl;
@Configuration
public class AppConfig {
@Bean(name="helloBean")
public HelloWorld helloWorld() {
return new HelloWorldImpl();
}
}
使用@Bean注解榕吼,來(lái)標(biāo)識(shí)此方法構(gòu)造出一個(gè)由Spring容器管理的bean。Spring對(duì)Java配置的支持是由@Configuration注解和@Bean注解來(lái)實(shí)現(xiàn)的勉失。由@Bean注解的方法將會(huì)實(shí)例化羹蚣、配置和初始化一個(gè)新對(duì)象,這個(gè)對(duì)象將由Spring的IoC容器來(lái)管理乱凿。@Bean聲明所起到的作用與<bean/> 元素類似顽素。被@Configuration所注解的類則表示這個(gè)類的主要目的是作為bean定義的資源。被@Configuration聲明的類可以通過(guò)在同一個(gè)類的內(nèi)部調(diào)用@bean方法來(lái)設(shè)置嵌入bean的依賴關(guān)系徒蟆。
一般在一個(gè)大型工程項(xiàng)目中胁出,如果將所有的bean都配置在一個(gè)xml文件中,那么這個(gè)文件就會(huì)非常的大后专。所以一般會(huì)將一個(gè)大的xml配置文件分割為好幾份划鸽。這樣方便管理,最后在總的那個(gè)xml文件中導(dǎo)入戚哎。比如:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<import resource="config/customer.xml"/>
<import resource="config/scheduler.xml"/>
</beans>
但是現(xiàn)在我們也可以使用JavaConfig來(lái)完成同樣的工作了:
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
@Import({ CustomerConfig.class, SchedulerConfig.class })
public class AppConfig {
}
@Configuration可以被認(rèn)為是相當(dāng)于XML的< bean / >元素裸诽。
Spring在2.5版本以后開(kāi)始支持用注解的方式來(lái)配置依賴注入⌒偷剩可以用注解的方式來(lái)替代XML方式的bean描述丈冬,可以將bean描述轉(zhuǎn)移到組件類的內(nèi)部,只需要在相關(guān)類上甘畅、方法上或者字段聲明上使用注解即可埂蕊。使用JavaConfig的配置方式,一行XML代碼都不需要疏唾,什么web.xml,Application-context.xml蓄氧,Beans.xml,統(tǒng)統(tǒng)再見(jiàn)槐脏。
在 Spring XML中, 啟動(dòng)注解注入bean喉童,通過(guò)如下標(biāo)簽實(shí)現(xiàn):
<context:annotation-config/>
在 JavaConfig中, 等同于 @AnnotationDrivenConfig注解。
代碼示例:
@Configuration
@AnnotationDrivenConfig
public class Config {
// may now use @Autowired to reference beans from other @Configuration classes, XML, etc
}
使用@ComponentScan注解顿天,等同于在 Spring XML中的
<context:component-scan/>
代碼示例:
package com.company.foo;
@Service
public class FooServiceImpl implements FooService {
private final FooRepository fooRepository;
@Autowired
public FooService(FooRepository fooRepository) {
this.fooRepository = fooRepository;
}
// ...
}
package com.company.foo;
@Repository
public class JdbcFooRepository implements FooRepository {
private final DataSource dataSource;
@Autowired
public FooRepository(DataSource dataSource) {
this.dataSource = dataSource;
}
// ...
}
@Configuration
@ComponentScan("com.company") // search the com.company package for @Component classes
@ImportXml("classpath:com/company/data-access-config.xml") // XML with DataSource bean
public class Config {
}
在配置類中使用上述的配置堂氯,我們就可以在代碼里調(diào)用service方法了:
public class Main {
public static void main(String[] args) {
JavaConfigApplicationContext ctx = new JavaConfigApplicationContext(Config.class);
FooService fooService = ctx.getBean(FooService.class);
fooService.doStuff();
}
}
小結(jié)
Spring框架項(xiàng)目的出發(fā)點(diǎn)是為了解決被其他框架所忽略的部分蔑担。在J2EE各個(gè)具體領(lǐng)域,都有很多出色的解決方案咽白,web框架持久化方案啤握,遠(yuǎn)程調(diào)用工具等等,然而將這些工具整合成一個(gè)全面的架構(gòu)晶框,卻困難重重排抬,甚至成為一種負(fù)擔(dān)。spring提供了一個(gè)完整的解決方案授段,將各種專用框架整合成一個(gè)連貫的整體的架構(gòu)畜埋。
Spring誕生之初,就是為了解決當(dāng)初EJB的重量級(jí)復(fù)雜編程問(wèn)題畴蒲。Spring通過(guò)輕量級(jí)的架構(gòu),使用IOC(DI)和AOP对室,用POJO實(shí)現(xiàn)了EJB的功能模燥。可是掩宜,Spring令人頭疼的繁雜的配置蔫骂,讓開(kāi)發(fā)者陷入了另一個(gè)深淵(世間萬(wàn)物,往往如此)牺汤。一開(kāi)始辽旋,Spring使用大量xml配置。Spring 2.5引入了基于注解的組件掃描檐迟,消除了大量針對(duì)應(yīng)用自身的組件的xml配置补胚。Spring 3.0 有了Java Config解決方案,可以替代xml追迟。但是溶其,還是有使用很多Spring的特性,諸如事務(wù)管理敦间,SpringMVC瓶逃,以及集成第三方框架的時(shí)候(比如模板引擎:velocity, freemarker, thymeleaf),還是需要大量的顯式配置廓块。配置Servlet和Filter等同樣需要在web.xml里面配置厢绝。[9]
對(duì)了,還有運(yùn)行調(diào)試的時(shí)候带猴,需要配置web容器等大量手工勞動(dòng)昔汉。
這些配置,耗去了程序員們的大量的精力和時(shí)間浓利,使得生產(chǎn)效率大減折扣挤庇。程序員們的大腦不得不在編寫(xiě)業(yè)務(wù)邏輯代碼跟xml配置之間來(lái)回切換钞速。
在后面的章節(jié)中,我們將看到Spring Boot對(duì)程序員更加簡(jiǎn)易地使用Spring框架上面所帶來(lái)的巨大變化嫡秕,以及對(duì)Spring生態(tài)體系渴语,各種技術(shù)框架的的整合集成。
參考資料
- http://docs.spring.io/spring-javaconfig/docs/1.0.0.M4/reference/html/
- https://docs.spring.io/spring/docs/current/javadoc-api/
- https://www.ibm.com/developerworks/cn/java/j2ee/
- http://baike.baidu.com/item/spring/85061
- http://howtodoinjava.com/spring/spring-core/top-spring-core-interview-questions-with-answers/
- http://howtodoinjava.com/java-spring-framework-tutorials/
- http://baike.baidu.com/item/MyBatis
- http://baike.baidu.com/item/Hibernate/206989
- 《Spring Boot In Action》(Craig Walls)
- 《Expert one on one J2EE design and development》(Rod Johnson)