靜態(tài)代理
靜態(tài)代理是代理模式的實現(xiàn)方式之一理朋,是相對于動態(tài)代理而言的絮识。所謂靜態(tài)代理是指,在程序運行前嗽上,由程序員創(chuàng)建或特定工具自動生成源代碼并對其編譯生成.class文件次舌。
靜態(tài)代理的實現(xiàn)只需要三步:首先,定義業(yè)務(wù)接口兽愤;其次彼念,實現(xiàn)業(yè)務(wù)接口挪圾;然后,定義代理類并實現(xiàn)業(yè)務(wù)接口逐沙;最后便可通過客戶端進(jìn)行調(diào)用哲思。
/**
* 代理接口
*/
public interface DemoService {
public void print(String param);
}
/**
* 真正的實現(xiàn)類
*/
public class DemoServiceImpl implements DemoService {
@Override
public void print(String param) {
System.out.println("real method:" + param);
}
}
/**
* 代理類
*/
public class DemoProxy implements DemoService {
private DemoService demoService;
public DemoProxy(DemoServiceImpl impl) {
this.demoService = impl;
}
@Override
public void print(String param) {
System.out.println("before real method");
demoService.print("AAA");
System.out.println("after real method");
}
}
//測試類
public class Test {
public static void main(String[] args) {
DemoService demoService = new DemoProxy(new DemoServiceImpl());
demoService.print("AAA");
}
}
靜態(tài)代理的局限性:
一個代理類Proxy只能服務(wù)Subject一種接口,如果有10個不同類型的對象吩案,需要創(chuàng)建10個代理類棚赔,類的數(shù)量激增、也增加了代碼的冗余
如果只用一個代理類徘郭,就能完成全部的代理功能就好了靠益,于是就有了動態(tài)代理
動態(tài)代理
和靜態(tài)代理不同,動態(tài)代理的字節(jié)碼是在程序運行期間残揉,由JVM根據(jù)反射等機(jī)制動態(tài)生成的胧后。代理類和實際類的關(guān)系是在程序運行時確定的,依托反射等機(jī)制抱环,動態(tài)代理可以動態(tài)生成任意類型的代理類壳快,一個代理的處理程序就可以處理多種對象。
java中的動態(tài)代理有兩種镇草,一種是java自帶的jdk動態(tài)代理眶痰,一種是基于cglib的動態(tài)代理
JDK動態(tài)代理
(1)Proxy 類提供了用于創(chuàng)建動態(tài)代理類和實例對象的方法,它是所創(chuàng)建的動態(tài)代理類的父類
(2)InvocationHandler 接口是代理處理程序類的實現(xiàn)接口梯啤,每一個被生成的代理類實例都可以提供一個相關(guān)的代理處理程序類凛驮,代理類實例的方法被調(diào)用時會回調(diào)invoke()方法
public interface DemoService {
public String print(String param);
}
public class DemoServiceImpl implements DemoService {
@Override
public String print(String param) {
System.out.println("REAL Method");
return param + " REAL METHOD";
}
}
public class ProxyHandler implements InvocationHandler {
private Object obj;
public ProxyHandler(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before Real Method");
String print = (String)method.invoke(obj, args);
System.out.println("after Real Method");
return print;
}
}
public class Test {
public static void main(String[] args) {
DemoServiceImpl impl = new DemoServiceImpl();
ProxyHandler handler = new ProxyHandler(impl);
DemoService demo = (DemoService) Proxy.newProxyInstance(impl.getClass().getClassLoader(),
impl.getClass().getInterfaces(), handler);
demo.print("AAAA");
}
}
JDK動態(tài)代理的局限性:如果是抽象類或者一般的類需要進(jìn)行代理,jdk動態(tài)代理就無法滿足了条辟,只有使用cglib動態(tài)代理
cglib動態(tài)代理
主要用到import net.sf.cglib.proxy包下的MethodInterceptor、MethodProxy和Enhancer類
(1)宏胯、MethodInterceptor
MethodInterceptor類是方法攔截器羽嫡,代理類實例的方法被調(diào)用時會回調(diào)MethodInterceptor的intercept()方法攔截,用來實現(xiàn)自己的代理邏輯肩袍,類似于jdk動態(tài)代理的InvocationHandler接口
(2)杭棵、MethodProxy
MethodProxy是intercept()方法中的第四個參數(shù)的類型,它是實際類方法的代理引用氛赐,使用methodProxy比使用jdk自身的method在效率上會有提升
(3)魂爪、Enhancer
Enhancer用來動態(tài)創(chuàng)建實際類子類的代理類實例,setSuperclass()方法設(shè)置實際類為父類艰管,setCallback()方法建立方法回調(diào)滓侍,create()方法創(chuàng)建一個代理類實例
public class RealDemo {
public void print(String param) {
System.out.println("REAL METHOD " + param);
}
}
public Object newInstance(Object target) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object arg0, Method mrthod, Object[] arg2, MethodProxy proxy) throws Throwable {
System.out.println("BEFORE......");
Object object = proxy.invokeSuper(arg0, arg2);
System.out.println("AFTER......");
return object;
}
}
public class Test {
public static void main(String[] args) {
RealDemo demo = new RealDemo();
ProxyIntercept intercept = new ProxyIntercept();
RealDemo proxyDemo = (RealDemo) intercept.newInstance(demo);
proxyDemo.print("AAA");
}
}
jdk動態(tài)代理是由java內(nèi)部的反射機(jī)制生成一個實現(xiàn)代理接口的匿名類,被代理的類必須要實現(xiàn)一個接口牲芋,如果某個類沒有實現(xiàn)接口則不能生成代理對象撩笆,實際使用中會有一些局限性
cglib動態(tài)代理底層是借助asm來實現(xiàn)的捺球,加載實際類的.class文件,修改其字節(jié)碼生成子類來處理夕冲,比java反射效率要高一些氮兵,不過生成子類的方式也帶來小問題:目標(biāo)類不能聲明成final,因為final類不能被繼承歹鱼,無法生成代理泣栈;目標(biāo)方法也不能聲明成final,final方法不能被重寫弥姻,無法得到處理
參考:https://blog.csdn.net/justloveyou_/article/details/79407248
https://www.cnblogs.com/ctxsdhy/p/5815492.html