Spring系列之六:AOP的代理詳解
Aop是面向切片的程式設計,首先先用圖解釋AOP的程式設計
這是沒有用aop的情況,程式碼中存在大量的重複的程式碼:
使用aop就是採用一個切片,對封裝好的程式進行切開,減少重複的程式碼,對重複的程式碼進行復用:
那麼如何實現這種aop的切片程式設計了?就是使用動態代理的方式,為方法增加方法,現在就講一講代理的原理:
代理就相當於處於一箇中間層,當一個物件不能呼叫另一個物件的方法時候,可以通過代理進行呼叫。
首先是靜態代理:
靜態代理相當於首先定義了一個介面,介面中有個方法,出於不同的需要,我們有很多子類實現了這個介面並重寫了這個介面中的方法(被代理類)。靜態代理處於中間層不斷呼叫代理類。
下面給出實現代理的原始碼:
1.介面的實現
/** * Subject介面的實現 */ public interface Subject { void visit(); }
2.產生被代理類
/** * Subject介面的實現 */ public class SubjectImpl implements Subject { public void visit() { System.out.println("SubjectImpl!"); } }
3.中間層代理類
public class ProxySubject implements Subject { privateSubject subject; public ProxySubject(Subject subject) { this.subject = subject; } public void visit() { subject.visit(); } }
4.使用代理類
public class Client { public static void main(String[] args) { ProxySubject subject=new ProxySubject(new SubjectImpl()); subject.visit();} }
由此可以看到,我們對介面中的方法進行了擴充。aop中使用代理就是對方法進行擴充
現在講一講動態代理:
由上面的例子可以看出,你對介面中的方法進行擴充的時候,你每次都要進行新建一個類,給代理類進行呼叫,以後程式越寫越多就會十分麻煩,那這個時候就要用到動態代理,就在產生的被代理類上進行擴充,而不需要頻繁的進行建類。
下面給出動態代理的實現原始碼:
1.介面類
/** * Subject介面的實現 */ public interface Subject { void visit(); }
2.被代理類
/** * Subject介面的實現 */ public class SubjectImpl implements Subject { public void visit() { System.out.println("SubjectImpl!"); } }3.使用handler對被代理類進行擴充
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class Handler implements InvocationHandler { private Object target; public Handler(Object target) { this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("開始事務!"); method.invoke(target,args); System.out.println("事務結束!"); return null; } }
4.呼叫代理類
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class Client { public static void main(String[] args) { SubjectImpl subjectImpl=new SubjectImpl(); InvocationHandler handler=new Handler(subjectImpl); Subject subject = (Subject) Proxy.newProxyInstance(subjectImpl.getClass().getClassLoader(), subjectImpl.getClass().getInterfaces(), handler); subject.visit(); } }
Proxy.newProxyInstance用於產生引數
第一個引數:ClassLoader loader:它是類載入器型別
第二個引數:Class[] interfaces:指定newProxyInstance()方法返回的物件要實現哪些介面,沒錯,可以指定多個介面
第三個引數:handler主要就是對方法增加內容
aop面向切片程式設計就是這樣為方法增加內容,aop主要使用Cglin代理和動態代理,動態代理傳入的是個介面,而cglib闖入是物件,Spirng自行選擇該使用何種方法。總之是為了在原基礎上增加內容。