分享給大家Spring中兩種動態(tài)代理(筆記留存,收藏備用)
動態(tài)代理
相較于靜態(tài)代理,動態(tài)代理更為靈活,在程序運行期間產(chǎn)生代理類(動態(tài)生成不固定) 通過使用放射的機制
可以理解為全能中介的作用吧.代理行為均可以增強目標對象的行為
和cglib的區(qū)別在于: 目標對象是否有接口的實現(xiàn) 若有就選擇jdk動態(tài)代理
首先 自定義一個代理對象接口 我這里寫的是ProxyInter ?將目標對象實現(xiàn)這個接口
我將得到代理對象提取成一個類中的方法
public class JdkProxy {
? ?//目標對象
? ?private Object target;
? ?public JdkProxy(Object target) {
? ? ? ?this.target = target;
? ?}
/**
*
/**
? ? * ClassLoader loader 類加載器
? ? * Class[] interfaces 目標對象的接口數(shù)組
? ? *InvocationHandler是由代理實例的調(diào)用處理程序?qū)崿F(xiàn)的接口。
? ? * 每個代理實例都有一個關(guān)聯(lián)的調(diào)用處理程序。 當(dāng)在代理實例上調(diào)用方法時,方法調(diào)用將被編碼并分派到其調(diào)用處理 ?? *程序的invoke方法
? ? * @return
? ? */
? ?public Object getProxy() {
? ? ? ?ClassLoader loader = this.getClass().getClassLoader();
? ? ? ?Class[] interfaces = target.getClass().getInterfaces();
? ? ? ?InvocationHandler invocationHandler = new InvocationHandler() {
? ? ? ? ? ?@Override
? ? ? ? ? ?public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
? ? ? ? ? ? ? ?Object result = method.invoke(target, args);
? ? ? ? ? ? ? ?return result;
? ? ? ? ? ?}
? ? ? ?};
? ? ? ?;
? ? ? ?Object proxy = Proxy.newProxyInstance(loader, interfaces, invocationHandler);
? ? ? ?return proxy;
? ?}
}
這樣做 主程序中只需要new出目標對象 將目標對象放入得到代理對象后 ?代理對象再執(zhí)行其方法即可
public static void main(String[] args) {
? ?//目標對象
? ?Zhangsan zs = new Zhangsan();
? ?//得到代理對象類
? ?JdkProxy jdkProxy = new JdkProxy(zs);
? ?//得到代理對象
? ?ProxyInter proxy = (ProxyInter) jdkProxy.getProxy();
? ?//通過代理對象調(diào)用目標對象的方法
? ?proxy.method();
}
增強方式就是在 invocationHandler類中的invoke方法上下進行增強即可
2. Cglib動態(tài)代理
與jdk動態(tài)代理不同,他不需要實現(xiàn)接口類
運行過程中只會生成目標對象的子類Enhancer enhancer 運用繼承的方式實現(xiàn)動態(tài)代理
首先 定義一個目標對象
public class Person {
? ? public? void eat(){
? ? ? ? System.out.println("吃飯...");
? ? }
}
想jdk代理一樣 我們將方法提取到一個類中
public class CglibProxy {
? ?//目標對象
? ?private Object target;
? ?public CglibProxy(Object target) {
? ? ? ?this.target = target;
? ?}
? ?//得到代理對象
? ?public Object getProxy() {
? ? ? ?//得到目標類的代理類
? ? ? ?Enhancer enhancer = new Enhancer();
? ? ? ?//設(shè)置父類
? ? ? ?enhancer.setSuperclass(target.getClass());
? ? ? ?MethodInterceptor methodInterceptor = new MethodInterceptor() {
? ? ? ? ? ?/**
? ? ? ? ? ? * 當(dāng)代理對象調(diào)用任意方法時 都會將調(diào)用信息傳遞到形參中
? ? ? ? ? ? * @param obj 代理對象
? ? ? ? ? ? * @param method 目標對象的方法
? ? ? ? ? ? * @param args 目標對象方法列表
? ? ? ? ? ? * @param proxy 子類中目標方法的引用
? ? ? ? ? ? * @return
? ? ? ? ? ? * @throws Throwable
? ? ? ? ? ? */
? ? ? ? ? ?@Override
? ? ? ? ? ?public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
? ? ? ? ? ? ? ?System.out.println("飯前洗手...");
? ? ? ? ? ? ? ?Object result = method.invoke(target, args);
? ? ? ? ? ? ? ?System.out.println("飯后洗碗...");
? ? ? ? ? ? ? ?return result;
? ? ? ? ? ?}
? ? ? ?};
? ? ? ?//設(shè)置Callback回調(diào)
? ? ? ?enhancer.setCallback(methodInterceptor);
? ? ? ?//生成類
? ? ? ?return enhancer.create();
? ?}
}
主程序我們執(zhí)行
public class Starts {
? ?public static void main(String[] args) {
? ? ? ?//目標對象
? ? ? ?Person person = new Person();
? ? ? ?CglibProxy cglibProxy = new CglibProxy(person);
? ? ? ?Person proxy = (Person) cglibProxy.getProxy();
? ? ? ?proxy.eat();
? ?}
}
那么cglib動態(tài)代理完成了
3.兩者的區(qū)別
在我看來,但凡目標對象有實現(xiàn)的接口就會選擇jdk動態(tài)代理的方式,因為效率更高
沒有接口只能借助第三方的cglib了(使用之前一定要配置pom哦)
<dependency>
? ? <groupId>cglib</groupId>
? ? <artifactId>cglib</artifactId>
? ? <version>2.2</version>
</dependency>