欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
Spring Framework中的面向方面編程(AOP),第二部分

  在本系列的第一部分,我介紹了如何實(shí)現面向方面領(lǐng)域的“HelloWorld”:跟蹤和記錄方面。利用Spring框架所提供的面向方面編程(Aspect-Oriented Programming,AOP)功能,您看到了如何使用before-、after-和基于異常的通知,以及如何使用基于正則表達式的簡(jiǎn)單切入點(diǎn)。跟蹤和記錄方面提供了非常不錯的上手例子,而本文將進(jìn)一步介紹一種新的通知形式:around通知。

  比起第一部分中介紹的那些通知類(lèi)型,around形式的通知是一種更具侵入性也更強大的面向對象概念。本文將描述around通知的每個(gè)特性,以便您可以在自己的Spring AOP應用程序中正確地使用它。在本文最后,我將向您展示如何使用around通知來(lái)截獲和改變應用程序中各個(gè)特性相互作用的方式,以便實(shí)現Cuckoo‘s Egg(杜鵑的蛋)面向方面設計模式。

概述Spring AOP、IoC和代理
  在第一部分,我們快速瀏覽了Spring的一些AOP特性,而沒(méi)有闡明Spring如何實(shí)現AOP的細節。要理解Spring框架如何運轉,尤其是它如何實(shí)現其AOP功能,首先您要明白,Spring是一個(gè)依賴(lài)于控制反轉(Inversion of Control,IoC)設計模式的輕量級框架。

  注意:本文的目的不是要深入介紹IoC模式,介紹IoC只是為了使您明白該設計模式是如何影響Spring AOP實(shí)現的。有關(guān)IoC模式的更詳細的介紹請參見(jiàn)本文末尾的參考資料。

  IoC設計模式的出現已經(jīng)有一段時(shí)間了。一個(gè)最明顯的例子就是J2EE架構本身。隨著(zhù)企業(yè)開(kāi)發(fā)尤其是J2EE平臺的出現,應用程序開(kāi)始依賴(lài)于由外部容器所提供的一些特性,比如bean創(chuàng )建、持久性、消息傳遞、會(huì )話(huà)以及事務(wù)管理。

  IoC引入了一個(gè)新概念:由組件構成的框架,它與J2EE容器有許多類(lèi)似之處。IoC框架分離了組件所依賴(lài)的功能,并且,根據Sam Newman文章中的說(shuō)法,提供了“連接組件的‘膠水’”。

  對組件所依賴(lài)特性的控制 被反轉 了,這樣外部框架就可以盡可能透明地提供這些特性了。IoC模式真正意識到了從傳統的由依賴(lài)于功能的組件來(lái)負責這些功能,到由獨立的框架來(lái)配置和提供這些功能的方式轉變。

  圖1顯示了一些構成IoC模式的不同組件角色的例子。


圖1. 沒(méi)有對BusinessLogic bean應用方面時(shí)的順序圖.

  圖字:

  Component:組件

  Provides Facilities:提供功能

  Relies on and conforms to:依賴(lài)于并服從

  Manages the services the framework can then use to provide facilities:管理框架隨后可以用來(lái)提供功能的服務(wù)

  Service:服務(wù)

  Your Component:您的組件

  IoC Framework:IoC框架

  External services:外部服務(wù)

  IoC模式使用3種不同的方法來(lái)解除組件與服務(wù)控制的耦合:類(lèi)型1、類(lèi)型2和類(lèi)型3。

  • 類(lèi)型1:接口注入
    這是大部分J2EE實(shí)現所使用的方法。組件顯式地服從于一組接口,帶有關(guān)聯(lián)的配置元數據,以便允許框架對它們進(jìn)行正確的管理。
  • 類(lèi)型2:Setter注入
    外部元數據被用來(lái)配置組件相互作用的方式。在第一部分中,我們就是使用這種IoC方法利用springconfig.xml文件來(lái)配置Spring組件的。
  • 類(lèi)型3:構造函數注入
    組件(包括構造組件時(shí)要用的參數)注冊到框架,而框架提供組件的實(shí)例以及所有要應用的指定功能。

  IoC在組件開(kāi)發(fā)和企業(yè)開(kāi)發(fā)中越來(lái)越受歡迎。IoC的實(shí)際例子包括傳統的J2EE解決方案,比如:JBoss、Apache基金會(huì )的Avalon項目以及本文的Spring框架。實(shí)際上,Spring框架構建于IoC模式的基礎上是為了幫助將它的輕量級功能注入到它的相關(guān)應用程序的組件中。

  那么IoC對于Spring AOP有何意義呢?Spring的IoC特性是使用IoC springconfig.xml配置文件對應用程序應用方面的推動(dòng)因素之一。springconfig.xml配置文件通知Spring框架運行時(shí)有關(guān)應用程序的組件要被注入的功能類(lèi)型的信息,所以自然輕量級的AOP功能就以同樣的方式應用了。然后Spring使用代理模式圍繞現有的類(lèi)和bean實(shí)現指定的AOP功能。

  圖2顯示了Spring及其IoC框架如何使用代理對象提供AOP功能(根據springconfig.xml文件中的IoC配置。)


圖2. springconfig.xml配置文件改變了Spring框架IoC,以便隨后向第一部分中的一個(gè)順序圖提供AOP代理(單擊圖像查看大圖)

  在本系列下面的部分,您將不斷看到現在包含在順序圖中的代理對象。這只是為了說(shuō)明對于Spring AOP來(lái)說(shuō)沒(méi)有“魔法”,實(shí)際上只有一個(gè)面向對象設計模式的良好例子。

回到AOP:使用around通知的積極方面
  在第一部分,您看到了如何使用Spring AOP來(lái)實(shí)現跟蹤和記錄方面。跟蹤和記錄都是“消極”方面,因為它們的出現并不會(huì )對應用程序的其他行為產(chǎn)生影響。它們都使用了消極的before和after形式的通知。

  但是如果您希望改變應用程序的常規行為呢?例如說(shuō),您希望重寫(xiě)一個(gè)方法?這樣的話(huà),您就需要使用更積極的around形式的通知。

  第一部分的簡(jiǎn)單例子應用程序包括IbusinessLogic接口、BusinessLogic類(lèi)和MainApplication類(lèi),如下所示:

public interface IBusinessLogic{public void foo();}public class BusinessLogicimplements IBusinessLogic{public void foo(){System.out.println("Inside BusinessLogic.foo()");}}import org.springframework.context.ApplicationContext;import org.springframework.context.support.FileSystemXmlApplicationContext;public class MainApplication{public static void main(String [] args){// Read the configuration fileApplicationContext ctx =new FileSystemXmlApplicationContext("springconfig.xml");//Instantiate an objectIBusinessLogic testObject =(IBusinessLogic) ctx.getBean("businesslogicbean");// Execute the public// method of the beantestObject.foo();}}

  要對一個(gè)BusinessLogic類(lèi)的實(shí)例徹底重寫(xiě)對foo()方法的調用,需要創(chuàng )建around通知,如下面的AroundAdvice類(lèi)所示:

import org.aopalliance.intercept.MethodInvocation;import org.aopalliance.intercept.MethodInterceptor;public class AroundAdviceimplements MethodInterceptor{public Object invoke(MethodInvocation invocation)throws Throwable{System.out.println("Hello world! (by " +this.getClass().getName() +")");return null;}}

  要在Spring中用作around通知,AroundAdvice類(lèi)必須實(shí)現MethodInterceptor接口和它的invoke(..)方法。每當截獲到方法的重寫(xiě),invoke(..)方法就會(huì )被調用。最后一步是改變包含在應用程序的springconfig.xml文件中的Spring運行時(shí)配置,以便可以對應用程序應用AroundAdvice。

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE beans PUBLIC  "-//SPRING//DTD BEAN//EN""http://www.springframework.org/dtd/spring-beans.dtd"><beans><!-- Bean configuration --><bean id="businesslogicbean"class="org.springframework.aop.framework.ProxyFactoryBean"><property name="proxyInterfaces"><value>IBusinessLogic</value></property><property name="target"><ref local="beanTarget"/></property><property name="interceptorNames"><list><value>theAroundAdvisor</value></list></property></bean><!-- Bean Classes --><bean id="beanTarget"class="BusinessLogic"/><!-- Advisor pointcut definition for around advice --><bean id="theAroundAdvisor"class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"><property name="advice"><ref local="theAroundAdvice"/></property><property name="pattern"><value>.*</value></property></bean><!-- Advice classes --><bean id="theAroundAdvice"class="AroundAdvice"/></beans>

  根據該springconfig.xml配置文件,theAroundAdvisor截獲所有對BusinessLogic類(lèi)的方法的調用。接下來(lái),theAroundAdvisor被關(guān)聯(lián)到theAroundAdvice,表明當截獲一個(gè)方法時(shí),就應該使用在A(yíng)roundAdvice類(lèi)中指定的通知。既然已經(jīng)指定了around通知的正確配置,下一次執行MainApplication類(lèi)時(shí),BusinessLogic bean的foo()方法就會(huì )被截獲并重寫(xiě),如圖3所示:


圖3. 使用around通知重寫(xiě)對BusinessLogic類(lèi)中的foo()方法的調用

  前面的例子顯示,BusinessLogic類(lèi)中的foo()方法可以通過(guò)AroundAdvice類(lèi)中的invoke(..)方法徹底重寫(xiě)。原來(lái)的foo()方法完全不能被invoke(..)方法調用。如果希望從around通知內調用foo()方法,可以使用proceed()方法,可從invoke(..)方法的MethodInvocation參數中得到它。

public class AroundAdviceimplements MethodInterceptor{public Object invoke(MethodInvocation invocation)throws Throwable{System.out.println("Hello world! (by " +this.getClass().getName() +")");invocation.proceed();System.out.println("Goodbye! (by " +this.getClass().getName() +")");return null;}}

  圖4顯示了對proceed()的調用如何影響操作的順序(與圖3所示的初始around通知執行相比較)。


圖4. 從around通知內使用proceed()調用原來(lái)的方法

  當調用proceed()時(shí),實(shí)際是在指示被截獲的方法(在本例中是foo()方法)利用包含在MethodInvocation對象中的信息運行。您可以通過(guò)調用MethodInvocation類(lèi)中的其他方法來(lái)改變該信息。

  您可能希望更改包含在MethodInvocation類(lèi)中的信息,以便在使用proceed()調用被截獲的方法之前對被截獲方法的參數設置新值。

  通過(guò)對MethodInvocation對象調用getArguments()方法,然后在返回的數組中設置其中的一個(gè)參數對象,最初傳遞給被截獲的方法的參數可以被更改。

  如果IbusinessClass和BusinessLogic類(lèi)的foo()方法被更改為使用整型參數,那么就可以將傳遞給被截獲的調用的值由在A(yíng)roundAdvice的notify(..)方法中傳遞改為在foo(int)中傳遞。

public class AroundAdviceimplements MethodInterceptor{public Object invoke(MethodInvocation invocation)throws Throwable{System.out.println("Hello world! (by " +this.getClass().getName() +")");invocation.getArguments()[0] = new Integer(20);invocation.proceed();System.out.println("Goodbye! (by " +this.getClass().getName() +")");return null;}}

  在本例中,被截獲的方法的第一個(gè)形參被假設為int。實(shí)參本身是作為對象傳遞的,所以通過(guò)將其包裝在Integer類(lèi)實(shí)例中的方法,基本的int類(lèi)型的形參被改為對應數組中的新值。如果您將該參數設置為一個(gè)非Integer對象的值,那么在運行時(shí)就會(huì )拋出IllegalArgumentException異常。

  您還將注意到,invoke(..)方法必須包含一個(gè)return語(yǔ)句,因為該方法需要返回值。但是,被重寫(xiě)的foo()方法并不返回對象,所以invoke(..)方法可以以返回null結束。如果在foo()方法不需要的情況下,您仍然返回了一個(gè)對象,那么該對象將被忽略。

  如果foo()方法確實(shí)需要返回值,那么需要返回一個(gè)與foo()方法的初始返回類(lèi)型在同一個(gè)類(lèi)或其子類(lèi)中的對象。如果foo()方法返回一個(gè)簡(jiǎn)單類(lèi)型,例如,一個(gè)integer,那么您需要返回一個(gè)Integer類(lèi)的對象,當方法被重寫(xiě)時(shí),該對象會(huì )自動(dòng)由AOP代理拆箱,如圖5所示:


圖5. around通知的裝箱和自動(dòng)拆箱

  圖字:

  Object invoke:對象調用

  The integer return value is boxed in a Integer object in the AroundAdvice and then unboxed by the AOP Proxy:整型返回值被裝箱在A(yíng)roundAdvic通知的一個(gè)Integer對象中,然后由AOP代理拆箱。

  面向方面編程還是一個(gè)比較新的領(lǐng)域,尤其是與衍生出它的面向對象編程相比。設計模式通常被認為是常見(jiàn)問(wèn)題的通用解決方案,因為面向方面發(fā)展的時(shí)間還不長(cháng),所以已發(fā)現的面向方面設計模式比較少。

  此處要介紹的是一種正在浮現的模式,即Cuckoo‘s Egg設計模式。該模式還有其他的叫法,它在面向對象領(lǐng)域的對等體包括模仿對象(Mock Object)和模仿測試(Mock Testing),甚至代理模式也與它有一些類(lèi)似之處。

  Cuckoo‘s Egg面向方面設計模式可以被定義為應用程序上下文中功能部件的透明和模塊化的置換。就像杜鵑偷偷地把自己的蛋放在另一種鳥(niǎo)的巢中一樣,Cuckoo‘s Egg設計模式用一個(gè)替代功能部件實(shí)現置換現有的功能部件,而使造成的干擾盡可能少。

  這種置換的實(shí)現方式可以是靜態(tài)的、動(dòng)態(tài)的、部分的、完全的,針對一個(gè)對象的多個(gè)部分,或針對多個(gè)組件。使用面向方面的方法可以透明地實(shí)現功能部件的置換,而無(wú)需對應用程序的其余部分進(jìn)行更改。要置換應用程序中現有功能部件的替代功能部件就是“杜鵑的蛋”。圖6顯示了Cuckoo‘s Egg設計模式中的主要組成元素。


圖6. Cuckoo‘s Egg設計模式中的主要組成元素

  圖字:

  Application:應用程序

  Component:組件

  Replacement Feature:替代功能部件

  Component 1 and 2 together encompass a distinct feature of the software:組件1和2共同包含了軟件的一個(gè)獨立的功能部件

  The Cuckoo‘s Egg pattern transparently replaces an existing feature of the software:Cuckoo‘s Egg模式透明地置換了軟件現有的功能部件

  Before the pattern is applied:應用該模式前

  After the pattern is applied:應用該模式后

  Cuckoo‘s Egg設計模式依賴(lài)于around通知的概念。您需要借助于積極的和侵入性的around通知來(lái)截獲并有效置換應用程序中現有的功能部件。

  有關(guān)Cuckoo‘s Egg設計模式的更多信息,以及AspectJ中的一個(gè)可選實(shí)現,請參見(jiàn)《AspectJ Cookbook》(O‘Reilly,2004年12月出版)。

  要使用Spring AOP實(shí)現Cuckoo‘s Egg設計模式,需要聲明一個(gè)around通知來(lái)截獲所有對要置換的功能部件的調用。與hot-swappable target sources(Spring AOP的一個(gè)功能部件,將在本系列的另一篇文章中介紹)不同,around通知的顯式使用使得Cuckoo‘s Egg實(shí)現可以有效地跨越對象邊界(因此也可以跨越bean邊界)進(jìn)行整個(gè)功能部件的置換,如圖7所示。


圖7. 一個(gè)跨越bean邊界的組件

  圖字:

  A feature crosses the boundaries of BusinessLogic and BusinessLogic2 by depending on behavior supplied separately by the two beans:一個(gè)功能部件通過(guò)依賴(lài)于由BusinessLogic和BusinessLogic2各自提供的行為而跨越了這兩個(gè)bean的邊界

  下面的代碼顯示了一個(gè)具有兩個(gè)bean的簡(jiǎn)單應用程序,其中有一個(gè)功能部件跨越了該應用程序的多個(gè)方面。要置換的功能部件可以被視為包含IBusinessLogic bean中的foo()方法和IBusinessLogic2 bean中的bar()方法。IBusinessLogic2 bean中的baz()方法不是 該功能部件的一部分,所以不進(jìn)行置換。

public interface IBusinessLogic{public void foo();}public interface IBusinessLogic2{public void bar();public void baz();}

  該例子的完整源代碼可在本文末尾的參考資料小節中下載。

  此處,ReplacementFeature類(lèi)扮演了“杜鵑的蛋”的角色,它提供了將被透明地引入應用程序的替代實(shí)現。ReplacementFeature類(lèi)實(shí)現了所有在該類(lèi)引入時(shí)要被置換的方法。

public class ReplacementFeature{public void foo(){System.out.println("Inside ReplacementFeature.foo()");}public void bar(){System.out.println("Inside ReplacementFeature.bar()");}}

  現在需要聲明一個(gè)around通知來(lái)截獲對跨越bean的功能部件的方法調用。CuckoosEgg類(lèi)提供了某種around通知來(lái)檢查被截獲的方法,并將適當的方法調用傳遞給ReplacementFeature類(lèi)的實(shí)例。

public class CuckoosEgg implements MethodInterceptor{public ReplacementFeature replacementFeature =new ReplacementFeature();public Object invoke(MethodInvocation invocation)throws Throwable{if (invocation.getMethod().getName().equals("foo")){replacementFeature.foo();}else{replacementFeature.bar();}return null;}}

  因為與Spring框架關(guān)系密切,Cuckoo‘s Egg設計的詳細信息被放在springconfig.xml配置文件中。對springconfig.xml文件的更改將確保所有對IbusinessLogic和IBusinessLogic2 bean的foo()方法和bar()方法的調用都將被截獲,并傳遞給CuckoosEgg類(lèi)的around通知。

   ...<!--CONFIG--><bean id="businesslogicbean"class="org.springframework.aop.framework.ProxyFactoryBean"><property name="proxyInterfaces"><value>IBusinessLogic</value></property><property name="target"><ref local="beanTarget"/></property><property name="interceptorNames"><list><value>theCuckoosEggAdvisor</value></list></property></bean><bean id="businesslogicbean2"class="org.springframework.aop.framework.ProxyFactoryBean"><property name="proxyInterfaces"><value>IBusinessLogic2</value></property><property name="target"><ref local="beanTarget2"/></property><property name="interceptorNames"><list><value>theCuckoosEgg2Advisor</value></list></property></bean><!--CLASS--><bean id="beanTarget" class="BusinessLogic"/><bean id="beanTarget2" class="BusinessLogic2"/><!--ADVISOR--><bean id="theCuckoosEggAdvisor"class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"><property name="advice"><ref local="theReplacementFeaturePart1Advice"/></property><property name="pattern"><value>IBusinessLogic.*</value></property></bean><bean id="theCuckoosEgg2Advisor"class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"><property name="advice"><ref local="theReplacementFeaturePart2Advice"/></property><property name="pattern"><value>IBusinessLogic2.bar*</value></property></bean><!--ADVICE--><bean id="theReplacementFeaturePart1Advice" class="CuckoosEgg"/><bean id="theReplacementFeaturePart2Advice" class="CuckoosEgg"/>...

  當使用修改后的springconfig.xml文件運行例子應用程序時(shí),要替換的、被指定為功能部件的一部分的方法調用完全被截獲并傳遞給ReplacementFeature類(lèi)。

  通常,即使在同一個(gè)實(shí)現環(huán)境中,我們也可以用不同的方法來(lái)實(shí)現同一種設計模式。實(shí)現上例的另一種方法是實(shí)現兩個(gè)獨立的通知。

  最后需要注意的是,使用Cuckoo‘s Egg設計模式置換的功能部件,不管它是跨越bean的還是在一個(gè)類(lèi)中,它的生命周期與它所置換的功能部件的目標生命周期匹配。在上例中這沒(méi)什么問(wèn)題,因為只有一個(gè)功能部件實(shí)例被置換了,而且唯一的Cuckoo‘s Egg通知只維護一個(gè)替代功能部件。

  這個(gè)例子非常簡(jiǎn)單,而在實(shí)踐中,您很可能必須處理大量需要用各自的Cuckoo‘s Egg實(shí)例置換的功能部件實(shí)例。在這種情況下,單個(gè)的方面實(shí)例需要被關(guān)聯(lián)到單個(gè)的要置換的功能部件實(shí)例。本系列的下一篇文章將會(huì )考慮方面生命周期的用法,屆時(shí)將解決這個(gè)問(wèn)題。

結束語(yǔ)
  本文介紹了如何在Spring框架內謹慎使用around形式的通知。around形式的通知常用于實(shí)現Cuckoo‘s Egg設計模式時(shí),所以我們引入了一個(gè)例子來(lái)說(shuō)明如何使用Spring AOP實(shí)現這種面向方面設計模式。

  在本系列的第三部分中,您將看到如何使用Spring框架中其他的AOP基本概念。這些概念包括:控制方面生命周期、使用基于introduction通知的積極方面改變應用程序的靜態(tài)結構,以及使用control flow切入點(diǎn)實(shí)現對方面編織的更細微的控制。

  參考資料

  原文出處
An Introduction to Aspect-Oriented Programming with the Spring Framework, Part 2 http://www.onjava.com/pub/a/onjava/2004/10/20/springaop2.html

 作者簡(jiǎn)介
Russell Miles是General Dynamics UK公司的一名軟件工程師,他負責Java和分布式系統,但是他目前主要的興趣在面向方面領(lǐng)域,尤其是AspectJ。

  作者其它文章
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
Spring Framework中的面向方面編程(AOP)
Spring Framework中的AOP編程之入門(mén)篇 2
ZhiMap導圖
Spring、SpringMVC、Shiro面試題
spring學(xué)習總結
spring面試題
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久