Spring中AOP概念與兩種動(dòng)態(tài)代理模式原理詳解
1.概念
1.AOP技術(shù)簡(jiǎn)介
AOP 為Aspect Oriented Programming 的縮寫,意思為面向切面編程,是通過預(yù)編譯方式和運(yùn)行期動(dòng)態(tài)代理實(shí)現(xiàn)程序功能的統(tǒng)一維護(hù)的一種技術(shù)。
AOP 是 OOP 的延續(xù),是軟件開發(fā)中的一個(gè)熱點(diǎn),也是Spring框架中的一個(gè)重要內(nèi)容,是函數(shù)式編程的一種衍生范型。利用AOP可以對(duì)業(yè)務(wù)邏輯的各個(gè)部分進(jìn)行隔離,從而使得業(yè)務(wù)邏輯各部分之間的耦合度降低,提高程序的可重用性,同時(shí)提高了開發(fā)的效率。
2.AOP的優(yōu)勢(shì)
作用:在程序運(yùn)行期間,在不修改源碼的情況下對(duì)方法進(jìn)行功能增強(qiáng)優(yōu)勢(shì):減少重復(fù)代碼,提高開發(fā)效率,并且便于維護(hù)
3.Spring AOP術(shù)語(yǔ)
Spring 的 AOP 實(shí)現(xiàn)底層就是對(duì)上面的動(dòng)態(tài)代理的代碼進(jìn)行了封裝,封裝后我們只需要對(duì)需要關(guān)注的部分進(jìn)行代碼編寫,并通過配置的方式完成指定目標(biāo)的方法增強(qiáng)。在正式講解 AOP 的操作之前,我們必須理解 AOP 的相關(guān)術(shù)語(yǔ),常用的術(shù)語(yǔ)如下:
Target(目標(biāo)對(duì)象):代理的目標(biāo)對(duì)象Proxy (代理):一個(gè)類被 AOP 織入增強(qiáng)后,就產(chǎn)生一個(gè)結(jié)果代理類Joinpoint(連接點(diǎn)):所謂連接點(diǎn)是指那些被攔截到的點(diǎn)。在spring中,這些點(diǎn)指的是方法,因?yàn)閟pring只支持方法類型的連接點(diǎn).(可能被增強(qiáng)的方法)Pointcut(切入點(diǎn)):所謂切入點(diǎn)是指我們要對(duì)哪些 Joinpoint 進(jìn)行攔截的定義(被增強(qiáng)的方法)Advice(通知/ 增強(qiáng)):所謂通知是指攔截到 Joinpoint 之后所要做的事情就是通知(對(duì)目標(biāo)對(duì)象增強(qiáng)的方法)Aspect(切面):是切入點(diǎn)和通知(引介)的結(jié)合(目標(biāo)方法+增強(qiáng)=切面)Weaving(織入):是指把增強(qiáng)應(yīng)用到目標(biāo)對(duì)象來(lái)創(chuàng)建新的代理對(duì)象的過程。 spring采用動(dòng)態(tài)代理織入,而AspectJ采用編譯期織入和類裝載期織入.(一個(gè)動(dòng)作,切點(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ī)制,動(dòng)態(tài)創(chuàng)建目標(biāo)對(duì)象的代理對(duì)象,根據(jù)通知類別,在代理對(duì)象的對(duì)應(yīng)位置,將通知對(duì)應(yīng)的功能織入,完成完整的代碼邏輯運(yùn)行。 AOP 底層使用哪種代理方式 在 spring 中,框架會(huì)根據(jù)目標(biāo)類是否實(shí)現(xiàn)了接口來(lái)決定采用哪種動(dòng)態(tài)代理的方式。
2.AOP底層實(shí)現(xiàn)
實(shí)際上, AOP 的底層是通過 Spring 提供的的動(dòng)態(tài)代理技術(shù)實(shí)現(xiàn)的。在運(yùn)行期間, Spring通過動(dòng)態(tài)代理技術(shù)動(dòng)態(tài)的生成代理對(duì)象,代理對(duì)象方法執(zhí)行時(shí)進(jìn)行增強(qiáng)功能的介入,在去調(diào)用目標(biāo)對(duì)象的方法,從而完成功能的增強(qiáng)。
1.AOP 的動(dòng)態(tài)代理技術(shù):
常用的動(dòng)態(tài)代理技術(shù)
- JDK 代理 : 基于接口的動(dòng)態(tài)代理技術(shù)
- cglib 代理:基于父類的動(dòng)態(tài)代理技術(shù)

2.基于jdk的動(dòng)態(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)...");
}
}
//---------測(cè)試代碼------------
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();
//返回值就是動(dòng)態(tài)生成的代理對(duì)象
TargetInterface1 proxy1 = (TargetInterface1) Proxy.newProxyInstance(
target.getClass().getClassLoader(), //目標(biāo)類的類加載器
target.getClass().getInterfaces(), //目標(biāo)類實(shí)現(xiàn)的接口(可能有多個(gè))
new InvocationHandler() {
//調(diào)用代理對(duì)象的任何方法,實(shí)質(zhì)上都是調(diào)用invoke方法
public Object invoke(Object proxy, //代理對(duì)象
Method method, //目標(biāo)方法對(duì)象
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();
//返回值就是動(dòng)態(tài)生成的代理對(duì)象
TargetInterface2 proxy2 = (TargetInterface2) Proxy.newProxyInstance(
target.getClass().getClassLoader(), //目標(biāo)類的類加載器
target.getClass().getInterfaces(), //目標(biāo)類實(shí)現(xiàn)的接口(可能有多個(gè))
new InvocationHandler() {
//調(diào)用代理對(duì)象的任何方法,實(shí)質(zhì)上都是調(diào)用invoke方法
public Object invoke(Object proxy, //代理對(duì)象
Method method, //目標(biāo)方法對(duì)象
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的動(dòng)態(tài)代理代碼
cglib是第三方的庫(kù),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)...");
}
}
//---------測(cè)試代碼-------------
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)對(duì)象
final Target target = new Target();
//增強(qiáng)對(duì)象
final Advice advice = new Advice();
//基于cglib生成動(dòng)態(tài)代理對(duì)象
//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, //代理對(duì)象
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.生成代理對(duì)象
Target target1 = (Target) enhancer.create();
//5.測(cè)試
target1.save();
target1.update();
}
}

總結(jié)
到此這篇關(guān)于Spring中AOP概念與兩種動(dòng)態(tài)代理模式原理的文章就介紹到這了,更多相關(guān)Spring動(dòng)態(tài)代理模式原理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
利用spring的攔截器自定義緩存的實(shí)現(xiàn)實(shí)例代碼
這篇文章主要介紹了利用spring的攔截器自定義緩存的實(shí)現(xiàn)實(shí)例代碼,分享了相關(guān)代碼示例,小編覺得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下2018-02-02
SpringBoot中如何處理不同的類型的POST請(qǐng)求
在Web開發(fā)中,POST請(qǐng)求是非常常見的,用于向服務(wù)器提交數(shù)據(jù),根據(jù)數(shù)據(jù)的編碼方式,POST請(qǐng)求可以分為form-data、x-www-form-urlencoded和raw三種類型,本文將介紹這三種請(qǐng)求方式的區(qū)別,并展示如何在Spring Boot中編寫代碼來(lái)處理它們,需要的朋友可以參考下2024-08-08
Java 實(shí)戰(zhàn)練手項(xiàng)目之醫(yī)院預(yù)約掛號(hào)系統(tǒng)的實(shí)現(xiàn)流程
讀萬(wàn)卷書不如行萬(wàn)里路,只學(xué)書上的理論是遠(yuǎn)遠(yuǎn)不夠的,只有在實(shí)戰(zhàn)中才能獲得能力的提升,本篇文章手把手帶你用java+SpringBoot+Maven+Vue+mysql實(shí)現(xiàn)一個(gè)醫(yī)院預(yù)約掛號(hào)系統(tǒng),大家可以在過程中查缺補(bǔ)漏,提升水平2021-11-11
MyBatis自定義映射關(guān)系和關(guān)聯(lián)查詢實(shí)現(xiàn)方法詳解
這篇文章主要介紹了MyBatis自定義映射關(guān)系和關(guān)聯(lián)查詢實(shí)現(xiàn)方法,當(dāng)POJO屬性名與數(shù)據(jù)庫(kù)列名不一致時(shí),需要自定義實(shí)體類和結(jié)果集的映射關(guān)系,在MyBatis注解開發(fā)中,使用@Results定義并使用自定義映射,使用 @ResultMap使用自定義映射2023-04-04
Java IO流之原理分類與節(jié)點(diǎn)流文件操作詳解
流(Stream)是指一連串的數(shù)據(jù)(字符或字節(jié)),是以先進(jìn)先出的方式發(fā)送信息的通道,數(shù)據(jù)源發(fā)送的數(shù)據(jù)經(jīng)過這個(gè)通道到達(dá)目的地,按流向區(qū)分為輸入流和輸出流2021-10-10
Hibernate連接三種數(shù)據(jù)庫(kù)的配置文件
今天小編就為大家分享一篇關(guān)于Hibernate連接三種數(shù)據(jù)庫(kù)的配置文件,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-03-03

