typora-copy-images-to: img
代理模式
代理模式(Proxy Pattern)的定義很簡單,是指為其他對象提供一種代理,以控制對這個對象的訪問。
代理對象在客服端和目標對象之間起到中介作用,代理模式屬于結構型設計模式。
使用代理模式主要有兩個目的:
- 保護目標對象
- 增強目標對象
靜態(tài)代理
顯式聲明被代理對象
靜態(tài)代理其實在平時的開發(fā)當中應用非常廣泛,最常見的就是三層架構
- UML類圖

- 代碼:
頂層接口 Person
package com.pmz.proxy;
public interface Person {
public void getGril();
}
被代理對象 User 實現(xiàn)Person接口
package com.pmz.proxy.staticproxy;
import com.pmz.proxy.Person;
public class User implements Person {
@Override
public void getGril() {
System.out.println("我想找個女朋友");
}
}
代理類 UserStaticProxy,持有被代理對象的引用,以及在調用被代理對象前后進行代碼增強
package com.pmz.proxy.staticproxy;
public class UserStaticProxy {
//顯示聲明被代理對象 user
private User user ;
public UserStaticProxy (User user){
this.user = user;
}
public void getGirl(){
System.out.println("找對象的前提要有房有車");
user.getGril();
System.out.println("一見鐘情,準備結婚");
}
}
調用端 UserAction 只需要把被代理對象傳給代理類,就可以直接調用執(zhí)行。
package com.pmz.proxy.staticproxy;
public class UserAction {
public static void main(String[] args) {
UserStaticProxy usp = new UserStaticProxy(new User());
usp.getGirl();
}
}
Person是頂層接口,User是真實對象(被代理對象),UserStaticProxy是代理對象,代
理對象持有被代理對象的引用,客戶端調用代理對象方法,同時也調用被代理對象的方
法,但是在代理對象前后增加一些處理。
在代碼中,我們想到代理,就會理解為是代碼 增強,其實就是在原本邏輯前后增加一些邏輯,而調用者無感知。
缺點:如果再來一個Cat也要找對象,那就沒辦法調用這個代理,就是說不具備擴展性,這個UserStaticProxy只為User類代理。
動態(tài)代理
動態(tài)代理和靜態(tài)對比基本思路是一致的,只不過動態(tài)代理功能更加強大,隨著業(yè)務的擴 展適應性更強。
jdk動態(tài)代理
實現(xiàn)動態(tài)代理的前提是被代理對象必須要實現(xiàn)接口
- UML類圖

- 代碼:
Person和User跟上面的靜態(tài)代理一樣,保持不變
UserDynamicProxy
package com.pmz.proxy.dynamic.jdkd;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class UserDynamicProxy implements InvocationHandler {
//通用類引用
private Object object ;
public Object getInstance(Object object){
this.object = object;
//通過反射獲取被代理類的所有接口實現(xiàn)方法
Class<?> clazz = object.getClass();
//返回對象是新生成的一個以$Proxy0開頭的對象,繼承UserDynamicProxy代理類
// 并實現(xiàn)頂層接口Person
return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object obj = method.invoke(this.object,args);
after();
return obj;
}
private void before() {
System.out.println("找對象的前提要有房有車");
}
private void after() {
System.out.println("一見鐘情,準備結婚");
}
}
UserAction
package com.pmz.proxy.dynamic.jdkd;
import java.lang.reflect.Method;
public class UserAction {
public static void main(String[] args) {
try {
Object obj = new UserDynamicProxy().getInstance(new User());
//通過jdk靜態(tài)代理拿到的對象已經不是User了
//而是新生成的一個以$Proxy0開頭的對象,繼承UserDynamicProxy代理類
System.out.println(obj);
//通過反射獲取被代理類的指定實現(xiàn)方法
Method method = obj.getClass().getMethod("getGril",null);
method.invoke(obj);
} catch (Exception e) {
e.printStackTrace();
}
}
}
- 輸出
JDK動態(tài)代理的新生成實現(xiàn)類都是以$Proxy開頭,后面的數(shù)字是以第幾個實現(xiàn)類為基礎計算的。
該實現(xiàn)類 繼承代理對象UserDynamicProxy,并且實現(xiàn)頂層接口Person
class com.sun.proxy.$Proxy0
找對象的前提要有房有車
我想找個女朋友
一見鐘情,準備結婚
JDK Proxy 生成對象的步驟如下:
1、拿到被代理對象的引用,并且獲取到它的所有的接口,反射獲取。
2、JDK Proxy 類重新生成一個新的類、同時新的類要實現(xiàn)被代理類的所有接口。
3、動態(tài)生成 Java 代碼,把新加的業(yè)務邏輯方法由一定的邏輯代碼去調用(在代碼中體現(xiàn))。
4、編譯新生成的 Java 代碼.class。
5、再重新加載到 JVM 中運行。
cglib動態(tài)代理
行業(yè)內較為流行的動態(tài)代理實現(xiàn)方案,采用繼承被代理類的方式。cglib包的底層是通過使用一個小而快的字節(jié)碼處理框架ASM,來轉換字節(jié)碼并生成新的類
注意:被final修飾的方法不能使用cglib動態(tài)代理調用,因為final修飾的方法不能被繼承
- UML類圖

老規(guī)矩看代碼
User不需要實現(xiàn)接口,就是一個干凈的類
import com.pmz.proxy.Person;
public class User{
public void getGril() {
System.out.println("我想找個女朋友");
}
}
UserDynamicProxy必須實現(xiàn)MethodInterceptor(方法攔截器)接口
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class UserDynamicProxy implements MethodInterceptor {
private Object object ;
public Object getInstance(Class<?> clazz){
//Enhancer為被代理類創(chuàng)建一個子類,
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
private void before() {
System.out.println("找對象的前提要有房有車");
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
before();
Object obj = methodProxy.invokeSuper(o,objects);
after();
return obj;
}
private void after() {
System.out.println("一見鐘情,準備結婚");
}
}
UserAction
import net.sf.cglib.core.DebuggingClassWriter;
public class UserAction {
public static void main(String[] args) {
try {
//會把生成的3個class文件,存到E://cglib_proxy_classes目錄下面去,便于查看源碼
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,
"E://cglib_proxy_classes");
User obj = (User) new UserDynamicProxy().getInstance(User.class);
System.out.println(obj.getClass());
obj.getGril();
} catch (Exception e) {
e.printStackTrace();
}
}
}