深入了解SpringAOP中的jdk動(dòng)態(tài)代理與CGlib
理解AOP
一般我們編寫程序的思想是縱向的,也就是一個(gè)方法代碼從該方法第一行開始往下一步一步走,直到走完最后一行代碼。
也就是說很多業(yè)務(wù)都需要的比如用戶鑒權(quán),資源釋放等我們都要在每個(gè)方法里面重復(fù)再去調(diào)用,如下所示:
public void doMethodOne() { System.out.println("doMethodOne由上往下第一步:用戶鑒權(quán)"); System.out.println("doMethodOne由上往下第二步:業(yè)務(wù)邏輯,調(diào)用服務(wù)1"); System.out.println("doMethodOne由上往下最后一步:釋放資源"); } public void doMethodTwo() { System.out.println("doMethodTwo由上往下第一步:用戶鑒權(quán)"); System.out.println("doMethodTwo由上往下第二步:業(yè)務(wù)邏輯,調(diào)用服務(wù)1"); System.out.println("doMethodTwo由上往下最后一步:釋放資源"); } public static void main(String[] args) { doMethodOne(); doMethodTwo(); }
AOP(面向切面編程),它可以用來攔截方法前后,來達(dá)到增強(qiáng)方法的目的。
所以我理解的AOP的本質(zhì)是在一系列縱向的控制流程中,把那些相同的子流程提取成一個(gè)橫向的面,就像下面這張圖把相同的邏輯,用戶鑒權(quán)、資源釋放抽取出來,橫切到各個(gè)需要該場(chǎng)景的方法的開頭、中間以及結(jié)尾。
SpringAOP中的一些術(shù)語
- 通知(Advice): 何時(shí)(Before,After,Around,After還有幾個(gè)變種) 做什么
- 連接點(diǎn)(JoinPoint): 應(yīng)用對(duì)象提供可以切入的所有功能(一般是方法,有時(shí)也是參數(shù))
- 切點(diǎn)(PointCut): 通過指定,比如指定名稱,正則表達(dá)式過濾, 指定某個(gè)/些連接點(diǎn), 切點(diǎn)描繪了 在何地 做
- 切面(Aspect): 通知 + 切點(diǎn) 何時(shí)何地做什么
- 引入(Introduction):向現(xiàn)有類添加新的屬性或方法
- 織入(Weaving): 就是將切面應(yīng)用到目標(biāo)對(duì)象的過程
實(shí)現(xiàn)方式之JDK的動(dòng)態(tài)代理
JDK動(dòng)態(tài)代理目標(biāo)是按照接口實(shí)現(xiàn)類的形式。
你需要?jiǎng)?chuàng)建一個(gè)jdkproxy 類來繼承InvocatoinHandler 接口,將你想要增強(qiáng)的代碼添加到里面的invoke方法中。
目標(biāo)類如下
package com.lee.aop.jdkaop; /** * @author lee */ public interface UserServiceInf { void updateUser(); }
package com.lee.aop.jdkaop; /** * @author lee */ public class UserServiceImpl implements UserServiceInf { @Override public void updateUser() { System.out.println("修改用戶"); } }
代理類如下:
package com.lee.aop.jdkaop; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * @author lee */ public class MyProxy implements InvocationHandler { private Object target ; public Object getTarget() { return target; } public void setTarget(Object target) { this.target = target; } public Object createProxy(Object target) { this.target = target ; return Proxy.newProxyInstance(this.target.getClass(). getClassLoader(),this.target.getClass().getInterfaces(),this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Method methods = this.target.getClass().getMethod("updateUser",null); System.out.println("用戶鑒權(quán)"); methods.invoke(this.target,null); return null; } }
測(cè)試類:
package com.lee.aop.jdkaop; public class Tester { public static void main(String[] args) { UserServiceImpl userImpl = new UserServiceImpl(); UserServiceInf service = (UserServiceInf) new MyProxy().createProxy(userImpl); service.updateUser(); } }
實(shí)現(xiàn)方式之CGlib動(dòng)態(tài)代理
目標(biāo)類
package com.lee.aop.cglib; /** * @author lee */ public class UserService { public void updateUser(String uid) { System.out.println("獲取User" + uid); } }
代理類
package com.lee.aop.cglib; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; /** * @author lee */ public class UserProxy implements MethodInterceptor { //通過Enhacer創(chuàng)建一個(gè)代理對(duì)象 Enhancer proxy = new Enhancer(); public Object getProxy(Class clz) { proxy.setSuperclass(clz); proxy.setCallback(this); return proxy.create(); } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("用戶鑒權(quán)"); methodProxy.invokeSuper(o,objects); return null; } }
測(cè)試類
package com.lee.aop.cglib; /** * @author lee */ public class Tester { public static void main(String[] args) { UserProxy proxy = new UserProxy(); UserService userService = (UserService) proxy.getProxy(UserService.class); userService.updateUser("lee"); } }
JDK動(dòng)態(tài)代理與CGlib代理的區(qū)別
- JDK動(dòng)態(tài)代理只能對(duì)實(shí)現(xiàn)了接口的類生成代理,而不能針對(duì)類
- CGLIB是針對(duì)類實(shí)現(xiàn)代理,主要是對(duì)指定的類生成一個(gè)子類,覆蓋其中的方法(繼承)
- JDK的動(dòng)態(tài)代理是基于類實(shí)現(xiàn)了接口,cglib是基于類,沒有強(qiáng)制要求目標(biāo)類一定要是實(shí)現(xiàn)接口。
- JDK的核心是實(shí)現(xiàn)InvocationHandler接口,使用invoke()方法進(jìn)行面向切面的處理,調(diào)用相應(yīng)的通知。
- CGLIB的核心是實(shí)現(xiàn)MethodInterceptor接口,使用intercept()方法進(jìn)行面向切面的處理,調(diào)用相應(yīng)的通知。
所以在Spring中當(dāng)Bean實(shí)現(xiàn)接口時(shí),Spring就會(huì)用JDK的動(dòng)態(tài)代理,當(dāng)Bean沒有實(shí)現(xiàn)接口時(shí),Spring使用CGlib來實(shí)現(xiàn)。
到此這篇關(guān)于深入了解SpringAOP中的jdk動(dòng)態(tài)代理與CGlib的文章就介紹到這了,更多相關(guān)jdk動(dòng)態(tài)代理與CGlib內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Java兩種動(dòng)態(tài)代理JDK動(dòng)態(tài)代理和CGLIB動(dòng)態(tài)代理詳解
- Java的動(dòng)態(tài)代理模式之JDK代理詳解
- JDK動(dòng)態(tài)代理提高代碼可維護(hù)性和復(fù)用性利器
- Spring之AOP兩種代理機(jī)制對(duì)比分析(JDK和CGLib動(dòng)態(tài)代理)
- Java JDK與cglib動(dòng)態(tài)代理有什么區(qū)別
- 解讀jdk動(dòng)態(tài)代理為什么必須實(shí)現(xiàn)接口
- Java實(shí)現(xiàn)JDK動(dòng)態(tài)代理的原理詳解
- Java反射(JDK)與動(dòng)態(tài)代理(CGLIB)詳解
- Java JDK動(dòng)態(tài)代理在攔截器和聲明式接口中的應(yīng)用小結(jié)
相關(guān)文章
SpringBoot接收J(rèn)SON類型的參數(shù)方式
這篇文章主要介紹了SpringBoot接收J(rèn)SON類型的參數(shù)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-03-03SpringBoot使用MapStruct生成映射代碼的示例詳解
MapStruct 是一個(gè)用于 Java 的代碼生成器,專門用于生成類型安全的 bean 映射代碼,它通過注解處理器在編譯時(shí)生成映射代碼,從而避免了運(yùn)行時(shí)的性能開銷和潛在的錯(cuò)誤,本文給大家介紹了SpringBoot使用MapStruct生成映射代碼的示例,需要的朋友可以參考下2024-11-11Java 策略模式與模板方法模式相關(guān)總結(jié)
這篇文章主要介紹了Java 策略模式與模板方法模式相關(guān)總結(jié),幫助大家更好的理解和使用Java,感興趣的朋友可以了解下2021-01-01Java Socket聊天室編程(二)之利用socket實(shí)現(xiàn)單聊聊天室
這篇文章主要介紹了Java Socket聊天室編程(二)之利用socket實(shí)現(xiàn)單聊聊天室的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-09-09Java8 如何移除兩個(gè)相同的List對(duì)象
這篇文章主要介紹了Java8 如何移除兩個(gè)相同的List對(duì)象,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01