本文目標:帶領大家閱讀aop的源碼,深入理解aop的原理,內容有點長,消化需要大概一週時間,做好準備。
閱讀本文之前,需要先掌握下面3篇文章內容,不然會比較喫力。
本文主要分4部分
Aop原理介紹
介紹aop相關的一些類
通過源碼詳解aop代理的創建過程
通過源碼詳解aop代理的調用過程
Aop代理一些特性的使用案例
Spring AOP原理
原理比較簡單,主要就是使用jdk動態代理和cglib代理來創建代理對象,通過代理對象來訪問目標對象,而代理對象中融入了增強的代碼,最終起到對目標對象增強的效果。
aop相關的一些類
連接點(JoinPoint)相關類
通知(Advice)相關的類
切入點(Pointcut)相關的類
切面(Advisor)相關的類
連接點(JoinPoint)相關類
JoinPoint接口
這個接口表示一個通用的運行時連接點(在AOP術語中)
package org.aopalliance.intercept;
public interface Joinpoint {
/**
* 轉到攔截器鏈中的下一個攔截器
*/
Object proceed() throws Throwable;
/**
* 返回保存當前連接點靜態部分【的對象】,這裏一般指被代理的目標對象
*/
Object getThis();
/**
* 返回此靜態連接點 一般就爲當前的Method(至少目前的唯一實現是MethodInvocation,所以連接點得靜態部分肯定就是本方法)
*/
AccessibleObject getStaticPart();
}
幾個重要的子接口和實現類,如下:
Invocation接口
此接口表示程序中的調用,調用是一個連接點,可以被攔截器攔截。
package org.aopalliance.intercept;
/**
* 此接口表示程序中的調用
* 調用是一個連接點,可以被攔截器攔截。
*/
public interface Invocation extends Joinpoint {
/**
* 將參數作爲數組對象獲取,可以更改此數組中的元素值以更改參數。
* 通常用來獲取調用目標方法的參數
*/
Object[] getArguments();
}
MethodInvocation接口
用來表示連接點中方法的調用,可以獲取調用過程中的目標方法。
package org.aopalliance.intercept;
import java.lang.reflect.Method;
/**
* 方法調用的描述,在方法調用時提供給攔截器。
* 方法調用是一個連接點,可以被方法攔截器攔截。
*/
public interface MethodInvocation extends Invocation {
/**
* 返回正在被調用得方法~~~ 返回的是當前Method對象。
* 此時,效果同父類的AccessibleObject getStaticPart() 這個方法
*/
Method getMethod();
}
ProxyMethodInvocation接口
表示代理方法的調用
public interface ProxyMethodInvocation extends MethodInvocation {
/**
* 獲取被調用的代理對象
*/
Object getProxy();
/**
* 克隆一個方法調用器MethodInvocation
*/
MethodInvocation invocableClone();
/**
* 克隆一個方法調用器MethodInvocation,併爲方法調用器指定參數
*/
MethodInvocation invocableClone(Object... arguments);
/**
* 設置要用於此鏈中任何通知的後續調用的參數。
*/
void setArguments(Object... arguments);
/**
* 添加一些擴展用戶屬性,這些屬性不在AOP框架內使用。它們只是作爲調用對象的一部分保留,用於特殊的攔截器。
*/
void setUserAttribute(String key, @Nullable Object value);
/**
* 根據key獲取對應的用戶屬性
*/
@Nullable
Object getUserAttribute(String key);
}
通俗點理解:連接點表示方法的調用過程,內部包含了方法調用過程中的所有信息,比如被調用的方法、目標、代理對象、執行攔截器鏈等信息。
上面定義都是一些接口,最終有2個實現。
ReflectiveMethodInvocation
當代理對象是採用jdk動態代理創建的,通過代理對象來訪問目標對象的方法的時,最終過程是由ReflectiveMethodInvocation來處理的,內部會通過遞歸調用方法攔截器,最終會調用到目標方法。
CglibMethodInvocation
功能和上面的類似,當代理對象是採用cglib創建的,通過代理對象來訪問目標對象的方法的時,最終過程是由CglibMethodInvocation來處理的,內部會通過遞歸調用方法攔截器,最終會調用到目標方法。
這2個類源碼稍後詳解。
通知相關的類
通知用來定義需要增強的邏輯。
Advice接口
通知的底層接口
package org.aopalliance.aop;
public interface Advice {
}
BeforeAdvice接口
方法前置通知,內部空的
package org.springframework.aop;
public interface BeforeAdvice extends Advice {
}
Interceptor接口
此接口表示通用攔截器
package org.aopalliance.intercept;
public interface Interceptor extends Advice {
}
MethodInterceptor接口
方法攔截器,所有的通知均需要轉換爲MethodInterceptor類型的,最終多個MethodInterceptor組成一個方法攔截器連。
package org.aopalliance.intercept;
@FunctionalInterface
public interface MethodInterceptor extends Interceptor {
/**
* 攔截目標方法的執行,可以在這個方法內部實現需要增強的邏輯,以及主動調用目標方法
*/
Object invoke(MethodInvocation invocation) throws Throwable;
}
AfterAdvice接口
後置通知的公共標記接口
package org.springframework.aop;
public interface AfterAdvice extends Advice {
}
MethodBeforeAdvice接口
方法執行前通知,需要在目標方法執行前執行一些邏輯的,可以通過這個實現。
通俗點說:需要在目標方法執行之前增強一些邏輯,可以通過這個接口來實現。before方法:在調用給定方法之前回調。
package org.springframework.aop;
public interface MethodBeforeAdvice extends BeforeAdvice {
/**
* 調用目標方法之前會先調用這個before方法
* method:需要執行的目標方法
* args:目標方法的參數
* target:目標對象
*/
void before(Method method, Object[] args, @Nullable Object target) throws Throwable;
}
如同
public Object invoke(){
調用MethodBeforeAdvice#before方法
return 調用目標方法;
}
AfterReturningAdvice接口
方法執行後通知,需要在目標方法執行之後執行增強一些邏輯的,可以通過這個實現。
不過需要注意一點:目標方法正常執行後,纔會回調這個接口,當目標方法有異常,那麼這通知會被跳過。
package org.springframework.aop;
public interface AfterReturningAdvice extends AfterAdvice {
/**
* 目標方法執行之後會回調這個方法
* method:需要執行的目標方法
* args:目標方法的參數
* target:目標對象
*/
void afterReturning(@Nullable Object returnValue, Method method, Object[] args, @Nullable Object target) throws Throwable;
}
如同
public Object invoke(){
Object retVal = 調用目標方法;
調用AfterReturningAdvice#afterReturning方法
return retVal;
}
ThrowsAdvice接口
package org.springframework.aop;
public interface ThrowsAdvice extends AfterAdvice {
}
此接口上沒有任何方法,因爲方法由反射調用,實現類必須實現以下形式的方法,前3個參數是可選的,最後一個參數爲需要匹配的異常的類型。
void afterThrowing([Method, args, target], ThrowableSubclass);
有效方法的一些例子如下:
public void afterThrowing(Exception ex)
public void afterThrowing(RemoteException)
public void afterThrowing(Method method, Object[] args, Object target, Exception ex)
public void afterThrowing(Method method, Object[] args, Object target, ServletException ex)
通知包裝器
負責將各種非MethodInterceptor類型的通知(Advice)包裝爲MethodInterceptor類型。
剛纔有說過:Aop中所有的Advice最終都會轉換爲MethodInterceptor類型的,組成一個方法調用鏈,然後執行
3個包裝器類
MethodBeforeAdviceInterceptor
AfterReturningAdviceInterceptor
ThrowsAdviceInterceptor
MethodBeforeAdviceInterceptor類
這個類實現了MethodInterceptor
接口,負責將MethodBeforeAdvice
方法前置通知包裝爲MethodInterceptor
類型,創建這個類型的對象的時候需要傳遞一個MethodBeforeAdvice
類型的參數,重點是invoke
方法
package org.springframework.aop.framework.adapter;
@SuppressWarnings("serial")
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {
private final MethodBeforeAdvice advice;
public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
}
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
//負責調用前置通知的方法
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
//繼續執行方法調用鏈
return mi.proceed();
}
}
AfterReturningAdviceInterceptor類
這個類實現了MethodInterceptor
接口,負責將AfterReturningAdvice
方法後置通知包裝爲MethodInterceptor
類型,創建這個類型的對象的時候需要傳遞一個AfterReturningAdvice
類型的參數,重點是invoke
方法
public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable {
private final AfterReturningAdvice advice;
public AfterReturningAdviceInterceptor(AfterReturningAdvice advice) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
}
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
//先執行方法調用鏈,可以獲取目標方法的執行結果
Object retVal = mi.proceed();
//執行後置通知
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
//返回結果
return retVal;
}
}
ThrowsAdviceInterceptor類
這個類實現了MethodInterceptor
接口,負責將ThrowsAdvice
異常通知包裝爲MethodInterceptor
類型,創建這個類型的對象的時候需要傳遞一個Object
類型的參數,通常這個參數是ThrowsAdvice
類型的,重點是invoke
方法
package org.springframework.aop.framework.adapter;
public class ThrowsAdviceInterceptor implements MethodInterceptor, AfterAdvice {
private static final String AFTER_THROWING = "afterThrowing";
private final Object throwsAdvice;
//創建ThrowsAdviceInterceptor
public ThrowsAdviceInterceptor(Object throwsAdvice) {
Assert.notNull(throwsAdvice, "Advice must not be null");
this.throwsAdvice = throwsAdvice;
//獲取異常通知中定義的所有方法(public、默認的、protected、private)
Method[] methods = throwsAdvice.getClass().getMethods();
//輪詢methods
for (Method method : methods) {
//方法名稱爲afterThrowing && 方法參數爲1或者4
if (method.getName().equals(AFTER_THROWING) &&
(method.getParameterCount() == 1 || method.getParameterCount() == 4)) {
//獲取方法的最後一個參數類型
Class<?> throwableParam = method.getParameterTypes()[method.getParameterCount() - 1];
//判斷方法參數類型是不是Throwable類型的
if (Throwable.class.isAssignableFrom(throwableParam)) {
// 緩存異常處理方法到map中(異常類型->異常處理方法)
this.exceptionHandlerMap.put(throwableParam, method);
}
}
}
//如果exceptionHandlerMap,拋出異常,所以最少要有一個異常處理方法
if (this.exceptionHandlerMap.isEmpty()) {
throw new IllegalArgumentException(
"At least one handler method must be found in class [" + throwsAdvice.getClass() + "]");
}
}
/**
* 獲取異常通知中自定義的處理異常方法的數量
*/
public int getHandlerMethodCount() {
return this.exceptionHandlerMap.size();
}
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
//調用通知鏈
return mi.proceed();
}
catch (Throwable ex) {
//獲取異常通知中自定義的處理異常的方法
Method handlerMethod = getExceptionHandler(ex);
//當處理的方法不爲空
if (handlerMethod != null) {
//調用異常處理方法
invokeHandlerMethod(mi, ex, handlerMethod);
}
//繼續向外拋出異常
throw ex; //@1
}
}
/**
* 獲取throwsAdvice中處理exception參數指定的異常的方法
*/
@Nullable
private Method getExceptionHandler(Throwable exception) {
//獲取異常類型
Class<?> exceptionClass = exception.getClass();
//從緩存中獲取異常類型對應的方法
Method handler = this.exceptionHandlerMap.get(exceptionClass);
//來一個循環,查詢處理方法,循環條件:方法爲空 && 異常類型!=Throwable
while (handler == null && exceptionClass != Throwable.class) {
//獲取異常的父類型
exceptionClass = exceptionClass.getSuperclass();
//從緩存中查找異常對應的處理方法
handler = this.exceptionHandlerMap.get(exceptionClass);
}
//將查找結果返回
return handler;
}
//通過反射調用異常通知中的異常方法
private void invokeHandlerMethod(MethodInvocation mi, Throwable ex, Method method) throws Throwable {
//構建方法請求參數
Object[] handlerArgs;
//若只有1個參數,參數爲:異常對象
if (method.getParameterCount() == 1) {
handlerArgs = new Object[] {ex};
}
else {
//4個參數(方法、方法請求參數、目標對象、異常對象)
handlerArgs = new Object[] {mi.getMethod(), mi.getArguments(), mi.getThis(), ex};
}
try {
//通過反射調用異常通知中的方法
method.invoke(this.throwsAdvice, handlerArgs);
}
catch (InvocationTargetException targetEx) {
throw targetEx.getTargetException();
}
}
}
從上面可以看出,異常通知,自定義處理異常的方法有幾個特點
方法名稱必須爲
afterThrowing
方法參數必須1個或4個,最後一個參數是
Throwable
類型或其子類型可以在異常處理中記錄一些異常信息,這個還是比較有用的,但是注意一點目標方法拋出的異常最後還是會向外繼續拋出
@1
光講源碼,大家看着枯燥乏味,來點案例。
先來一個類,用來模擬用戶資金操作:充值、提現、查詢資金餘額;提現的時候餘額不足的時候,會拋出異常。
package com.javacode2018.aop.demo4;
//模擬資金操作
public class FundsService {
//賬戶餘額
private double balance = 1000;
//模擬提現
double recharge(String userName, double price) {
System.out.println(String.format("%s提現%s", userName, price));
balance += price;
return balance;
}
//模擬提現
double cashOut(String userName, double price) {
if (balance < price) {
throw new RuntimeException("餘額不足!");
}
System.out.println(String.format("%s提現%s", userName, price));
balance -= price;
return balance;
}
//獲取餘額
double getBalance(String userName) {
return balance;
}
}
案例1:前置通知攔截非法訪問
資金操作的所有方法都需要驗證用戶名,當用戶名不是“路人”的時候,直接拋出非法訪問異常。
package com.javacode2018.aop.demo4;
import org.junit.Test;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.lang.Nullable;
import java.lang.reflect.Method;
public class AopTest4 {
@Test
public void test1() {
//代理工廠
ProxyFactory proxyFactory = new ProxyFactory(new FundsService());
//添加一個方法前置通知,判斷用戶名不是“路人”的時候,拋出非法訪問異常
proxyFactory.addAdvice(new MethodBeforeAdvice() {
@Override
public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {
String userName = (String) args[0];
//如果不是路人的時候,拋出非法訪問異常
if (!"路人".equals(userName)) {
throw new RuntimeException(String.format("[%s]非法訪問!", userName));
}
}
});
//通過代理工廠創建代理
FundsService proxy = (FundsService) proxyFactory.getProxy();
//調用代理的方法
proxy.recharge("路人", 100);
proxy.recharge("張學友", 100);
}
}
運行輸出
路人提現100.0
java.lang.RuntimeException: [張學友]非法訪問!
at com.javacode2018.aop.demo4.AopTest4$1.before(AopTest4.java:25)
at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:55)
案例2:通過異常通知記錄異常
通過異常通知來捕獲所有方法的運行,發現異常之後,通知開發修復bug。
public static class SendMsgThrowsAdvice implements ThrowsAdvice {
//注意方法名稱必須爲afterThrowing
public void afterThrowing(Method method, Object[] args, Object target, RuntimeException e) {
//監控到異常後發送消息通知開發者
System.out.println("異常警報:");
System.out.println(String.format("method:[%s],args:[%s]", method.toGenericString(), Arrays.stream(args).collect(Collectors.toList())));
System.out.println(e.getMessage());
System.out.println("請儘快修復bug!");
}
}
@Test
public void test2() {
//代理工廠
ProxyFactory proxyFactory = new ProxyFactory(new FundsService());
//添加一個異常通知,發現異常之後發送消息給開發者儘快修復bug
proxyFactory.addAdvice(new SendMsgThrowsAdvice());
//通過代理工廠創建代理
FundsService proxy = (FundsService) proxyFactory.getProxy();
//調用代理的方法
proxy.cashOut("路人", 2000);
}
運行輸出
異常警報:
method:[double com.javacode2018.aop.demo4.FundsService.cashOut(java.lang.String,double)],args:[[路人, 2000.0]]
餘額不足!
請儘快修復bug!
java.lang.RuntimeException: 餘額不足!
at com.javacode2018.aop.demo4.FundsService.cashOut(FundsService.java:18)
切入點(PointCut)相關類
通知(Advice)用來指定需要增強的邏輯,但是哪些類的哪些方法中需要使用這些通知呢?這個就是通過切入點來配置的。
PointCut接口
package org.springframework.aop;
public interface Pointcut {
/**
* 類過濾器, 可以知道哪些類需要攔截
*/
ClassFilter getClassFilter();
/**
* 方法匹配器, 可以知道哪些方法需要攔截
*/
MethodMatcher getMethodMatcher();
/**
* 匹配所有對象的 Pointcut,內部的2個過濾器默認都會返回true
*/
Pointcut TRUE = TruePointcut.INSTANCE;
}
ClassFilter接口
類過濾器。
@FunctionalInterface
public interface ClassFilter {
/**
* 用來判斷目標類型是否匹配
*/
boolean matches(Class<?> clazz);
}
MethodMatcher接口
方法過濾器。
public interface MethodMatcher {
/**
* 執行靜態檢查給定方法是否匹配
* @param method 目標方法
* @param targetClass 目標對象類型
*/
boolean matches(Method method, Class<?> targetClass);
/**
* 是否是動態匹配,即是否每次執行目標方法的時候都去驗證一下
*/
boolean isRuntime();
/**
* 動態匹配驗證的方法,比第一個matches方法多了一個參數args,這個參數是調用目標方法傳入的參數
*/
boolean matches(Method method, Class<?> targetClass, Object... args);
/**
* 匹配所有方法,這個內部的2個matches方法任何時候都返回true
*/
MethodMatcher TRUE = TrueMethodMatcher.INSTANCE;
}
我估計大家看MethodMatcher還是有點暈的,爲什麼需要2個maches方法?什麼是動態匹配?
比如下面一個類
public class UserService{
public void work(String userName){
System.out.print(userName+",開始工作了!");
}
}
work方法表示當前用戶的工作方法,內部可以實現一些工作的邏輯。
我們希望通過aop對這個類進行增強,調用這個方法的時候,當傳入的用戶名是路人的粉絲的
的時候,需要先進行問候,其他用戶的時候,無需問候,將這個問題的代碼可以放在MethodBeforeAdvice中實現,這種情況就是當參數滿足一定的條件了,纔會使用這個通知,不滿足的時候,通知無效,此時就可以使用上面的動態匹配來實現,MethodMatcher類中3個參數的matches方法可以用來對目標方法的參數做校驗。
來看一下MethodMatcher
過濾的整個過程
1.調用matches(Method method, Class<?> targetClass)方法,驗證方法是否匹配
2.isRuntime方法是否爲true,如果爲false,則以第一步的結果爲準,否則繼續向下
3.調用matches(Method method, Class<?> targetClass, Object... args)方法繼續驗證,這個方法多了一個參數,可以對目標方法傳入的參數進行校驗。
通過上面的過程,大家可以看出來,如果isRuntime
爲false的時候,只需要對方法名稱進行校驗,當目標方法調用多次的時候,實際上第一步的驗證結果是一樣的,所以如果isRuntime
爲false的情況,可以將驗證結果放在緩存中,提升效率,而spring內部就是這麼做的,isRuntime
爲false的時候,需要每次都進行校驗,效率會低一些,不過對性能的影響基本上可以忽略。
顧問(Advisor)
通知定義了需要做什麼,切入點定義了在哪些類的哪些方法中執行通知,那麼需要將他們2個組合起來纔有效啊。
顧問(Advisor)就是做這個事情的。
在spring aop中,你可以將advisor理解爲切面,切面中通常有2個關鍵信息:
需要增強的目標方法列表,這個通過切入點(Pointcut)來指定
需要在目標方法中增強的邏輯,這個通過(Advice)通知來指定
Advisor接口
package org.springframework.aop;
import org.aopalliance.aop.Advice;
/**
* 包含AOP通知(在joinpoint處執行的操作)和確定通知適用性的過濾器(如切入點[PointCut])的基本接口。
* 這個接口不是供Spring用戶使用的,而是爲了支持不同類型的建議的通用性。
*/
public interface Advisor {
/**
* 返回引用的通知
*/
Advice getAdvice();
}
上面這個接口通常不會直接使用,這個接口有2個子接口,通常我們會和這2個子接口來打交道,下面看一下這2個子接口。
PointcutAdvisor接口
通過名字就能看出來,這個和Pointcut有關,內部有個方法用來獲取Pointcut
,AOP使用到的大部分Advisor都屬於這種類型的。
在目標方法中實現各種增強功能基本上都是通過PointcutAdvisor來實現的。
package org.springframework.aop;
/**
* 切入點類型的Advisor
*/
public interface PointcutAdvisor extends Advisor {
/**
* 獲取顧問中使用的切入點
*/
Pointcut getPointcut();
}
DefaultPointcutAdvisor類
PointcutAdvisor的默認實現,這是最常用的Advisor實現,它可以用於任何Pointcut和Advice類型,代碼相當簡單,裏面定義了2個屬性:pointcut和advisor,由使用者指定。
IntroductionAdvisor接口
這個接口,估計大家比較陌生,幹什麼的呢?
一個Java類,沒有實現A接口,在不修改Java類的情況下,使其具備A接口的功能。可以通過IntroductionAdvisor給目標類引入更多接口的功能,這個功能是不是非常牛逼。
下面開始2個重點工作。
通過源碼介紹aop中代理創建過程
通過源碼介紹代理方法的調用執行過程
代理創建過程源碼解析
先看一段代碼
//代理工廠
ProxyFactory proxyFactory = new ProxyFactory(new FundsService());
//添加一個方法前置通知,判斷用戶名不是“路人”的時候,拋出非法訪問異常
proxyFactory.addAdvice(new MethodBeforeAdvice() {
@Override
public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {
String userName = (String) args[0];
//如果不是路人的時候,拋出非法訪問異常
if (!"路人".equals(userName)) {
throw new RuntimeException(String.format("[%s]非法訪問!", userName));
}
}
});
//通過代理工廠創建代理
FundsService proxy = (FundsService) proxyFactory.getProxy();
我們將上面代碼拆分一下,變成下面這樣
//1.創建代理所需參數配置(如:採用什麼方式的代理、通知列表等)
AdvisedSupport advisedSupport = new AdvisedSupport();
//如:添加一個前置通知
advisedSupport.addAdvice(new MethodBeforeAdvice() {
@Override
public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {
String userName = (String) args[0];
//如果不是路人的時候,拋出非法訪問異常
if (!"路人".equals(userName)) {
throw new RuntimeException(String.format("[%s]非法訪問!", userName));
}
}
});
//設置被代理的目標對象
FundsService target = new FundsService();
advisedSupport.setTarget(target);
//2.根據配置信息獲取AopProxy對象,AopProxy用來負責創建最終的代理對象
// AopProxy接口有2個實現類(JDK動態代理、cglib代理)
// 具體最終會使用哪種方式,需要根據AdvisedSupport中指定的參數來判斷
// 創建AopProxy使用了簡單工廠模式
AopProxyFactory aopProxyFactory = new DefaultAopProxyFactory();
//通過AopProxy工廠獲取AopProxy對象
AopProxy aopProxy = aopProxyFactory.createAopProxy(advisedSupport);
//3.通過AopProxy創建代理對象
Object proxy = aopProxy.getProxy();
從上面可以看出創建代理有3個步驟。
創建代理3大步驟
創建代理所需參數配置
根據代理參數獲取AopProxy對象
通過AopProxy獲取代理對象
創建代理所需參數配置
創建代理所需參數配置主要是通過AdvisedSupport
這個類來做的,看一下類圖,下面一個個來介紹。
根據代理參數獲取AopProxy對象
TargetClassAware接口
比較簡單的一個接口,定義了一個方法,用來獲取目標對象類型。
所謂目標對象:就是被代理對象,比如上面的fundsService
對象。
package org.springframework.aop;
public interface TargetClassAware {
@Nullable
Class<?> getTargetClass();
}
ProxyConfig類
這個類比較關鍵了,代理配置類,內部包含了創建代理時需要配置的各種參數。
package org.springframework.aop.framework;
/**
* 對外提供統一的代理參數配置類,以確保所有代理創建程序具有一致的屬性
*/
public class ProxyConfig implements Serializable {
// 標記是否直接對目標類進行代理,而不是通過接口產生代理
private boolean proxyTargetClass = false;
// 標記是否對代理進行優化。啓動優化通常意味着在代理對象被創建後,增強的修改將不會生效,因此默認值爲false。
// 如果exposeProxy設置爲true,即使optimize爲true也會被忽略。
private boolean optimize = false;
// 標記是否需要阻止通過該配置創建的代理對象轉換爲Advised類型,默認值爲false,表示代理對象可以被轉換爲Advised類型
boolean opaque = false;
// 標記代理對象是否應該被aop框架通過AopContext以ThreadLocal的形式暴露出去。
// 當一個代理對象需要調用它自己的另外一個代理方法時,這個屬性將非常有用。默認是是false,以避免不必要的攔截。
boolean exposeProxy = false;
// 標記該配置是否需要被凍結,如果被凍結,將不可以修改增強的配置。
// 當我們不希望調用方修改轉換成Advised對象之後的代理對象時,這個配置將非常有用。
private boolean frozen = false;
//省略了屬性的get set方法
}
Advised接口
這個接口中定義了操作Aop代理配置的各種方法(比如指定被代理的目標對象、添加通知、添加顧問等等)。
所有由spring aop創建的代理對象默認都會實現這個接口。
public interface Advised extends TargetClassAware {
/**
* 返回配置是否已凍結,被凍結之後,無法修改已創建好的代理對象中的通知
*/
boolean isFrozen();
/**
* 是否對目標類直接創建代理,而不是對接口創建代理,通俗點講:如果是通過cglib創建代理,此方法返回true,否則返回false
*/
boolean isProxyTargetClass();
/**
* 獲取配置中需要代理的接口列表
*/
Class<?>[] getProxiedInterfaces();
/**
* 判斷某個接口是否被代理
*/
boolean isInterfaceProxied(Class<?> intf);
/**
* 設置被代理的目標源,創建代理的時候,通常需要傳入被代理的對象,最終被代理的對象會被包裝爲TargetSource類型的
*/
void setTargetSource(TargetSource targetSource);
/**
* 返回被代理的目標源
*/
TargetSource getTargetSource();
/**
* 設置是否需要將代理暴露在ThreadLocal中,這樣可以在線程中獲取到被代理對象,這個配置挺有用的,稍後會舉例說明使用場景
*/
void setExposeProxy(boolean exposeProxy);
/**
* 返回exposeProxy
*/
boolean isExposeProxy();
/**
* 設置此代理配置是否經過預篩選,以便它只包含適用的顧問(匹配此代理的目標類)。
* 默認設置是“假”。如果已經對advisor進行了預先篩選,則將其設置爲“true”
* 這意味着在爲代理調用構建實際的advisor鏈時可以跳過ClassFilter檢查。
*/
void setPreFiltered(boolean preFiltered);
/**
* 返回preFiltered
*/
boolean isPreFiltered();
/**
* 返回代理配置中幹掉所有Advisor列表
*/
Advisor[] getAdvisors();
/**
* 添加一個Advisor
*/
void addAdvisor(Advisor advisor) throws AopConfigException;
/**
* 指定的位置添加一個Advisor
*/
void addAdvisor(int pos, Advisor advisor) throws AopConfigException;
/**
* 移除一個Advisor
*/
boolean removeAdvisor(Advisor advisor);
/**
* 移除指定位置的Advisor
*/
void removeAdvisor(int index) throws AopConfigException;
/**
* 查找某個Advisor的位置
*/
int indexOf(Advisor advisor);
/**
* 對advisor列表中的a替換爲b
*/
boolean replaceAdvisor(Advisor a, Advisor b) throws AopConfigException;
/**
* 添加一個通知
*/
void addAdvice(Advice advice) throws AopConfigException;
/**
* 向指定的位置添加一個通知
*/
void addAdvice(int pos, Advice advice) throws AopConfigException;
/**
* 移除一個通知
*/
boolean removeAdvice(Advice advice);
/**
* 獲取通知的位置
*/
int indexOf(Advice advice);
/**
* 將代理配置轉換爲字符串,這個方便排錯和調試使用的
*/
String toProxyConfigString();
}
AdvisedSupport類
這個類是個重點,AOP代理配置管理器的基類,繼承了ProxyConfig
並且實現了Advised
接口,創建aop代理之前,所有需要配置的信息都是通過這個類來操作的。
比如:設置是否爲目標類創建代理、設置目標對象、配置通知列表等等。
package org.springframework.aop.framework;
public class AdvisedSupport extends ProxyConfig implements Advised {
public static final TargetSource EMPTY_TARGET_SOURCE = EmptyTargetSource.INSTANCE;
TargetSource targetSource = EMPTY_TARGET_SOURCE;
/** 建議器是否已經針對特定的目標類進行篩選 */
private boolean preFiltered = false;
/** 調用鏈工廠,用來獲取目標方法的調用鏈 */
AdvisorChainFactory advisorChainFactory = new DefaultAdvisorChainFactory();
/** 方法調用鏈緩存:以方法爲鍵,以顧問鏈表爲值的緩存。 */
private transient Map<MethodCacheKey, List<Object>> methodCache;
//代理對象需要實現的接口列表。保存在列表中以保持註冊的順序,以創建具有指定接口順序的JDK代理。
private List<Class<?>> interfaces = new ArrayList<>();
//配置的顧問列表。所有添加的Advise對象都會被包裝爲Advisor對象
private List<Advisor> advisors = new ArrayList<>();
//數組更新了對advisor列表的更改,這更容易在內部操作。
private Advisor[] advisorArray = new Advisor[0];
//無參構造方法
public AdvisedSupport() {
this.methodCache = new ConcurrentHashMap<>(32);
}
//有參構造方法,參數爲:代理需要實現的接口列表
public AdvisedSupport(Class<?>... interfaces) {
this();
setInterfaces(interfaces);
}
//設置需要被代理的目標對象,目標對象會被包裝爲TargetSource格式的對象
public void setTarget(Object target) {
setTargetSource(new SingletonTargetSource(target));
}
//設置被代理的目標源
@Override
public void setTargetSource(@Nullable TargetSource targetSource) {
this.targetSource = (targetSource != null ? targetSource : EMPTY_TARGET_SOURCE);
}
//獲取被代理的目標源
@Override
public TargetSource getTargetSource() {
return this.targetSource;
}
//設置被代理的目標類
public void setTargetClass(@Nullable Class<?> targetClass) {
this.targetSource = EmptyTargetSource.forClass(targetClass);
}
//獲取被代理的目標類型
@Override
@Nullable
public Class<?> getTargetClass() {
return this.targetSource.getTargetClass();
}
/**
* 設置此代理配置是否經過預篩選,這個什麼意思呢:通過目標方法調用代理的時候,
* 需要通過匹配的方式獲取這個方法上的調用鏈列表,查找過程需要2個步驟:
* 第一步:類是否匹配,第二步:方法是否匹配,當這個屬性爲true的時候,會直接跳過第一步,這個懂了不
*/
@Override
public void setPreFiltered(boolean preFiltered) {
this.preFiltered = preFiltered;
}
// 返回preFiltered
@Override
public boolean isPreFiltered() {
return this.preFiltered;
}
/**
* 設置顧問鏈工廠,當調用目標方法的時候,需要獲取這個方法上匹配的Advisor列表,
* 獲取目標方法上匹配的Advisor列表的功能就是AdvisorChainFactory來負責的
*/
public void setAdvisorChainFactory(AdvisorChainFactory advisorChainFactory) {
Assert.notNull(advisorChainFactory, "AdvisorChainFactory must not be null");
this.advisorChainFactory = advisorChainFactory;
}
// 返回顧問鏈工廠對象
public AdvisorChainFactory getAdvisorChainFactory() {
return this.advisorChainFactory;
}
//設置代理對象需要實現的接口
public void setInterfaces(Class<?>... interfaces) {
Assert.notNull(interfaces, "Interfaces must not be null");
this.interfaces.clear();
for (Class<?> ifc : interfaces) {
addInterface(ifc);
}
}
//爲代理對象添加需要實現的接口
public void addInterface(Class<?> intf) {
Assert.notNull(intf, "Interface must not be null");
if (!intf.isInterface()) {
throw new IllegalArgumentException("[" + intf.getName() + "] is not an interface");
}
if (!this.interfaces.contains(intf)) {
this.interfaces.add(intf);
adviceChanged();
}
}
//移除代理對象需要實現的接口
public boolean removeInterface(Class<?> intf) {
return this.interfaces.remove(intf);
}
//獲取代理對象需要實現的接口列表
@Override
public Class<?>[] getProxiedInterfaces() {
return ClassUtils.toClassArray(this.interfaces);
}
//判斷代理對象是否需要實現某個接口
@Override
public boolean isInterfaceProxied(Class<?> intf) {
for (Class<?> proxyIntf : this.interfaces) {
if (intf.isAssignableFrom(proxyIntf)) {
return true;
}
}
return false;
}
//獲取配置的所有顧問列表
@Override
public final Advisor[] getAdvisors() {
return this.advisorArray;
}
//添加顧問
@Override
public void addAdvisor(Advisor advisor) {
int pos = this.advisors.size();
addAdvisor(pos, advisor);
}
//指定的位置添加顧問
@Override
public void addAdvisor(int pos, Advisor advisor) throws AopConfigException {
//這塊先忽略,以後講解
if (advisor instanceof IntroductionAdvisor) {
validateIntroductionAdvisor((IntroductionAdvisor) advisor);
}
addAdvisorInternal(pos, advisor);
}
//移除指定的顧問
@Override
public boolean removeAdvisor(Advisor advisor) {
int index = indexOf(advisor);
if (index == -1) {
return false;
}
else {
removeAdvisor(index);
return true;
}
}
//移除指定位置的顧問
@Override
public void removeAdvisor(int index) throws AopConfigException {
//當配置如果是凍結狀態,是不允許對顧問進行修改的,否則會拋出異常
if (isFrozen()) {
throw new AopConfigException("Cannot remove Advisor: Configuration is frozen.");
}
if (index < 0 || index > this.advisors.size() - 1) {
throw new AopConfigException("Advisor index " + index + " is out of bounds: " +
"This configuration only has " + this.advisors.size() + " advisors.");
}
//移除advisors中的顧問
Advisor advisor = this.advisors.remove(index);
if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
// We need to remove introduction interfaces.
for (Class<?> ifc : ia.getInterfaces()) {
removeInterface(ifc);
}
}
//更新advisorArray
updateAdvisorArray();
//通知已改變,內部會清除方法調用鏈緩存信息。
adviceChanged();
}
@Override
public int indexOf(Advisor advisor) {
Assert.notNull(advisor, "Advisor must not be null");
return this.advisors.indexOf(advisor);
}
@Override
public boolean replaceAdvisor(Advisor a, Advisor b) throws AopConfigException {
Assert.notNull(a, "Advisor a must not be null");
Assert.notNull(b, "Advisor b must not be null");
int index = indexOf(a);
if (index == -1) {
return false;
}
removeAdvisor(index);
addAdvisor(index, b);
return true;
}
//批量添加顧問
public void addAdvisors(Advisor... advisors) {
addAdvisors(Arrays.asList(advisors));
}
//批量添加顧問
public void addAdvisors(Collection<Advisor> advisors) {
//配置如果是凍結狀態,會拋出異常
if (isFrozen()) {
throw new AopConfigException("Cannot add advisor: Configuration is frozen.");
}
if (!CollectionUtils.isEmpty(advisors)) {
for (Advisor advisor : advisors) {
if (advisor instanceof IntroductionAdvisor) {
validateIntroductionAdvisor((IntroductionAdvisor) advisor);
}
Assert.notNull(advisor, "Advisor must not be null");
this.advisors.add(advisor);
}
updateAdvisorArray();
adviceChanged();
}
}
//此方法先忽略,用來爲目標類引入接口的
private void validateIntroductionAdvisor(IntroductionAdvisor advisor) {
advisor.validateInterfaces();
// If the advisor passed validation, we can make the change.
Class<?>[] ifcs = advisor.getInterfaces();
for (Class<?> ifc : ifcs) {
addInterface(ifc);
}
}
//指定的位置添加顧問
private void addAdvisorInternal(int pos, Advisor advisor) throws AopConfigException {
Assert.notNull(advisor, "Advisor must not be null");
if (isFrozen()) {
throw new AopConfigException("Cannot add advisor: Configuration is frozen.");
}
if (pos > this.advisors.size()) {
throw new IllegalArgumentException(
"Illegal position " + pos + " in advisor list with size " + this.advisors.size());
}
this.advisors.add(pos, advisor);
updateAdvisorArray();
adviceChanged();
}
//將advisorArray和advisors保持一致
protected final void updateAdvisorArray() {
this.advisorArray = this.advisors.toArray(new Advisor[0]);
}
//獲取顧問列表
protected final List<Advisor> getAdvisorsInternal() {
return this.advisors;
}
//添加通知
@Override
public void addAdvice(Advice advice) throws AopConfigException {
int pos = this.advisors.size();
addAdvice(pos, advice);
}
//指定的位置添加通知
@Override
public void addAdvice(int pos, Advice advice) throws AopConfigException {
//此處會將advice通知包裝爲DefaultPointcutAdvisor類型的Advisor
addAdvisor(pos, new DefaultPointcutAdvisor(advice));
}
//移除通知
@Override
public boolean removeAdvice(Advice advice) throws AopConfigException {
int index = indexOf(advice);
if (index == -1) {
return false;
}
else {
removeAdvisor(index);
return true;
}
}
//獲取通知的位置
@Override
public int indexOf(Advice advice) {
Assert.notNull(advice, "Advice must not be null");
for (int i = 0; i < this.advisors.size(); i++) {
Advisor advisor = this.advisors.get(i);
if (advisor.getAdvice() == advice) {
return i;
}
}
return -1;
}
//是否包含某個通知
public boolean adviceIncluded(@Nullable Advice advice) {
if (advice != null) {
for (Advisor advisor : this.advisors) {
if (advisor.getAdvice() == advice) {
return true;
}
}
}
return false;
}
//獲取當前配置中某種類型通知的數量
public int countAdvicesOfType(@Nullable Class<?> adviceClass) {
int count = 0;
if (adviceClass != null) {
for (Advisor advisor : this.advisors) {
if (adviceClass.isInstance(advisor.getAdvice())) {
count++;
}
}
}
return count;
}
//基於當前配置,獲取給定方法的方法調用鏈列表(即org.aopalliance.intercept.MethodInterceptor對象列表)
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
MethodCacheKey cacheKey = new MethodCacheKey(method);
//先從緩存中獲取
List<Object> cached = this.methodCache.get(cacheKey);
//緩存中沒有時,從advisorChainFactory中獲取
if (cached == null) {
cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
this, method, targetClass);
this.methodCache.put(cacheKey, cached);
}
return cached;
}
//通知更改時調用,會清空當前方法調用鏈緩存
protected void adviceChanged() {
this.methodCache.clear();
}
//將other中的配置信息複製到當前對象中
protected void copyConfigurationFrom(AdvisedSupport other) {
copyConfigurationFrom(other, other.targetSource, new ArrayList<>(other.advisors));
}
//將other中的配置信息複製到當前對象中
protected void copyConfigurationFrom(AdvisedSupport other, TargetSource targetSource, List<Advisor> advisors) {
copyFrom(other);
this.targetSource = targetSource;
this.advisorChainFactory = other.advisorChainFactory;
this.interfaces = new ArrayList<>(other.interfaces);
for (Advisor advisor : advisors) {
if (advisor instanceof IntroductionAdvisor) {
validateIntroductionAdvisor((IntroductionAdvisor) advisor);
}
Assert.notNull(advisor, "Advisor must not be null");
this.advisors.add(advisor);
}
updateAdvisorArray();
adviceChanged();
}
//構建此AdvisedSupport的僅配置副本,替換TargetSource。
AdvisedSupport getConfigurationOnlyCopy() {
AdvisedSupport copy = new AdvisedSupport();
copy.copyFrom(this);
copy.targetSource = EmptyTargetSource.forClass(getTargetClass(), getTargetSource().isStatic());
copy.advisorChainFactory = this.advisorChainFactory;
copy.interfaces = this.interfaces;
copy.advisors = this.advisors;
copy.updateAdvisorArray();
return copy;
}
}
上面幾個類有幾個結論,這裏說一下。
配置中添加的Advice對象最終都會被轉換爲DefaultPointcutAdvisor對象,此時DefaultPointcutAdvisor未指定pointcut,大家可以去看一下DefaultPointcutAdvisor中pointcut有個默認值,默認會匹配任意類的任意方法。
當配置被凍結的時候,即frozen爲true的時,此時配置中的Advisor列表是不允許修改的。
上面的
getInterceptorsAndDynamicInterceptionAdvice
方法,通過代理調用目標方法的時候,最後需要通過方法和目標類的類型,從當前配置中會獲取匹配的方法攔截器列表,獲取方法攔截器列表是由AdvisorChainFactory
負責的。getInterceptorsAndDynamicInterceptionAdvice
會在調用代理的方法時會執行,稍後在執行階段會詳解。目標方法和其關聯的方法攔截器列表會被緩存在
methodCache
中,當顧問列表有變化的時候,methodCache
緩存會被清除。
配置階段完成之後,下面進入AopProxy獲取階段。
根據配置獲取AopProxy
這個階段對應的代碼:
// 創建AopProxy使用了簡單工廠模式
AopProxyFactory aopProxyFactory = new DefaultAopProxyFactory();
//通過AopProxy工廠獲取AopProxy對象
AopProxy aopProxy = aopProxyFactory.createAopProxy(advisedSupport);
此階段會根據AdvisedSupport中配置信息,判斷具體是採用cglib的方式還是採用jdk動態代理的方式獲取代理對象,先看一下涉及到的一些類。
AopProxy接口
這個接口定義了一個方法,用來創建最終的代理對象,這個接口有2個實現類
CglibAopProxy:採用cglib的方式創建代理對象
JkdDynamicAopProxy:採用jdk動態代理的方式創建代理對象
package org.springframework.aop.framework;
public interface AopProxy {
/**
* 創建一個新的代理對象
*/
Object getProxy();
/**
* 創建一個新的代理對象
*/
Object getProxy(@Nullable ClassLoader classLoader);
}
AopProxy的2個實現類,實現了上面定義的2個方法,稍後在代理的創建階段詳細介紹。
AopProxyFactory接口
通過名稱就可以看出來,是一個工廠,負責創建AopProxy,使用的是簡單工廠模式。
接口中定義了一個方法,會根據Aop的配置信息AdvisedSupport來獲取AopProxy對象,主要是判斷採用cglib的方式還是採用jdk動態代理的方式。
package org.springframework.aop.framework;
public interface AopProxyFactory {
/**
* 根據aop配置信息獲取AopProxy對象
*/
AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException;
}
DefaultAopProxyFactory類
AopProxyFactory接口的默認實現,代碼比較簡單,我們來細看一下
package org.springframework.aop.framework;
/**
* 默認AopProxyFactory實現,創建CGLIB代理或JDK動態代理。
* 對於給定的AdvisedSupport實例,以下條件爲真,則創建一個CGLIB代理:
* optimize = true
* proxyTargetClass = true
* 未指定代理接口
* 通常,指定proxyTargetClass來強制執行CGLIB代理,或者指定一個或多個接口來使用JDK動態代理。
*/
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
// optimize==true || proxyTargetClass 爲true || 配置中沒有需要代理的接口
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
//獲取需要被代理的類
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
//如果被代理的類爲接口 或者 被代理的類是jdk動態代理創建代理類,則採用JdkDynamicAopProxy的方式,否則採用cglib代理的方式
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
//採用jdk動態代理的方式
return new JdkDynamicAopProxy(config);
}
//採用cglib代理的方式
return new ObjenesisCglibAopProxy(config);
}
else {
//採用jdk動態代理的方式
return new JdkDynamicAopProxy(config);
}
}
/**
* 確定所提供的AdvisedSupport是否只指定了SpringProxy接口(或者根本沒有指定代理接口)
*/
private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
Class<?>[] ifcs = config.getProxiedInterfaces();
return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
}
}
代理創建階段
到目前爲止我們已經根據aop配置信息得到了AopProxy對象了,下面就可以調用AopProxy.getProxy方法獲取代理對象了。
AopProxy.createAopProxy方法返回的結果有2種情況
JdkDynamicAopProxy:以jdk動態代理的方式創建代理
ObjenesisCglibAopProxy:以cglib的方式創建動態代理
項目詳解這2個類的源碼 。
JdkDynamicAopProxy類
作用:採用jdk動態代理的方式創建代理對象,並處理代理對象的所有方法調用。
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
//代理的配置信息
private final AdvisedSupport advised;
//需要被代理的接口中是否定義了equals方法
private boolean equalsDefined;
//需要被代理的接口中是否定義了hashCode方法
private boolean hashCodeDefined;
//通過AdvisedSupport創建實例
public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
Assert.notNull(config, "AdvisedSupport must not be null");
if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
throw new AopConfigException("No advisors and no TargetSource specified");
}
this.advised = config;
}
//生成一個代理對象
@Override
public Object getProxy() {
return getProxy(ClassUtils.getDefaultClassLoader());
}
//生成一個代理對象
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
//@0:根據advised的信息獲取代理需要被代理的所有接口列表
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
//查找被代理的接口中是否定義了equals、hashCode方法
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
/**
* 這個大家應該很熟悉吧,通過jdk動態代理創建代理對象,注意最後一個參數是this
* 表示當前類,當前類是InvocationHandler類型的,當調用代理對象的任何方法的時候
* 都會被被當前類的 invoke 方法處理
*/
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
//判斷需要代理的接口中是否定義了這幾個方法(equals、hashCode)
private void findDefinedEqualsAndHashCodeMethods(Class<?>[] proxiedInterfaces) {
for (Class<?> proxiedInterface : proxiedInterfaces) {
//獲取接口中定義的方法
Method[] methods = proxiedInterface.getDeclaredMethods();
for (Method method : methods) {
//是否是equals方法
if (AopUtils.isEqualsMethod(method)) {
this.equalsDefined = true;
}
//是否是hashCode方法
if (AopUtils.isHashCodeMethod(method)) {
this.hashCodeDefined = true;
}
//如果發現這2個方法都定義了,結束循環查找
if (this.equalsDefined && this.hashCodeDefined) {
return;
}
}
}
}
// 這個方法比較關鍵了,當在程序中調用代理對象的任何方法,最終都會被下面這個invoke方法處理
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//舊的代理對象
Object oldProxy = null;
//用來標記是否需要將代理對象暴露在ThreadLocal中
boolean setProxyContext = false;
//獲取目標源
TargetSource targetSource = this.advised.targetSource;
//目標對象
Object target = null;
//下面進入代理方法的處理階段
try {
// 處理equals方法:被代理的接口中沒有定義equals方法 && 當前調用是equals方法
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// 直接調用當前類中的equals方法
return equals(args[0]);
}
// 處理hashCode方法:被代理的接口中沒有定義hashCode方法 && 當前調用是hashCode方法
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// 直接調用當前類中的hashCode方法
return hashCode();
}
/**
* 方法來源於 DecoratingProxy 接口,這個接口中定義了一個方法
* 用來獲取原始的被代理的目標類,主要是用在嵌套代理的情況下(所謂嵌套代理:代理對象又被作爲目標對象進行了代理)
*/
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// 調用AopProxyUtils工具類的方法,內部通過循環遍歷的方式,找到最原始的被代理的目標類
return AopProxyUtils.ultimateTargetClass(this.advised);
}
// 方法來源於 Advised 接口,代理對象默認情況下會實現 Advised 接口,可以通過代理對象來動態向代理對象中添加通知等
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// this.advised是AdvisedSupport類型的,AdvisedSupport實現了Advised接口中的所有方法
// 所以最終通過通過反射方式交給this.advised來響應當前調用
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
// 用來記錄方法返回值
Object retVal;
//是否需要在threadLocal中暴露代理對象
if (this.advised.exposeProxy) {
// 將代理對象暴露在上線文中,即暴露在threadLocal中,那麼在當前線程中可以通過靜態方法
// AopContext#currentProxy獲取當前被暴露的代理對象,這個是非常有用的,稍後用案例來講解,瞬間就會明白
oldProxy = AopContext.setCurrentProxy(proxy);
// 將setProxyContext標記爲true
setProxyContext = true;
}
// 通過目標源獲取目標對象
target = targetSource.getTarget();
// 獲取目標對象類型
Class<?> targetClass = (target != null ? target.getClass() : null);
// @1:獲取當前方法的攔截器鏈
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// 攔截器鏈爲空的情況下,表示這個方法上面沒有找到任何增強的通知,那麼會直接通過反射直接調用目標對象
if (chain.isEmpty()) {
// 獲取方法請求的參數(有時候方法中有可變參數,所謂可變參數就是帶有省略號(...)這種格式的參數,傳入的參數類型和這種類型不一樣的時候,會通過下面的adaptArgumentsIfNecessary方法進行轉換)
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
//通過反射直接調用目標方法
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// 創建一個方法調用器(包含了代理對象、目標對象、調用的方法、參數、目標類型、方法攔截器鏈)
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// @3:通過攔截器鏈一個個調用最終到目標方法的調用
retVal = invocation.proceed();
}
// 下面會根據方法返回值的類型,做一些處理,比如方法返回的類型爲自己,則最後需要將返回值置爲代理對象
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// 將返回值設置爲代理對象
retVal = proxy;
}
// 方法的返回值類型returnType爲原始類型(即int、byte、double等這種類型的) && retVal爲null,
// 此時如果將null轉換爲原始類型會報錯,所以此處直接拋出異常
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
// 返回方法調用結果
return retVal;
}
finally {
// 目標對象不爲null && 目標源不是靜態的
//所謂靜態的,你可以理解爲是否是單例的
// isStatic爲true,表示目標對象是單例的,同一個代理對象中所有方法共享一個目標對象
// isStatic爲false的時候,通常每次調用代理的方法,target對象是不一樣的,所以方法調用萬之後需要進行釋放,可能有些資源清理,連接的關閉等操作
if (target != null && !targetSource.isStatic()) {
// 必須釋放來自TargetSource中的目標對象
targetSource.releaseTarget(target);
}
// setProxyContext爲ture
if (setProxyContext) {
// 需要將舊的代理再放回到上線文中
AopContext.setCurrentProxy(oldProxy);
}
}
}
}
關於上面代碼,有幾點細說一下
@0:completeProxiedInterfaces方法
@0
處的代碼如下,根據代理配置信息,獲取需要被代理的所有接口
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
AopProxyUtils.completeProxiedInterfaces
方法源碼如下
static Class<?>[] completeProxiedInterfaces(AdvisedSupport advised, boolean decoratingProxy) {
//獲取代理配置中需要被代理的接口
Class<?>[] specifiedInterfaces = advised.getProxiedInterfaces();
// 需要被代理的接口數量爲0
if (specifiedInterfaces.length == 0) {
// 獲取需要被代理的目標類型
Class<?> targetClass = advised.getTargetClass();
//目標類型不爲空
if (targetClass != null) {
//目標類型爲接口
if (targetClass.isInterface()) {
//將其添加到需要代理的接口中
advised.setInterfaces(targetClass);
}
// 目標類型爲jdk動態代理創建的代理對象
else if (Proxy.isProxyClass(targetClass)) {
// 獲取目標類型上的所有接口,將其添加到需要被代理的接口中
advised.setInterfaces(targetClass.getInterfaces());
}
//再次獲取代理配置中需要被代理的接口
specifiedInterfaces = advised.getProxiedInterfaces();
}
}
//判斷SpringProxy接口是否已經在被代理的接口中
boolean addSpringProxy = !advised.isInterfaceProxied(SpringProxy.class);
//判斷Advised接口是否已經在被代理的接口中
boolean addAdvised = !advised.isOpaque() && !advised.isInterfaceProxied(Advised.class);
//判斷DecoratingProxy接口是否已經在被代理的接口中
boolean addDecoratingProxy = (decoratingProxy && !advised.isInterfaceProxied(DecoratingProxy.class));
//一個計數器,會根據上面三個boolean值做遞增
int nonUserIfcCount = 0;
if (addSpringProxy) {
nonUserIfcCount++;
}
if (addAdvised) {
nonUserIfcCount++;
}
if (addDecoratingProxy) {
nonUserIfcCount++;
}
// 下面就是構建所有需要被代理的接口
Class<?>[] proxiedInterfaces = new Class<?>[specifiedInterfaces.length + nonUserIfcCount];
System.arraycopy(specifiedInterfaces, 0, proxiedInterfaces, 0, specifiedInterfaces.length);
int index = specifiedInterfaces.length;
if (addSpringProxy) {
proxiedInterfaces[index] = SpringProxy.class;
index++;
}
if (addAdvised) {
proxiedInterfaces[index] = Advised.class;
index++;
}
if (addDecoratingProxy) {
proxiedInterfaces[index] = DecoratingProxy.class;
}
return proxiedInterfaces;
}
上面的方法執行完畢之後,會得到一個被代理的接口列表,默認情況下會得到下面的一個列表
[開發者硬編碼指定的需要被代理的接口列表,SpringProxy,Advised,DecoratingProxy]
最終創建出來的代理對象,默認會實現上面列的所有接口,後面3個接口是aop中自動給我們加上的。
@1:getInterceptorsAndDynamicInterceptionAdvice
這個方法位於AdvisedSupport
中,根據方法和目標類型獲取方法上面匹配的攔截器鏈
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
//會先嚐試從還中獲取,如果獲取不到,會從advisorChainFactory中獲取,然後將其丟到緩存中
MethodCacheKey cacheKey = new MethodCacheKey(method);
List<Object> cached = this.methodCache.get(cacheKey);
if (cached == null) {
cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
this, method, targetClass);
this.methodCache.put(cacheKey, cached);
}
return cached;
}
從advisorChainFactory中獲取攔截器鏈稍後細說,我們把這個階段叫做連接器鏈的獲取階段。
@3:ReflectiveMethodInvocation.proceed()
這個是一次會調用攔截器鏈,最終會調用到目標方法,獲得目標方法的返回值,裏面的細節見後面的代理方法調用處理階段
JdkDynamicAopProxy小結
被創建的代理對象默認會實現
SpringProxy,Advised,DecoratingProxy 3個接口
SpringProxy
這個接口中沒有任何方法,只是起一個標記作用,用來標記代理對象是使用spring aop創建的代理對象默認都會實現
Advised
接口,所以可以通過這個接口動態變更代理對象中的通知DecoratingProxy
接口中定義了一個方法getDecoratedClass
,用來獲取被代理的原始目標對象的類型
下面來看另外一個類:ObjenesisCglibAopProxy
,這個繼承了CglibAopProxy
,大部分邏輯都在CglibAopProxy
中,所以我們主要看CglibAopProxy
中代碼。
CglibAopProxy類
作用:採用cglib代理的方式創建代理對象,並處理代理對象的所有方法調用。
以getProxy
方法爲入口,通過方法一個個來解說。
getProxy方法
public Object getProxy(@Nullable ClassLoader classLoader) {
// 獲取被代理的類
Class<?> rootClass = this.advised.getTargetClass();
// 代理對象的父類(cglib是採用繼承的方式是創建代理對象的,所以將被代理的類作爲代理對象的父類)
Class<?> proxySuperClass = rootClass;
// 判斷被代理的類是不是cglib創建的類,如果是cblib創建的類,會將其父類作爲被代理的類
if (rootClass.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) {
proxySuperClass = rootClass.getSuperclass();
//添加需要被代理的接口
Class<?>[] additionalInterfaces = rootClass.getInterfaces();
for (Class<?> additionalInterface : additionalInterfaces) {
this.advised.addInterface(additionalInterface);
}
}
// 開始cglib創建代理,這個大家對cglib比較熟悉的一看就懂
Enhancer enhancer = createEnhancer();
// 設置被代理的父類
enhancer.setSuperclass(proxySuperClass);
// 設置被代理的接口[開發者硬編碼指定的需要被代理的接口列表,SpringProxy,Advised],這個比jdk動態代理的方式少了一個DecoratingProxy接口
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
// 設置代理類類名生成策略
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
// 設置字節碼的生成策略
enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));
// @1:獲取Callback列表,這個稍後詳解
Callback[] callbacks = getCallbacks(rootClass);
Class<?>[] types = new Class<?>[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
// @2:設置CallbackFilter,CallbackFilter內部會判斷被代理對象中的方法最終會被callbacks列表中的那個Callback來處理
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);
// 獲取代理對象(內部會先創建代理類,然後會根據代理類生成一個代理對象)
return createProxyClassAndInstance(enhancer, callbacks);
}
上面方法中有2個點比較難,需要說明,分別是@1:getCallbacks方法
和@2:創建ProxyCallbackFilter對象
@1:getCallbacks方法
通過被代理的類來獲取Callback
列表,Callback
是用來處理代理對象的方法調用的,代理對象中可能有很多方法,每個方法可能採用不同的處理方式,所以會有多個Callback
private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
// 是否需要將代理暴露在threadLocal中
boolean exposeProxy = this.advised.isExposeProxy();
// 配置是否是凍結的
boolean isFrozen = this.advised.isFrozen();
// 被代理的目標對象是否是動態的(是否是單例的)
boolean isStatic = this.advised.getTargetSource().isStatic();
// 當方法上有需要執行的攔截器的時候,會用這個來處理
Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
// 當方法上沒有需要執行的攔截器的時候,會使用targetInterceptor來處理,內部會通過反射直接調用目標對象的方法
Callback targetInterceptor;
/**
* 這塊根據是否需要暴露代理到threadLocal中以及目標對象是否是動態的,會創建不同的Callback
* isStatic爲true的時候,同一個代理的不同方法可能都是新的目標對象,所以當代理方法執行完畢之後,需要對目標對象進行釋放
*/
if (exposeProxy) {
targetInterceptor = (isStatic ?
new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :
new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource()));
}
else {
targetInterceptor = (isStatic ?
new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :
new DynamicUnadvisedInterceptor(this.advised.getTargetSource()));
}
// targetDispatcher會直接調用目標方法
Callback targetDispatcher = (isStatic ?
new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp());
Callback[] mainCallbacks = new Callback[] {
aopInterceptor, // 處理匹配到攔截器的方法
targetInterceptor, // 處理未匹配到攔截器的方法
new SerializableNoOp(),
targetDispatcher, // 處理未匹配到攔截器的方法,和targetInterceptor有何不同呢?目標方法如果返回值的結果是目標對象類型的,會使用 targetInterceptor 處理,內部會返回代理對象
this.advisedDispatcher, // 處理Advised接口中定義的方法
new EqualsInterceptor(this.advised), // 處理equals方法
new HashCodeInterceptor(this.advised) // 處理hashCode方法
};
Callback[] callbacks;
// 如果被代理的對象是單例的 && 配置是凍結的,此時會進行優化,怎麼優化呢?
// 配置凍結的情況下,生成好的代理中通知是無法修改的,所以可以提前將每個方法對應的攔截器鏈找到給緩存起來
// 調用方法的時候,就直接從緩存中可以拿到方法對應的緩存信息,效率會高一些
if (isStatic && isFrozen) {
Method[] methods = rootClass.getMethods();
Callback[] fixedCallbacks = new Callback[methods.length];
this.fixedInterceptorMap = new HashMap<>(methods.length);
// 獲取每個方法的調用鏈,然後給緩存在fixedInterceptorMap中
for (int x = 0; x < methods.length; x++) {
Method method = methods[x];
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, rootClass);
fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(
chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());
this.fixedInterceptorMap.put(method, x);
}
callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length];
System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length);
System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length);
this.fixedInterceptorOffset = mainCallbacks.length;
}
else {
callbacks = mainCallbacks;
}
return callbacks;
}
@2:創建ProxyCallbackFilter對象
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
這塊重點在於ProxyCallbackFilter
中的accept
方法,這個方法會根據目標放,獲取目標對方最後會讓callbacks列表中的哪個Callback處理,大家可以看一下源碼,比較簡單。
上面getCallbacks
方法中涉及到了5個類如下
DynamicAdvisedInterceptor
StaticUnadvisedExposedInterceptor
StaticUnadvisedInterceptor
DynamicUnadvisedInterceptor
StaticDispatcher
後面4個比較簡單,大家可以去看一下源碼,主要來看第一個類,基本上代理對象中的大部分自定義的方法都會進入到這個類的intercept
方法中進行處理,代碼如下
DynamicAdvisedInterceptor類
private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {
//代理配置信息
private final AdvisedSupport advised;
//構造器,需要一個AdvisedSupport
public DynamicAdvisedInterceptor(AdvisedSupport advised) {
this.advised = advised;
}
//這個方法是關鍵,用來處理代理對象中方法的調用
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
//被暴露在threadLocal中舊的代理對象
Object oldProxy = null;
//用來標記代理對象是否被暴露在threadLocal中
boolean setProxyContext = false;
//目標對象
Object target = null;
//目標源
TargetSource targetSource = this.advised.getTargetSource();
try {
//代理配置中是否需要將代理暴露在threadLocal中
if (this.advised.exposeProxy) {
//將代理對象暴露出去
oldProxy = AopContext.setCurrentProxy(proxy);
//將setProxyContext置爲true
setProxyContext = true;
}
//獲取目標對象(即被代理的對象)
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
//@1:獲取當前方法的攔截器鏈
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
//記錄方法返回值
Object retVal;
//攔截器鏈不爲空 && 方法是public類型的
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
//獲取方法調用參數
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
// 直接調用目標對象的方法
retVal = methodProxy.invoke(target, argsToUse);
}
else {
// 創建一個方法調用器(包含了代理對象、目標對象、調用的方法、參數、目標類型、方法攔截器鏈)
// @2:並執行方法調用器的processd()方法,此方法會一次執行方法調用鏈,最終會調用目標方法,獲取返回結果
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
// 處理方法返回結果:會根據方法返回值的類型,做一些處理,比如方法返回的類型爲自己,則最後需要將返回值置爲代理對象
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
// 目標對象不爲null && 目標源不是靜態的
//所謂靜態的,你可以理解爲是否是單例的
// isStatic爲true,表示目標對象是單例的,同一個代理對象中所有方法共享一個目標對象
// isStatic爲false的時候,通常每次調用代理的方法,target對象是不一樣的,所以方法調用萬之後需要進行釋放,可能有些資源清理,連接的關閉等操作
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
// setProxyContext爲ture
if (setProxyContext) {
// 需要將舊的代理再放回到上線文中
AopContext.setCurrentProxy(oldProxy);
}
}
}
}
上面代碼中2個重點:@1
和@2
@1:獲取當前方法的攔截器鏈,這個在JdkDynamicAopProxy的也有,稍後說。
@2:調用CglibMethodInvocation.proceed()
,內部會一次調用方法攔截器鏈,最終會調用目標方法,獲取目標方法返回值,這個稍後放在代理方法處理階段詳解。
下面來看一下方法攔截器鏈的獲取。
方法攔截器鏈的獲取
我們在創建代理的時候,增強的代碼通常都放在Advise通知中,但是最終調用方法的時候,這些通知都會被轉換爲MethodInterceptor來執行,調用方法的過程中,需要先獲取方法上匹配的所有方法連接器連,然後依次執行,最終會調用到目標方法。
獲取方法對應的攔截器鏈,對應下面這段代碼
org.springframework.aop.framework.AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice
AdvisorChainFactory advisorChainFactory = new DefaultAdvisorChainFactory();
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
MethodCacheKey cacheKey = new MethodCacheKey(method);
List<Object> cached = this.methodCache.get(cacheKey);
if (cached == null) {
cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
this, method, targetClass);
this.methodCache.put(cacheKey, cached);
}
return cached;
}
會調用DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice方法
獲取方法上匹配的攔截器鏈。
涉及到的類
AdvisorChainFactory接口
攔截器鏈工廠接口,定義了一個方法,用來獲取方法匹配的攔截器鏈列表
package org.springframework.aop.framework;
public interface AdvisorChainFactory {
/**
* 獲取方法匹配的攔截器鏈列表
* @param config:代理配置信息,裏面包含了創建代理的所有信息,如:Advisor列表,此方法會從Advisor列表中找到和mehod匹配的
* @param targetClass:目標類
*/
List<Object> getInterceptorsAndDynamicInterceptionAdvice(Advised config, Method method, @Nullable Class<?> targetClass);
}
DefaultAdvisorChainFactory類
AdvisorChainFactory接口的默認實現。
public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable {
@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, @Nullable Class<?> targetClass) {
// 獲取Advisor適配器註冊器,前面我們有提到過一個知識點:所有的Advisor最終都會轉換爲MethodInterceptor類型的,
// 然後註冊方法調用鏈去執行,AdvisorAdapterRegistry就是搞這個事情的,
// 其內部會將非MethodInterceptor類型通知通過適配器轉換爲MethodInterceptor類型
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
//獲取配置中的Advisor列表
Advisor[] advisors = config.getAdvisors();
List<Object> interceptorList = new ArrayList<>(advisors.length);
//獲取被調用方法所在類實際的類型
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
Boolean hasIntroductions = null;
//遍歷Advisor列表,找到和actualClass和方法匹配的所有方法攔截器(MethodInterceptor)鏈列表
for (Advisor advisor : advisors) {
//判斷是否是PointcutAdvisor類型的,這種類型的匹配分爲2個階段,先看類是否匹配,然後再看方法是否匹配
if (advisor instanceof PointcutAdvisor) {
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
// 如果isPreFiltered爲ture,表示類以及匹配過,不需要看類是否匹配了
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
boolean match;
if (mm instanceof IntroductionAwareMethodMatcher) {
if (hasIntroductions == null) {
hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
}
match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
}
else {
//方法是否匹配
match = mm.matches(method, actualClass);
}
//方法匹配
if (match) {
// 通過AdvisorAdapterRegistry的getInterceptors將advisor轉換爲MethodInterceptor列表
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
//方法是否動態匹配
if (mm.isRuntime()) {
//輪詢連接器,將其包裝爲InterceptorAndDynamicMethodMatcher對象,後續方法調用的時候可以做動態匹配
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}
else if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
return interceptorList;
}
}
下面來看AdvisorAdapterRegistry這個接口。
AdvisorAdapterRegistry接口
AdvisorAdapter註冊器,AdvisorAdapter可以將Advisor中的Advice適配爲MethodInterceptor
package org.springframework.aop.framework.adapter;
public interface AdvisorAdapterRegistry {
//將一個通知(Advice)包裝爲Advisor對象
Advisor wrap(Object advice) throws UnknownAdviceTypeException;
//根據Advisor獲取方法MethodInterceptor列表
MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException;
//註冊AdvisorAdapter,AdvisorAdapter可以將Advisor中的Advice適配爲MethodInterceptor
void registerAdvisorAdapter(AdvisorAdapter adapter);
}
DefaultAdvisorAdapterRegistry類
AdvisorAdapterRegistry的默認實現,目前裏面做的事情主要是將負責將前置通知,異常通知,後置通知轉換爲MethodInterceptor類型的,源碼比較簡單,大家看一下就懂了。
public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {
//AdvisorAdapter轉換器列表,AdvisorAdapter負責將Advisor中的Advice轉換爲MethodInterceptor類型的
private final List<AdvisorAdapter> adapters = new ArrayList<>(3);
//默認會註冊3個AdvisorAdapter,這3個負責將前置通知,異常通知,後置通知轉換爲MethodInterceptor類型的
public DefaultAdvisorAdapterRegistry() {
registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
registerAdvisorAdapter(new AfterReturningAdviceAdapter());
registerAdvisorAdapter(new ThrowsAdviceAdapter());
}
@Override
public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
if (adviceObject instanceof Advisor) {
return (Advisor) adviceObject;
}
if (!(adviceObject instanceof Advice)) {
throw new UnknownAdviceTypeException(adviceObject);
}
Advice advice = (Advice) adviceObject;
if (advice instanceof MethodInterceptor) {
// So well-known it doesn't even need an adapter.
return new DefaultPointcutAdvisor(advice);
}
//輪詢adapters
for (AdvisorAdapter adapter : this.adapters) {
//adapter是否支持適配advice這個通知
if (adapter.supportsAdvice(advice)) {
return new DefaultPointcutAdvisor(advice);
}
}
throw new UnknownAdviceTypeException(advice);
}
//將Advisor對象轉換爲MethodInterceptor列表,不過通常情況下一個advisor會返回一個MethodInterceptor
@Override
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
List<MethodInterceptor> interceptors = new ArrayList<>(3);
Advice advice = advisor.getAdvice();
if (advice instanceof MethodInterceptor) {
interceptors.add((MethodInterceptor) advice);
}
//輪詢adapters
for (AdvisorAdapter adapter : this.adapters) {
//先看一下adapter是否支持適配advice這個通知
if (adapter.supportsAdvice(advice)) {
//如果匹配,這調用適配器的getInterceptor方法將advisor轉換爲MethodInterceptor
interceptors.add(adapter.getInterceptor(advisor));
}
}
if (interceptors.isEmpty()) {
throw new UnknownAdviceTypeException(advisor.getAdvice());
}
return interceptors.toArray(new MethodInterceptor[0]);
}
@Override
public void registerAdvisorAdapter(AdvisorAdapter adapter) {
this.adapters.add(adapter);
}
}
AdvisorAdapter接口
package org.springframework.aop.framework.adapter;
public interface AdvisorAdapter {
//判斷這個適配器支持advice這個通知麼
boolean supportsAdvice(Advice advice);
//獲取advisor對應的MethodInterceptor
MethodInterceptor getInterceptor(Advisor advisor);
}
MethodBeforeAdviceAdapter類
適配MethodBeforeAdvice
前置通知,負責將MethodBeforeAdvice
類型的通知轉換爲MethodBeforeAdviceInterceptor
類型的
class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {
@Override
public boolean supportsAdvice(Advice advice) {
return (advice instanceof MethodBeforeAdvice);
}
@Override
public MethodInterceptor getInterceptor(Advisor advisor) {
MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
return new MethodBeforeAdviceInterceptor(advice);
}
}
MethodBeforeAdviceInterceptor類
將MethodBeforeAdvice
通知適配爲MethodInterceptor
類型的,代碼很簡單,大家一看就懂。
package org.springframework.aop.framework.adapter;
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {
private final MethodBeforeAdvice advice;
public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
}
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
//先調用前置通知
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
//然後繼續處理連接器連,內部會調用目標方法
return mi.proceed();
}
}
AfterReturningAdviceAdapter類
適配AfterReturningAdvice
後置通知,負責將AfterReturningAdvice
類型的通知轉換爲AfterReturningAdviceInterceptor
類型的
class AfterReturningAdviceAdapter implements AdvisorAdapter, Serializable {
@Override
public boolean supportsAdvice(Advice advice) {
return (advice instanceof AfterReturningAdvice);
}
@Override
public MethodInterceptor getInterceptor(Advisor advisor) {
AfterReturningAdvice advice = (AfterReturningAdvice) advisor.getAdvice();
return new AfterReturningAdviceInterceptor(advice);
}
}
AfterReturningAdviceInterceptor類
將AfterReturningAdvice
通知適配爲MethodInterceptor
類型的,代碼很簡單,大家一看就懂。
public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable {
private final AfterReturningAdvice advice;
public AfterReturningAdviceInterceptor(AfterReturningAdvice advice) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
}
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
//先調用攔截器鏈,內部會調用目標方法
Object retVal = mi.proceed();
//然後執行後置通知
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
//返回結果
return retVal;
}
}
ThrowsAdviceAdapter類
適配ThrowsAdvice
前置通知,負責將MethodBeforeAdvice
類型的通知轉換爲MethodBeforeAdviceInterceptor
類型的
class ThrowsAdviceAdapter implements AdvisorAdapter, Serializable {
@Override
public boolean supportsAdvice(Advice advice) {
return (advice instanceof ThrowsAdvice);
}
@Override
public MethodInterceptor getInterceptor(Advisor advisor) {
return new ThrowsAdviceInterceptor(advisor.getAdvice());
}
}
ThrowsAdviceInterceptor類
將ThrowsAdvice
通知適配爲MethodInterceptor
類型的,代碼很簡單,大家一看就懂。
package org.springframework.aop.framework.adapter;
public class ThrowsAdviceInterceptor implements MethodInterceptor, AfterAdvice {
private static final String AFTER_THROWING = "afterThrowing";
private final Object throwsAdvice;
//創建ThrowsAdviceInterceptor
public ThrowsAdviceInterceptor(Object throwsAdvice) {
Assert.notNull(throwsAdvice, "Advice must not be null");
this.throwsAdvice = throwsAdvice;
//獲取異常通知中定義的所有方法(public、默認的、protected、private)
Method[] methods = throwsAdvice.getClass().getMethods();
//輪詢methods
for (Method method : methods) {
//方法名稱爲afterThrowing && 方法參數爲1或者4
if (method.getName().equals(AFTER_THROWING) &&
(method.getParameterCount() == 1 || method.getParameterCount() == 4)) {
//獲取方法的最後一個參數類型
Class<?> throwableParam = method.getParameterTypes()[method.getParameterCount() - 1];
//判斷方法參數類型是不是Throwable類型的
if (Throwable.class.isAssignableFrom(throwableParam)) {
// 緩存異常處理方法到map中(異常類型->異常處理方法)
this.exceptionHandlerMap.put(throwableParam, method);
}
}
}
//如果exceptionHandlerMap,拋出異常,所以最少要有一個異常處理方法
if (this.exceptionHandlerMap.isEmpty()) {
throw new IllegalArgumentException(
"At least one handler method must be found in class [" + throwsAdvice.getClass() + "]");
}
}
/**
* 獲取異常通知中自定義的處理異常方法的數量
*/
public int getHandlerMethodCount() {
return this.exceptionHandlerMap.size();
}
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
//調用通知鏈
return mi.proceed();
}
catch (Throwable ex) {
//獲取異常通知中自定義的處理異常的方法
Method handlerMethod = getExceptionHandler(ex);
//當處理的方法不爲空
if (handlerMethod != null) {
//調用異常處理方法
invokeHandlerMethod(mi, ex, handlerMethod);
}
//繼續向外拋出異常
throw ex; //@1
}
}
/**
* 獲取throwsAdvice中處理exception參數指定的異常的方法
*/
@Nullable
private Method getExceptionHandler(Throwable exception) {
//獲取異常類型
Class<?> exceptionClass = exception.getClass();
//從緩存中獲取異常類型對應的方法
Method handler = this.exceptionHandlerMap.get(exceptionClass);
//來一個循環,查詢處理方法,循環條件:方法爲空 && 異常類型!=Throwable
while (handler == null && exceptionClass != Throwable.class) {
//獲取異常的父類型
exceptionClass = exceptionClass.getSuperclass();
//從緩存中查找異常對應的處理方法
handler = this.exceptionHandlerMap.get(exceptionClass);
}
//將查找結果返回
return handler;
}
//通過反射調用異常通知中的異常方法
private void invokeHandlerMethod(MethodInvocation mi, Throwable ex, Method method) throws Throwable {
//構建方法請求參數
Object[] handlerArgs;
//若只有1個參數,參數爲:異常對象
if (method.getParameterCount() == 1) {
handlerArgs = new Object[] {ex};
}
else {
//4個參數(方法、方法請求參數、目標對象、異常對象)
handlerArgs = new Object[] {mi.getMethod(), mi.getArguments(), mi.getThis(), ex};
}
try {
//通過反射調用異常通知中的方法
method.invoke(this.throwsAdvice, handlerArgs);
}
catch (InvocationTargetException targetEx) {
throw targetEx.getTargetException();
}
}
}
代理方法的調用過程(攔截器鏈的執行)
攔截器鏈執行過程
到目前,已經獲取到代理對象,接着會開始使用這個代理對象,在代理對象上執行一些方法調用,此時會依次調用此方法上的所有MethodInterceptor,最終會調用到目標上對應的方法,執行過程如下圖
jdk動態代理方式創建代理最終會調用ReflectiveMethodInvocation#proceed
方法。
cglib方式創建的代理最終會調用CglibAopProxy.CglibMethodInvocation#proceed
方法。
下面來看一下這個兩個類的代碼。
ReflectiveMethodInvocation類
package org.springframework.aop.framework;
public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable {
//生成的代理對象
protected final Object proxy;
//被代理的目標對象
protected final Object target;
//被調用的方法
protected final Method method;
//調用方法傳入參數
protected Object[] arguments;
//目標對象類型
private final Class<?> targetClass;
/**
* 當期被調用的方法上匹配的 MethodInterceptor and InterceptorAndDynamicMethodMatcher 列表
* 即方法調用鏈列表
*/
protected final List<?> interceptorsAndDynamicMethodMatchers;
//當前正在調用的連接器索引
private int currentInterceptorIndex = -1;
//構造器
protected ReflectiveMethodInvocation(
Object proxy, @Nullable Object target, Method method, @Nullable Object[] arguments,
@Nullable Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {
this.proxy = proxy;
this.target = target;
this.targetClass = targetClass;
//獲取橋接方法,關於什麼是橋接方法,比較簡單,百度一下,這裏不做說明
this.method = BridgeMethodResolver.findBridgedMethod(method);
this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments);
this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
}
//這裏是重點,用來處理被調用的方法,會遞歸進行調用,所有的攔截器都執行完畢之後,會通過反射調用目標方法
public Object proceed() throws Throwable {
// 攔截器都執行完畢之後,通過反射調用目標對象中的方法
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
//獲取++this.currentInterceptorIndex指定的攔截器
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
//判斷攔截器是否是InterceptorAndDynamicMethodMatcher,這種表示是動態攔截器,
// 所謂動態攔截器就是要根據方法的參數的值來判斷攔截器是否需要執行
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
//判斷動態攔截器是否需要執行
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
//執行當前攔截器的調用
return dm.interceptor.invoke(this);
}
else {
//如果不匹配,直接遞歸進入下一個攔截器的調用
return proceed();
}
}
else {
//執行攔截器的調用
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
//通過反射調用目標方法
@Nullable
protected Object invokeJoinpoint() throws Throwable {
return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
}
}
ProxyFactory簡化代理的創建
上面代理的整個創建過程和使用過程還是挺負載的,spring在AdvisedSupport
類的基礎上又添加2個子類
ProxyCreatorSupport
ProxyFactory
通過這2個子類,將步驟稍微簡化了一些,這2個類的代碼比較簡單,上面的如果理解了,看這2個類的代碼會非常的輕鬆,這裏就不細說了。
ProxyCreatorSupport
用來對代理的創建提供支持,內部添加了AopProxyFactory
對象的引用,將代理的創建過程給簡化了。
AopProxyFactory aopProxyFactory;
ProxyFactory
類繼承了ProxyCreatorSupport
,讓創建代理的過程更簡單了,如果採用硬編碼的方式,通常我們會使用ProxyFactory
來創建代理對象,代碼只需要下面幾行了
//通過spring提供的代理創建工廠來創建代理
ProxyFactory proxyFactory = new ProxyFactory();
//ProxyFactory繼承了AdvisedSupport類,所以可以直接可以通過ProxyFactory來設置創建代理需要的參數
//爲工廠指定目標對象
proxyFactory.setTarget(target);
//添加顧問
proxyFactory.addAdvisor(advisor);
//調用proxyFactory.getProxy();創建代理
Object proxy = proxyFactory.getProxy();
案例
下面來一些案例,通過案例理解會更容易一些。
案例1
這個案例主要看一下生成的代理對象的一些信息。
package com.javacode2018.aop.demo5;
import com.javacode2018.aop.demo4.FundsService;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.lang.Nullable;
import java.lang.reflect.Method;
public class AopTest5 {
public static void main(String[] args) {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new FundsService());
proxyFactory.addAdvisor(new DefaultPointcutAdvisor(new MethodBeforeAdvice() {
@Override
public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {
System.out.println(method);
}
}));
//創建代理對象
Object proxy = proxyFactory.getProxy();
System.out.println("代理對象的類型:" + proxy.getClass());
System.out.println("代理對象的父類:" + proxy.getClass().getSuperclass());
System.out.println("代理對象實現的接口列表");
for (Class<?> cf : proxy.getClass().getInterfaces()) {
System.out.println(cf);
}
}
}
運行輸出
代理對象的類型:class com.javacode2018.aop.demo4.FundsService$$EnhancerBySpringCGLIB$$ad14161a
代理對象的父類:class com.javacode2018.aop.demo4.FundsService
代理對象實現的接口列表
interface org.springframework.aop.SpringProxy
interface org.springframework.aop.framework.Advised
interface org.springframework.cglib.proxy.Factory
輸出中可以看出默認幫我們實現了3個接口
[SpringProxy,Advised,Factory]
案例2:代理接口
有接口的情況默認會通過jdk動態代理的方式生成代理,下面來看一下。
來個接口
package com.javacode2018.aop.demo6;
public interface IService {
void say(String name);
}
實現類
package com.javacode2018.aop.demo6;
public class Service implements IService {
@Override
public void say(String name) {
System.out.println("hello:" + name);
}
}
測試案例
package com.javacode2018.aop.demo6;
import org.junit.Test;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.lang.Nullable;
import java.lang.reflect.Method;
public class AopTest6 {
@Test
public void test1() {
Service target = new Service();
ProxyFactory proxyFactory = new ProxyFactory();
//設置需要被代理的對象
proxyFactory.setTarget(target);
//設置需要代理的接口
proxyFactory.addInterface(IService.class);
proxyFactory.addAdvice(new MethodBeforeAdvice() {
@Override
public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {
System.out.println(method);
}
});
IService proxy = (IService) proxyFactory.getProxy();
System.out.println("代理對象的類型:" + proxy.getClass());
System.out.println("代理對象的父類:" + proxy.getClass().getSuperclass());
System.out.println("代理對象實現的接口列表");
for (Class<?> cf : proxy.getClass().getInterfaces()) {
System.out.println(cf);
}
//調用代理的方法
System.out.println("\n調用代理的方法");
proxy.say("spring aop");
}
}
運行輸出
代理對象的類型:class com.sun.proxy.$Proxy4
代理對象的父類:class java.lang.reflect.Proxy
代理對象實現的接口列表
interface com.javacode2018.aop.demo6.IService
interface org.springframework.aop.SpringProxy
interface org.springframework.aop.framework.Advised
interface org.springframework.core.DecoratingProxy
調用代理的方法
public abstract void com.javacode2018.aop.demo6.IService.say(java.lang.String)
hello:spring aop
從第一行輸出中可以看出是採用jdk動態代理方式創建的代理
第二行驗證了,所有通過jdk動態代理方式創建的代理對象都是Proxy的子類
輸出的接口列表中可以看出,默認幫我們實現了3個接口[SpringAop,Advised,DecoratingProxy]
案例3:強制使用cglib代理
在案例2中加入下面代碼,設置proxyTargetClass
爲true
,會強制使用cglib代理。
//強制使用cglib代理
proxyFactory.setProxyTargetClass(true);
案例4:將代理暴露在threadLocal中
先來看一段代碼,Service
類中有2個方法,m1方法中會調用m2,通過aop代理對這個類創建了一個代理,通過代理來統計所有調用方法的耗時
package com.javacode2018.aop.demo7;
class Service {
public void m1() {
System.out.println("m1");
this.m2();
}
public void m2() {
System.out.println("m2");
}
}
public class AopTest7 {
@Test
public void test1() {
Service target = new Service();
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(target);
proxyFactory.addAdvice(new MethodInterceptor() {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
long startTime = System.nanoTime();
Object result = invocation.proceed();
long endTime = System.nanoTime();
System.out.println(String.format("%s方法耗時(納秒):%s", invocation.getMethod().getName(), endTime - startTime));
return result;
}
});
Service proxy = (Service) proxyFactory.getProxy();
proxy.m1();
}
}
運行輸出
m1
m2
m1方法耗時(納秒):11056000
爲什麼沒有輸出m2方法的耗時?
原因:m2方法是在m1方法中通過this的方式來調用的,this實際上指向的是上面代碼中的target
對象。
那麼我們如何能讓此處的m2也能被增強,你需要通過代理來調用m2方法纔可以,可以將代理對象暴露在threadLocal中,然後在m1方法中獲取到threadLoca中的代理對象,通過代理對象來調用m2就可以了。
需要調整改動2處。
第1處:配置代理創建時,將其暴露出去
proxyFactory.setExposeProxy(true);
第2處:m1中調用m2的方法需要修改爲下面這樣
((Service)AopContext.currentProxy()).m2();
再次執行,結果如下
m1
m2
m2方法耗時(納秒):51200
m1方法耗時(納秒):12794500
這個功能還是挺有用的,以後我估計大家是可以用到的。
總結
本文內容比較多,大家好好吸收一下,有問題的歡迎留言。
下一篇文章將深入詳解介紹spring中如何將aop搞成自動化的,東西也是比較多的,敬請期待。
案例源碼
https://gitee.com/javacode2018/spring-series
路人甲java所有案例代碼以後都會放到這個上面,大家watch一下,可以持續關注動態。
Spring系列
Spring系列第21篇:註解實現依賴注入(@Autowired、@Resource、@Primary、@Qulifier)
Spring系列第29篇:BeanFactory擴展(BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor)
更多好文章
世界上最好的關係是相互成就,點贊轉發 感恩開心????
路人甲java
▲長按圖片識別二維碼關注
路人甲Java:工作10年的前阿里P7,所有文章以系列的方式呈現,帶領大家成爲java高手,目前已出:java高併發系列、mysql高手系列、Maven高手系列、mybatis系列、spring系列,正在連載springcloud系列,歡迎關注!