java 動態代理 cglib記錄

代理是一種常用的設計模式,其目的就是爲其他對象提供一個代理以控制對某個對象的訪問。代理類負責爲委託類預處理消息,過濾消息並轉發消息,以及進行消息被委託類執行後的後續處理。
爲 了保持行爲的一致性,代理類和委託類通常會實現相同的接口,所以在訪問者看來兩者沒有絲毫的區別。通過代理類這中間一層,能有效控制對委託類對象的直接訪 問,也可以很好地隱藏和保護委託類對象,同時也爲實施不同控制策略預留了空間,從而在設計上獲得了更大的靈活性。Java 動態代理機制以巧妙的方式近乎完美地實踐了代理模式的設計理念。
Java 動態代理。具體有如下四步驟:

1、通過實現 InvocationHandler 接口創建自己的調用處理器;
InvocationHandlerImpl 實現了 InvocationHandler 接口,並能實現方法調用從代理類到委託類的分派轉發, 其內部通常包含指向委託類實例的引用,用於真正執行分派轉發過來的方法調用
InvocationHandler handler = new InvocationHandlerImpl(..);
2、通過爲 Proxy 類指定 ClassLoader 對象和一組 interface 來創建動態代理類;
通過 Proxy 爲包括 Interface 接口在內的一組接口動態創建代理類的類對象 代理類對象
Class clazz = Proxy.getProxyClass(classLoader, new Class[] { Interface.class, … });
3、通過反射機制獲得動態代理類的構造函數,其唯一參數類型是調用處理器接口類型;
通過反射從生成的代理類對象中獲得構造函數對象
Constructor constructor = clazz.getConstructor(new Class[] { InvocationHandler.class });

4、通過構造函數創建動態代理類實例,構造時調用處理器對象作爲參數被傳入。
通過構造函數對象創建動態代理類實例
Interface Proxy = (Interface)constructor.newInstance(new Object[] { handler });
實際使用過程更加簡單,因爲 Proxy 的靜態方法 newProxyInstance 已經爲我們封裝了步驟 2 到步驟 4 的過程,所以簡化後的過程如下:
InvocationHandler handler = new InvocationHandlerImpl(..);
// 通過 Proxy 直接創建動態代理類實例
Interface proxy = (Interface)Proxy.newProxyInstance( classLoader,
new Class[] { Interface.class },
handler );
注意:
1、Proxy 類是代理類的父類,這個規則適用於所有由 Proxy 創建的動態代理類。而且代理類類還實現了其所代理的一組接口,這就是爲什麼它能夠被安全地類型轉換到其所代理的某接口的根本原因。
2、委託類。首先,要注意不能有重複的接口,以避免動態代理類代碼生成時的編譯錯誤。其次,這些接口對於類裝載器必須可見,否則類裝載器將無 法鏈接它們,將會導致類定義失敗。再次,需被代理的所有非 public 的接口必須在同一個包中,否則代理類生成也會失敗。最後,接口的數目不能超過 65535,這是 JVM 設定的限制。
demo:
接口:
public interface PersonService {
public void eat(String foodName);
public void drink(String drinkName);
}
實現類:
public class PersonServiceImpl implements PersonService{
@Override
public void eat(String foodName) {
System.out.println(“eat…..” + foodName);
drink(“可樂”);
}
//看看在這個方法 執行的時候 能否執行代理類裏面想要的代碼?
//沒能夠執行,原因:因爲執行eat(String foodName)的時候 已經不是代理類啦
@Override
public void drink(String drinkName) {
System.out.println(“drink….” + drinkName);

}

}
jdk動態代理
public class JdkProxyOne {
private Object targetObject;//代理目標
public Object createProxyInstance(Object obj){
this.targetObject = obj;
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), new TargetHandelr());//代理類實例
}
class TargetHandelr implements InvocationHandler{

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        System.out.println("找飯店。。。");
        Object invoke = method.invoke(targetObject, args);//回掉委託類的方法
        System.out.println("吃完付錢");
        System.out.println(proxy.getClass());//class com.sun.proxy.$Proxy0
        return invoke;
    }

}

}
測試:
public class TestJdkProxy {
public static void main(String[] args) {
JdkProxyOne jdkProxy = new JdkProxyOne();
PersonService personService = (PersonService) jdkProxy.createProxyInstance(new PersonServiceImpl());
InvocationHandler invocationHandler = Proxy.getInvocationHandler(personService);
System.out.println(invocationHandler.getClass());//獲得代理類實例的調用處理器對象 class com.example.proxy.one.JdkProxyOne$TargetHandelr
personService.eat(“拉麪”);//代理類執行方法 在不改變委託類的代碼的情況下 添加要執行的代碼
System.out.println(Proxy.isProxyClass(personService.getClass()));//true
}
}

jdk動態代理 對接口進行代理 對於非接口的 可以考慮cglib
他的原理是對指定的目標類生成一個子類,並覆蓋其中方法實現增強,但因爲採用的是繼承,所以不能對final修飾的類進行代理。
//一個需要被代理的類【委託類】,也就是父類,通過字節碼技術創建這個類的子類,實現動態代理
public class AnimalService {
public void run(){
System.out.println(“dog is running”);
}
}
cglib獲取代理類
///實現MethodInterceptor接口方法
public class CglibProxy implements MethodInterceptor{
private Object targetObject;
public Object createProxyInstance(Object target){
this.targetObject = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.targetObject.getClass());//設置需要創建子類的類
enhancer.setCallback(this);
enhancer.setClassLoader(targetObject.getClass().getClassLoader());
return enhancer.create();////通過字節碼技術動態創建子類實例
}
//intercept()方法攔截所有目標類方法的調用,obj表示目標類的實例,
//method爲目標類方法的反射對象,args爲方法的動態入參,proxy爲代理類實例。
//proxy.invokeSuper(obj, args)通過代理類調用父類中的方法。
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println(“前置代理”);
//通過代理類調用父類中的方法
Object result = proxy.invokeSuper(obj, args);
System.out.println(“後置代理”);
return result;
}

private void doBefore() {
    System.out.println("before method invoke");
}

private void doAfter() {
    System.out.println("after method invoke");
}

}
測試:
public static void main(String[] args) {
AnimalService animalService = new AnimalService();
CglibProxy cglibProxy = new CglibProxy();
AnimalService proxyAnimalService = (AnimalService) cglibProxy.createProxyInstance(animalService);
proxyAnimalService.run();
}
打印:
前置代理
dog is running
後置代理

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章