代理模式是常用的 Java 設計模式,代理類可以分為兩種:
*靜態(tài)代理:由程序員或特定工具自動生成源代碼,再對其編譯。在程序運行前,代理類的 .class字節(jié)碼 文件就已經(jīng)存在。
*動態(tài)代理:在程序運行時,工具類會動態(tài)的生成代理類的 .class字節(jié)碼 緩存在內存中,再運用反射機制,實例化出代理對象。動態(tài)代理有以下幾種實現(xiàn)形式:JDK自帶的動態(tài)代理(常用)、CGLIB(常用)、javaassist字節(jié)碼操作庫實現(xiàn)、ASM(底層使用指令,可維護性較差)。
靜態(tài)代理
兩種實現(xiàn)方式:
*基于接口的靜態(tài)代理:只能針對有接口的類進行代理。
*基于繼承的靜態(tài)代理:無法對 static、final 類或方法進行代理。
基于接口的靜態(tài)代理
public interface Person {
void doSomeThing();
}
public class ChinesePerson implements Person {
@Override
public void doSomeThing() {
System.out.println("ChinesePerson do some thing");
}
}
public class InterfaceStaticProxy implements Person {
private Person person;
InterfaceStaticProxy(Person person){
this.person = person;
}
@Override
public void doSomeThing() {
System.out.println("before interface static proxy");
try{
person.doSomeThing();
}catch (Exception ex){
System.out.println("ex: " + ex.getMessage());
throw ex;
} finally {
System.out.println("after interface static proxy");
}
}
}
public class Client {
public static void main(String ar[]){
Person proxy = new InterfaceStaticProxy(new ChinesePerson());
proxy.doSomeThing();
}
}
//執(zhí)行結果
before interface static proxy
ChinesePerson do some thing
after interface static proxy
基于繼承的靜態(tài)代理
public class ChinesePerson {
public void doSomeThing() {
System.out.println("ChinesePerson do some thing");
}
}
public class InheritStaticProxy extends ChinesePerson {
@Override
public void doSomeThing() {
System.out.println("before inherit static proxy");
super.doSomeThing();
System.out.println("after inherit static proxy");
}
}
public class Client {
public static void main(String ar[]){
ChinesePerson person = new InheritStaticProxy();
person.doSomeThing();
}
}
//執(zhí)行結果
before inherit static proxy
ChinesePerson do some thing
after inherit static proxy
動態(tài)代理
程序運行中,工具類會動態(tài)的生成代理類的 .class字節(jié)碼 緩存在內存中,再運用反射機制,實例化出代理對象。實現(xiàn)方式是 jdk代理 和 cglib。
JDK代理
1.定義一個類 JdkProxy 實現(xiàn)接口 InvocationHandler。
2.在類 JdkProxy 的構造函數(shù)的入?yún)⒅校瑐魅腩?ChinesePerson 的實例 chinesePerson。
3.在類 JdkProxy 的方法 invoke() 中使用 method.invoke(this.chinesePerson, args); 調用真實對象 chinesePerson 的方法,并在方法的 執(zhí)行前、執(zhí)行后、異常時 輸出日志。
public interface Person {
void doSomeThing();
}
public class ChinesePerson implements Person {
@Override
public void doSomeThing() {
System.out.println("ChinesePerson do some thing");
}
}
public class JdkProxy implements InvocationHandler {
private ChinesePerson chinesePerson;
JdkProxy(ChinesePerson chinesePerson){
this.chinesePerson = chinesePerson;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before jdk dynamic proxy");
Object result;
try{
result = method.invoke(this.chinesePerson,args);
}catch (Exception ex){
System.out.println("ex: " + ex.getMessage());
throw ex;
} finally {
System.out.println("after jdk dynamic proxy");
}
return result;
}
}
public class Client {
public static void main(String ar[]){
//創(chuàng)建動態(tài)代理類的實例
Person proxy = (Person) Proxy.newProxyInstance(Client.class.getClassLoader(),new Class[]{Person.class},new JdkProxy(new ChinesePerson()));
proxy.doSomeThing();
}
}
//執(zhí)行結果
before jdk dynamic proxy
ChinesePerson do some thing
after jdk dynamic proxy
CGLIB代理
1.定義一個類 CglibProxy 實現(xiàn)接口 MethodInterceptor。
2.在類 CglibProxy 的方法 intercept() 中使用 methodProxy.invokeSuper(o, objects); 調用父類 RealSubject 的方法,并在方法的 執(zhí)行前、執(zhí)行后、異常時 輸出日志。
public class ChinesePerson {
public void doSomeThing() {
System.out.println("ChinesePerson do some thing");
}
}
public class CglibProxy implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("before cglib dynamic proxy");
Object result;
try {
result = methodProxy.invokeSuper(o, objects);
} catch (Exception ex) {
System.out.println("ex: " + ex.getMessage());
throw ex;
} finally {
System.out.println("after cglib dynamic proxy");
}
return result;
}
}
public class Client {
public static void main(String ar[]){
//創(chuàng)建一個類生成器 enhancer,設置其父類為 ChinesePerson.class,設置其回調函數(shù)為 new CglibProxy()。
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(ChinesePerson.class);
enhancer.setCallback(new CglibProxy());
// 創(chuàng)建動態(tài)代理類的實例 proxy,執(zhí)行方法 doSomething() 。
ChinesePerson proxy = (ChinesePerson) enhancer.create();
proxy.doSomeThing();
}
}
//執(zhí)行結果
before cglib dynamic proxy
ChinesePerson do some thing
after cglib dynamic proxy