Java筆記(二十一) 動態代理
阿新 • • 發佈:2018-12-25
動態代理
一、靜態代理
代理的背後一般至少有一個實際物件,代理的外部功能和實際物件一般是一樣的,
使用者與代理打交道,不直接接觸實際物件。代理存在的價值:
1)節省成本比較高的實際物件建立開銷,按需延遲載入,建立代理時
並不正真建立實際物件,而只是儲存實際物件的地址,在需要時再載入或者建立。
2)執行許可權檢查,代理檢查許可權後再呼叫實際物件。
3)遮蔽網路的差異性和複雜性,代理在本地,而實際物件在其他伺服器上,呼叫
本地代理時,本地代理請求其他伺服器。
靜態代理示例:
public class SimpleStaticProxy { //服務介面 staticinterface IService { void sayHello(); } //服務類 static class RealService implements IService { @Override public void sayHello() { System.out.println("hi"); } } //代理類 static class TraceProxy implements IService { private IService realService;public TraceProxy(IService realService) { this.realService = realService; } @Override public void sayHello() { System.out.println("Start say hi"); realService.sayHello(); System.out.println("End say hi"); } } publicstatic void main(String[] args) { RealService service = new RealService(); TraceProxy traceProxy = new TraceProxy(service); traceProxy.sayHello(); } }
靜態代理缺陷:如果每個類都需要代理,我們需要為每個類都建立代理類,
實現所有介面,這個工作量相當大。
二、Java SDK代理
所謂動態代理,代理類是動態生成的。
1.用法
public class SimpleJDKDynamicProxy { interface IService { void sayHello(); void sayGoodBye(); } static class RealService implements IService { @Override public void sayHello() { System.out.println("hi"); } @Override public void sayGoodBye() { System.out.println("GoodBye world!"); } } static class SimpleInvocateHandler implements InvocationHandler { private Object realObj; public SimpleInvocateHandler(Object realObj) { this.realObj = realObj; } /** * @param proxy 表示代理物件本身,注意它不是被代理的物件,這個引數用處不大 * @param method 表示正在被呼叫的方法 * @param args 表示方法的引數 * */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Start " + method.getName()); Object result = method.invoke(realObj, args); System.out.println("End " + method.getName()); return result; } } public static void main(String[] args) { IService realService = new RealService(); IService proxyService = (IService) Proxy.newProxyInstance(IService.class.getClassLoader(), new Class<?>[]{IService.class}, new SimpleInvocateHandler(realService)); proxyService.sayHello(); proxyService.sayGoodBye(); } }
/** * @param loader 類載入器 * @param interfaces 代理類要實現的介面列表 * @param h 該介面定義了invoke方法,對代理介面所有的方法呼叫都會轉給該方法 * @return 可以轉換為interfaces陣列中的某個介面型別,注意只能轉換為介面不能轉換為具體的類 * */ public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h);
2.基本原理
建立proxyService的程式碼可以用如下的程式碼代替:
//建立代理類定義,類定義會被快取 Class<?> proxyCls = Proxy.getProxyClass(IService.class.getClassLoader(), new Class<?>[] { IService.class }); //獲取代理類的構造方法 Constructor<?> ctor = proxyCls.getConstructor(new Class<?>[] { InvocationHandler.class }); InvocationHandler handler = new SimpleInvocationHandler(realService); //建立代理類物件 IService proxyService = (IService) ctor.newInstance(handler);
final class $Proxy0 extends Proxy implements SimpleJDKDynamicProxyDemo.IService { private static Method m1; private static Method m3; private static Method m2; private static Method m0; public $Proxy0(InvocationHandler paramInvocationHandler) { super(paramInvocationHandler); } public final boolean equals(Object paramObject) { return((Boolean) this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue(); } public final void sayHello() { this.h.invoke(this, m3, null); } public final String toString() { return (String) this.h.invoke(this, m2, null); } public final int hashCode() { return ((Integer) this.h.invoke(this, m0, null)).intValue(); } static { m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") }); m3 = Class.forName( "laoma.demo.proxy.SimpleJDKDynamicProxyDemo$IService") .getMethod("sayHello",new Class[0]); m2 = Class.forName("java.lang.Object") .getMethod("toString", new Class[0]); m0 = Class.forName("java.lang.Object") .getMethod("hashCode", new Class[0]); } }
三、cglib動態代理
Java SDK動態代理的侷限,它只能為介面建立代理,返回的代理物件也只能轉換到某個介面型別。
public class SimpleCGLibDemo { static class RealService { public void sayHello() { System.out.println("hello"); } } static class SimpleInterceptor implements MethodInterceptor { @Override public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("start " + method.getName()); Object result = methodProxy.invokeSuper(object, args); System.out.println("end " + method.getName()); return result; } } private static <T> T getProxy(Class<T> cls) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(cls); enhancer.setCallback(new SimpleInterceptor()); return (T) enhancer.create(); } public static void main(String[] args) { RealService proxy = getProxy(RealService.class); proxy.sayHello(); } }
cglib是通過繼承實現的,具體原理略。