Spring中AOP概念與兩種動態(tài)代理模式原理詳解
1.概念
1.AOP技術(shù)簡介
AOP 為Aspect Oriented Programming 的縮寫,意思為面向切面編程,是通過預(yù)編譯方式和運(yùn)行期動態(tài)代理實(shí)現(xiàn)程序功能的統(tǒng)一維護(hù)的一種技術(shù)。
AOP 是 OOP 的延續(xù),是軟件開發(fā)中的一個熱點(diǎn),也是Spring框架中的一個重要內(nèi)容,是函數(shù)式編程的一種衍生范型。利用AOP可以對業(yè)務(wù)邏輯的各個部分進(jìn)行隔離,從而使得業(yè)務(wù)邏輯各部分之間的耦合度降低,提高程序的可重用性,同時提高了開發(fā)的效率。
2.AOP的優(yōu)勢
作用:在程序運(yùn)行期間,在不修改源碼的情況下對方法進(jìn)行功能增強(qiáng)優(yōu)勢:減少重復(fù)代碼,提高開發(fā)效率,并且便于維護(hù)
3.Spring AOP術(shù)語
Spring 的 AOP 實(shí)現(xiàn)底層就是對上面的動態(tài)代理的代碼進(jìn)行了封裝,封裝后我們只需要對需要關(guān)注的部分進(jìn)行代碼編寫,并通過配置的方式完成指定目標(biāo)的方法增強(qiáng)。在正式講解 AOP 的操作之前,我們必須理解 AOP 的相關(guān)術(shù)語,常用的術(shù)語如下:
Target(目標(biāo)對象):代理的目標(biāo)對象Proxy (代理):一個類被 AOP 織入增強(qiáng)后,就產(chǎn)生一個結(jié)果代理類Joinpoint(連接點(diǎn)):所謂連接點(diǎn)是指那些被攔截到的點(diǎn)。在spring中,這些點(diǎn)指的是方法,因?yàn)閟pring只支持方法類型的連接點(diǎn).(可能被增強(qiáng)的方法)Pointcut(切入點(diǎn)):所謂切入點(diǎn)是指我們要對哪些 Joinpoint 進(jìn)行攔截的定義(被增強(qiáng)的方法)Advice(通知/ 增強(qiáng)):所謂通知是指攔截到 Joinpoint 之后所要做的事情就是通知(對目標(biāo)對象增強(qiáng)的方法)Aspect(切面):是切入點(diǎn)和通知(引介)的結(jié)合(目標(biāo)方法+增強(qiáng)=切面)Weaving(織入):是指把增強(qiáng)應(yīng)用到目標(biāo)對象來創(chuàng)建新的代理對象的過程。 spring采用動態(tài)代理織入,而AspectJ采用編譯期織入和類裝載期織入.(一個動作,切點(diǎn)和通知結(jié)合的過程=織入)
4.AOP 開發(fā)明確的事項(xiàng)
需要編寫的內(nèi)容 編寫核心業(yè)務(wù)代碼(目標(biāo)類的目標(biāo)方法)編寫切面類,切面類中有通知(增強(qiáng)功能方法)在配置文件中,配置織入關(guān)系,即將哪些通知與哪些連接點(diǎn)進(jìn)行結(jié)合 AOP 技術(shù)實(shí)現(xiàn)的內(nèi)容 Spring 框架監(jiān)控切入點(diǎn)方法的執(zhí)行。一旦監(jiān)控到切入點(diǎn)方法被運(yùn)行,使用代理機(jī)制,動態(tài)創(chuàng)建目標(biāo)對象的代理對象,根據(jù)通知類別,在代理對象的對應(yīng)位置,將通知對應(yīng)的功能織入,完成完整的代碼邏輯運(yùn)行。 AOP 底層使用哪種代理方式 在 spring 中,框架會根據(jù)目標(biāo)類是否實(shí)現(xiàn)了接口來決定采用哪種動態(tài)代理的方式。
2.AOP底層實(shí)現(xiàn)
實(shí)際上, AOP 的底層是通過 Spring 提供的的動態(tài)代理技術(shù)實(shí)現(xiàn)的。在運(yùn)行期間, Spring通過動態(tài)代理技術(shù)動態(tài)的生成代理對象,代理對象方法執(zhí)行時進(jìn)行增強(qiáng)功能的介入,在去調(diào)用目標(biāo)對象的方法,從而完成功能的增強(qiáng)。
1.AOP 的動態(tài)代理技術(shù):
常用的動態(tài)代理技術(shù)
- JDK 代理 : 基于接口的動態(tài)代理技術(shù)
- cglib 代理:基于父類的動態(tài)代理技術(shù)
2.基于jdk的動態(tài)代理代碼
//---------接口1------------ package com.itspring.proxy.jdk; public interface TargetInterface1 { void save(); } //---------接口2------------ package com.itspring.proxy.jdk; public interface TargetInterface2 { void update(); } //---------接口1,接口2實(shí)現(xiàn)類(目標(biāo)類)------------ package com.itspring.proxy.jdk; //目標(biāo)類(被增強(qiáng)的類) public class Target implements TargetInterface1 ,TargetInterface2{ public void save() { System.out.println("save running..."); } public void update() { System.out.println("update running..."); } }
//---------通知類(方法增強(qiáng)類)------------ package com.itspring.proxy.jdk; //通知類(增強(qiáng)類) public class Advice { public void before() { System.out.println("前置增強(qiáng)..."); } public void afterRunning() { System.out.println("后置增強(qiáng)..."); } }
//---------測試代碼------------ package com.itspring.proxy.jdk; import org.junit.Test; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class ProxyTest { @Test public void test1() { final Target target = new Target(); final Advice advice = new Advice(); //返回值就是動態(tài)生成的代理對象 TargetInterface1 proxy1 = (TargetInterface1) Proxy.newProxyInstance( target.getClass().getClassLoader(), //目標(biāo)類的類加載器 target.getClass().getInterfaces(), //目標(biāo)類實(shí)現(xiàn)的接口(可能有多個) new InvocationHandler() { //調(diào)用代理對象的任何方法,實(shí)質(zhì)上都是調(diào)用invoke方法 public Object invoke(Object proxy, //代理對象 Method method, //目標(biāo)方法對象 Object[] args //目標(biāo)方法的參數(shù) ) throws Throwable { System.out.println("正在執(zhí)行的方法:" + method.getName()); advice.before(); //前置增強(qiáng) Object invoke = method.invoke(target, args); //執(zhí)行目標(biāo)方法 advice.afterRunning(); //后置增強(qiáng) return invoke; } } ); proxy1.save(); //返回值就是動態(tài)生成的代理對象 TargetInterface2 proxy2 = (TargetInterface2) Proxy.newProxyInstance( target.getClass().getClassLoader(), //目標(biāo)類的類加載器 target.getClass().getInterfaces(), //目標(biāo)類實(shí)現(xiàn)的接口(可能有多個) new InvocationHandler() { //調(diào)用代理對象的任何方法,實(shí)質(zhì)上都是調(diào)用invoke方法 public Object invoke(Object proxy, //代理對象 Method method, //目標(biāo)方法對象 Object[] args //目標(biāo)方法的參數(shù) ) throws Throwable { System.out.println("正在執(zhí)行的方法:" + method.getName()); advice.before(); Object invoke = method.invoke(target, args); //執(zhí)行目標(biāo)方法 advice.afterRunning(); return invoke; } } ); proxy2.update(); } }
3.基于cglib的動態(tài)代理代碼
cglib是第三方的庫,spring集成了cglib.
//---------目標(biāo)類------------- package com.itspring.proxy.cglib; import com.itspring.proxy.jdk.TargetInterface1; import com.itspring.proxy.jdk.TargetInterface2; //目標(biāo)類(被增強(qiáng)的類) public class Target { public void save() { System.out.println("save running..."); } public void update() { System.out.println("update running..."); } }
//---------通知類(增強(qiáng)類)------------- package com.itspring.proxy.cglib; //通知類(增強(qiáng)類) public class Advice { public void before() { System.out.println("前置增強(qiáng)..."); } public void afterRunning() { System.out.println("后置增強(qiáng)..."); } }
//---------測試代碼------------- package com.itspring.proxy.cglib; import com.itspring.proxy.jdk.TargetInterface1; import com.itspring.proxy.jdk.TargetInterface2; import org.junit.Test; import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class ProxyTest { @Test public void test1() { //目標(biāo)對象 final Target target = new Target(); //增強(qiáng)對象 final Advice advice = new Advice(); //基于cglib生成動態(tài)代理對象 //1.創(chuàng)建增強(qiáng)器 Enhancer enhancer = new Enhancer(); //2.創(chuàng)建父類 enhancer.setSuperclass(Target.class); //3.設(shè)置回調(diào) enhancer.setCallback(new MethodInterceptor() { public Object intercept(Object proxy, //代理對象 Method method, //目標(biāo)方法 Object[] objects, //目標(biāo)方法的參數(shù) MethodProxy methodProxy) //目標(biāo)方法的代理 throws Throwable { //前置增強(qiáng) advice.before(); //目標(biāo)方法 Object invoke = method.invoke(target, objects); //后置增強(qiáng) advice.afterRunning(); return invoke; } }); //4.生成代理對象 Target target1 = (Target) enhancer.create(); //5.測試 target1.save(); target1.update(); } }
總結(jié)
到此這篇關(guān)于Spring中AOP概念與兩種動態(tài)代理模式原理的文章就介紹到這了,更多相關(guān)Spring動態(tài)代理模式原理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java兩種方法計(jì)算出階乘尾部連續(xù)0的個數(shù)
這篇文章主要介紹了Java兩種方法計(jì)算出階乘尾部連續(xù)0的個數(shù),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03SpringMVC整合SSM實(shí)現(xiàn)表現(xiàn)層數(shù)據(jù)封裝詳解
這篇文章主要介紹了SpringMVC整合SSM實(shí)現(xiàn)表現(xiàn)層數(shù)據(jù)封裝,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2022-10-10Spring Boot統(tǒng)一異常處理最佳實(shí)踐(拓展篇)
這篇文章主要給大家介紹了關(guān)于Spring Boot統(tǒng)一異常處理最佳實(shí)踐(拓展篇)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-02-02Java基礎(chǔ)學(xué)習(xí)之ArrayList類概述與常用方法
這篇文章主要為大家簡單的介紹Java中ArrayList類的概述、常用方法及存儲字符串并遍歷,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2022-08-08Java多線程定時器Timer原理及實(shí)現(xiàn)
這篇文章主要介紹了Java多線程定時器Timer原理及實(shí)現(xiàn),涉及Timer的schedule的使用,定時器Timer的schedule等相關(guān)內(nèi)容以及代碼示例,具有一定參考價(jià)值,需要的朋友可以了解下。2017-11-11