Spring AOP實現原理

jopen 12年前發布 | 101K 次閱讀 Spring 面向方面AOP/IoC

用到了AOP的動態代理模式:

1.畫圖:把切面畫出來

2.舉個例子進行說明

3:實現原理:


切面的意義何在?
 

首先根據上例,假設我們實現了一個通用的權限檢查模塊,那么就可以在這層切面上進
 行統一的集中式權限管理。權限檢查模塊可以和業務邏輯代碼分離,而業務邏輯組件則無需關心權限方面的問題。系統大部分有權限檢查模塊,用的時候直接拿來用這個切面。也就是說,通過切面,我們可以將系統中各個不同層次上的問題隔離開來,實現統一集約式處理。各切面只需集中于自己領域內的邏輯實現。 


這一方面使得開發邏輯更加清晰,專業化分工更加易于進行;另一方面,由于切面的隔


離,降低了耦合性,我們就可以在不同的應用中將各個切面組合使用,從而使得代碼可重用


性大大增強。 


JDKProxy


如果是面向接口的動態代理的實現,即JDKProxy,其代理對象必須是某個接口的實現,使用java.lang.reflect.Proxy類根據一個被代理對象產生一個代理對象userDAOProxy,通過Proxy類的調用靜態方法newProxyInstance,根據要實現的接口來產生(這里為UserDao接口)也就是說接口里面有哪些方法,我生成的代理里面就有哪些方法);以及實現java.lang.reflect.InvocationHandler接口,實現invoke方法實現方法的截獲處理,也就是在方法的前后加上業務邏輯。


當你想在多個方法前后加上業務邏輯的時候,可以使用動態代理,更加靈活方便,代碼的可重用性大大的提高。


根據一個被代理對象通過Proxy靜態方法newProxyInstance產生代理對象:


newProxyInstance里面的參數解釋:


第一個參數是說與被代理對象有同一個ClassLoader,


第二個參數說產生的代理對象實現的那個接口應該與被代理對象實現同一個接口(UserDao),也可以這樣寫new Class[]{UserDao.class}。


第三個參數:當產生代理之后,調用代理里面的方法后要用哪個Handler進行處理。

 LogIntercepter li = new LogIntercepter();

li.setTarget(userDAO);//引入一個被代理的對象userDAO

UserDao userDAOProxy = (UserDao) Proxy.newProxyInstance(userDAO.getClass().getClassLoader(),userDAO.getClass().getInterfaces(), li); </pre>

實現InvocationHandler接口 :


 public Object invoke(Object proxy, Method m, Object[] args)

throws Throwable {

beforeMethod();//在方法前面添加業務邏輯,也就是日志

m.invoke(target, args);//target Method方法所屬的對象,表示被代理對象動態調用invoke()

return null;

} </pre>

CGLibProxy


如果沒有實現接口,也沒有關系,可以用CGLib(面向Class)實現AOP


CGLibProxyJDKProxy的代理機制基本類似,只是其動態代理的代理對象并非某個接口的實現,而是針對目標類擴展的子類。話句話說JDKProxy返回動態代理類,是目標類所實現接口的另一個實現版本,它實現了對目標類的代理(如同UserDAOProxyUserDAOImp的關系),而CGLibProxy返回的動態代理類,則是目標代理類的一個子類(代理類擴展了UserDaoImpl


EnhancerMethodInterceptorCGLib中負責完成代理對象創建和方法截獲處理。


Enhancer創建代理對象,實現MethodInterceptor接口,實現intercept方法來進行方法截取處理。


(CGLib (Code Generation Library) 字節碼類庫是一個強大的,高性能,高質量的Code生成類庫。它可以在運行期擴展Java類與實現Java接口。Hibernate用它來實現PO字節碼的動態生成。CGLib 比 Java 的 java.lang.reflect.Proxy 類更強的在于它不僅可以接管接口類的方法,還可以接管普通類的方法。)



JDK動態代理和CGLIB字節碼生成的區別
 * JDK動態代理只能對實現了接口的類生成代理,而不能針對類.
 * CGLIB針對類實現代理,主要是對指定的類生成一個子類,覆蓋其中的方法
   因為是繼承,所以該類或方法最好不要聲明成final


JDK代理是不需要以來第三方的庫,只要JDK環境就可以進行代理,它有幾個要求


實現InvocationHandler
* 使用Proxy.newProxyInstance產生代理對象


* 被代理的對象必須要實現接口


CGLib 必須依賴于CGLib的類庫,但是它需要類來實現任何接口代理的是指定的類生成一個子類,覆蓋其中的方法,是一種繼承

AOP的應用:

做權限的檢查:設計完備的權限管理組件,完成以往需要大費周折才能完成的權限判定功能。

但是目前還沒有一個完善的實現,一方面是因為權限檢查過于復雜多變,不同的業務邏輯中的權限判定邏輯可能多種多樣;另一方面,就目前的AOP應用的粒度而言,“權限管理”作為一個切面顯得過于龐大,需要進一步設計,設計復雜,實現難度大。


,做日志,做審計,做性能,做事務的處理。項目里面主要用在了聲明式的事務處理上。

1、JDK方式:PersonService為接口,PersonServiceBean為實現類,


   public class JDKProxyFactory implements InvocationHandler {
   private
Object targetObject;

public Object createProxyIntance(Object targetObject) { this.targetObject=targetObject; return Proxy.newProxyInstance(this.targetObject.getClass().getClassLoader(),

this.targetObject.getClass().getInterfaces(), this); }

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { PersonServiceBean person=(PersonServiceBean)this.targetObject; Object result=null;

if(person.getUser()!=null) { result = method.invoke(targetObject, args); } return result; } } </pre>

 2、使用CGlib包實現:PersonServiceBean為實現類,   而沒有PersonService接口,         


 public class CGlibProxyFactory implements MethodInterceptor{
  private
Object targetObject;

public Object createProxyInstance(Object targetObject) { this.targetObject=targetObject; Enhancer enhancer=new Enhancer();

enhancer.setSuperclass(this.targetObject.getClass());//設置目標類的子類,該子類會覆蓋所有父類中的非final方法

enhancer.setCallback(this);//設置回調 return enhancer.create(); }

public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { PersonServiceBean person=(PersonServiceBean)this.targetObject; Object result=null;

if(person.getUser()!=null) { result = methodProxy.invoke(targetObject, args); } return null; } } </pre>

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!