Java是一種可以撰寫跨平臺應(yīng)用軟件的面向?qū)ο蟮某绦蛟O(shè)計語言蔚晨。Java 技術(shù)具有卓越的通用性、高效性肛循、平臺移植性和安全性铭腕,廣泛應(yīng)用于PC、數(shù)據(jù)中心多糠、游戲控制臺累舷、科學(xué)超級計算機、移動電話和互聯(lián)網(wǎng)夹孔,同時擁有全球最大的開發(fā)者專業(yè)社群被盈。
給你學(xué)習(xí)路線:html-css-js-jq-javase-數(shù)據(jù)庫-jsp-servlet-Struts2-hibernate-mybatis-spring4-springmvc-ssh-ssm
現(xiàn)在的Java程序員趕上了好時候析孽。在將近20年的歷史中,Java的發(fā)展歷經(jīng)沉浮只怎。盡管有很多為人詬病的產(chǎn)品袜瞬,例如applets、EJB身堡、Java Data Object(JDO)和數(shù)不清的日志框架邓尤,Java還是發(fā)展為一個龐大且豐富的開發(fā)平臺,很多企業(yè)級應(yīng)用都是基于JVM平臺構(gòu)建贴谎。Spring是JVM開發(fā)平臺中的一顆明珠汞扎。
小編推薦一個學(xué)Java的學(xué)習(xí)裙【 六五零,五五四擅这,六零七 】澈魄,無論你是大牛還是小白,是想轉(zhuǎn)行還是想入行都可以來了解一起進步一起學(xué)習(xí)蕾哟!裙內(nèi)有開發(fā)工具一忱,很多干貨和技術(shù)資料分享!
Spring最開始出現(xiàn)的目的是替代企業(yè)級開發(fā)框架EJB谭确,相比EJB帘营,Spring提供更輕量和更易用的編程模型。Spring的重要特點是非侵入式增強POJO(plain old java object)的能力逐哈。
在后續(xù)的發(fā)展過程中芬迄,EJB也效仿Spring的做法提供了簡單的以POJO為中心的編程模型,現(xiàn)在的EJB框架也擁有依賴注入(DI)和面向切面編程(AOP)能力昂秃,可以論證是受Spring成功的影響禀梳。
盡管J2EE一直在追趕Spring的發(fā)展,但是Spring本身也沒有停止進步〕β妫現(xiàn)在算途,Spring在一些J2EE剛剛涉入或者完全沒有涉入的領(lǐng)域飛速發(fā)展:移動開發(fā)、社交API整合蚀腿、NoSQL數(shù)據(jù)庫嘴瓤、云計算和大數(shù)據(jù)。就目前來看莉钙,Spring的未來一片光明廓脆。
重要的事情再強調(diào)一遍:現(xiàn)在的Java程序員趕上了好時候。
這篇文章會從一個比較高的層次探索Spring磁玉,介紹Spring框架解決了哪些主要問題停忿。
1.1 簡化Java開發(fā)
Spring是一種開源框架,由Rod Johnson發(fā)明蚊伞,并在其著作《Expert One-on-One:J2EE設(shè)計與開發(fā)》席赂。Spring的初衷是降低企業(yè)級開發(fā)的復(fù)雜性吮铭,并試圖通過POJO對象實現(xiàn)之前EJB這類重型框架才能實現(xiàn)的功能。Spring不僅僅對服務(wù)端開發(fā)有用颅停,任何Java應(yīng)用都可受益于Spring的簡潔沐兵、易測試和低耦合等特性。
Spring框架中使用beans或JavaBeans來表示應(yīng)用程序中的組件便监,但這并不意味著該組件必須嚴(yán)格滿足Java Bean的規(guī)范扎谎。
Spring做了很多事情,但是歸根到底是一些基本的思路烧董,而所有這些思路最終都導(dǎo)向Spring的使命:簡化Java開發(fā)毁靶。
Spring通過下列四種策略來簡化Java開發(fā):
基于POJO的輕量級、最小侵入式開發(fā)逊移;
通過依賴注入和面向接口編程實現(xiàn)松耦合预吆;
通過面向切面編程和慣例實現(xiàn)聲明式編程;
通過面向切面編程和模板消除樣板式代碼(boierplate code)
幾乎Spring的每條特性都可以追溯到這四條策略之一胳泉,接下來分別對這四條策略進行闡述拐叉,并給出具體的代碼說明Spring如何簡化Java開發(fā)。
1.1.1 激發(fā)POJO的能力
如果你做Java開發(fā)足夠久扇商,你應(yīng)該遇到過很多會束縛程序員能力的開發(fā)框架凤瘦,這些框架要求程序員繼承框架提供的類或者實現(xiàn)它提供的接口,例如EJB框架中的session beans案铺,另外蔬芥,在EJB之前的很多框架中也有類似的侵入式編程模型,如Struts控汉、WebWork笔诵、Tapestry等等。
Spring盡量避免讓自己的API污染你的應(yīng)用代碼姑子。Spring幾乎不會強制要求開發(fā)人員實現(xiàn)某個Spring提供的接口或者繼承某個Spring提供的類乎婿,在Spring應(yīng)用中的Java類看起來和普通類一樣,不過街佑,Spring現(xiàn)在經(jīng)常使用注解來修飾Java類谢翎,但是這個類還是一個POJO。
舉個代碼例子說明舆乔,看如下的HelloWorldBean
可以看出岳服,這就是一個簡單的Java類-POJO剂公,沒有什么特殊的標(biāo)志表明它是一個Spring組件希俩。Spring這種非侵入式編程模型使得這個類在Spring和非Spring框架下具備相同的功能。
盡管形式非常簡單纲辽,POJO的能力值卻可能非常高颜武,例如Spring可以通過依賴注入編織這些POJOs來激發(fā)POJO的能力璃搜。
1.1.2 依賴注入
依賴注入聽起來比較嚇人,貌似一種非常復(fù)雜的編程技術(shù)或者設(shè)計模式鳞上。實際上依賴注入并不復(fù)雜这吻,通過在工程中應(yīng)用依賴注入技術(shù),可以得到更簡單篙议、更容易理解和測試的代碼唾糯。
How DI works
除了Hello-world級別的程序,稍微復(fù)雜一點的Java應(yīng)用都需要多個類配合實現(xiàn)功能鬼贱。一般而言移怯,每個類自己負(fù)責(zé)獲取它要合作的類對象的引用,這會導(dǎo)致代碼高度耦合且難以測試这难。
首先看如下代碼:
可以看出舟误,DamselRescuingKnight在它的構(gòu)造函數(shù)中創(chuàng)建了自己的Quest實例——RescueDamselQuest實例,這使得DamselRescuingKnight與RescueDamselQuest緊密耦合姻乓,如果需要刺殺Damsel嵌溢,則這個刀可以使用,但是如果需要刺殺恐龍蹋岩,則這個刀就派不上用場了赖草。
更糟的是,給DamselRescuingKnight寫單元測試很不方便剪个,在這個測試中疚顷,你必須確認(rèn):當(dāng)調(diào)用knight的emarkOnQuest函數(shù)時,quest的embark函數(shù)也正確調(diào)用禁偎,但這并不容易腿堤。
耦合是一頭雙頭怪:一方面,緊耦合的代碼難以測試如暖、難以復(fù)用并且難以理解笆檀,并且經(jīng)常陷入“修復(fù)一個bug但引入一個新的bug”的開發(fā)怪圈中;另一方面盒至,應(yīng)用程序必須存在適當(dāng)?shù)鸟詈闲锶鳎駝t該應(yīng)用無法完成任何功能〖纤欤總之樱衷,耦合是必要的,但是應(yīng)該控制組件之間的耦合程度酒唉。
通過使用依賴注入(DI)技術(shù)矩桂,對象之間的依賴關(guān)系由Spring框架提供的容器進行管理,而不需要某個對象主動創(chuàng)建自己需要的引用痪伦,如下圖所示:
依賴注入的作用
再看一個BraveKnight類的例子:
該對象不再局限于一種quest實例侄榴,在構(gòu)造過程中利用構(gòu)造函數(shù)的參數(shù)傳入quest實例雹锣,這種類型的依賴注入稱為構(gòu)造注入。
還有一點需要注意癞蚕,使用接口定義quest實例蕊爵,這就是面向接口編程,使得BraveKnight不再局限于某種特定的Quest實現(xiàn)桦山,這就是DI帶來的最大的好處——松耦合攒射。
實現(xiàn)依賴注入
在上述例子代碼可以看出,Spring相當(dāng)于將依賴注入的位置從BraveKnight類中剝離出來恒水,那么具體的依賴注入代碼如何寫呢匆篓?開發(fā)人員如何規(guī)定給BraveKnight注入哪個Quest實現(xiàn),例如SlayDragonQuest寇窑?
小編推薦一個學(xué)Java的學(xué)習(xí)裙【 六五零鸦概,五五四,六零七 】甩骏,無論你是大牛還是小白窗市,是想轉(zhuǎn)行還是想入行都可以來了解一起進步一起學(xué)習(xí)!裙內(nèi)有開發(fā)工具饮笛,很多干貨和技術(shù)資料分享咨察!
在Spirng框架中,最通用的方法是通過寫XML配置文件來定義組件之間的依賴關(guān)系福青,如下所示:
在這個xml配置文件中分別定義了BraveKnight和SlayDragonQuest兩個bean:在BraveKnightbean的定義中摄狱,通過構(gòu)造器函數(shù)傳入一個SlayDragonQuest的引用;在SlayDragonQuest的定義中无午,通過SpEL語言將System.out傳入它的構(gòu)造函數(shù)媒役。
Spring 3.0引入了JavaConfig,這種寫法比xml文件的好處是具備類型安全檢查宪迟,例如酣衷,上面XML配置文件可以這么寫:
不論是基于XML的配置還是基于Java文件的配置,都由Spring框架負(fù)責(zé)管理beans之間的依賴關(guān)系次泽。
啟動依賴注入
在Spring應(yīng)用中穿仪,由application context負(fù)責(zé)加載beans,并將這些beans根據(jù)配置文件編織在一起意荤。Spring框架提供了幾種application context的實現(xiàn)啊片,如果使用XML格式的配置文件,則使用ClassPathXmlApplicationContext玖像;如果使用Java文件形式的配置文件紫谷,則使用AnnotationConfigApplicationContext。
上述代碼中,根據(jù)KnightConfig.java文件創(chuàng)建Spring應(yīng)用上下文碴里,可以把該應(yīng)用上下文看成對象工廠,來獲取idknight的bean上真。
1.1.3 切面編程
依賴注入(DI)實現(xiàn)了模塊之間的松耦合咬腋,而利用面向切面編程(AOP)可以將涉及整個應(yīng)用的基礎(chǔ)功能(安全、日志)放在一個可復(fù)用的模塊中睡互。
AOP是一種在軟件系統(tǒng)中實現(xiàn)關(guān)注點分離的技術(shù)根竿。軟件系統(tǒng)由幾個模塊構(gòu)成,每個模塊負(fù)責(zé)一種功能就珠,不過在系統(tǒng)中有些需求需要涉及到所有的模塊寇壳,例如日志、事務(wù)管理和安全等妻怎。如果將這些需求相關(guān)的代碼都分散在各個模塊中壳炎,一方面是不方便維護厂财、另一方面是與原來每個模塊的業(yè)務(wù)邏輯代碼混淆在一起茶凳,不符合單一職責(zé)原則。
實現(xiàn)系統(tǒng)級別處理的代碼分散在多個子模塊中源请,這意味著如果要修改這些處理代碼榛丢,則要在每個模塊中都進行修改铲球。即使將這些代碼封裝到一個模塊中,在沒給個子模塊中只保留對方法的調(diào)用晰赞,這些方法調(diào)用還是在各個模塊中重復(fù)出現(xiàn)稼病。
業(yè)務(wù)邏輯代碼與非核心功能的代碼混淆在一起。例如掖鱼,一個添加address book的方法應(yīng)該只關(guān)心如何添加address book然走,而不應(yīng)該關(guān)心該操作是否安全或者是否能夠?qū)崿F(xiàn)事務(wù)處理。
下面這張圖可以體現(xiàn)這種復(fù)雜性戏挡,左邊的業(yè)務(wù)邏輯模塊與右邊的系統(tǒng)服務(wù)模塊溝通太過密切丰刊,每個業(yè)務(wù)模塊需要自己負(fù)責(zé)調(diào)用這些系統(tǒng)服務(wù)模塊。
業(yè)務(wù)邏輯模塊與系統(tǒng)服務(wù)模塊過度交互
AOP可以模塊化這些系統(tǒng)服務(wù)增拥,然后利用聲明式編程定義該模塊需要應(yīng)用到那些業(yè)務(wù)邏輯模塊上啄巧。這使得業(yè)務(wù)模塊更簡潔,更專注于處理業(yè)務(wù)邏輯掌栅,簡而言之秩仆,切面(aspects)確保POJO仍然是普通的Java類。
可以將切面想象為覆蓋在一些業(yè)務(wù)模塊上的毯子猾封,如下圖所示澄耍。在系統(tǒng)中有一些模塊負(fù)責(zé)核心的業(yè)務(wù)邏輯,利用AOP可以為所有這些模塊增加額外的功能,而且核心業(yè)務(wù)模塊無需知道切面模塊的存在齐莲。
切面就像毯子一樣覆蓋在幾個核心業(yè)務(wù)模塊之上
AOP實踐
繼續(xù)上面的例子痢站,如果需要一個人記錄BraveKnight的所作所為,下面代碼是該日志服務(wù):
然后在XML文件中定義Minstrel對應(yīng)的切面:
小編推薦一個學(xué)Java的學(xué)習(xí)裙【 六五零选酗,五五四阵难,六零七 】,無論你是大牛還是小白芒填,是想轉(zhuǎn)行還是想入行都可以來了解一起進步一起學(xué)習(xí)呜叫!裙內(nèi)有開發(fā)工具,很多干貨和技術(shù)資料分享殿衰!
在這個配置文件中增加了aop配置名字空間朱庆。首先定義Minstrel的bean,然后利用標(biāo)簽定義aop相關(guān)的配置闷祥;然后在節(jié)點中引用minstrel娱颊,定義方面;aspect負(fù)責(zé)將pointcut和要執(zhí)行的函數(shù)(before凯砍、after或者around)連接在一起维蒙。
還有一種更先進的寫法,利用注解和Java配置文件果覆,可以參考aop docs
Spring框架中的一些子模塊也是基于AOP實現(xiàn)的颅痊,例如負(fù)責(zé)事務(wù)處理和負(fù)責(zé)安全的模塊。