動態代理jdk和cglib的區別

longmanma發表於2021-09-09

動態代理的描述在前兩篇文章已經做了一部分描述和,JDK的動態代理只能針對實現了介面的類生成代理。而cglib的動態代理是針對類實現代理,這兩種代理我們可以靈活使用。我們透過汽車跑的例子來解讀這兩種動態代理。

一.JDK動態代理

Car介面

package proxy;public interface Car {    public void run();
}

Car實現類

package proxy;public class CarImpl implements Car{    public void run() {
        System.out.println("car running");
    }

}

Car代理類

package proxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;//JDK動態代理代理類 public class CarHandler implements InvocationHandler{    //真實類的物件
    private Object car;    //構造方法賦值給真實的類
    public CarHandler(Object obj){        this.car = obj;
    }//代理類執行方法時,呼叫的是這個方法
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before");
        Object res = method.invoke(car, args);
        System.out.println("after");        return res;
    }
}

main方法

package proxy;import java.lang.reflect.Proxy;public class main {    public static void main(String[] args) {
        CarImpl carImpl = new CarImpl();
        CarHandler carHandler = new CarHandler(carImpl);
        Car proxy = (Car)Proxy.newProxyInstance(
                main.class.getClassLoader(), //第一個引數,獲取ClassLoader
                carImpl.getClass().getInterfaces(), //第二個引數,獲取被代理類的介面
                carHandler);//第三個引數,一個InvocationHandler物件,表示的是當我這個動態代理物件在呼叫方法的時候,會關聯到哪一個InvocationHandler物件上
        proxy.run();
    }
}

執行結果

before
car running
after

透過上面的例子三個引數我們可以看到,JDK的動態代理依靠介面實現,入參必須有被代理類的介面,也就是carImpl.getClass().getInterfaces(),如果有些類並沒有實現介面,則不能使用JDK代理,這就要使用cglib動態代理了。

二.Cglib動態代理

沒有實現介面的Car

package proxy;public class CarNoInterface {    public void run() {
        System.out.println("car running");
    }
}

cglib代理類

package proxy;import java.lang.reflect.Method;import org.springframework.cglib.proxy.Enhancer;import org.springframework.cglib.proxy.MethodInterceptor;import org.springframework.cglib.proxy.MethodProxy;public class CglibProxy implements MethodInterceptor{    private Object car;    
    /** 
     * 建立代理物件 
     *  
     * @param target 
     * @return 
     */  
    public Object getInstance(Object object) {  
        this.car = object;  
        Enhancer enhancer = new Enhancer();  
        enhancer.setSuperclass(this.car.getClass());  
        // 回撥方法  
        enhancer.setCallback(this);  
        // 建立代理物件  
        return enhancer.create();  
    }  
    
    @Override
    public Object intercept(Object obj, Method method, Object[] args,MethodProxy proxy) throws Throwable {
        System.out.println("事物開始");  
        proxy.invokeSuper(obj, args);  
        System.out.println("事物結束");  
        return null;  
    }

}

main方法

package proxy;import java.lang.reflect.Proxy;public class main {    public static void main(String[] args) {    
        CglibProxy cglibProxy = new CglibProxy();
        CarNoInterface carNoInterface = (CarNoInterface)cglibProxy.getInstance(new CarNoInterface());
        carNoInterface.run();
    }
}

結果輸出

事物開始
car running
事物結束

上面兩個例子我們已經看到這兩種動態代理各自的分工了,在實際開發中,可以根據需求來靈活安排使用介面來代理還是類來代理了。


作者:激情的狼王
連結:


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2730/viewspace-2809662/,如需轉載,請註明出處,否則將追究法律責任。

相關文章