深入理解Spring(AOP)(四)

上一篇聊到關於spring
1、自定義註解
2、springAOP切面
3、各種連接點joinPoint的意義
4、spring的JDK代理,與產生的一些問題
接上篇,繼續講解SpringAOP通知。其他通知都比較簡單,大家可以參考官方文檔。這裏只講解一個比較難得環繞通知!

1、spring通知

1、前置通知,證明springAOP默認是使用JDK動態代理。

在這裏插入圖片描述

如下代碼片段,可以通過joinPoint對象,獲取目標對象。以及代理對象,還能獲取方法傳入的參數。實際業務開發中。可以對目標對象,與參數做一些業務處理。

(面試問題)joinPoint是什麼?它是AOP中的連接點,可以通過它得到。類信息,代理對象信息,方法信息,參數信息。常用的API見下面代碼片段:

    /**
     * 申明before通知,在pintCut切入點前執行
     * 通知與切入點表達式相關聯,
     * 並在切入點匹配的方法執行之前、之後或前後運行。
     * 切入點表達式可以是對指定切入點的簡單引用,也可以是在適當位置聲明的切入點表達式。
     */
    @Before("pointCut()")
    public void beforeAdvice(JoinPoint joinPoint){
        System.out.println("before");
        //獲取當前執行的代理對象
        System.out.println(joinPoint.getThis());
        //獲取目標對象
        System.out.println(joinPoint.getTarget());
        //獲取當前傳入參數
        Object[] args = joinPoint.getArgs();
        System.out.println(args);
        //獲取切點的目標方法
        String name = joinPoint.getSignature().getName();
        System.out.println(name);
    }
2、環繞通知

環繞通知部分代碼如下。文章示例,可用於項目中改變連接參數值。控制檯輸出


    @Override
    public void query(String str) {
        System.out.println("query2 " + str);
    }
/*   * 增強通知(也叫環繞通知)
       Proceedingjoinpoint 和JoinPoint的區別:
       Proceedingjoinpoint 繼承了JoinPoint,proceed()這個是aop代理鏈執行的方法。並擴充實現了proceed()方法,
       用於繼續執行連接點。JoinPoint僅能獲取相關參數,無法執行連接點。
        proceed()有重載,有個帶參數的方法,可以修改目標方法的的參數
     * @param pjp 用於描述切點的所有連接點(這裏很抽象,就是描述所有需要增強方法的信息)
     */
    @Around("execution(* com.bing.dao.IndexDao.query(..))")
    public void around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("aaaaa");
        Object[] args = pjp.getArgs();
        for (int i = 0; i < args.length; i++) {
            args[i]+="world";
        }
        //處理下一個通知,或者目標方法的執行。就是這個方法實現了環繞
        //最牛逼之處,這個方法重載參數。可以改變目標方法的一些參數信息
        pjp.proceed(args);
        System.out.println("bbbbbb");
    }
3.@DeclareParents註解引入(spring5 AOP引入的新特性)

話不多說,上代碼片段。領略神奇之處。(面試中可能會被問到,怎麼克隆一個類的方法)

項目結構如下

在這裏插入圖片描述
1.在spring切面中引入要申明的Dao類型
2.聲明一個類交給spring管理,不實現任何藉口。
3.獲取聲明類,強轉成Dao類型。(正常情況下這裏肯定會報錯吧,因爲Order並沒有實現Dao接口)
4.然而我們執行query方法,控制檯輸出Query11 說明 springAOP 去幫我們實現Dao 幫我們繼承了 indexDao這個類。

@Component
@Aspect
public class UserAspectj {
    /**
     * 引入 dao
     */
    @DeclareParents(value = "com.bing.dao.*",defaultImpl = IndexDao.class)
    public static Dao dao;
    }
    //聲明一個類交給Spring管理
@Component("orderDao")
public class OrderDao {
			}
	//獲取聲明類,強轉成Dao類型
public class Test {
    public static void main(String[] args) throws IOException {
        AnnotationConfigApplicationContext applicationContext =
                new AnnotationConfigApplicationContext(Appconfig.class);
        Dao dao = (Dao) applicationContext.getBean("orderDao");
        dao.query();
        	}
        }

在這裏插入圖片描述

4.切面如何多例。下面看一個例子。。當我們併發編程,一般會用多例模式,但是我們切面始終都是單例。。

1.將IndexDao設置爲多例模式
2.定義切換,打印當前切面類的hashCode
3.執行多例對象 方法,發現。輸出的切面類hashcode始終都是同一個(說明切面類是單例。)

怎麼解決這個問題呢?(面試官:切面模型怎麼變成多例?)

@Repository(value = "indexDao")
@Scope("prototype")
public class IndexDao implements Dao{
    @Override
    public void query(){
        System.out.println("Query11");
    }
    @Override
    public void query(String str) {
        System.out.println("query2 " + str);
    }
}

在這裏插入圖片描述
在這裏插入圖片描述

解決方案:perthis定義哪個類執行該切面時當前類變成多例,若不定義perthis則所以類執行時都會變成多例 。perthis限定某一個對象。

在這裏插入圖片描述

Advisors ? 什麼是Advisors ?

Advisors 又叫spring聲明式事務,或者AOP事務,很多人理解,AOP就是事務。。這種說法是錯誤的,Spring事務,只是藉助了AOP的技術去實現。。並不是真正意義上的AOP。爲什麼這麼說呢?

我們到這裏已經學完了,SpringAOP 所有內容,可以發現,AOP 的通知類型,要麼是在方法執行前執行,要麼是在方法執行後 執行。要麼方法執行前跟後一起執行。。卻沒有一種通知,可以在方法中執行。都知道事務在做增刪改時候,會提交事務,回滾事務。所以可以說Spring聲明式事務,是一個特殊的通知。但是它並不在我們AOP 的內容中(可以從官方文檔發現)

@transactional 是Spring基於Aspect技術開發的事務控制註解,並不是Aspect的註解。(這裏是一個很多高級開發的誤區

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章