版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
1、<p><b> 引言</b></p><p> 框架從某種意義上講是某種應(yīng)用的半成品,它是由一組組件所構(gòu)成。對于程序的重用性與所設(shè)計的系統(tǒng)的擴展性以達到開發(fā)周期的縮減的目的與開發(fā)質(zhì)量的提高等目的,往往是框架一直追求并良好的實現(xiàn)了的。</p><p> 在軟件設(shè)計中,最終遵循的還是一個設(shè)計理念,就是“高內(nèi)聚,低耦合”??蚣芤话闶菍栴}分割成若干子問題進
2、行一一攻破,從而起到易于控制、擴展,易于分配資源的效果。設(shè)計過程中,常常引入“層”的概念,及將各個義務(wù)分層實現(xiàn)。其間難免會出現(xiàn)耦合,而耦合度過高會降低系統(tǒng)的擴展性和維護性。而框架主要工作在層與層之間,很好的解決了這一問題。在軟件設(shè)計中有一個概念叫做IoC,及控制反轉(zhuǎn),也叫DI(依賴注入),它主要就是實現(xiàn)層與層之間的松耦合。</p><p> 面向?qū)ο缶幊淘谲浖O(shè)計中無處不在,非常完美的解決了代碼重用。但有時候具
3、體的業(yè)務(wù)貫穿整個系統(tǒng),而往往這個業(yè)務(wù)是重復出現(xiàn)的,利用面向?qū)ο笠巡荒芎芎媒鉀Q。在這里便出現(xiàn)了AOP(面向切面編程),將其中相同的業(yè)務(wù)抽取出來進行統(tǒng)一解決。在這里不得不說一下Spring框架的強大魅力,Spring對IoC和AOP的操作可謂前無古人。</p><p> 本文主要利用IoC和AOP的概念,解決層與層之間的依賴關(guān)系以及重復業(yè)務(wù)的處理。</p><p><b> 研究
4、背景</b></p><p> 上世紀末與本世紀初,J2EE開始盛行,主要歸功于它對中間層概念提出了系統(tǒng)性標準。但事實上,它并沒有取得實質(zhì)性的成功,原因主要是因為不管從其效率、難度還是性能上來講都不孚眾望。</p><p> 在J2EE早期階段,都是利用EJB技術(shù)來開發(fā)J2EE應(yīng)用的。但是,對于EJB,其學習成本非常高也難于理解,而且要想應(yīng)用EJB技術(shù)也是相當困難的。因為E
5、JB強制程序員必須依照它的規(guī)范去繼續(xù)各種不同的接口,這樣便會導致代碼冗余及相似。此外對于其配置既是紛繁復雜又是味同嚼蠟。對于使用JNDI查找對象也是如此。雖然xdoclet的應(yīng)運而生和緩了其中部分的開發(fā)工作,但是EJB存在的各大問題都造成了對其使用的不方便性。隨著Java語言的發(fā)展,AOP和IoC等技術(shù)的逐漸成熟,一種新的J2EE解決方案應(yīng)運而生,即輕量級框架。[1]</p><p><b> 研究平
6、臺</b></p><p> 本文主要是基于Eclipse平臺,使用Java語言編寫IoC和AOP的實現(xiàn)程序。</p><p><b> Java語言</b></p><p> Java是一種面向?qū)ο蟮模蒘un公司開發(fā)的程序設(shè)計語言,具體研發(fā)是James Gosling及其同事,在上世紀90年代末正式推出。Java的強大之處
7、在于其跨平臺性,可在不同操作系統(tǒng)上編寫應(yīng)用軟件。Java語言不同于其他編程語言,其優(yōu)勢主要體現(xiàn)在它具有通用、高效、安全等優(yōu)點。而且該語言的應(yīng)用領(lǐng)域也極其廣泛。在微型電腦、數(shù)據(jù)中心、超級計算機以及各種網(wǎng)頁應(yīng)用等都能見到Java的身影。雖然Java的編程風格與之C、C++非常接近,但與C語言不同的是,Java是完全的面相對象,對于C++核心的面向?qū)ο蠹夹g(shù)它也是完美的繼承了。同時,Java一改C中指針的概念,取而代之的是引用的概念。同時也摒棄
8、了C中運算符重載和多繼承等特征。在此基礎(chǔ)上,Java也增加了自己的新特性,就是垃圾回收機制,對于不再引用而又一直在內(nèi)存中的引用進行回收處理。程序員也從中得益而不用手動進行內(nèi)存管理。</p><p><b> Eclipse</b></p><p> Eclipse是一個開源的軟件開發(fā)工具,同時也是功能完備,能進行商用的工業(yè)開發(fā)平臺。主要組成為Eclipse項目、工
9、具項目、技術(shù)項目,具體是指Eclipse Platform,JDT,CDT,PDE。其中,Eclipse Platform是可擴展的集成開發(fā)環(huán)境;JDT是Java開發(fā)工具,主要用于Java開發(fā);CDT是C語言開發(fā)工具,主要用于C開發(fā);PDE則是對插件的開發(fā)。Eclipse為構(gòu)建IDE和建造塊建立堅實的基礎(chǔ)。對于Eclipse Platform,它允許第三方工具的無縫對接,從而起到無須辨別具體工具的功能體現(xiàn)在哪里的作用。</p>
10、;<p><b> IoC和AOP</b></p><p><b> IoC(控制反轉(zhuǎn))</b></p><p> IoC,英文全稱為Inversion of Control,及控制反轉(zhuǎn),主要用于降低程序間的耦合度??刂品崔D(zhuǎn)一般分為兩種類型,依賴注入(Dependency Injection,簡稱DI)和依賴查找(Depend
11、ency Lookup)。依賴注入應(yīng)用比較廣泛。[2]</p><p><b> 依賴注入</b></p><p> 依賴注入就是容器全權(quán)負責組件,給予其回調(diào)接口和上下文條件。EJB和Apache Avalon 都使用這種方式。如此看來,對于依賴對象的查找以及資源的查找就必須使用容器提供的接口,控制反轉(zhuǎn)也就體現(xiàn)在了回調(diào)接口上。容器提供應(yīng)用代碼資源也是通過回調(diào)接口的
12、。 [3]</p><p><b> 實現(xiàn)方式</b></p><p> 對于依賴注入,主要的實現(xiàn)方式分別為接口注入(Interface Injection)、Set方法注入(Setter Injection)和構(gòu)造注入(Constructor Injection)。[4]</p><p><b> 接口注入</b>
13、</p><p> 在接口中定義要注入的信息再通過接口來完成此功能就叫接口注入。具體示例如下:</p><p> 編寫一個IBiz接口,Dao層的注入將通過這個接口進行。假設(shè)該接口中有一getDao()方法,用于獲取數(shù)據(jù)訪問層的對象。</p><p> public interface IBiz{</p><p><b>
14、/**</b></p><p> * @param dao 數(shù)據(jù)訪問層對象</p><p><b> */</b></p><p> public void getDao(Dao dao);</p><p><b> }</b></p><p> 對于想
15、要進行數(shù)據(jù)庫操作的類就必須得實現(xiàn)IBiz接口,業(yè)務(wù)邏輯類Biz實現(xiàn)這個接口IBiz。</p><p><b> /*</b></p><p> * 具體實現(xiàn)IBiz接口的類,重寫了getDao方法</p><p><b> */</b></p><p> public class Biz i
16、mplements IBusiness{</p><p> private Dao dao;</p><p><b> @Override</b></p><p> public void getDao(Dao dao){</p><p> this.dao=dao;</p><p>&l
17、t;b> }</b></p><p><b> }</b></p><p> 只有實現(xiàn)IBiz接口才能完成依賴注入。</p><p><b> Set方法注入</b></p><p> Set方法注入就是在需要屬性注入的類中定義一個Set方法,并設(shè)置注入元素為其參數(shù)。&l
18、t;/p><p> 假設(shè)業(yè)務(wù)層Biz依賴數(shù)據(jù)訪問層,且持有其屬性,需定義一個Set方法來接受數(shù)據(jù)訪問層的注入。</p><p> public class Biz{</p><p> //數(shù)據(jù)訪問層對象的引用</p><p> private Dao dao;</p><p> public void setDa
19、o(Dao dao){</p><p> this.dao=dao;</p><p><b> }</b></p><p> //其他調(diào)用數(shù)據(jù)訪問層的方法及其他操作</p><p><b> }</b></p><p><b> 構(gòu)造注入</b>
20、;</p><p> 構(gòu)造注入就是在需要屬性注入的類中提供一個有參構(gòu)造,其參數(shù)就是注入的元素。假設(shè)業(yè)務(wù)層Biz依賴數(shù)據(jù)訪問層,且持有其屬性,可通過一個構(gòu)造器來接受數(shù)據(jù)訪問層的注入。</p><p> public class Biz{</p><p> private Dao dao;</p><p> public Biz(Dao
21、dao){</p><p> this.dao=dao;</p><p><b> }</b></p><p> //其他調(diào)用數(shù)據(jù)訪問層的方法及其他操作</p><p><b> }</b></p><p><b> IoC圖解</b><
22、/p><p> AOP(面向切面編程) </p><p> AOP就是Aspect Oriented Programming的縮寫,意為:面向切面編程。具體是指它是一種通過預編譯和動態(tài)代理來實現(xiàn)程序功能的統(tǒng)一維護的技術(shù)。[5]AOP是OOP的延續(xù),是軟件開發(fā)中的一個熱點,是函數(shù)式編程的一種衍生范型。AOP技術(shù)可以使業(yè)務(wù)邏輯的各個功能模塊耦合度降低,從而達到提高程序的重用性和開發(fā)效率。 [
23、6]</p><p><b> 實現(xiàn)技術(shù)</b></p><p> 對于AOP技術(shù)的實現(xiàn),主要可通過以下兩種方式實現(xiàn):一種是動態(tài)代理,對原有對象的行為通過截取消息,修飾消息,最終執(zhí)行修飾后的行為;另一種是靜態(tài)織入,以特定語法創(chuàng)建切面,以達到編譯器在編譯期織入切面代碼的目的。[7]然而殊途同歸,實現(xiàn)AOP的技術(shù)特性卻是相同的,分別為:</p><
24、p> join point(連接點):連接點是程序運行過程中具體的執(zhí)行點,比如它 可以是一個方法。對于連接點并不是一個具體的概念,所以在是實現(xiàn)AOP時并不用去定義它。</p><p> point cut(切入點):對于切入點這個概念,它實質(zhì)上是一個捕獲連接點的一種結(jié)構(gòu)。所以在實現(xiàn)AOP中,可通過定義一個切入點來攔截相關(guān)方法的調(diào)用。</p><p> advice(通
25、知):本質(zhì)上是切入點是執(zhí)行程序,具體執(zhí)行切面的邏輯。</p><p> aspect(方面):切點與通知合稱切面,雖與面向?qū)ο笾械念愊嗨?,但它更多的表達的是對象間的橫向關(guān)系。</p><p> introduce(引入):以附加屬性方法的形式達到修改對象結(jié)構(gòu)的目的。有的AOP工具又將其稱為mixin。</p><p><b> 主要目的</b&
26、gt;</p><p> 對于AOP的主要目的大致可分為事務(wù)處理、性能監(jiān)測、日志記錄、安全控制等。[8]</p><p><b> 主要意圖</b></p><p> 對邏輯代碼中事務(wù)處理、性能監(jiān)測、日志記錄、安全控制等的處理從中分離,重新獨立到非向?qū)I(yè)務(wù)方法中。此等做法的好處是在修改這些代碼的時候不影響業(yè)務(wù)邏輯,進一步體現(xiàn)了軟件開發(fā)的“
27、開閉原則”。[9]</p><p> 注解(Annotation)</p><p> Annotation(注解)是JDK5.0及以后版本引入的。對于注解,主要作用大致是監(jiān)測代碼依賴性,創(chuàng)建文檔,通過注解甚至可以執(zhí)行基礎(chǔ)的編譯檢查。[10]注解的編寫方式是以“@”開頭加上自定義的注解名,通過其參數(shù)個數(shù)的不同,大致可分為三類:單值注解、標記注解和完整注解。注解只是作為標識存在,一般不會直
28、接影響到程序的語義,通過反射機制我們可以訪問到這些元數(shù)據(jù),元數(shù)據(jù)就是用來描述數(shù)據(jù)的數(shù)據(jù)。注解的存在級別一共有三種:RUNTIME,CLASS,SOURCE。RUNTIME表示運行時存在,CLASS表示能作用于class文件,SOURCE表示只存在源代碼中。程序員可在編譯時選擇代碼的存在級別。 [11]</p><p><b> 基本作用</b></p><p>
29、雖然對于注解的作用還沒有明確的定義,但是大致可以分為三種:</p><p> 編寫文檔:檢查代碼中存在的標識注解來生成文檔。</p><p> 代碼分析:以代碼中標識的注解對代碼進行分析。</p><p> 編譯檢查:檢查標識的注解使編譯器能執(zhí)行基礎(chǔ)的編譯檢查。[12]</p><p><b> 基本的內(nèi)置注解</b&
30、gt;</p><p> @Override:只能用在方法上,用來申明該方法是改寫父類的。</p><p> @Deprecated:對于棄用的方法添加的注解。當程序員調(diào)用這些方法時, 在編譯時將會顯示提示信息。該注解可添加在程序的所有元素上。 </p><p> @SuperressWarnings:暫時關(guān)閉警告信息。[13]</p>&
31、lt;p> 基于注解的IoC和AOP的實現(xiàn)</p><p> 就IoC而言,主要實現(xiàn)是靠設(shè)計模式中的工廠模式,工廠模式負責將大量具有Component注解的類進行實例化,而不必事先知道每次是要實例化哪一個類。換句話說,工廠模式對于具體的new的細節(jié)都進行了隱藏和封裝。</p><p> 對于工廠模式的優(yōu)點主要分為下列四點:</p><p> 代碼結(jié)構(gòu)清
32、晰,具有良好的封裝性。對于對象的創(chuàng)建不是無條件的。假設(shè)一個調(diào)用者需要一個具體的產(chǎn)品,調(diào)用者并不需要知道產(chǎn)品具體是如何被生產(chǎn)的。對于他而言只需要知道產(chǎn)品類名或者產(chǎn)品約束字符串就可以了,從而降低模塊耦合度。</p><p> 優(yōu)秀的可擴展性。如果具體需求需要增加產(chǎn)品,不必具體對產(chǎn)品類進行修改,只需適當修改工廠類或者再增加一個工廠就可以了。</p><p> 屏蔽產(chǎn)品類。對于具體產(chǎn)品是如何生
33、產(chǎn)的,調(diào)用者并不用關(guān)心,他的關(guān)注點主要在于產(chǎn)品的接口。如果產(chǎn)品接口不發(fā)生變化,那么系統(tǒng)上層的模塊也不會發(fā)生改變。具體的產(chǎn)品的實例化主要由工廠類管理,對于不同的產(chǎn)品對象的生產(chǎn)應(yīng)取決于不同的工廠類。</p><p> 關(guān)于工廠方法的經(jīng)典應(yīng)用就是解耦合了。處于較高層的模塊只需知道實現(xiàn)類的接口,具體實現(xiàn)類無需關(guān)心。對于工廠方法,它也遵循迪米特和依賴倒置法則,僅僅依賴實現(xiàn)類的接口;除此之外,工廠方法也遵循里氏替換原則,子
34、類可以隨時隨地替換父類。[14]</p><p> 而對于AOP來說,在掃描系統(tǒng)組件時,如果該組件存在Interception注解且已聲明需要攔截的方法。那么在調(diào)用存在Interception注解的類的方法時,如果該方法已被攔截,則該方法執(zhí)行前和執(zhí)行后會進行相應(yīng)的操作。而實現(xiàn)AOP技術(shù)主要用到了代理模式。</p><p> 對于使用代理模式,只要有點體現(xiàn)在以下幾個方面:</p&g
35、t;<p> 職責清晰:具體的產(chǎn)品類實現(xiàn)具體的業(yè)務(wù),不必去在意非自身所要實現(xiàn)的業(yè)務(wù)。如需其他業(yè)務(wù)可通過后期代理完成附加,此種做法的好處是代碼簡潔清晰。</p><p> 高擴展性:對于產(chǎn)品類可能需求不同,但是只要是實現(xiàn)了其接口的,可通過代理手段代理各種產(chǎn)品類,而代理類卻不用做任何修改。</p><p> 智能化:代理對象可在運行時才去調(diào)用具體的代理類,換言之就是代理類可
36、以在運行時才確定代理對象。[15]</p><p><b> 注解的編寫</b></p><p> 在本文中,主要用到的注解有@Component,@Property,@Aspect,@Interception。@Component注解主要說明該類是一個組件,用于在初始化容器時將其實例創(chuàng)建放入一個Map中;@Property注解主要說明該類是組件類的屬性,在運行時
37、將注入屬性,以便調(diào)用該類的方法;@Aspect注解主要用于說明該類是一個切面類,用來執(zhí)行在攔截方法執(zhí)行過程中要處理的操作;@Interception注解用于說明該類中的方法需要被攔截,可指定要攔截的方法,攔截下來的方法將先進行其他操作,如事務(wù)處理。具體注解的代碼如下:</p><p> @Component注解:</p><p> public @interface Component
38、 {</p><p> //組件在HashTable中的名字,當為空時默認為組件類名的小寫</p><p> public String name() default "";</p><p> //組件是否存在單例,默認為存在</p><p> public boolean isSingleton() defaul
39、t true;</p><p><b> }</b></p><p> @Property注解:</p><p> public @interface Property {</p><p> //需要注入的屬性注入的對象的名稱,默認為空時則直接獲取組件中屬性的名稱</p><p> pu
40、blic String ref() default "";</p><p><b> }</b></p><p> @Aspect注解:</p><p> public @interface Aspect {</p><p><b> //切面類的名稱</b></p
41、><p> public String name() default "";</p><p><b> }</b></p><p> @Interception注解:</p><p> public @interface Interception {</p><p><
42、;b> //攔截的方法</b></p><p> public String[]methods();</p><p><b> }</b></p><p> IoC實現(xiàn)(對象工廠)</p><p> 首先,在工廠初始化的時候會創(chuàng)建組件的對象,而對于組件類的存放放在對應(yīng)的包中,對于讀取的包及包的
43、掃描則配置在XML中。讀取XML獲取包名及子包名代碼如下:</p><p> String packageInfo="";</p><p> URL url=XMLParse.class.getResource("");</p><p> File file=new File(url.getPath()+xmlName
44、);</p><p> DocumentBuilder builder=null;</p><p><b> try {</b></p><p> builder=DocumentBuilderFactory.newInstance().newDocumentBuilder();</p><p> Documen
45、t doc=builder.parse(file);</p><p> Element ele=doc.getDocumentElement();</p><p> NodeList nls=ele.getChildNodes();</p><p> Element ce=null;</p><p> for (int i = 0;
46、i < nls.getLength(); i++) {</p><p> Node n=nls.item(i);</p><p> if(n.getNodeType()==Node.ELEMENT_NODE){</p><p> if(n.getNodeName().equals("component-package")){</
47、p><p> ce=(Element)n;</p><p><b> break;</b></p><p><b> }</b></p><p><b> }</b></p><p><b> }</b></p>
48、<p> packageInfo=ce.getTextContent();</p><p> } catch (Exception e) {</p><p> e.printStackTrace();</p><p><b> }</b></p><p> 其次通過包名,獲取包中的所有類,而類的存放
49、是以文件形式存在,則需進行文件的掃描。文件掃描代碼如下:</p><p> public void findAndAddClassesInPackageByFile(String packageName,</p><p> String physicsPath, final boolean recursive, Set<Class<?>> classes) {&
50、lt;/p><p> //獲取此包的目錄建立一個file</p><p> File dir=new File(physicsPath);</p><p> //如果不存在或者也不是一個目錄就直接返回</p><p> if(!dir.exists()||!dir.isDirectory()){</p><p>&
51、lt;b> return;</b></p><p><b> }</b></p><p> //如果存在就獲取包下的所有文件及目錄</p><p> File[] dirFiles=dir.listFiles(new FileFilter() {</p><p><b> @Over
52、ride</b></p><p> public boolean accept(File file) {</p><p> //如果可以循環(huán)(即包含子目錄)或是以.class結(jié)尾的文件(即編譯好的java文件)</p><p> return (recursive&&file.isDirectory())||(file.getNam
53、e().endsWith(".class"));</p><p><b> }</b></p><p><b> });</b></p><p><b> //循環(huán)所有文件</b></p><p> for (File file : dirFiles
54、) {</p><p> //如果是目錄則繼續(xù)掃描</p><p> if(file.isDirectory()){</p><p> findAndAddClassesInPackageByFile(packageName+"."+file.getName(), file.getAbsolutePath(), recursive, cla
55、sses);</p><p><b> }else{</b></p><p> //如果是java類文件去掉后面的.class只留下類名</p><p> String className=file.getName().substring(0,file.getName().length()-6);</p><p>
56、 //System.out.println(className);</p><p><b> try {</b></p><p><b> //添加到集合中</b></p><p> //System.out.println(packageName+'.'+className);</p>
57、<p> classes.add(Thread.currentThread().getContextClassLoader().loadClass(packageName+'.'+className));</p><p> } catch (Exception e) {</p><p> e.printStackTrace();</p>&
58、lt;p><b> }</b></p><p><b> }</b></p><p><b> }</b></p><p><b> }</b></p><p> 獲取包中所有類的代碼如下:</p><p> pu
59、blic Set<Class<?>>getClasses(String packages){</p><p> //存放包中的class</p><p> Set<Class<?>>classes=new LinkedHashSet<Class<?>>();</p><p><b>
60、; //是否迭代循環(huán)</b></p><p> boolean recursive=true;</p><p> //將包名從以"."隔開換成以"/"隔開</p><p> String packageName=packages;</p><p> String packageTo
61、Dir=packageName.replace(".", "/");</p><p> //System.out.println(packageToDir);</p><p> //定義一個枚舉的集合循環(huán)處理該目錄下的所有東西</p><p> Enumeration<URL> dirs;</p>
62、<p><b> try {</b></p><p> dirs=Thread.currentThread().getContextClassLoader().getResources(packageToDir);</p><p><b> //循環(huán)迭代</b></p><p> while(dirs
63、.hasMoreElements()){</p><p><b> //獲取下一個元素</b></p><p> URL url=dirs.nextElement();</p><p><b> //獲取協(xié)議名</b></p><p> String protocal=url.getProt
64、ocol();</p><p> //如果是文件形式保存在服務(wù)器上</p><p> if("file".equals(protocal)){</p><p> //System.err.println("file類型的掃描");</p><p> //獲取包的物理路勁</p>&
65、lt;p> String physicsPath=URLDecoder.decode(url.getFile(), "utf-8");</p><p> //sSystem.out.println(physicsPath);</p><p> //以文件方式掃描整個包下的文件并添加到集合中</p><p> findAndAddCl
66、assesInPackageByFile(packageName,physicsPath,recursive,classes);</p><p> }else if("jar".equals(protocal)){</p><p> //如果是jar文件,則定義一個jarFile</p><p> JarFile jar;</p>
67、;<p><b> try {</b></p><p><b> //獲取jar</b></p><p> jar=((JarURLConnection)url.openConnection()).getJarFile();</p><p> //從此jar包中獲取一個枚舉類</p>&
68、lt;p> Enumeration<JarEntry>entries=jar.entries();</p><p> //同樣進行循環(huán)迭代</p><p> while(entries.hasMoreElements()){</p><p> //獲取jar里的一個實體,可以是目錄和一些jar包里的其他文件,如META-INF等文件<
69、/p><p> JarEntry entry=entries.nextElement();</p><p> String name=entry.getName();</p><p> //如果以"/"開頭</p><p> if(name.charAt(0)=='/'){</p><
70、;p> //獲取"/"后的字符串</p><p> name=name.substring(1);</p><p><b> }</b></p><p> //如果前半部分與定義的包名相同</p><p> if(name.startsWith(packageToDir)){</
71、p><p> //若以"/"結(jié)尾是一個包</p><p> int index=name.lastIndexOf("/");</p><p> if(index!=-1){</p><p> //獲取包名且把"/"替換成"."</p><p
72、> packageName=name.substring(0,index).replace("/", ".");</p><p><b> }</b></p><p> //若可迭代下去且是一個包</p><p> if((index!=-1)||recursive){</p>
73、<p> if(name.endsWith(".class")&&!entry.isDirectory()){</p><p> //去掉".class"獲取正真的類名</p><p> String className=name.substring(packageName.length()+1,name.lengt
74、h()-6);</p><p><b> try {</b></p><p> //添加到classes中</p><p> classes.add(Class.forName(packageName+"."+className));</p><p> } catch (Exception e
75、) {</p><p> e.printStackTrace();</p><p><b> }</b></p><p><b> }</b></p><p><b> }</b></p><p><b> }</b>&l
76、t;/p><p><b> } </b></p><p> }catch (Exception e) {</p><p> e.printStackTrace();</p><p><b> }</b></p><p><b> }</b><
77、/p><p><b> }</b></p><p> } catch (Exception e) {</p><p> e.printStackTrace();</p><p><b> }</b></p><p> return classes;</p>
78、<p><b> }</b></p><p> 接著就是對工廠的初始化。具體代碼如下:</p><p> public void init() {</p><p> //獲取配置文件中的包信息</p><p> String packageInfo=XMLParse.getInstance().ge
79、tPackage();</p><p> //System.out.println(packageInfo);</p><p> //獲取包下的所有class</p><p> Set<Class<?>>classes=getClasses(packageInfo);</p><p> //System.out
80、.println(classes.size());</p><p> for (Class<?> cls : classes) {</p><p> //判斷是否存在Component注解</p><p> if(cls.isAnnotationPresent(Component.class)){</p><p><b
81、> //獲取注解對象</b></p><p> Component component=cls.getAnnotation(Component.class);</p><p> //獲取注解name的屬性值</p><p> String comName=component.name();</p><p><b
82、> try {</b></p><p> //判斷注解comName是否為空</p><p> if(comName.equals("")){</p><p> //如果為空將comName設(shè)置為類名的小寫</p><p> comName=cls.getSimpleName();</p&
83、gt;<p> comName=comName.substring(0,1).toLowerCase()+comName.substring(1);</p><p> //System.out.println(comName);</p><p><b> }</b></p><p> //最終將處理后或未處理的類名對應(yīng)的實
84、例存入cms中</p><p> cms.put(comName, cls.newInstance());</p><p> } catch (Exception e) {</p><p> e.printStackTrace();</p><p><b> }</b></p><p>&
85、lt;b> }</b></p><p><b> }</b></p><p><b> }</b></p><p> 接下來則是在程序運行過程中,對存在@Property注解的屬性進行屬性注入,獲取其對應(yīng)的實例對象。具體代碼如下:</p><p> public <
86、T> T getObject(String name,Class<T> cz){</p><p> T target=(T)cms.get(name);</p><p> //獲取組件時首先要判斷該組件是否存在</p><p> if(target==null){</p><p> throw new Runtime
87、Exception("對象不存在");</p><p><b> }</b></p><p> //如果對象存在,則要判斷對象是否需要注入屬性,如果需要注入屬性,則先注入屬性在返回對象</p><p> Field []fields=target.getClass().getDeclaredFields();</
88、p><p> for (Field field : fields) {</p><p> //判斷該屬性是否存在Property注解</p><p> if(field.isAnnotationPresent(Property.class)){</p><p><b> //獲取屬性名</b></p>
89、<p> String fieldName=field.getName();</p><p> Property pro=(Property)field.getAnnotation(Property.class);</p><p> String ref=pro.ref();</p><p> //判斷ref是否為空</p><
90、p> if(ref.equals("")){</p><p> ref=fieldName;</p><p><b> }</b></p><p> //獲取set方法的名稱</p><p> String methodName="set"+fieldName.su
91、bstring(0,1).toUpperCase()+fieldName.substring(1);</p><p><b> try {</b></p><p> Method m=cz.getMethod(methodName, field.getType());</p><p> m.invoke(target, this.getO
92、bject(ref, field.getType()));</p><p> } catch (Exception e) {</p><p> e.printStackTrace();</p><p><b> }</b></p><p> //target=this.getObject(fieldName, c
93、z);</p><p><b> }</b></p><p><b> }</b></p><p> if(target.getClass().isAnnotationPresent(Interception.class)){</p><p> Interception inter=targ
94、et.getClass().getAnnotation(Interception.class);</p><p><b> //攔截的方法</b></p><p> String methods[]=inter.methods();</p><p> SpringInterceptor mi=null;</p><p&
95、gt;<b> try {</b></p><p> mi=(SpringInterceptor)Class.forName(interceptionName).newInstance();</p><p> mi.setMethodsName(methods);</p><p> mi.setTarget(target.getClas
96、s().newInstance());</p><p> } catch(ClassNotFoundException e){</p><p> e.printStackTrace();</p><p> }catch (InstantiationException e) {</p><p> // TODO Auto-generat
97、ed catch block</p><p> e.printStackTrace();</p><p> } catch (IllegalAccessException e) {</p><p> // TODO Auto-generated catch block</p><p> e.printStackTrace();<
98、/p><p><b> }</b></p><p> return (T)mi.getInstance();</p><p><b> }</b></p><p> return target;</p><p><b> }</b></p&g
99、t;<p> 在屬性注入的同時會判斷該屬性是否存在攔截器以及要攔截的方法。接下來則是利用AOP實現(xiàn)攔截器功能。</p><p> AOP實現(xiàn)(攔截器)</p><p> 對于攔截器,其實就是代理模式的具體實現(xiàn),首先需實現(xiàn)InvocationHandler接口,該接口是代理實例的調(diào)用處理程序?qū)崿F(xiàn)的接口。對于各個代理實例都被聯(lián)接了具體的處理程序代碼。在代理實例調(diào)用處理程序時
100、,將對該程序方法編碼設(shè)置且將其指派到它的invoke方法。 </p><p> 以下是實現(xiàn)InvocationHandler的抽象類,該類需要一個目標對象及該目標對象需要攔截的方法。具體代碼如下:</p><p> public abstract class SpringInterceptor implements InvocationHandler {</p><
101、p><b> //目標對象</b></p><p> private Object target;</p><p><b> //所要攔截的方法</b></p><p> private String[] methodsName;</p><p> public Object get
102、Instance(){</p><p> Object obj=Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);</p><p> return obj;</p><p><b> }</b&g
103、t;</p><p> public void setTarget(Object target){</p><p> this.target=target;</p><p><b> }</b></p><p> public void setMethodsName(String[] methodsName){&
104、lt;/p><p> this.methodsName=methodsName;</p><p><b> }</b></p><p><b> @Override</b></p><p> public Object invoke(Object proxy, Method method, Ob
105、ject[] args)</p><p> throws Throwable {</p><p> for (String name : methodsName) {</p><p> if(name.equals(method.getName())){</p><p> return interceptor(target,metho
106、d,args);</p><p><b> }</b></p><p><b> }</b></p><p> return method.invoke(target, args);</p><p><b> }</b></p><p><
107、b> /**</b></p><p><b> * </b></p><p> * @param target 攔截類的對象</p><p> * @param method 攔截的方法</p><p> * @param args 方法的參數(shù)</p><p> *
108、@return 返回值</p><p> * @throws IllegalArgumentException</p><p> * @throws IllegalAccessException</p><p> * @throws InvocationTargetException</p><p><b> */</
109、b></p><p> public abstract Object interceptor(Object target, Method method, Object[] args)throws IllegalArgumentException, IllegalAccessException, InvocationTargetException;</p><p><b>
110、; }</b></p><p> 接下來則是編寫具體實現(xiàn)攔截功能的實現(xiàn)類。具體代碼如下:</p><p> public class MyInterception extends SpringInterceptor {</p><p><b> @Override</b></p><p> publ
111、ic Object interceptor(Object target, Method method, Object[] args)</p><p> throws IllegalArgumentException, IllegalAccessException,</p><p> InvocationTargetException {</p><p> Ob
112、ject result=null;</p><p> System.out.println("開啟事務(wù)");</p><p> result=method.invoke(target, args);</p><p> System.out.println("提交事務(wù)");</p><p> re
113、turn result;</p><p><b> }</b></p><p><b> }</b></p><p> 至此,基本實現(xiàn)了攔截器功能。對于AOP編程,能實現(xiàn)的功能主要有事務(wù)處理、性能監(jiān)測、日志記錄、安全控制等,在這里只是象征性的輸出語句。</p><p> IoC和AOP實現(xiàn)流
114、程圖</p><p> 根據(jù)IoC和AOP的描述以及實現(xiàn)程序,繪制了實現(xiàn)的基本流程圖,如圖3.1和圖3.2所示:</p><p> 基于注解的IoC和AOP的框架在WEB中的應(yīng)用</p><p> 下面是該框架在WEB中的應(yīng)用,主要為了驗證IoC和AOP,所以只是實現(xiàn)了簡單的增刪改查,而沒有過多是去追求系統(tǒng)的其他功能。前臺顯示頁面利用AJAX異步請求數(shù)據(jù),當訪
115、問主頁就會顯示數(shù)據(jù),對于顯示的方法并沒有進行攔截。提供基本的增刪改功能,當點擊相應(yīng)功能時會提交給servlet進行處理,servlet中將創(chuàng)建service層的對象,而對象的創(chuàng)建利用框架中的獲取對象方法,而不是直接new出來,實現(xiàn)了層與層之間的松耦合。在service層將申明dao層的屬性,配有setDao方法獲取屬性對象。而在dao層中將實現(xiàn)方法的攔截,攔截的方法主要就是增刪改,對于攔截的方法會進行相應(yīng)的處理,而在這只是象征性的輸出語
116、句。下面是WEB的具體實現(xiàn)。</p><p> 表4.1 用戶信息表</p><p><b> 用戶顯示</b></p><p> 當客戶端訪問主界面時,主界面中利用AJAX異步請求servlet,將傳過去一個op,也就是請求的操作。servlet根據(jù)請求的op判斷該執(zhí)行什么操作,然后調(diào)用相應(yīng)的方法。在這里則是進行查詢操作。在servle
117、t中將使用框架中的對象工廠獲取service層,也就是業(yè)務(wù)層的對象,所以servlet將調(diào)用service層的查詢方法。而在service層中存在dao層(數(shù)據(jù)訪問層)的屬性,要想獲取dao層的對象,首先需對dao屬性進行set處理,這樣在對象工廠初始化的時候凡是有@Property注解的將通過set方式注入其對象。當然也會判斷該屬性對應(yīng)的類是否需要方法攔截。在該web顯示中只對修改、刪除和更新用戶的方法進行了攔截,對于其他方法并沒有進
118、行攔截。用戶顯示如下圖所示:</p><p> 圖4.2 用戶信息顯示</p><p> 查詢用戶的servlet代碼如下所示:</p><p><b> //查詢相關(guān)用戶</b></p><p> List<User>users=userService.queryUser();</p>
119、<p> ObjectMapper mapper=new ObjectMapper();</p><p> //將其轉(zhuǎn)換成json數(shù)據(jù)</p><p> String json=mapper.writeValueAsString(users);</p><p> response.setCharacterEncoding("utf-8&
120、quot;);</p><p> PrintWriter pw=response.getWriter();</p><p> pw.write(json);</p><p> pw.flush();</p><p> pw.close();</p><p><b> 用戶的增刪改</b>
121、</p><p> 對于用戶的增刪改操作,具體實現(xiàn)方法不同,但大致的操作過程和查詢用戶類似,在這里就不再贅述。唯一有區(qū)別的就是,對于用戶的增刪改方法進行了方法攔截,即在dao層中存在@Intecerption注解,并指明了攔截的方法有“saveUser”,“delUser”和“updateUser”。對于攔截的方法采用AOP編程思想,將調(diào)用具有@Aspect注解的類,在方法執(zhí)行過程中執(zhí)行該類相應(yīng)的方法。但是在本
122、web實現(xiàn)中也只是象征性的輸出語句。具體增加修改用戶的頁面和進行攔截的結(jié)果如下所示:</p><p><b> 圖4.3 增加用戶</b></p><p><b> 圖4.4 修改用戶</b></p><p> 增刪改底層公共代碼如下:</p><p><b> /**</b
123、></p><p> * 底層增刪改公共類</p><p> * @param sql 執(zhí)行的sql語句</p><p> * @param o sql語句占位參數(shù)</p><p><b> */</b></p><p> public void execute(String sq
124、l,Object[] o){</p><p> Connection con=null;</p><p> PreparedStatement ps=null;</p><p><b> try {</b></p><p> con=getCon();</p><p> ps=con.p
125、repareStatement(sql);</p><p> for (int i = 0; i < o.length; i++) {</p><p> ps.setObject(i+1, o[i]);</p><p><b> }</b></p><p> ps.executeUpdate();</
126、p><p> } catch (Exception e) {</p><p> e.printStackTrace();</p><p><b> }finally{</b></p><p> closeAll(null, ps, con);</p><p><b> }</
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 眾賞文庫僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 五層框架結(jié)構(gòu)畢業(yè)設(shè)計論文
- 框架畢業(yè)設(shè)計.rar
- 框架畢業(yè)設(shè)計.rar
- 框架畢業(yè)設(shè)計.rar
- 框架畢業(yè)設(shè)計.rar
- 框架畢業(yè)設(shè)計.rar
- 多層框架(畢業(yè)設(shè)計)
- 框架畢業(yè)設(shè)計.rar
- 運用essh框架的考勤日志系統(tǒng)畢業(yè)設(shè)計(論文)
- 畢業(yè)設(shè)計---某框架多層住宅結(jié)構(gòu)畢業(yè)設(shè)計
- 背光框架畢業(yè)設(shè)計---設(shè)計背光框架的數(shù)控加工工藝設(shè)計
- 論文框架辦公樓畢業(yè)設(shè)計計算書
- 辦公樓框架結(jié)構(gòu)-畢業(yè)設(shè)計論文
- 建筑畢業(yè)設(shè)計--中框架5軸框架的抗震設(shè)計
- 畢業(yè)設(shè)計(論文)+道路排水畢業(yè)設(shè)計論文
- 畢業(yè)設(shè)計論文 畢業(yè)設(shè)計管理系統(tǒng)設(shè)計
- 液壓系統(tǒng)設(shè)計論文畢業(yè)設(shè)計(doc畢業(yè)設(shè)計論文)
- 十一層框架畢業(yè)設(shè)計
- 標準框架廠房畢業(yè)設(shè)計
- 五層框架畢業(yè)設(shè)計
評論
0/150
提交評論