Java 動態(tài)代理的多種實現方式
一、動態(tài)代理簡介
優(yōu)勢:在不修改源碼的情況下,對目標方法進行相應的增強。
作用:完成程序功能之間的松耦合。
二、動態(tài)代理的多種實現
- JDK代理:基于接口的動態(tài)代理技術(缺點,目標對象必須有接口,如果沒有接口,則無法完成動態(tài)代理的實現)
- cglib代理:基于父類的動態(tài)代理技術
兩者的區(qū)別如圖所示:
1. 基于JDK的實現
目標接口類:
public interface TargetInterface { public void save(); public void print(String str); }
目標類:
public class Target implements TargetInterface{ public void save() { System.out.println("save running..."); } public void print(String str) { System.out.println(str); } }
增強類:
public class Advice { public void before() { System.out.println("前置增強"); } public void after() { System.out.println("后置增強"); } }
測試類:
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class ProxyTest { public static void main(String[] args) { //目標對象 final Target target = new Target(); //增強對象 final Advice advice = new Advice(); TargetInterface proxyInstance = (TargetInterface)Proxy.newProxyInstance( target.getClass().getClassLoader(), //目標對象類加載器 target.getClass().getInterfaces(), //目標對象相同的接口字節(jié)碼對象數組 new InvocationHandler() { //調用代理對象的任何方法,實質執(zhí)行的都是invoke方法 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{ advice.before(); //前置增強 Object invoke = method.invoke(target, args); //執(zhí)行目標方法 advice.after(); //后置增強 System.out.println(); return invoke; } }); //代理對象的方法測試 proxyInstance.save(); proxyInstance.print("JDK動態(tài)代理"); } }
運行截圖:
2. 基于cglib的實現
需要導入Jar包,如果是maven項目,則在pom.xml文件加入如下配置:
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.2.4.RELEASE</version> </dependency>
目標類:
public class Target { public void save() { System.out.println("save running..."); } public void print(String str) { System.out.println(str); } }
增強類:
public class Advice { public void before() { System.out.println("前置增強"); } public void after() { System.out.println("后置增強"); } }
測試類:
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 ProxyTest { public static void main(String[] args) { final Target target = new Target(); final Advice advice = new Advice(); //返回值就是動態(tài)生成的代理對象,基于cglib //創(chuàng)建增強器 Enhancer enhancer = new Enhancer(); //設置父類(目標) enhancer.setSuperclass(Target.class); //設置回調 enhancer.setCallback(new MethodInterceptor() { public Object intercept(Object o, Method method, Object[] obj, MethodProxy methodProxy) throws Throwable{ advice.before(); Object invoke = method.invoke(target, obj); advice.after(); System.out.println(); return invoke; } }); //創(chuàng)建代理對象 Target proxy = (Target)enhancer.create(); //測試代理方法 proxy.save(); proxy.print("基于cglib實現動態(tài)規(guī)劃"); } }
運行截圖:
三、為什么要有基于cglib的實現
使用JDK動態(tài)代理實現時,最大限制是被增強對象必須實現接口,并且增強的方法只能是接口中聲明的方法。但在實際的項目中,可能總是存在對不實現業(yè)務接口的對象進行增強的需求,這時JDK動態(tài)代理將無能為力。
四、兩種方式的適用場景
JDK動態(tài)代理
優(yōu)點
- 不依賴第三方jar包, 使用方便
- 隨著JDK的升級,JDK動態(tài)代理的性能在穩(wěn)步提升
缺點
- 只能代理實現了接口的類
- 執(zhí)行速度較慢
適用場景
- 如果你的程序需要頻繁、反復地創(chuàng)建代理對象,則JDK動態(tài)代理在性能上更占優(yōu)。
cglib
優(yōu)點
由于是動態(tài)生成字節(jié)碼實現代理,因此代理對象的執(zhí)行速度較快, 約為JDK動態(tài)代理的1.5 ~ 2倍
可以代理沒有實現接口的對象
缺點
- 不能代理final類
- 動態(tài)生成字節(jié)碼雖然執(zhí)行較快,但是生成速度很慢,根據網上一些人的測試結果,cglib創(chuàng)建代理對象的速度要比JDK慢10 ~ 15倍。
適用場景
- 不需要頻繁創(chuàng)建代理對象的應用,如Spring中默認的單例bean,只需要在容器啟動時生成一次代理對象。
以上就是Java 動態(tài)代理的多種實現方式的詳細內容,更多關于Java 動態(tài)代理的實現的資料請關注腳本之家其它相關文章!
相關文章
為什么Spring和IDEA都不推薦使用 @Autowired 注解
本文主要介紹了為什么Spring和IDEA都不推薦使用 @Autowired 注解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-04-04Springboot單體架構http請求轉換https請求來支持微信小程序調用接口
這篇文章主要介紹了Springboot單體架構http請求轉換https請求來支持微信小程序調用接口,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-11-11