您好,登錄后才能下訂單哦!
這篇文章給大家介紹如何在Spring框架中實現動態代理,內容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。
動態代理,是一種通過運行時操作字節碼,以達到增強類的功能的技術,也是Spring AOP操作的基礎,關于AOP的內容,將在后面的筆記中詳細講解,本小節主要是理清楚動態代理,畢竟,Spring的AOP是基于動態代理技術,對動態代理技術有所了解,對于學習Spring AOP也會有幫助
動態代理技術詳解
動態代理,現在主要是用于增強類的功能,同時由于是具有動態性,所以避免了需要頻繁創建類的操作,同時,也使得原有的代碼在不需要改變的情況下,對類的功能進行增強,主要的動態代理技術有:通過實現目標接口,重寫其方法,以增強其能力,典型的以JDK動態代理為代表;或者,通過繼承類,重寫其方法以增強其能力,典型的以CGLib為代表,這兩種技術分別從不同的方向來對類的能力進行擴充,接下來來具體看下這兩種技術的特點以及差異。
基于JDK動態代理
基于JDK的動態代理技術,其主要特點就是目標類,也就是需要被代理的類,必須有接口,并且代理類必須實現跟它一樣的接口,從而來起到代理其事務的功能,具體使用如下代碼所示,假設有一個UserService類,主要用于負責用戶的登錄和退出,同時,有個日志類,負責記錄用戶的操作信息,直接將信息日志寫在對應的UserService實現類中,可以達到目的,但顯然這種方式不是很合理,特別是在UserService有很多個方法需要做日志記錄的時候,就會使得日志記錄代碼遍布整個UserService,不僅使得代碼的冗余很大,而且當需要進行修改的時候,也需要逐個修改,非常麻煩,這個時候,采用動態代理技術就是一種非常好的方法了。
/** * UserService接口 */ interface UserService{ void login(); void logout(); } /** * UseService實現類 */ class UserServiceImpl implements UserService{ @Override public void login() { System.out.println("someone login...."); } @Override public void logout() { System.out.println("someone logout...."); } } /** * 實現InvocationHandle接口,用于織入所要增強的代碼 */ class UserServiceHandle implements InvocationHandler{ private UserService userService; public UserServiceHandle(UserService userService) { this.userService = userService; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { LogService.info(); Object object = method.invoke(userService, args); LogService.info(); return object; } } /** * 代理類工廠,用于產生UseService類的代理類 */ class ProxyFactory{ public static UserService getProxyObject(UserService userService){ // 使用JDK動態代理技術來創建對應的代理類 return (UserService) Proxy.newProxyInstance( userService.getClass().getClassLoader(), userService.getClass().getInterfaces(), new UserServiceHandle(userService) ); } }
這樣,當我們需要使用UseService類的時候,只需要從ProxyFactory中獲取即可,而且獲取的對象是UserService對象的代理類,也就是說,獲得的對象是UserService對象的增強版
基于CGLib的動態代理技術
從上面的ProxyFactory工廠中可以看到,在使用JDK進行創建動態代理對象的時候,需要為其提供接口,或者說,如果所要增強的目標類沒有實現任何接口,則JDK動態代理技術是無法為其創建對應的代理對象的,這是JDK動態代理技術的一種缺點,而CGLib動態代理技術則恰好彌補了這個缺點,CGLib動態代理技術使用的是繼承該類的方式,從而避免了需要接口的缺陷,具體使用如下所示,注意,需要導入對應的依賴文件
/** * 基于CGLib的動態代理技術 * 注意這里需要實現MethodInterceptor接口 */ class ProxyFactory implements MethodInterceptor{ // 提供對應的增強操作類 private Enhancer enhancer = new Enhancer(); public UserService getProxyObject(Class clazz){ // 設置所要增強的類的父類 enhancer.setSuperclass(clazz); // 設置回調對象 enhancer.setCallback(this); // 創建對應的對象 return (UserService) enhancer.create(); } // 實現攔截方法,用于攔截對應的方法,并且對對應的方法進行增強 // 參數含義:傳入的對象, Method對象,方法的參數,進行代理后的Method對象 @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { LogService.info(); // 這里需要注意,由于methodProxy對象是增強后的Method對象,所以這里需要調用的 // 是methodProxy父類的方法,也就是所以增強的類的方法,以實現原來的功能 Object object = methodProxy.invokeSuper(o, objects); LogService.info(); return object; } }
可以看到,使用CGLib動態代理技術可以在不需要實現接口的情況下東塔為對象創建代理對象,在很大程度上彌補了JDK動態代理技術的缺點,不過由于CGLib動態代理技術是采用繼承目標類的方式,所以也存在一些問題,比如說,對于final以及private修飾的方法是無法為其增強的,這里還需要注意一下。
總結
動態代理技術是實現AOP技術的基礎,也是一種很方便地實現方式,常用的動態代理技術有基于JDK動態代理技術以及基于CGLib的動態代理技術,兩種技術各有千秋,也都各有缺點基于JDK的動態代理技術需要為其提供接口,基于CGLib的動態代理技術不能為final以及private修飾的方法進行增強,在使用的時候需要根據具體進行進行合理選擇。
關于如何在Spring框架中實現動態代理就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。