版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
可能解決該問題的方法是設(shè)計(jì)模式。GOF將面向?qū)ο筌浖脑O(shè)計(jì)經(jīng)驗(yàn)作為設(shè)計(jì)模式下來,它使Aspect-OrientedProgramming(面向方面編程,AOP)正好可以解決這一問題。它允許開發(fā)者面向方面編程(AOP)是施樂公司(XeroxPARC)在上世紀(jì)90年代發(fā)明的一大型的企業(yè)級(jí)應(yīng)用越來越需要人們將業(yè)務(wù)與公共業(yè)務(wù)分離。AOP技術(shù)正是通過編寫橫切關(guān)注點(diǎn)企業(yè)的商業(yè)邏輯。因此,AOP技術(shù)也就受到越來越多的關(guān)注,而應(yīng)用于各種平臺(tái)下的AOP技術(shù)也應(yīng)運(yùn)而生。但由于AOP技術(shù)相對于成OOP技術(shù)而言,在性能、穩(wěn)定性、適用性等方面還有 AOP1990XeroxPaloAltoResearchLab(PARC)或以通過減少代碼重復(fù)模塊從而幫助開發(fā)人員提高工作效率。隨著研究的逐漸深入,AOP也逐AOP的技術(shù)也應(yīng)運(yùn)而生。AOPJavaPARC對于面向方面編程進(jìn)行研究的同時(shí),NortheasternUniversity的博士生CristinaLopes和其同事也開始了類似的思考。最終,國防先進(jìn)技術(shù)研究計(jì)劃署(DefenseAdvancedResearchProjectsAgencyDARPA)注意到了2002EclipseFoundationAOP技術(shù)的先鋒,也是目前最A(yù)OP工具。AspectWerkzJavaAOP框架。AspectWerkz仍然是開源社區(qū)中的產(chǎn)AspectWerkz2.0。20051月,AspectJAspectWerkz達(dá)成協(xié)議,同意將二者AspectJ5,它擴(kuò)Java5AOP支持。(InversionofControl,控制反轉(zhuǎn)模式)AOPSpringAOP2004年,Spring事務(wù)管理、日志和其他各種特性的上下文中。在.Net的陣營中,AOPJavaAOP的關(guān)注。20051月,微軟發(fā)布的發(fā)展的原動(dòng)力并非微軟,而是開源社區(qū)。雖然,微軟的技術(shù)專家們亦然聽到了在.NetFrameworkAOP技術(shù)的群眾呼聲,但作為如此巨大的軟件公司,要讓它靈活地轉(zhuǎn)變戰(zhàn)略方向,顯然是不AOP技術(shù)的研究與探索上一個(gè)巨大的發(fā)展空間。段。但一些在技術(shù)上領(lǐng)先且逐漸成AOP產(chǎn)品,也在開源社區(qū)中漸露崢嶸。這其中主要包括Aspect#,AspectDNG,EosAOP等。Aspect#是基于Castle動(dòng)態(tài)技術(shù)來實(shí)現(xiàn)的。Castle源于ApacheAvalon項(xiàng)目,其目的在于實(shí)IL級(jí)別下的代碼織入,因此在.Net平臺(tái)下,并不受具體的編程語言限制。Professor)Eos誕生之初,就帶有濃厚的學(xué)院派特色。AOP的本質(zhì),以及它的技術(shù)要素。AOP(Aspect-entedProgammng,面向方面編程),可以說是P(je-entedPogamng,面向?qū)ο缶幊蹋┑难a(bǔ)充和完善。P引入封裝、繼承和多態(tài)性等概念來建立一種對象層次結(jié)構(gòu),用以模擬公共行為的一個(gè)集合。當(dāng)我們需要為分散的對象引入公共行為的時(shí)候,O則顯得為力。也就是說,OP允許你定義從上到下的關(guān)系,但并不適合定義從左到右的關(guān)系。例如日志功能日志代碼往往水平地散布在所有對象層次中而與它所散布到的對象的功能毫無(cross-cutnPAOP技術(shù)則恰恰相反,它利用一種稱為“橫切”的技術(shù),剖解開封裝的對象內(nèi)部,并將那些影響了降低模塊間的耦合度,并有利于未來的可操作性和可性。AOP代表的是一個(gè)橫向的關(guān)系,如果使用“橫切”技術(shù),AOP把軟件系統(tǒng)分為兩個(gè)部分:關(guān)注點(diǎn)和橫切關(guān)注點(diǎn)。業(yè)務(wù)處理的主要流程關(guān)注點(diǎn)的多處,而各處都基本相似。比如權(quán)限認(rèn)證、日志、事務(wù)處理。Aop的作用在于分離系統(tǒng)中實(shí)現(xiàn)AOP的技術(shù),主要分為兩大類:一是采用動(dòng)態(tài)技術(shù),利用截取消息的方式,對該消息進(jìn)行1、joinpoint(連接點(diǎn)):是程序執(zhí)行中的一個(gè)精確執(zhí)行點(diǎn),例如類中的一個(gè)方法。它是一個(gè)抽象AOPjoinpoint。2、pointcut(切入點(diǎn)):AOPpointcut,,,權(quán)、安全及性能問題等,許多關(guān)注點(diǎn)——即橫切關(guān)注點(diǎn)(crosscuttingconcerns)——會(huì)在多個(gè)模實(shí)現(xiàn)和演進(jìn)。AOP能夠比上述方法更好地分離系統(tǒng)關(guān)注點(diǎn),從而提供模塊化的橫切關(guān)注點(diǎn)。例如一個(gè)復(fù)雜的系統(tǒng),它由許多關(guān)注點(diǎn)組合實(shí)現(xiàn),如業(yè)務(wù)邏輯、性能,數(shù)據(jù)、日志和調(diào)度信息、、安全、線程、錯(cuò)誤檢查等,還有開發(fā)過程中的關(guān)注點(diǎn),如易懂、易、易追查、易擴(kuò)展等,2.1演示了由不同模塊實(shí)現(xiàn)的一批關(guān)注點(diǎn)組成一個(gè)系統(tǒng)。2.1邏輯模塊所共同需要的,這些邏輯分布于關(guān)注點(diǎn)的各處。在AOP中,諸如這些模塊,都稱為橫AOP的橫切技術(shù),關(guān)鍵就是要實(shí)現(xiàn)對關(guān)注點(diǎn)的識(shí)別。2.2上圖識(shí)別出來的關(guān)注點(diǎn)中,BusinessLogic屬于關(guān)注點(diǎn),它會(huì)調(diào)用到Security,Logging,Persistence等橫切關(guān)注點(diǎn)。publicclass{publicvoid{}}BusinessLogic類中不再包含橫切關(guān)注點(diǎn)的邏輯代碼,為達(dá)到調(diào)用橫切關(guān)注點(diǎn)的目的,可以利用橫BusinessLogicSomeOperation()方法,然后將這些“aspect”2.3:圖2.3將橫切關(guān)注點(diǎn)織入到關(guān)注點(diǎn)AOPAOP的思想,分離出發(fā)人員就可以專注于關(guān)注點(diǎn),將精力投入到解決企業(yè)的商業(yè)邏輯上來。同時(shí),這些封裝好了的橫AOP。AOP動(dòng)態(tài)橫切中實(shí)現(xiàn)的意義??紤]一個(gè)電子商務(wù)系統(tǒng),需要對訂單進(jìn)行添加、刪除等管理操作。,在實(shí)際的應(yīng)用場景中,這些行為應(yīng)與權(quán)限管理結(jié)合,只有獲得的用戶方能夠?qū)嵤┻@些行為。采用傳統(tǒng)的設(shè)計(jì)方法,其偽publicclass{privateArrayListm_Orders;publicOrderManager(){m_Orders=new}publicvoidAddOrder(Order{if{}}publicvoidRemoveOrder(Order{if{}}}publicclass{privateArrayListm_Products;publicProductManager(){m_Products=new}publicvoidAddProduct(Product{if{}}publicvoidRemoveProduct(Product{if{}}},2.4所示:,2.4,利用AOP技術(shù),我們可以分離出系統(tǒng)的關(guān)注點(diǎn)和橫切關(guān)注點(diǎn),從橫向的角度,截取AOPjoinpoint。對于電子商務(wù)系統(tǒng)而言,每個(gè)需限驗(yàn)證的方法都是一個(gè)單獨(dú)的joinpoint。由于權(quán)限驗(yàn)證將在每個(gè)方法執(zhí)行前執(zhí)行,adviceaspect。privatestaticaspectAuthorizationAspect{……}privatepointcutexecution(publicvoidOrderManager.AddOrder(Order))||execution(publicvoidOrderManager.DeleteOrder(Order))||execution(publicvoidProductManager.AddProduct(Product))||execution(publicvoidProductManager.DeleteProduct(Product));before():{if{thrownew}}pointcutadvice邏輯。如此以來,OrderManager和ProductManager模塊就與權(quán)限管理模塊完全解除了依賴關(guān)系,同時(shí)也消除了傳統(tǒng)設(shè)計(jì)中不可避免AOPintroducemixin。AOP技術(shù)中,受到的關(guān)注相對較少。事實(shí)上,這一技術(shù)蘊(yùn)含的潛力是巨大的。使用靜態(tài)Mail完成了收發(fā)郵件的功能。但在產(chǎn)品交付IValidatable:publicinterface{bool}MailAdapterIValidatableMail類:publicclass{publicbool{if(this.getToAddress()!={return}{return}}}Mailmail=newIValidatablevalidate=Mailmail=newintroduceaspect中完成:importpublicaspect{declareparents:Mailimplementspublicboolean{if(this.getToAddress()!={return}{return}}}MailAdapterMailValidateAspect方Mailmail=newIValidatablevalidate=2.3AOP、AOP技術(shù)的優(yōu)勢是顯而易見的。在面向?qū)ο蟮氖澜缋?,人們提出了各種方法和設(shè)計(jì)原則來保障系統(tǒng)、通過“橫切”技術(shù),AOP技術(shù)就能深入到對象內(nèi)部翻云覆雨,截取方法之間傳遞的消息為我所用。由創(chuàng)建一段單獨(dú)的代碼片段,AOP提供了解決這一問題的持久簡單的方案,這一方案強(qiáng)調(diào)了未來功能的重用性和易性:不需要在整個(gè)應(yīng)用程序中一遍遍重新編寫日志代碼,AOP使得僅僅編寫日志方面(loggingaspect)成為可能,并且可以在這之上為整個(gè)應(yīng)用程序提供新的功能。總而言之,AOP技術(shù)的優(yōu)勢使得需要編寫的代碼量大大縮減,節(jié)省了時(shí)間,控制了開發(fā)成本。同時(shí) (seperationofconcerns)JavaJ2EE莫屬。J2EEJ2EEJ2EEJ2EE應(yīng)J2EETomcatJBoss、Websphere、WebLogic等。從J2EE將應(yīng)用系統(tǒng)和容器分離的策略,我們能夠看到AOP的。J2EE應(yīng)用系統(tǒng)就相當(dāng)于AOP技術(shù)中的關(guān)注點(diǎn),它的內(nèi)容主要包括企業(yè)系統(tǒng)的商業(yè)邏輯;而J2EE容器則類似于橫切關(guān)注點(diǎn),J2EEEJB這種重量級(jí)容器服務(wù)器而言,雖J2EE技術(shù)的強(qiáng)勢地位。而所謂“輕量級(jí)容器”EJB提供的重量級(jí)架構(gòu)的區(qū)別,就在于借助了AOP技術(shù)和IoC(InversionofControl,反轉(zhuǎn)模式)機(jī)制,降低了代碼對于接口的依賴AOPJava對象,那么深盔重鎧的應(yīng)用服務(wù)器就不再有存在正是看到了AOP技術(shù)在企業(yè)級(jí)開發(fā)中的巨大潛力而“輕量級(jí)容器”也喚起了EJB容器的呼(事實(shí)上,的EJBV3.0標(biāo)準(zhǔn)就使用了輕量級(jí)容器模型),越來越多的AOP工具在Java平臺(tái)下應(yīng)AOPJBossAOP等。AspectJ、SpringAOPJBossAOP進(jìn)行比較。AspectJAOPJavaAOP語法,以pointcut等特殊關(guān)鍵字,然后利用靜態(tài)織入的方式,修改需要被截取的方法所屬類的源代碼,把a(bǔ)dvice或者introduce的業(yè)務(wù)邏輯代碼注入到正確的位置。利用AspectJ,可以將關(guān)注點(diǎn)完全AOP技術(shù)的系統(tǒng)在運(yùn)行性AOP雖然在性能上具備一定的優(yōu)勢,但它同時(shí)會(huì)給開發(fā)帶來一定的問題。SpringAOPSpring框架中的一部分,但可以作為一個(gè)獨(dú)立的模塊單獨(dú)存在。SpringAOP實(shí)現(xiàn)AOP技術(shù)從本質(zhì)上來講,是利用了JDK提供的動(dòng)態(tài)技術(shù)。而從實(shí)際的實(shí)現(xiàn)方式來看,則是利用了IoC(InversionofControl,反轉(zhuǎn)模式)機(jī)制,同時(shí)采用了AOP(AOPAlliance)的通用作為設(shè)定的觸發(fā)條件。InterceptorAOPadvice,但該Interceptor需要實(shí)現(xiàn)AOP的通用AOP接口,例如ercept.MethodInterceptor。最后定義一個(gè)SpringAOPFactory用AOPIoCadvice注入到接口以及實(shí)現(xiàn)類中。JBoss4.0AOPSpringJBoss應(yīng)用服務(wù)器緊密結(jié)合,也可以單獨(dú)運(yùn)行在自己的應(yīng)用中。JBossAOP同樣需要Interceptor器來完成對方法的,它要求Interceptororg.jboss.aop.Interceptor接口。在這個(gè)接口中最重要的方法就是invoke()。該方法對元數(shù)據(jù)直接進(jìn)行操作,并利用反射的原理去方法的消息。InterceptorAOPAspectJ在實(shí)現(xiàn)上是迥然不同的兩種方式。Aspect中的方面類似于Java語言中的類,如圖3.1所示AspectJJava語言語法和語義的擴(kuò)展,所以它提供了自己的一套處理方面的關(guān)鍵字。除了包含字段和方法之外,AspectJ的方面還包含pointcut和advice成員。示例中的pointcutpointcut參數(shù)提供。advicepointcut則用this(account)把它綁定。這樣做似。advice可以包含認(rèn)證代碼,或者就像在這個(gè)示例中一樣,可以調(diào)用其他方法。JBossAOP基于XML的風(fēng)格來方面,如圖3.2所示3.2JBossAOP的方面在XML風(fēng)格中,aspect、pointcut和advice的都以XML形式表示的。advice的實(shí)現(xiàn),用JavaJBossAOP框架調(diào)用。pointcutpointcutadvice的綁定都在方面中用XML注釋。JBoss沒有顯式地綁定Account參數(shù),而是提供了對當(dāng)前正在執(zhí)行的對象的反射,因此需要把類型轉(zhuǎn)換到對應(yīng)的類型。JBossAOP還可以通過的方式對方面進(jìn)行聲明。均以“@”字符開始,它的使用有點(diǎn)類似于.Net中的Attribute。SpringAOP同樣是基于XML的風(fēng)格來方面,如圖3.3所示3.3SpringAOP的方面JBossAOP類似,SpringadviceJavaSpring框架調(diào)用。XML描述accountBean,Spring框架通過它Account對象包括通知使用的器advisor及其匹配模式,還有應(yīng)用到模式的向前(before)通知。SpringAOPJBossAOPSpringAOPSpring框架方便的、最小化的運(yùn)行時(shí)配置,所以不需要獨(dú)立的啟動(dòng)器。AspectJ、JBossAOPSpringAOP之間的區(qū)別。pointcut匹配和復(fù)合:AspectJ和JBossAOP提供了類似的類型模式支持。它們都允許簽名方面的匹配,對于Java5應(yīng)用程序來說,這些匹配包括注釋和泛型。AspectJ提供了一種簡潔SpringAOP還提供了對正則表達(dá)式的支持。雖然這看起來可能是一個(gè)強(qiáng)大的優(yōu)勢,但還是要其pointcut讀起來不是太難,同時(shí)不會(huì)存在潛在的損害。pointcut復(fù)合操作符基本上都是相同的。SpringAOP不提供“非”操作,這個(gè)操作通常與沒有在SpringAOP連接點(diǎn)模型的容器(containment)連接點(diǎn)結(jié)合使用。advice形式:AspectJ支持比其他技術(shù)的advice形式而JBossAOP只支持一種advicearoundadviceJBoss的技術(shù)是無限的,而且它advice去遵守普通的Java(XML風(fēng)格做的那樣joinpoint上下文:在AspectJ中,通過指定和綁定pointcut參數(shù)動(dòng)態(tài)連接點(diǎn)的狀態(tài),類似于在Java語言中方法參數(shù)的技術(shù)(請參閱圖3.1)。這為連接點(diǎn)上下文提供了靜態(tài)類型化的好處。JBossAOP和SpringAOP反射性地連接點(diǎn)的狀態(tài),這消除了在切入點(diǎn)表達(dá)式中參數(shù)綁定的復(fù)雜性,代價(jià)是參數(shù)靜態(tài)類型化。Java程序員習(xí)慣了方法參數(shù)靜態(tài)類型化帶來的好處,同擴(kuò)展性:aspectpointcutjoinpoint。AspectJ用抽象方面支持?jǐn)U。JBossAOPaspect的子類、并在XMLadvice綁定而實(shí)現(xiàn)的。pointcutadvice的顯式綁定為JBossAOP提供了顯著優(yōu)勢,從而可以很容易地把方面擴(kuò)展到新系統(tǒng),無需要生成子類。AspectJ提供的特殊語法。接下來,我將通過一些實(shí)例,介紹AspectJAOP技術(shù)。中識(shí)別出橫切關(guān)注點(diǎn)——日志記錄。因此,我們需要定義關(guān)于“日志記錄”aspect:publicaspect{pointcutpublicMethods():execution(public*org.apache.cactus..*(..));pointcutlogObjectCalls():execution(*Logger.*(..));pointcutloggableCalls():publicMethods()&&!before():{}after():{}}pointcutadvice。pointcut共有三個(gè):publicMethod、logObjectCallsloggableCalls。publicMethod將選擇org.apache.cactus包中的所有公共(public)方法的執(zhí)行。所謂“選擇”joinpointpointcutadvicepointcut中,execution是一個(gè)原始的Pointcut(就象int是一種原始的Java類型)。它選擇與括號(hào)中定義的方法說明匹配的任何方法的執(zhí)行。方法說明允許包含通配符。logObjectCallspointcut則選擇Loggerpointcut比較特殊,它使用&&Pointcut,Logger類中的公共方法以外,org.apache.cactus中所有的公共方法。advice在aspect中被用來完成實(shí)際的日志advice有三種分別為beforeafter和around。advice:before():{}法除外)advice定義的邏輯。個(gè)接口或?qū)z查異常轉(zhuǎn)換為未檢查異常(uncheckedexception)。加時(shí)間戳記字段,以便容易地檢測對象是否與后備器同步。由于對象表示業(yè)務(wù)數(shù)據(jù),根據(jù)AOP的知識(shí),我們應(yīng)該將這種機(jī)制性細(xì)節(jié)從對象中。使用AspectJ,可以用如下代碼中所顯示的語publicaspect{privatelongValueObject.timestamp;publiclongValueObject.getTimestamp(){return}publicvoid{this.timestamp=}},除了必須限定在哪個(gè)類上引入的方法和成員變量以外引入的方法和成員變量幾乎與常,C++aspectTimestamp能夠泛化publicinterface{longgetTimestamp();voidtimestamp();}publicaspect{privatelongTimestampedObject.timestamp;publiclongTimestampedObject.getTimestamp(){return}publicvoid{this.timestamp=}}TimestampTimestampedObject接口中引入(introduction)了方法的實(shí)現(xiàn),使得TimestampedObject接口改變其本質(zhì),成為了一個(gè)特殊的類類型。特殊之處就在于一個(gè)已經(jīng)繼承AspectJ類型表達(dá)一樣,可以同時(shí)應(yīng)用于多個(gè)類型:declareparents:ValueObject||BigValueObjectimplementsajc編譯器完成。ajc編譯器用來編譯類和Aspect代碼。ajc既可以作為編譯器也可以作為預(yù)編譯器操作,生成有效的.class.javaJava環(huán)境(添加一個(gè)小的運(yùn)行時(shí)JAR)中編譯和運(yùn)行這些文件。要使用AspectJ進(jìn)行編譯,將需要顯式地指定希望在給定編譯中包含的源文件(Aspect和類),ajcjavacJava應(yīng)用程序中的每個(gè)類都是相對分離的組件。為了正確操作,一個(gè)類只要求其直接的類的存在。Aspect表AspectJaspect承諾未來的版本(正式版2.0)將允許字節(jié)碼的修改。AspectJ版包含了幾種開發(fā)工具。這預(yù)示著AspectJ將有美好的前景,因?yàn)樗砻髁俗髡邔@AspectJAspect的系統(tǒng)工具支持AspectJAspect如何與其它系統(tǒng)組除了結(jié)構(gòu)瀏覽器和編譯器之外,您還可以從AspectJ一個(gè)Aspect支持的調(diào)試器、一javadocAntEmacs插件。JBossAOP法進(jìn)行,并將被的方法與aspect邏輯進(jìn)行關(guān)聯(lián)。publicinterface{publicStringpublicInvocationResponseinvoke(Invocationinvocation)throws}Invocation對象,而方法的返回值、字段的存取以及構(gòu)造函數(shù)則被填入一個(gè)importorg.jboss.aop.*;importjava.lang.reflect.*;publicclassTracingInterceptorimplements{publicString{return}publicInvocationResponseinvoke(Invocationinvocation)throws{Stringmessage=if(invocation.getType()=={Methodmethod=MethodInvocation.getMethod(invocation);message=method:+method.getName();}{if(invocation.getType()=={Constructorc=ConstructorInvocation.getConstructor(invocation);message=constructor:+c.toString();}{//不對字處理,太繁瑣return}System.out.println(Entering+}//繼續(xù)。調(diào)用真正的方法或者構(gòu)造函數(shù)InvocationResponserspinvocation.invokeNext();System.out.println(Leaving+message);return}}invocation。BusinessObjectpointcutxml中的定義如下:pointcutTracingInterceptorBusinessObject的類。如果要將該當(dāng)JBossAOP獨(dú)立運(yùn)行時(shí)任何符合META-INF/jboss-aop.xml模式的XML文件將被JBossAOP運(yùn)行期程序載入。如果相關(guān)的路徑被包含在任何JAR或你的CLASSPATH 中,該XML文件將在啟動(dòng)時(shí),由JBossAOP運(yùn)行期程序載入。get()set()main()xml文件:<class-metadatagroup="tracing"class="BusinessObjectpublicclassTracingInterceptorimplements{publicInvocationResponseinvoke(Invocationinvocation)throws{Stringfilter=(String)invocation.getMetaData(tracing,filter);if(filter!=null&&filter.equals(true))return}}JBossAOP同樣提供introduction功能,通過它,就可以為現(xiàn)有的類引入第接口或類的APIBusinessObjectTracingBusinessObject對象能夠根據(jù)具體的情況打開或關(guān)閉aspectTracingTracingpublicinterface{voidenableTracing();void}BusinessObject上。實(shí)現(xiàn)方法如下:importpublicclassTracingMixinimplements{Advised{this.advised=}publicvoid{}publicvoid{advised._getInstanceAdvisor().getMetaData().addMetaData("tracing","filter",}}BusinessObjectTracing接口:單行的Java代碼都可以放到中。publicclass{publicBusinessObject()publicvoidoWorld(){System.out.println(oWorld!);publicstaticvoidmain(String[]{BusinessObjectbo=newBusinessObject();Tracingtrace=(Tracing)this;System.out.println("Turnofftracing.");System.out.println("Turnontracing.");}}Tracingtrace=TracingTracing類型是不成功的。但通過“引入”功能,BusinessObjectTracing接口,從而使得如上的代碼能夠順利執(zhí)行。隱BusinessObjectAOPBusinessObject擴(kuò)展實(shí)現(xiàn)了第提供的接口Tracing。SpringAOP相同,它仍然利用了器完成對方法的。然而,SpringAOP實(shí)現(xiàn)AOP的主要技術(shù)卻主要來自于AOP,如器應(yīng)實(shí)現(xiàn)ercept.MethodInterceptor接口,而所有SpringIoCAOP實(shí)現(xiàn)的區(qū)別。Springpointcutadvicepointcut有可能接受不publicinterface{ClassFiltergetClassFilter();MethodMatchergetMethodMatcher();}publicinterfaceClassFilter{booleanmatches(Class}publicinterface{booleanmatches(Methodm,Classbooleanmatches(Methodm,ClasstargetClass,Object[]args);booleanisRuntime();}matches(MethodClass)方法被用來測試這個(gè)切入點(diǎn)是否匹配目標(biāo)類的給定方法。這個(gè)測試可以在AOP創(chuàng)建的時(shí)候執(zhí)行避免在所有方法調(diào)用時(shí)都需要進(jìn)行測試如果2個(gè)參數(shù)的matches()trueMethodMatcherisRuntime()true3個(gè)參數(shù)的MethodMatcherisRuntime()方返回false。此種情況下,3個(gè)參數(shù)的matches()方法不會(huì)被調(diào)用。SpringAOP提供了幾個(gè)實(shí)用的切入點(diǎn)實(shí)現(xiàn),其中較為常用的是正則表達(dá)式切入點(diǎn):true。用<beanid="settersAndAbsquatulatePointcut"<property不過,情況下是直接使用RegexpMethodPointcut一個(gè)實(shí)用子類:可以是器,也可以是beforeadvice,throwsadvice等)。這就簡化了bean的裝配,因?yàn)橐籦eanpointcutadvice,如下所示:<beanid="myPointcutAdvisor"<property<reflocal="MyInterceptor"<propertymyPointcutAdvisorSpringAOPadvisoraspect完整advisorpointcutadvice(MyInterceptor)綁定起SpringAOP的advice可以多個(gè)被advice對象共享或者每個(gè)被advice對象有自己的advice。要實(shí)現(xiàn)advice,最簡單的做法就是定義一個(gè)器(Interceptor)。它采用了AOP(AOPAlliance)AOP接口(aopalliance.jar)advice,需要實(shí)現(xiàn)aopalliance.jarMethodInterceptor接口。publicinterface{publicvoid}publicclassBusinessObjectImplimplements{publicvoid{System.out.println("saving }}BusinessObjectSave()LockSpringAOP的實(shí)現(xiàn)LockInterceptorMethodInterceptor接口:ercept.MethodInterceptor;importercept.MethodInvocation;publicclassLockInterceptorimplements{publicObjectinvoke(MethodInvocationinvocation)throws{//TODOAuto-generatedmethodstubObjectret=ceed();return}privatevoid{System.out.println("lock}privatevoid{System.out.println("unlock}}interceptoradvicebean:<beanid="MyInterceptor"class="test.aop.spring.LockInterceptor"/>。FactoryBean來創(chuàng)建AOPFactoryBean和其他Spring的FactoryBean實(shí)現(xiàn)一樣,引入一個(gè)間接的層次。如果你定義一個(gè)名字為foo的FactoryBean,foo的對象方法所創(chuàng)建的對象。這個(gè)方法將創(chuàng)建一個(gè)包裝了目標(biāo)對象的AOP。。<beanid="myAOP"<property<reflocal="impl"<property<beanid="impl"importimportpublicclass{privateBusinessObjectbo=null;publicstaticvoidmain(String[]args){ApplicationContextctx=newFileSystemXmlApplicationContext("Bean.xml");bo=(BusinessObject)ctx.getBean("myAOP");}}LockInterceptorRegexpMethodPointcutAdvisorpointcutadvice之間unlock()AOP。SpringAOPintroductionadviceadvice一樣,introductionadvice相當(dāng)于一種特殊類型的通知,需要實(shí)現(xiàn)IntroductionAdvisor和publicinterfaceIntroductionInterceptorextendsMethodInterceptor{}InterceptionIntroductionAdvisor來實(shí)現(xiàn)導(dǎo)入通知,它有下面的方法:publicinterfaceInterceptionIntroductionAdvisorextends{ClassFilterIntroductionInterceptorgetIntroductionInterceptor();Class[]getInterfaces();}JBossAOPintroductionSpringAOP中的應(yīng)用。我們的目標(biāo)仍然是為一個(gè)已有的業(yè)務(wù)對象引入第接口Tracing:publicinterface{voidenableTracing();voiddisableTracing();booleanenabled();}IntroductionInterceptor。在這里,我們繼承IntroductionInterceptor接口,但是大多數(shù)情況下DelegatingIntroductionInterceptor是最合適的。DelegatingIntroductionInterceptorintroductionintroduction接DelegatingIntroductionInterceptor的子類TracingMixin。給定一個(gè)委托(默認(rèn)是自身)的DelegatingIntroductionInterceptor實(shí)例尋找被這個(gè)委托(IntroductionInterceptor)TracingMixi也可能調(diào)用suppressInterflace(Classintf)方法來隱藏不應(yīng)的接口。然而,不管IntroductionInterceptor準(zhǔn)備支持多少接口,IntroductionAdvisor將控制哪個(gè)接口將被實(shí)際暴publicclassTracingMixinextendsDelegatingIntroductionInterceptorimplements{privatebooleanenabled;publicvoidenableTracing(){this.enabled=}publicvoiddisableTracing{this.enabled=}publicboolean{return}publicObjectinvoke(MethodInvocationinvocation)throws{return}}invoke()DelegatingIntroductionInterceptor就足夠了,如果是引introductionadvisorTracingMixin實(shí)例,并指定導(dǎo)入publicclassTracingMixinAdvisorextends{super(new}}IntroductionAdvisorIntroductionInterceptor。)和引入一樣,通常TracingMixin。advisor組成了被通知對象的狀態(tài)的一部分。在Spring中,SpringAOP的API已經(jīng)基本穩(wěn)定了。和Spring的其它部分一樣,AOP框架的切入點(diǎn)實(shí)現(xiàn)。Spring正在考慮提供一個(gè)簡單但具有強(qiáng)大表達(dá)式語言的實(shí)現(xiàn)。 目前而言,.NetAOP技術(shù)的直接實(shí)現(xiàn),而微軟在未來對于.Net的發(fā)展戰(zhàn)略目標(biāo),我們?nèi)晕纯芍5蚁嘈盼④泴τ谀壳爸耸挚蔁岬腁OP技術(shù)應(yīng)該不會(huì)。也許在未來的.NetWindowsServer操作系統(tǒng)的逐步推新,.Net平臺(tái)對于企業(yè)級(jí)系統(tǒng)開發(fā)的支持會(huì)越來越多。AOP技術(shù)在.NetJava平臺(tái)而言,還遠(yuǎn)不夠成熟,功能也相對較弱,目前能夠投入的AOP工具幾乎沒有。借鑒Java開源社區(qū)的成功,.Net平臺(tái)下AOP工具的開發(fā)也都依托于開源社區(qū)的力量。眾多開源者,仍然在堅(jiān)持不懈對AOP技術(shù)進(jìn)行研究和實(shí)踐,試圖找到AOP技術(shù)與.Net之間的完美結(jié)合點(diǎn),從而開發(fā)出真正能夠的功能強(qiáng)大的AOP工具。就目前而Spring,EosAspectJJava平臺(tái)和.Net平臺(tái)在語言機(jī)制上的相似性,使得它們在AOPaspect的實(shí)AOPAspect#,Spring.Net,Eos等。類。通過Castle動(dòng)態(tài)技術(shù),就可以方法的調(diào)用,并將Aspect的業(yè)務(wù)邏輯織入到方法中。利用Castle動(dòng)態(tài)技術(shù),最大的缺陷是它只對虛方法有效,這限制了Aspect#的一部分應(yīng)用。的實(shí)現(xiàn)上與Spring幾乎完全相似,仍然利用了AOP提供的器、Advice等實(shí)現(xiàn)AOP。Spring.NetSpring相同。將充分利用.Net的技術(shù)特性,包括元數(shù)據(jù)、Attribute、.NetRemoting的技術(shù),將其綜合運(yùn)AOPAOP所必需的.Net知識(shí)。元數(shù)據(jù)是一種二進(jìn)制信息,用以對在公共語言運(yùn)行庫(CLR)中可移植可執(zhí)行文件(PE)或在內(nèi)存中的程序進(jìn)行描述。在.Net中,如果將代碼編譯為PE文件時(shí),便會(huì)將元數(shù)據(jù)插入到該文件的一部分中,而該代碼被編譯成的中間語言(MSIL),則入到該文件的另一部分中。 在.NetFramework(IDL)文件、頭文件或任何外部組件方法。元數(shù)據(jù)允許.NET語言自動(dòng)以非特定語言的方式對其自身進(jìn)行描述,此外,通Attribute,可以對元數(shù)據(jù)進(jìn)行擴(kuò)展。元數(shù)據(jù)具有以下主要優(yōu)點(diǎn):元數(shù)據(jù)提供所有必需的有關(guān)已編譯代碼的信息,以供您從用不同語言編寫的PE文件中繼承類。您.NETFramework允許在編譯文件中特定種類的元數(shù)據(jù)(稱為Attribute)。在整個(gè).NETFrameworkAttribute的存在,Attribute用于更精確地控制運(yùn)行時(shí)程序如何工作。另外,用戶可以通過自定義屬性向.NETFramework文件發(fā)出用戶自己的自定義元數(shù)據(jù)。MSILMSILPEMSIL部分PEPEMSIL部分:最字節(jié)(0x06)表示這是一個(gè)MethodDef標(biāo)記低位的三個(gè)字節(jié)(000004)指示公共語言運(yùn)行庫在MethodDef表的第四行查找對該方法定義進(jìn)行描述的信息。PEPEPE4.1PEMSIL指令中包含了元數(shù)據(jù)標(biāo)記,因此,當(dāng)公共語言運(yùn)行庫(CLR)將代碼加載到內(nèi)存時(shí),將數(shù)據(jù)咨詢該代碼模塊中包含的信息運(yùn)行庫對中間語言(MSIL)流執(zhí)行廣泛的分析,將其轉(zhuǎn)換為快速本機(jī)指令。運(yùn)行庫根據(jù)需要使用實(shí)時(shí)(JIT)編譯器將MSIL指令轉(zhuǎn)換為本機(jī)代碼,APPMain()Add()方法:usingpublicclass{publicstaticint{intValueOne=10;intValueTwo=Console.Wriine("TheValueis:{0}",Add(ValueOne,ValueTwo));return0;}publicstaticintAdd(intOne,int{return(One+}}.maxstack.locals([0]int32int32int32int32IL_0000:ldc.i4.s IL_0002:stloc.0IL_0003:ldc.i4.s IL_0005:stloc.1IL_0006:ldstr "TheValueis:{0}"IL_000b:ldloc.0IL_000c:IL_000d:callint32ConsoleApplication.MyApp::Add(int32,int32) JIT編譯器整個(gè)方法的MSIL,對其進(jìn)行徹底地分析,然后為該方法生成有效的本機(jī)指令。在IL_000d遇到Add方法(/* */)的元數(shù)據(jù)標(biāo)記運(yùn)行庫使用該標(biāo)記參考MethodDef表4.2顯示了說明Add方法的元數(shù)據(jù)標(biāo)記所的MethodDef表的一部分行(Blob堆4.2RVAMSIL的起始內(nèi)存地址。ImplFlags和Flags列包含說明該方法的位(例如,該方法是公共的還是私有的)。Name列對來自字符串堆的方法的名稱進(jìn)行了索引。SignatureBlob堆中的方法簽名的定APPMethodDef表中,可以這種對元數(shù)據(jù)信息的獲取??梢哉f,正是因?yàn)橛辛嗽獢?shù)據(jù),才使得AOP的與織入功能的實(shí)現(xiàn)成MSDN中,Attribute被定義為“是被指定給某一的一則附加的性信息”。我們可以通過publicenum{}All。不管是.NetFrameworkAttributeAttribute,都是通過[]施加到目標(biāo)元但是,Attribute類的實(shí)例化發(fā)生在編譯時(shí),而非運(yùn)行時(shí),因而達(dá)到了擴(kuò)展元數(shù)據(jù)的目的。一個(gè)AttributeAttribute可由從目標(biāo)元素派生的元素繼承。staticAttributeGetCustomAttribute():8種重載的版本,它被用來取出施加在類成Attribute。staticAttribute[GetCustomAttributes():16種重載版本,用來取出施加在類成員Attribute數(shù)組。boolIsDefaultAttribute():Attributetrue。boolMatch():Attribute實(shí)例是否等于一個(gè)指定的對象。:個(gè)自定義的.NET屬性,我們就可以輕松地將調(diào)用Attribute與類的方法相關(guān)聯(lián):publicclass{[CallTracingAttribute("InBarctor")]publicBar(){}[CallTracingAttribute("InBar.Calculatemethod")]publicintCalculate(intx,inty){returnx+y;}}usingusing[AttributeUsage(AttributeTargets.ClassMembers,AllowMultiple=false)]publicclassCallTracingAttribute:Attribute{privatestring{m_TracingInfo=}publicstring{get{return}}CallTracingAttributeTracingBar的構(gòu)造函數(shù)和方法Attribute信息,如:publicclass{publicstaticvoidMain(string[]{System.Reflection.MemberInfoinfo=typeof(Bar);CallTracingAttributeattribute=(CallTracingAttribute)if(attribute!={ ine(“Tracing}}}Context的對象:4.1ContextContext中。在.NetContextBoundObject類,它代表的含義就是該對象應(yīng)存Context邊界中(Objectthatwillbeboundwithacontext)。凡是繼承了ContextBoundObjectdefaultContext供其生存。ContextBoundObjectContext,只需要為該類型對象施加Context(上下文)。同時(shí),ContextAttributeIContextAttributeIContextProperty接口。AttributeAttributeIContextAttribute即可。IContextAttribute接口的定義如下:publicinterface{boolIsContextOK(Contextctx,IConstructionCallMessagectorMsg);voidGetPropertiesForNewContext(IConstructionCallMessagectorMsg);}發(fā)的)IsContextOKContextBoundObjec(ctorMsg中存在?這個(gè)目的主要是減少應(yīng)用程序域中潛在的contextContextBoundObjeccontext)是正確地的(IsContextOKtrue),那么新的會(huì)立即創(chuàng)建一個(gè)新的contextCLR會(huì)再一次詢問每一個(gè)contextattribute新構(gòu)造的contextGetPropertiesForNewContext()方法,contextattribute可以用這個(gè)方法傳入的構(gòu)造器方法調(diào)用信息(ctorMsg)contextproperties列表(ContextProperties)來為新建contextcontextproperties。對象的。在GOF的《設(shè)計(jì)模式》中,將()模式分為四種:1、(Remote)。它為一個(gè)位于不同的地址空間的對象提供一個(gè)局域代表對象。這4、智能(SmartReference)。它取代了簡單的指針,在一個(gè)對象時(shí),提供在.NetRemoting中,采用了(Remote)模式。采用技術(shù),使得對象可以在兩個(gè)不同的應(yīng)用程序域(甚至可以是兩臺(tái)不同的機(jī)器)之間傳遞。在.Net中被分為(Transparent)和真實(shí)(Real)。Transparent的目標(biāo)是在CLR中在IL層面最大程度扮演被的遠(yuǎn)端對象,從類型轉(zhuǎn)換到類型獲取,從字段到方法調(diào)用。對CLR的使用者來說,Transparent和被其的對象完全沒有任何區(qū)別,只有通過RemotingServices.IsTransparent才能區(qū)分兩者的區(qū)別Real則是提供給CLR使用者擴(kuò)展機(jī)制的切入點(diǎn),通過從Real繼承并實(shí)現(xiàn)Invoke方法,用戶自定義實(shí)現(xiàn)理類派生,也不能通過自定義Attribute、實(shí)現(xiàn)標(biāo)志性接口等方式將類標(biāo)識(shí)為,從而讓CLR能夠認(rèn)識(shí)。要獲取,必須要提供一個(gè)真實(shí)。一個(gè)真實(shí)是一個(gè)從System.Runtime.Remoting.Proxies.Real派生而來的類。這個(gè)Real類的首要功能就是幫我們在運(yùn)行期動(dòng)態(tài)生成一個(gè)可以透明兼容于某一個(gè)指定類的類實(shí)例。從Realnamespace{publicclass{protectedReal(TypeclassTo):this(classTo,(IntPtr)0,null){}protectedReal(TypeclassTo,IntPtrstub,ObjectstubData){if(!classTo.IsMarshalByRef&&!classTo.IsInterface)thrownewArgumentException(...);if((IntPtr)0=={stub=_defaultStub;stubData=_defaultStubData;}_tp=if(stubData==thrownew_tp=RemotingServices.CreateTransparent(this,classTo,stub,}publicvirtualObjectGetTransparent{return}}}很明顯,(Transparent)是在Real類的構(gòu)造函數(shù)中,調(diào)用方法將把被的類型強(qiáng)制轉(zhuǎn)換為統(tǒng)一的由CLR在運(yùn)行時(shí)創(chuàng)建的RuntimeType類型,進(jìn)而調(diào)用usingpublicclassMyReal:Real{publicMyReal(TypeclassTo):base(classTo{…}}和真實(shí)在上下文(Context)中,會(huì)起到一個(gè)偵的作用。首先,將調(diào)用堆4.2所示。圖4.2()偵聽消息的順該消息,并織入需要執(zhí)行的方面邏輯,完成橫切關(guān)注邏輯與邏輯的動(dòng)態(tài)代碼織入。個(gè)類必須從System.ContextBoundObject類派生。這個(gè)類對象就相當(dāng)于AOP中的關(guān)注點(diǎn),關(guān)聯(lián)。AttributeAspect。一旦Attribute。為使得對象的元AttributeIContextAttribute。DecorateAspect邏輯注入到業(yè)務(wù)對象中。由于在大型的企業(yè)系統(tǒng)設(shè)計(jì)中,橫切關(guān)注點(diǎn)會(huì)派生這些類庫的類型,從而真正在.NetAOP技術(shù)。AOPusingSystem;usingSystem.Runtime.Remoting.Contexts;usingSystem.Runtime.Remoting.Activation; class{privatestringprivateconststringCONFIGFILE=@"configuration\aspect.xml";publicAOPAttribute(){m_AspectXml=}publicAOPAttribute(string{this.m_AspectXml=} AOPProperty#regionIContextAttribute{AOPPropertyproperty=property.AspectXml=m_AspectXml;}publicboolIsContextOK(Contextctx,IConstructionCallMessage{return}}AOPAttributeSystem.Attribute類之外,關(guān)鍵之處在于實(shí)現(xiàn)了接口IContextAttributeGetPropertiesForNewContext()Context添加屬性(Property)IConstructionCallMessageContextProperties屬性。而接口方法IsContextOK(),則用于判斷Context中是否存在指定的屬性。這個(gè)方在ContextContext。AOPPropertyGetPropertiesForNewContext()方法添加到屬性集合中。GetAOPProperty()AOPProperty對象。AOPIContextPropertyContext提供一些屬性。IContextProperty接口的定義如下:publicinterface{stringName{get;boolIsNewContextOK(ContextnewCtx);voidze(ContextnewCtx);}的截取。根據(jù)對技術(shù)的分析,要實(shí)現(xiàn)AOP,必須在方法調(diào)用截取消息傳遞,并形成一個(gè)消息鏈MessageSink。因此,如果需要向所在的Context的Transparent/Real中植入MessageSink,ContextPropertySink的功能。所幸的是,.Net已經(jīng)提供了實(shí)現(xiàn)MessageSink功能的相關(guān)接口,這些接口名規(guī)則為IContributeXXXSink,XXX代表了四種只具有一個(gè)方法用于返回一個(gè)Sink對象。由于我們需要獲取的對象,是能夠穿越不同的應(yīng)用程序域的。在一個(gè)應(yīng)用程序域收到其他應(yīng)用程序域的對象,則該對象在.Net中被稱為ServerContextContextContextPropertyIContributeServerContextSink接口。事實(shí)上,也只有usingusingSystem.Runtime.Remoting.Activation;usingSystem.Runtime.Remoting.Contexts;usingSystem.Runtime.Remoting.Messaging; classAOPProperty:IContextProperty,{privatestringm_AspectXml;publicAOPProperty(){m_AspectXml=}publicstring{set{m_AspectXml=value;} SinkCreateAspect(SinknextSink);protectedvirtualstringGetName(){return}protectedvirtualvoidzeImpl(Context{}protectedvirtualboolCheckNewContext(Context{return}#regionIContextPropertyMemberspublicvoidze(ContextnewContext){}publicboolIsNewContextOK(Context{return}publicstring{get{returnGetName();}publicSinkGetServerContextSink(Sink{Aspectaspect=(Aspect)CreateAspect(nextSink);return(}}在抽象類AOPProperty中,同樣利用了TemteMethod模式,將接口IContextProperty的方法的實(shí)現(xiàn)利用受保護(hù)的虛方法延繼承AOPProperty的子類中。同時(shí),對于接口IContributeServerContextSinkGetServerContextSink()AspectAspect類是AOP的,它的本質(zhì)是一個(gè)MessageSink,正是通過它進(jìn)行消息的傳遞,并截獲方法間傳遞的消息。Aspect類實(shí)現(xiàn)了Sink接口,其定義如下:publicinterface{SyncProcessMessage(msg);CtrlAsyncProcessMessage(msg,SinkSinkNextSink{get;}Sink接口利用NextSink將多個(gè)MessageSink連接起來,以形成一個(gè)消息鏈;注意方法SyncProcessMessage()中的參數(shù),是一個(gè)接口類型的對象。在.Net中,IMethodCallMessage和IMethodReturnMessage接口均繼承自接口前者是調(diào)用Aspect實(shí)現(xiàn)應(yīng)該如下: classAspect:{privateSinkpublicAOPSink(Sink{m_NextSink=}publicSink{get{returnm_NextSink;}publicSyncProcessMessage({IMethodCallMessagecall=msgasIMethodCallMessage;if(call==null){return}retMsg=null;retMsg=m_NextSink.SyncProcessMessage(msg);return}publicCtrlAsyncProcessMessage(msg,Sink{return}privatevoid{}privatevoid{}}注意在方法SyncProcessMessage()中,Sink對象m_NextSink通過Aspect構(gòu)造函數(shù)賦值為業(yè)務(wù)對象的,在調(diào)用m_NextSink的SyncProcessMessage()方法時(shí),此時(shí)調(diào)不斷的向后執(zhí)行。而對于一個(gè)業(yè)務(wù)對象而言,此時(shí)的即為該對象中被調(diào)用的方法,m_NextSink.SyncProcessMessage(msg)BeforeProcess()AfterProcess(),AOP技術(shù)的實(shí)際應(yīng)用而言,并非業(yè)務(wù)對象的所有方法都需要被截取進(jìn)而進(jìn)行方面的織入。BeforeAdviceAfterAdviceAspect類中應(yīng)該定義兩個(gè)集合對象:privateSortedListm_BeforeAdvices;privateSortedListm_Afdvices;SortedListKeyAdviceSortedListValue:{lock{if{}}}protectedvirtualvoidAddAfdvice(stringmethodName,IAfdvice{{if(!m_Af{}}}PointCutlock對該操作進(jìn)行了加鎖,避免并發(fā)處理時(shí)可能Advice,從而執(zhí)行相Advice代碼:publicSyncProcessMessage({IMethodCallMessagecall=msgasIMethodCallMessage;stringmethodName=call.MethodName.ToUpper();IBeforeAdvicebefore=FindBeforeAdvice(methodName);if(before!=null){}retMsg=m_NextSink.SyncProcessMessage(msg);IMethodReturnMessagereply=retMsgasIMethodReturnMessage;IAfdviceafter=FindAfdvice(methodName);if(after!={}return}{IBeforeAdvicelock{before=}return}publicIAfdviceFindAfdvice(string{IAfdvice{after=(IAfdvice)m_Af}return}那么,PointCutAOP的配置文件(Aspec
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年度拖車服務(wù)合同正規(guī)范范文本(含拖車租賃維修服務(wù))3篇
- 2024年中國旋轉(zhuǎn)展示控制板市場調(diào)查研究報(bào)告
- 《土壤入滲模型參數(shù)的分階段非線性預(yù)報(bào)模型研究》
- 2024年雙膠商標(biāo)原紙項(xiàng)目可行性研究報(bào)告
- 2024年單層噴塑床項(xiàng)目可行性研究報(bào)告
- 2025年度旅行社研學(xué)旅行保險(xiǎn)合作合同范本2篇
- 2025年度淘寶店鋪代運(yùn)營、用戶運(yùn)營與社群互動(dòng)合作合同3篇
- 2025年度消防滅火器材銷售與售后服務(wù)合同3篇
- 【北京特級(jí)教師】2020-2021學(xué)年人教版高中地理必修二輔導(dǎo)講義:環(huán)境問題和可持續(xù)發(fā)展
- 2025年度城市下水道與水溝清淤維護(hù)合作協(xié)議3篇
- 中小學(xué)數(shù)學(xué)學(xué)科德育實(shí)施指導(dǎo)綱要
- 并聯(lián)無功補(bǔ)償項(xiàng)目節(jié)約電量的計(jì)算中國電力企業(yè)聯(lián)合會(huì)
- 《病毒》教學(xué)設(shè)計(jì)
- 路面基層允許彎沉值計(jì)算+彎沉系數(shù)圖+允許彎沉值計(jì)算公式
- 連鑄意外事故處理
- 國家開放大學(xué)(中央廣播電視大學(xué))報(bào)名登記表【模板】
- 新職業(yè)英語1-基礎(chǔ)篇-Unit 3(課堂PPT)
- 公司各部門協(xié)作情況互評表滿意度調(diào)查表
- 第二章水準(zhǔn)測量PPT課件
- 長輸管道原油輸送基本知識(shí)
- 完美世界的材料
評論
0/150
提交評論