国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Spring | Srping AOP (AOP簡介、動(dòng)態(tài)代理、基于“代理類”的AOP實(shí)現(xiàn))

這篇具有很好參考價(jià)值的文章主要介紹了Spring | Srping AOP (AOP簡介、動(dòng)態(tài)代理、基于“代理類”的AOP實(shí)現(xiàn))。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

Spring | Srping AOP (AOP簡介、動(dòng)態(tài)代理、基于“代理類”的AOP實(shí)現(xiàn)),框架知識(shí)點(diǎn)-合集,spring,AOP,Spring AOP,java,動(dòng)態(tài)代理

作者簡介 :一只大皮卡丘,計(jì)算機(jī)專業(yè)學(xué)生,正在努力學(xué)習(xí)、努力敲代碼中! 讓我們一起繼續(xù)努力學(xué)習(xí)!

該文章參考學(xué)習(xí)教材為:
《Java EE企業(yè)級(jí)應(yīng)用開發(fā)教程 (Spring + Spring MVC +MyBatis)》 黑馬程序員 / 編著
文章以課本知識(shí)點(diǎn) + 代碼為主線,結(jié)合自己看書學(xué)習(xí)過程中的理解和感悟 ,最終成就了該文章

文章用于本人學(xué)習(xí)使用 , 同時(shí)希望能幫助大家。
歡迎大家點(diǎn)贊?? 收藏? 關(guān)注??哦!??!

(侵權(quán)教材方可聯(lián)系我,進(jìn)行刪除,如果雷同,純屬巧合)


1.Spring AOP簡介

1.1 AOP簡介

  • Spring的AOP模塊,是Spring框架體系結(jié)構(gòu)中十分重要的內(nèi)容,該模塊中提供了面向切面編程實(shí)現(xiàn)。

  • AOP的全稱是 Aspect-Oriented Programming,即面向切面編程( 也稱面向方面編程 )它是面向?qū)ο缶幊?OOP)的一種補(bǔ)充,目前已成為一種比較成熟的編程方式。
    在傳統(tǒng)的業(yè)務(wù)處理代碼中,通常都會(huì)進(jìn)行事務(wù)處理日志記錄等操作。雖然使用OOP可以通過組合或者繼承的方式來達(dá)到代碼的重用,但如果要實(shí)現(xiàn)某個(gè)功能(如日志記錄),同樣的代碼仍然會(huì)分散到各個(gè)方法中。這樣,如果想要關(guān)閉某個(gè)功能,或者對(duì)其進(jìn)行修改,就必須要修改所有的相關(guān)方法。這不但增加了開發(fā)人員的工作量,而且提高了代碼的出錯(cuò)率。

    (要實(shí)現(xiàn)AOP功能,核心關(guān)鍵之一是 : “代理”,通過“代理”可以獲得 “增強(qiáng)功能后的目標(biāo)對(duì)象” ,從而實(shí)現(xiàn)AOP功能)

  • 為了解決這一問題,AOP思想隨之產(chǎn)生。AOP采取橫向抽取機(jī)制,將分散在各個(gè)方法中的重復(fù)代碼 提取出來,然后在程序編譯運(yùn)行時(shí),再將這些提取出來的代碼應(yīng)用到需要執(zhí)行的地方。這種采用橫向抽取機(jī)制的方式,采用傳統(tǒng)的O0P思想顯然是無法辦到的,因?yàn)?0P只能實(shí)現(xiàn)父子關(guān)系縱向重用。雖然AOP是一種新的編程思想,但卻不是O0P的替代品,它只是OOP的延伸和補(bǔ)充。

  • 在AOP思想中,類與切面的關(guān)系圖 如下所示 :
    Spring | Srping AOP (AOP簡介、動(dòng)態(tài)代理、基于“代理類”的AOP實(shí)現(xiàn)),框架知識(shí)點(diǎn)-合集,spring,AOP,Spring AOP,java,動(dòng)態(tài)代理

    從上圖 (類與切面關(guān)系圖)可以看出,通過Aspect (切面) 分別在Class1Class2方法中加入了事務(wù)、日志、權(quán)限異常等功能。

  • AOP的使用,使開發(fā)人員在編寫業(yè)務(wù)邏輯時(shí)可以專心于核心業(yè)務(wù),而不用過多地關(guān)注其他業(yè)務(wù)邏輯的實(shí)現(xiàn),這不但提高了開發(fā)效率,而且增強(qiáng)了代碼的可維護(hù)性。

  • 目前最流行AOP框架有兩個(gè),分別為Spring AOPAspectJ。Spring AOP使用純Java實(shí)現(xiàn),不需要專門的編譯過程和類加載器,在運(yùn)行期間通過代理方式向目標(biāo)類織入增強(qiáng)的代碼。
    AspectJ是一個(gè)基于Java語言的AOP框架,從Spring 2.0開始,Spring AOP引入了對(duì)AspectJ的支持,AspectJ擴(kuò)展了Java語言,提供了一個(gè)專門的編譯器,在編譯時(shí)提供橫向代碼織入

1.2 AOP術(shù)語

AOP術(shù)語包括 Aspect、Joinpoint、Pointcut、 AdviceTarget Object、ProxyWeaving。具體講解如下。

  • 一、Aspect ( 切面 ) :
    實(shí)際應(yīng)用
    中,切面通常是指封裝的用于橫向插入系統(tǒng)功能 (如事務(wù)、日志等) 的。如 “類與切面關(guān)系圖” 的 Aspect。該 要被Spring容器識(shí)別為切面,需要在配置文件<bean>元素指定 (哪個(gè)將作為 切面)。
    切面 可以 理解為 “切面類”)

  • 二、Joinpoint ( 連接點(diǎn) ) :
    在程序執(zhí)行過程中的某個(gè)階段點(diǎn),它實(shí)際上是對(duì)象的一個(gè)操作。
    例子如:方法的調(diào)用異常的拋出。Spring AOP中,連接點(diǎn)就是指方法的調(diào)用 ( 非切面類的那個(gè)類的方法的調(diào)用)。

  • 三、Pointcut( 切入點(diǎn) ) :
    是指切面程序流程交叉點(diǎn),即那些 需要處理連接點(diǎn) ( 即待處理的“ 方法的調(diào)用 ” )。
    通常在程序中,切入點(diǎn)指的是或者方法名
    例子如 :某個(gè)通知要應(yīng)用到所有以add開頭方法中,那么所有滿足這一規(guī)則方法都是切入點(diǎn)。

切面、連接點(diǎn) 和切入點(diǎn)關(guān)系圖如下圖所示” :

Spring | Srping AOP (AOP簡介、動(dòng)態(tài)代理、基于“代理類”的AOP實(shí)現(xiàn)),框架知識(shí)點(diǎn)-合集,spring,AOP,Spring AOP,java,動(dòng)態(tài)代理

  • 四、Advice( 通知 / 增強(qiáng)處理 ) :
    AOP框架在特定的 切入點(diǎn) ( /方法名 )執(zhí)行的增強(qiáng)處理,即在定義好的切入點(diǎn)處所 要執(zhí)行的程序代碼。
    可以將 ( Advice ) 理解為 切面中的方法,Advice切面具體實(shí)現(xiàn)

  • 五、Target Object ( 目標(biāo)對(duì)象 ) :
    是指所有 被通知對(duì)象,也稱為被 增強(qiáng)對(duì)象。如果AOP框架采用的是動(dòng)態(tài)的AOP實(shí)現(xiàn),那么該對(duì)象就是一個(gè)被代理對(duì)象。

  • 六、Weaving ( 織入 ) :
    切面類中代碼插入到目標(biāo)對(duì)象上,從而生成代理對(duì)象過程。

  • 七、Proxy( 代理 ) :

    通知應(yīng)用到目標(biāo)對(duì)象之后,被動(dòng)態(tài)創(chuàng)建對(duì)象 ,該對(duì)象稱為“代理對(duì)象” / 增強(qiáng)功能后目標(biāo)對(duì)象 ,
    該對(duì)象可直接當(dāng)目標(biāo)對(duì)象使用。(Proxy (代理) 可理解為一個(gè) 過程,一個(gè)將目標(biāo)對(duì)象 進(jìn)行 增強(qiáng),變?yōu)?strong>代理對(duì)象 / “增強(qiáng)功能后的目標(biāo)對(duì)象過程。) ( 代理就是AOP框架動(dòng)態(tài)生成的一個(gè)對(duì)象 )

  • 八、Proxy Class (代理類) :
    實(shí)現(xiàn)“Proxy ( 代理 )功能”的。該類 (代理類) 中包含了 Proxy(代理)”所需的功能代碼。

  • 九、Proxy Object (代理對(duì)象) / 增強(qiáng)功能后目標(biāo)對(duì)象:
    Proxy Object (代理對(duì)象) 稱為 / 可理解為 “增強(qiáng)功能后目標(biāo)對(duì)象” 。該對(duì)象可直接當(dāng) “目標(biāo)對(duì)象” 使用。

    代理對(duì)象通常包含了目標(biāo)對(duì)象的功能,同時(shí)在 原目標(biāo)對(duì)象的基礎(chǔ)上 添加一些額外的功能邏輯,例如日志記錄、事務(wù)管理等,因此可以說,代理對(duì)象可以被理解為"增強(qiáng)功能后的目標(biāo)對(duì)象“。

2.動(dòng)態(tài)代理

  • AOP中的==代理就是由AOP框架動(dòng)態(tài)生成的一個(gè)對(duì)象==,該對(duì)象可直接當(dāng)目標(biāo)對(duì)象使用。
    (此處的代理 : 就是上面提到過的 生成增強(qiáng)功能后的目標(biāo)對(duì)象” 的代理)

  • Spring 中的AOP代理,有 JDK動(dòng)態(tài)代理CGLIB代理。(兩者都是 “動(dòng)態(tài)代理”)。
    ps :

    JDK動(dòng)態(tài)代理CGlib代理都屬于 動(dòng)態(tài)代理。

    JDK動(dòng)態(tài)代理目標(biāo)對(duì)象實(shí)現(xiàn)一個(gè)或多個(gè)接口,如果要對(duì)沒有實(shí)現(xiàn)接口的目標(biāo)類 / 目標(biāo)對(duì)象 進(jìn)行代理時(shí),可用CGLIB代理。

2.1 JDK動(dòng)態(tài)代理

  • JDK動(dòng)態(tài)代理 是通過java.lang.reflect.Proxy類來實(shí)現(xiàn)的,我們可以調(diào)用Proxy類的 newProxyInstance() 方法來創(chuàng)建代理對(duì)象。對(duì)于使用業(yè)務(wù)接口,Sping 默認(rèn)會(huì)使用JDK代理來實(shí)現(xiàn)AOP。

    (JDK動(dòng)態(tài)代理實(shí)現(xiàn)接口,CGLIB代理不用實(shí)現(xiàn)接口。)

  • SpringJDK動(dòng)態(tài)代理的例子如 :

第一步、在DIEA中創(chuàng)建一個(gè)Java項(xiàng)目,添加web功能模塊。

第二步、在項(xiàng)目WEB-INF目錄中創(chuàng)建lib文件夾,存放Spring框架最基本核心的jar包,讓jar包生效。

獲取spring框架基本核心jar包

第三步、創(chuàng)建UserDao接口,在該接口中編寫添加刪除的方法 。
創(chuàng)建UserDao的實(shí)現(xiàn)類 UserDaoImpl,分別實(shí)現(xiàn)接口中的方法,并在每個(gè)方法中添加一條輸出語句。
UserDao.java

public interface UserDao{

 public void addUser();

 public void deleteUser();
}

UserDaoImpl.java

public class UserDaoImpl implements UserDao { // ”目標(biāo)類“,該類創(chuàng)建的對(duì)象為”目標(biāo)對(duì)象“

@Override
public void addUser() {  //這方法將要被“增強(qiáng)處理”
    System.out.println("添加用戶");
}

@Override
public void deleteUser() { //這方法將要被“增強(qiáng)處理”
    System.out.println("刪除用戶");
}
}

實(shí)現(xiàn)類UserDaoImpl作為 目標(biāo)類 ,對(duì)其中的方法進(jìn)行 增強(qiáng)處理。

第四步、創(chuàng)建切面類MyAspect
在該類中定義一個(gè)模擬權(quán)限檢查的方法和一個(gè)模擬記錄日志方法,這兩個(gè)方法就表示切面中的通知。

public class MyAspect { //切面類 : 以下為兩個(gè)通知,將用于為“目標(biāo)對(duì)象”實(shí)現(xiàn)增強(qiáng)功能。

//通知 : 要執(zhí)行的切面類”的方法”
//在特定的 “切入點(diǎn)” 進(jìn)行增強(qiáng)處理 : 在“切入點(diǎn)”的前或后,執(zhí)行切面類中的方法

public void check_Permissions() { //該方法即為“通知” : 切面類中的方法
    System.out.println("模擬檢查權(quán)限...");
}

public void log() { //通知
    System.out.println("模擬記錄日志...");
}

/*
   對(duì)某個(gè)方法(切入點(diǎn))進(jìn)制“增強(qiáng)處理” : 即在程序執(zhí)行這個(gè)方法的“前或后”的時(shí)機(jī)執(zhí)行"切面方法"(添加通知)
 */
}

第五步、創(chuàng)建 代理類 JdkProxy ,該類實(shí)現(xiàn) InvocationHandler 接口,并編寫代理方法。在代理方法中,需要通過Proxy實(shí)現(xiàn)動(dòng)態(tài)代理。

/**
   *  JDK代理類 (JdkProxy) : 將通知應(yīng)用到目標(biāo)對(duì)象之后,被動(dòng)態(tài)創(chuàng)建的對(duì)象。
   *  代理對(duì)象 : 經(jīng)過“代理”這一過程,生成的類即為“代理對(duì)象”,也稱為“增強(qiáng)功能后的目標(biāo)對(duì)象”
   *  (可以理解為: “代理” / "代理類"的目的之一 : 生成“代理對(duì)象”)
*/
public class JdkProxy implements InvocationHandler {

//聲明目標(biāo)類接口
private UserDao userDao;

//創(chuàng)建代理方法
public Object createProxy(UserDao userDao) {

    this.userDao = userDao;
    //1.類加載器 (JdkProxy的類加載器) ---獲得JdkProxy對(duì)應(yīng)的“類加載器”
    ClassLoader classLoader = JdkProxy.class.getClassLoader();
    //2.被代理對(duì)象實(shí)現(xiàn)的所有接口 (此處為: UserDao 的接口內(nèi)容等。)
    Class[] clazz = userDao.getClass().getInterfaces();
    //3.使用代理類,進(jìn)行增強(qiáng),返回的是 ”代理后的對(duì)象“ / “增強(qiáng)功能后的目標(biāo)對(duì)象”
    return Proxy.newProxyInstance(classLoader, clazz, this);
}

/**
       * @param proxy  被代理后的對(duì)象
       * @param method 將要執(zhí)行的方法信息 (反射)
       * @param args   執(zhí)行方法時(shí)需要的參數(shù)
       * @throws Throwable
 */
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    /**
      聲明切面類 (其中有要用在特定“切入點(diǎn)”的“通知”)
       切入點(diǎn) : 要進(jìn)行“增強(qiáng)處理”/被“通知” 的 方法名
       通知(也稱“增強(qiáng)處理”): 切面類中的方法
       對(duì)切入點(diǎn)進(jìn)行“增強(qiáng)處理” : 在某個(gè)方法被執(zhí)行的前/后的時(shí)機(jī)執(zhí)行切面中的“方法”
     */
    //創(chuàng)建切面類
    MyAspect myAspect = new MyAspect();

 /**
     *  目標(biāo)方法執(zhí)行的前后,會(huì)分別執(zhí)行切面類中的 check_Permissions()方法 和 log()方法
     *  前增強(qiáng) : 執(zhí)行UserDao接口的方法之前先執(zhí)行 切面類中的 check_Permissions()這個(gè)方法
     *  后增強(qiáng) : 執(zhí)行完接口的方法后執(zhí)行l(wèi)og()這個(gè)方法
  */
    //前增強(qiáng)
    myAspect.check_Permissions();

    //在目標(biāo)類上調(diào)用方法,并傳入?yún)?shù)
    Object obj = method.invoke(userDao, args); //執(zhí)行UserDao接口中的方法

    //后增強(qiáng)
    myAspect.log();

    return obj;
}
}

上述例子中,JdkProxy類 (代理類) 實(shí)現(xiàn)了 InvocationHandler 接口,并實(shí)現(xiàn)了接口中的 invoke方法,所有動(dòng)態(tài)代理類調(diào)用的方法都會(huì)交由該 ( invoke) 方法處理。在創(chuàng)建的代理方法 createProxy()中使用了 Proxy 類的 newProxyInstance()方法來創(chuàng)建 代理對(duì)象。newProxyInstance()方法中包含3個(gè)參數(shù),其中第1個(gè)參數(shù)是當(dāng)前類的類加載器,第2個(gè)參數(shù)表示的是被代理對(duì)象實(shí)現(xiàn)的所有接口,第3個(gè)參數(shù)this代表的就是代理類JdkProxy本身。在invoke()方法中,目標(biāo)類方法執(zhí)行的前后會(huì)分別執(zhí)行切面類中的check _Permissions() 方法和 log() 方法。

第六步、創(chuàng)建測試類 JdkTest,在該類中的main()方法中創(chuàng)建代理對(duì)象目標(biāo)對(duì)象,然后從代理對(duì)象中獲得對(duì)目標(biāo)對(duì)象userDao增強(qiáng)功能后的對(duì)象,最后調(diào)用該對(duì)象的添加和刪除方法。

public class JdkTest {
public static void main(String[] args) {
    //實(shí)例化JdkProxy類(JDK代理類) : 該類能產(chǎn)生“代理對(duì)象”(增強(qiáng)功能的目標(biāo)對(duì)象)
    JdkProxy jdkProxy = new JdkProxy();
    //創(chuàng)建目標(biāo)對(duì)象
    UserDao userDao  = new UserDaoImpl();
    /*
      調(diào)用JdkProxy中的createProxy()方法獲得“代理對(duì)象”
     */
    UserDao userDao1 = (UserDao)jdkProxy.createProxy(userDao);

    //指向UserDao中的兩個(gè)方法,該UserDao已被進(jìn)行AOP操作,其中方法執(zhí)行的前后都會(huì)執(zhí)行切面類中的方法
    userDao1.addUser();
    userDao1.deleteUser();
}
}

測試類運(yùn)行結(jié)果
Spring | Srping AOP (AOP簡介、動(dòng)態(tài)代理、基于“代理類”的AOP實(shí)現(xiàn)),框架知識(shí)點(diǎn)-合集,spring,AOP,Spring AOP,java,動(dòng)態(tài)代理

UserDao實(shí)例添加用戶刪除用戶方法被成功調(diào)用,并且在調(diào)用前后分別添加了“權(quán)限檢查”和“記錄日志”的功能,這種實(shí)現(xiàn)了接口的代理方式,就是Spring中的JDK動(dòng)態(tài)代理。

2.2 CGLIB代理

  • JDK動(dòng)態(tài)代理的使用簡單,但它還有一定的局限性,使用 JDK動(dòng)態(tài)代理對(duì)象必須實(shí)現(xiàn)一個(gè)或多個(gè)接口

    如果要對(duì)沒有實(shí)現(xiàn)接口進(jìn)行代理,那么可以使用 CGLIB代理。即目標(biāo)類 / 目標(biāo)對(duì)象,沒有實(shí)現(xiàn)任何接口時(shí),可用CGLIB代理

    ps:
    JDK動(dòng)態(tài)代理目標(biāo)對(duì)象實(shí)現(xiàn)一個(gè)或多個(gè)接口,如果要對(duì)沒有實(shí)現(xiàn)接口的目標(biāo)類 / 目標(biāo)對(duì)象 進(jìn)行代理時(shí),可用CGLIB代理。

  • CGLIB ( Code Generation Library )是一個(gè)高性能開源代碼生成包,它采用非常底層字節(jié)碼技術(shù),對(duì)指定的目標(biāo)類生成一個(gè)子類, 并對(duì)子類進(jìn)行增強(qiáng)。在Spring的核心包中已經(jīng)集成CGLIB所需要的包,所以開發(fā)中不需要另外導(dǎo)入JAR包。
    JDK動(dòng)態(tài)代理CGLIB代理核心包就行,不需要額外的JAR包

  • SpringJDK動(dòng)態(tài)代理的例子如 :
    第一步、在DIEA中創(chuàng)建一個(gè)Java項(xiàng)目,添加web功能模塊。

    第二步、在項(xiàng)目WEB-INF目錄中創(chuàng)建lib文件夾,存放Spring框架最基本核心的jar包,讓jar包生效。

    獲取spring框架基本核心jar包

    第三步、創(chuàng)建目標(biāo)類 :UserDao,UserDao不需要實(shí)現(xiàn)任何接口,只需定義一個(gè)添加用戶的方法 和 一個(gè)刪除用戶的方法。

    public class UserDao { //目標(biāo)類,沒實(shí)現(xiàn)任何接口,可用CGLIB代理
         public void addUser() {
    	        System.out.println("添加用戶");
    	    }
        public void deleteUser() {
            System.out.println("刪除用戶");
        }
    }
    

    第四步、創(chuàng)建切面類MyAspect
    在該類中定義一個(gè)模擬權(quán)限檢查的方法和一個(gè)模擬記錄日志方法,這兩個(gè)方法就表示切面中的通知。

    public class MyAspect { //切面類 : 以下為兩個(gè)通知,將用于為“目標(biāo)對(duì)象”實(shí)現(xiàn)增強(qiáng)功能。
    
    //通知 : 要執(zhí)行的切面類”的方法”
    //在特定的 “切入點(diǎn)” 進(jìn)行增強(qiáng)處理 : 在“切入點(diǎn)”的前或后,執(zhí)行切面類中的方法
    
    public void check_Permissions() { //該方法即為“通知” : 切面類中的方法
        System.out.println("模擬檢查權(quán)限...");
    }
    
    public void log() { //通知
        System.out.println("模擬記錄日志...");
    }
    
    /*
       對(duì)某個(gè)方法(切入點(diǎn))進(jìn)制“增強(qiáng)處理” : 即在程序執(zhí)行這個(gè)方法的“前或后”的時(shí)機(jī)執(zhí)行"切面方法"(添加通知)
     */
    }
    

    第五步、創(chuàng)建代理類CglibProxy,該代理類需要實(shí)現(xiàn) MethodInterceptor 接口,并實(shí)現(xiàn)接口中的 intercept( ) 方法。

    import com.myh.cglib.aspect.MyAspect;
    import org.springframework.cglib.proxy.Enhancer;
    import org.springframework.cglib.proxy.MethodInterceptor;
    import org.springframework.cglib.proxy.MethodProxy;
    import java.lang.reflect.Method;
    
    //代理類
    public class CglibProxy implements MethodInterceptor { //CGLIB代理 : 目標(biāo)類不需要實(shí)現(xiàn)接口
    
        //代理方法
        public Object createProxy(Object target) { //創(chuàng)建“代理對(duì)象/增強(qiáng)后的目標(biāo)對(duì)象”的方法
            //創(chuàng)建一個(gè)動(dòng)態(tài)類對(duì)象 (Enhancer : 增強(qiáng)器)
            Enhancer enhancer = new Enhancer();
            //確定要增強(qiáng)的類,為Enhancer設(shè)置“父類”
            enhancer.setSuperclass(target.getClass());
            //添加回調(diào)函數(shù)
            enhancer.setCallback(this);
            //返回創(chuàng)建的代理類
            return enhancer.create();
        }
    
        /**
         * @param proxy CGlib指定“父類”生成的“代理對(duì)象”
         * @param method 攔截的方法
         * @param args   攔截方法的參數(shù)數(shù)組
         * @param methodProxy 方法的代理對(duì)象,用于執(zhí)行父類的方法
         * @throws Throwable
         */
        @Override
        public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
             //創(chuàng)建切面類對(duì)象
            MyAspect myAspect = new MyAspect();
            //前增強(qiáng)
            myAspect.check_Permissions();
            //目標(biāo)方法的執(zhí)行
            Object obj = methodProxy.invokeSuper(proxy, args); //執(zhí)行"代理對(duì)象"的 “父類的方法”
            //后增強(qiáng)
            myAspect.log();
            return obj;
        }
    }
    

    CglibProxy類的代理方法中,首先創(chuàng)建了一個(gè)動(dòng)態(tài)類對(duì)象Enhancer,它是CGLIB的核心類;然后調(diào)用了Enhancer類的 setSuperclass()方法來確定目標(biāo)對(duì)象 (為動(dòng)態(tài)類對(duì)象指定父類 );接下來調(diào)用了setCallback()方法添加回調(diào)函數(shù),其中的this代表的就是代理類CglibProxy本身;最后通過return語句將創(chuàng)建的代理類對(duì)象返回。 intercept()方法會(huì)在程序執(zhí)行目標(biāo)方法時(shí)被調(diào)用,方法運(yùn)行時(shí)將會(huì)執(zhí)行切面類中的增強(qiáng)方法。

    第六步、
    創(chuàng)建測試類 CglibTest 在該類的main()方法中首先創(chuàng)建代理對(duì)象目標(biāo)對(duì)象,然后從代理對(duì)象中獲得增強(qiáng)后的目標(biāo)對(duì)象,最后調(diào)用對(duì)象添加刪除方法。

    public class CglibTest {
        public static void main(String[] args) {
            //創(chuàng)建代理對(duì)象
            CglibProxy cglibProxy = new CglibProxy();
            //創(chuàng)建目標(biāo)對(duì)象
            UserDao userDao = new UserDao();
            UserDao userDao1 = (UserDao)cglibProxy.createProxy(userDao);
            //執(zhí)行方法
            userDao1.addUser();
            userDao1.deleteUser();
        }
    }
    

    測試類運(yùn)行結(jié)果
    Spring | Srping AOP (AOP簡介、動(dòng)態(tài)代理、基于“代理類”的AOP實(shí)現(xiàn)),框架知識(shí)點(diǎn)-合集,spring,AOP,Spring AOP,java,動(dòng)態(tài)代理

    從測試類結(jié)果可以看出,目標(biāo)類UserDao中方法被成功調(diào)用增強(qiáng)了,這種 (目標(biāo)類) 沒有實(shí)現(xiàn)接口的代理方式,就是CGLIB代理。

3.基于“代理類”的AOP實(shí)現(xiàn)

  • 動(dòng)態(tài)代理中的 JDK動(dòng)態(tài)代理CGLIB代理都是基于“代理類”的AOP實(shí)現(xiàn)
  • Spring中的 AOP代理默認(rèn)使用 的是 JDK動(dòng)態(tài)代理。
  • Spring中使用 ProxyFactoryBean創(chuàng)建 AOP代理最基本的方式。

3.1 Spring的通知類型

Spring 中的 通知 按照在 目標(biāo)類方法連接點(diǎn)位置,可以分為以下5種類型

  • org.aopalliance.intercept.MethodInterceptor (環(huán)繞通知) :
    目標(biāo)方法執(zhí)行前后實(shí)施增強(qiáng),可以應(yīng)用于日志、事務(wù)管理等功能。
  • org.springframework. aop.MethodBeforeAdvice (前置通知)
    目標(biāo)方法執(zhí)行實(shí)施增強(qiáng),可以應(yīng)用于權(quán)限管理等功能。
  • org.springframework. aop.AfterReturningAdvice (后置通知)
    目標(biāo)方法執(zhí)行實(shí)施增強(qiáng),可以應(yīng)用于關(guān)閉流、上傳文件、 刪除臨時(shí)文件等功能
  • org.springframework.aop.ThrowsAdvice (異常通知) :
    方法拋出異常后實(shí)施增強(qiáng),可以應(yīng)用于處理異常記錄日志等功能。
  • org.springframework.aop.IntroductionInterceptor (引介通知)
    目標(biāo)類中添加一些新方法屬性,可以應(yīng)用于修改老版本程序(增強(qiáng)類)。

3.2 ProxyFactoryBean ( 可通知.xml配置文件完成aop功能 )

  • ProxyFactoryBeanFactoryBean接口實(shí)現(xiàn)類FactoryBean負(fù)責(zé)實(shí)例化一個(gè)Bean,
    ProxyFactoryBean負(fù)責(zé)為其他Bean創(chuàng)建代理實(shí)例。在Spring中,使用ProxyFactoryBean 是 創(chuàng)建AOP代理基本方式

  • ProxyFactoryBean類中的常用可配置屬性如下表所示 :

    屬性名稱 描述
    target 代理目標(biāo)對(duì)象
    proxyInterfaces 代理要實(shí)現(xiàn)接口,如果是多個(gè)接口,可以使用**以下格式賦值
    <list>
    <value></value>

    </list>
    proxyTargetClass 是否對(duì)類代理不是接口,設(shè)置為true時(shí),使用CGLIB代理.
    (設(shè)置為true表示是對(duì)類代理,自然是用 CGLIB代理
    interceptorNames 需要織入目標(biāo)Advice。
    singleton 返回的代理是否為單實(shí)例,默認(rèn)true (即返回單實(shí)例)
    optimize 當(dāng)設(shè)置為true時(shí),強(qiáng)制使用CGLIB
  • 對(duì)ProxyFactoryBean類有了初步的了解后,接下來通過一個(gè)典型的環(huán)繞通知案例,來演示Spring使用ProxyFactoryBean創(chuàng)建AOP代理的過程,例子如下
    第一步
    核心JAR包的基礎(chǔ)上,項(xiàng)目的lib目錄導(dǎo)入AOP的兩個(gè)JAR包,①spring-aop.jar②aopalliance.jar ;
    spring-aop.jar : 是Spring為實(shí)現(xiàn)AOP功能提供的JAR包。
    aopalliance.jar : 是AOP聯(lián)盟提供的規(guī)范包,是實(shí)現(xiàn)AOP功能所需JAR包

    Spring核心jar + aop有關(guān)的jar

    第二步、創(chuàng)建UserDao接口,在該接口中編寫添加刪除的方法 。
    創(chuàng)建UserDao的實(shí)現(xiàn)類 UserDaoImpl,分別實(shí)現(xiàn)接口中的方法,并在每個(gè)方法中添加一條輸出語句。
    UserDao.java

    public interface UserDao{
    
     public void addUser();
    
     public void deleteUser();
    }
    

    UserDaoImpl.java

    public class UserDaoImpl implements UserDao { // ”目標(biāo)類“,該類創(chuàng)建的對(duì)象為”目標(biāo)對(duì)象“
    
    @Override
    public void addUser() {  //這方法將要被“增強(qiáng)處理”
        System.out.println("添加用戶");
    }
    
    @Override
    public void deleteUser() { //這方法將要被“增強(qiáng)處理”
        System.out.println("刪除用戶");
    }
    }
    

    實(shí)現(xiàn)類UserDaoImpl作為 目標(biāo)類 ,對(duì)其中的方法進(jìn)行 增強(qiáng)處理。

    第三步、
    創(chuàng)建切面類MyAspect。由于實(shí)現(xiàn)環(huán)繞通知需要實(shí)現(xiàn) org. aopalliance.intercept.MethodInterceptor接口,所以MyAspect需要實(shí)現(xiàn)該接口,并實(shí)現(xiàn)接口中的 invoke() 方法,來執(zhí)行目標(biāo)方法。
    MyAspect.java

    import org.aopalliance.intercept.MethodInterceptor;
    import org.aopalliance.intercept.MethodInvocation;
    //切面類
    public class MyAspect implements MethodInterceptor { //切面類,該切面類實(shí)現(xiàn)了aopalliance包下的 MethodInterceptor(環(huán)繞通知)接口
    
        public void check_Permission() { //切面方法 (通知)
            System.out.println("模擬權(quán)限檢查...");
        }
    
        public void log() { //切面方法 (通知)
            System.out.println("模擬記錄日志...");
        }
    
        @Override
        public Object invoke(MethodInvocation mi) throws Throwable {
            /*
            在目標(biāo)方法執(zhí)行的前后,分別執(zhí)行了“檢查權(quán)限” 和 “記錄日志”的方法,這兩個(gè)方法也就是“增強(qiáng)的方法”,也就是通知。
            */ 
            check_Permission();
            //執(zhí)行目標(biāo)方法
            Object obj = mi.proceed();
            log();
            return obj;
        }
    }
    

    第四步、
    創(chuàng)建配置文件applicationContext.xml,并指定對(duì)象。

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <!--  1.目標(biāo)類 (把對(duì)象放入IOC容器中,作為Bean)-->
        <bean id="userDao" class="com.myh.factorybean.UserDaoImpl"/>
    
        <!--  2.切面類 -->
        <bean id="myAspect" class="com.myh.factorybean.MyAspect"/>
    
        <!--  3.使用Spring代理工廠定義一個(gè)名稱為: userDaoProxy 的代理對(duì)象 -->
        <bean id="userDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
            <!-- 指定“代理實(shí)現(xiàn)的接口”  -->
            <property name="proxyInterfaces" value="com.myh.factorybean.UserDao"/>
            <!-- 指定“目標(biāo)對(duì)象”  -->
            <property name="target" ref="userDao"/>
            <!-- 指定“切面”,植入環(huán)繞通知  -->
            <property name="interceptorNames" value="myAspect"/>
            <!-- 指定代理方式,true : 使用cglib, false(默認(rèn)) : 使用jdk動(dòng)態(tài)代理  -->
            <property name="proxyTargetClass" value="true"/>
        </bean>
    </beans>
    

    上述配置文件代碼中,首先通過 <bean>元素定義了目標(biāo)類切面,然后使用 ProxyFactoryBean類定義了代理對(duì)象。在定義的代理對(duì)象中,分別通過 <property>子元素指定了①代理實(shí)現(xiàn)的接口切代理、②目標(biāo)對(duì)象、③需要織入目標(biāo)類的通知以及④代理方式

    第五步、

    創(chuàng)建ProxyFactoryBeanTest 測試類,在類中通過Spring容器獲取代理對(duì)象的實(shí)例,并執(zhí)行目標(biāo)方法

    package com.myh.factorybean;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    public class ProxyFactoryBeanTest { //測試類
        public static void main(String[] args) {
            String xmlPath = "com/myh/factorybean/applicationContext.xml";
            //創(chuàng)建ApplicationContext (從其中獲取IOC容器中的Bean)
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
            //從IOC容器中獲得“代理對(duì)象”
            UserDao userDao = (UserDao) applicationContext.getBean("userDaoProxy"); //獲得“增強(qiáng)功能后的目標(biāo)對(duì)象”
            //執(zhí)行目標(biāo)方法
            userDao.addUser();
            userDao.deleteUser();
        }
    }
    

    測試類運(yùn)行結(jié)果如下
    Spring | Srping AOP (AOP簡介、動(dòng)態(tài)代理、基于“代理類”的AOP實(shí)現(xiàn)),框架知識(shí)點(diǎn)-合集,spring,AOP,Spring AOP,java,動(dòng)態(tài)代理文章來源地址http://www.zghlxwxcb.cn/news/detail-814823.html

到了這里,關(guān)于Spring | Srping AOP (AOP簡介、動(dòng)態(tài)代理、基于“代理類”的AOP實(shí)現(xiàn))的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Spring Boot 中的 AOP,到底是 JDK 動(dòng)態(tài)代理還是 Cglib 動(dòng)態(tài)代理

    Spring Boot 中的 AOP,到底是 JDK 動(dòng)態(tài)代理還是 Cglib 動(dòng)態(tài)代理

    大家都知道,AOP 底層是動(dòng)態(tài)代理,而 Java 中的動(dòng)態(tài)代理有兩種實(shí)現(xiàn)方式: 基于 JDK 的動(dòng)態(tài)代理 基于 Cglib 的動(dòng)態(tài)代理 這兩者最大的區(qū)別在于基于 JDK 的動(dòng)態(tài)代理需要被代理的對(duì)象有接口,而基于 Cglib 的動(dòng)態(tài)代理并不需要被代理對(duì)象有接口。 那么,Spring 中的 AOP 是怎么實(shí)現(xiàn)的

    2024年02月12日
    瀏覽(24)
  • Spring AOP 學(xué)習(xí)(動(dòng)態(tài)代理、JdbcTemplate、Junit)

    Spring AOP 學(xué)習(xí)(動(dòng)態(tài)代理、JdbcTemplate、Junit)

    Proxy? jdk動(dòng)態(tài)代理,面向接口 cglib? ?第三方動(dòng)態(tài)代理,面向父類 在 不修改原有代碼 ,或者沒有辦法修改原有代碼的情況下, 增強(qiáng)對(duì)象功能 ,使用代理對(duì)象代替原來的對(duì)象去完成功能,進(jìn)而達(dá)到拓展功能的目的 JDK Proxy 動(dòng)態(tài)代理是 面向接口 的動(dòng)態(tài)代理,一定要有接口和實(shí)現(xiàn)

    2024年02月08日
    瀏覽(25)
  • 54.Spring的AOP是在哪里創(chuàng)建的動(dòng)態(tài)代理?

    正常的Bean會(huì)在Bean的生命周期的‘初始化’后, 通過BeanPostProcessor.postProcessAfterInitialization創(chuàng)建aop的動(dòng)態(tài)代理 還有一種特殊情況: 循環(huán)依賴的Bean會(huì)在Bean的生命周期‘屬性注入’時(shí)存在的循環(huán)依賴的情況下, 也會(huì)為循環(huán)依賴的Bean 通過MergedBeanDefinitionPostProcessor.postProcessMergedBe

    2024年02月02日
    瀏覽(16)
  • JDK 動(dòng)態(tài)代理(Spring AOP 的原理)(面試重點(diǎn))

    JDK 動(dòng)態(tài)代理(Spring AOP 的原理)(面試重點(diǎn))

    ????????也叫委托模式.定義:為其他對(duì)象提供?種代理以控制對(duì)這個(gè)對(duì)象的訪問.它的作?就是通過提供?個(gè)代理類,讓我們 在調(diào)??標(biāo)?法的時(shí)候,不再是直接對(duì)?標(biāo)?法進(jìn)?調(diào)?,?是通過代理類間接調(diào)?,在某些情況下,?個(gè)對(duì)象不適合或者不能直接引?另?個(gè)對(duì)象,?代

    2024年01月22日
    瀏覽(43)
  • spring動(dòng)態(tài)代理失效,AOP失效,事務(wù)@Transactional失效原因

    事務(wù)基于@Transactional注解和AOP(動(dòng)態(tài)代理) 對(duì)于基于接口動(dòng)態(tài)代理的 AOP 事務(wù)增強(qiáng)來說,由于接口的方法都必然是 public 的,這就要求實(shí)現(xiàn)類的實(shí)現(xiàn)方法也必須是 public 的(不能是 protected、private 等),同時(shí)不能使用 static 的修飾符。所以,可以實(shí)施接口動(dòng)態(tài)代理的方法只能是

    2024年02月15日
    瀏覽(27)
  • 【Spring教程21】Spring框架實(shí)戰(zhàn):Spring事務(wù)簡介、AOP事務(wù)管理、代碼示例全面詳解

    【Spring教程21】Spring框架實(shí)戰(zhàn):Spring事務(wù)簡介、AOP事務(wù)管理、代碼示例全面詳解

    歡迎大家回到《Java教程之Spring30天快速入門》,本教程所有示例均基于Maven實(shí)現(xiàn),如果您對(duì)Maven還很陌生,請(qǐng)移步本人的博文《如何在windows11下安裝Maven并配置以及 IDEA配置Maven環(huán)境》,本文的上一篇為《AOP(面對(duì)切面編程)知識(shí)總結(jié)》 事務(wù)作用:在數(shù)據(jù)層保障一系列的數(shù)據(jù)庫

    2024年02月04日
    瀏覽(53)
  • Spring5系列學(xué)習(xí)文章分享---第三篇(AOP概念+原理+動(dòng)態(tài)代理+術(shù)語+Aspect+操作案例(注解與配置方式))

    Spring5系列學(xué)習(xí)文章分享---第三篇(AOP概念+原理+動(dòng)態(tài)代理+術(shù)語+Aspect+操作案例(注解與配置方式))

    開篇: 歡迎再次來到 Spring 5 學(xué)習(xí)系列!在這個(gè)博客中,我們將深入研究 Spring 框架的AOP概念+原理+動(dòng)態(tài)代理+術(shù)語+Aspect+操作案例(注解與配置方式)。 概念 什么是AOP (1)面向切面編程(方面),利用 AOP 可以對(duì)業(yè)務(wù)邏輯的各個(gè)部分進(jìn)行隔離,從而使得 業(yè)務(wù)邏輯各部分之間的

    2024年01月24日
    瀏覽(28)
  • 注解實(shí)現(xiàn)(基于Spring AOP)

    切入點(diǎn)表達(dá)式 Spring AOP 支持的切入點(diǎn)主要有以下幾種: execution:用于匹配方法執(zhí)行的連接點(diǎn)。這是最常用的切入點(diǎn)指示器。你可以指定具體的方法,或者類來匹配。 例如: execution(* com.example.service.*.*(..)) ,這個(gè)表達(dá)式表示匹配 com.example.service 包下的所有類的所有方法。 wit

    2024年02月16日
    瀏覽(18)
  • 簡述 AOP 動(dòng)態(tài)代理

    CglibAutoProxyConfiguration 類 matchIfMissing = true,所以默認(rèn)使用 cglib 動(dòng)態(tài)代理 application.properties 里配置如下:spring.aop.auto=false,整個(gè) AOP 都不會(huì)生效了 application.properties 里配置如下:spring.aop.proxy-target-class=false,使用 jdk 動(dòng)態(tài)代理 JDK 動(dòng)態(tài)代理的限制在于,它只能代理實(shí)現(xiàn)了接口的類

    2024年02月07日
    瀏覽(20)
  • 動(dòng)態(tài)代理AOP機(jī)制分析

    動(dòng)態(tài)代理AOP機(jī)制分析

    有一個(gè)接口Vehicle,接口里有個(gè)run方法,有一個(gè)汽車類和一個(gè)輪船類,實(shí)現(xiàn)了這個(gè)接口。 要求在運(yùn)行Car對(duì)象的run方法或運(yùn)行ship對(duì)象的run方法前輸出一些日志。 交通工具開始運(yùn)行了… 輪船在海上running 交通工具停止運(yùn)行了… 交通工具開始運(yùn)行了… 輪船在海上running 交通工具停

    2024年02月15日
    瀏覽(22)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包