上一篇聊到關於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);
}
}