Jdk代理,也稱為動(dòng)態(tài)代理,其代理目標(biāo)對(duì)象的方式是生成一個(gè)與目標(biāo)對(duì)象實(shí)現(xiàn)同一個(gè)接口的類,該類的構(gòu)造函數(shù)中會(huì)傳入一個(gè) InvocationHandler 類型的對(duì)象。因?yàn)?InvocationHandler 對(duì)象是用戶自定義的織入了切面邏輯的類,因而在需要使用目標(biāo)對(duì)象的地方,只需要將生成的代理類的對(duì)象傳入即可。
又因?yàn)樯傻拇眍惻c目標(biāo)類都實(shí)現(xiàn)了同一接口,因而從語(yǔ)法上其是沒有任何問題的。另一方面,在傳入代理類對(duì)象之后,代理類通過調(diào)用構(gòu)造函數(shù)傳入的InvocationHandler.invoke() 方法,從而動(dòng)態(tài)的調(diào)用目標(biāo)類的方法,最終利用這種方式織入了代理邏輯。
1. 代理對(duì)象的構(gòu)造
前面我們講到,Spring Aop使用 AopProxy.getProxy() 方法獲取代理對(duì)象的,而 JdkDynamicAopProxy 則已經(jīng)實(shí)現(xiàn)了該接口,因而我們可以直接閱讀其 getProxy() 方法的源碼:
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating JDK dynamic proxy: target source is "
+ this.advised.getTargetSource());
}
// 完善代理對(duì)象需要實(shí)現(xiàn)的接口,主要是會(huì)默認(rèn)增加三個(gè)需要實(shí)現(xiàn)的接口:SpringProxy,
// Advised和DecoratingProxy。這三個(gè)接口的作用主要如下:
// SpringProxy:該接口沒有任何方法,主要用于標(biāo)識(shí)當(dāng)前對(duì)象是Spring生成的代理對(duì)象;
// Advised:用于封裝生成代理對(duì)象所需要的所有信息;
// DecoratingProxy:其有一個(gè)getDecoratedClass()方法,用于返回當(dāng)前代理對(duì)象的目標(biāo)對(duì)象的Class類型
Class<?>[] proxiedInterfaces = AopProxyUtils
.completeProxiedInterfaces(this.advised, true);
// 找到接口中是否包含有equals()和hashCode()方法,并進(jìn)行標(biāo)識(shí)
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
// 使用動(dòng)態(tài)代理生成代理對(duì)象
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
上述方法邏輯其實(shí)比較簡(jiǎn)單,主要就是首先獲取生成代理對(duì)象所需要實(shí)現(xiàn)的所有接口;然后判斷接口中是否包含有equals()和hashCode()方法,因?yàn)檫@將用于判斷生成的代理類是使用用于定義的equals()和hashCode()方法還是使用自動(dòng)生成的方法;最后就是通過動(dòng)態(tài)代理生成代理對(duì)象,這里需要注意的是 JdkDynamicAopProxy 不僅實(shí)現(xiàn)了AopProxy 接口還實(shí)現(xiàn)了 InvocationHandler 接口,因而這里生成代理對(duì)象的時(shí)候傳入的 InvocationHandler 對(duì)象是this。
2. 切面邏輯的織入
由于 JdkDynamicAopProxy 已經(jīng)實(shí)現(xiàn)了 InvocationHandler 接口,因而代理邏輯的織入就是在JdkDynamicAopProxy.invoke() 方法中,這里我們直接閱讀器源碼:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// 如果當(dāng)前方法是equals()方法,并且接口中并未定義該方法,就使用自動(dòng)生成的equals()方法
return equals(args[0]);
} else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// 如果當(dāng)前方法是hashCode()方法,并且接口中并未定義該方法,就使用自動(dòng)生成的hashCode()方法
return hashCode();
} else if (method.getDeclaringClass() == DecoratingProxy.class) {
// 如果當(dāng)前方法是Spring織入的DecoratingProxy接口中的方法,則返回目標(biāo)對(duì)象的Class類型
return AopProxyUtils.ultimateTargetClass(this.advised);
} else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// 如果當(dāng)前方法是Spring織入的Advised接口中的方法,
// 則使用反射調(diào)用當(dāng)前advised對(duì)象中的相關(guān)方法
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
if (this.advised.exposeProxy) {
// 如果設(shè)置了需要暴露代理對(duì)象,則將當(dāng)前對(duì)象設(shè)置到AopContext中
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// 獲取當(dāng)前方法需要織入的切面邏輯的調(diào)用鏈
List<Object> chain = this.advised
.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
if (chain.isEmpty()) {
// 如果切面邏輯的調(diào)用鏈為空,則對(duì)方法參數(shù)進(jìn)行類型轉(zhuǎn)換處理,
// 并且通過反射直接調(diào)用目標(biāo)對(duì)象的方法
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
} else {
// 獲取目標(biāo)對(duì)象的調(diào)用鏈邏輯,并且對(duì)該鏈進(jìn)行調(diào)用
invocation = new ReflectiveMethodInvocation(proxy,
target, method, args, targetClass, chain);
retVal = invocation.proceed();
}
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// 判斷返回值如果為目標(biāo)對(duì)象,并且當(dāng)前方法的返回值類型是當(dāng)前代理對(duì)象的類型,那么就將
// 當(dāng)前代理對(duì)象返回。這里的邏輯的實(shí)際意思簡(jiǎn)單的說就是,如果返回值是目標(biāo)對(duì)象,那么
// 就將當(dāng)前代理對(duì)象返回
retVal = proxy;
} else if (retVal == null && returnType != Void.TYPE
&& returnType.isPrimitive()) {
// 如果返回值滿足其為空,不是Void類型,并且是基本數(shù)據(jù)類型,那么就拋出異常,
// 因?yàn)榛緮?shù)據(jù)類型的返回值必然不為空
throw new AopInvocationException("Null return value from advice does not "
+ " match primitive return type for: " + method);
}
return retVal;
} finally {
if (target != null && !targetSource.isStatic()) {
// 如果TargetSource不是靜態(tài)的,則調(diào)用其releaseTarget()方法將生成的目標(biāo)對(duì)象釋放
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// 處理AopContext中保存的當(dāng)前代理對(duì)象
AopContext.setCurrentProxy(oldProxy);
}
}
}
可以看到,在進(jìn)行代理邏輯的織入的時(shí)候,首先會(huì)進(jìn)行如下判斷:
①當(dāng)前方法是否為equals()或hashCode()方法,如果是,并且接口中并未要求子類實(shí)現(xiàn)這些方法,那么就會(huì)調(diào)用自動(dòng)生成的方法;
②當(dāng)前方法是否為Spring織入的DecoratingProxy接口中的方法,如果是,則將目標(biāo)對(duì)象的Class類型返回;
③判斷目標(biāo)方法是否為Spring織入的Advised中的方法,如果是,則調(diào)用當(dāng)前advised對(duì)象中相應(yīng)的方法。然后就會(huì)獲取當(dāng)前方法需要織入的代理邏輯的調(diào)用鏈。接著就會(huì)將目標(biāo)對(duì)象和調(diào)用鏈邏輯封裝為ReflectiveMethodInvocation,并進(jìn)行調(diào)用。最后對(duì)調(diào)用的返回值進(jìn)行一些基本判斷,并且返回。
3. 小結(jié)
本文首先對(duì)Jdk代理進(jìn)行了簡(jiǎn)單的介紹,然后介紹了Spring Aop是如何調(diào)用將Jdk代理的Proxy引入并且生成代理對(duì)象的,最后對(duì)調(diào)用鏈的生成,以及切面邏輯的織入方式進(jìn)行了講解。關(guān)于調(diào)用鏈的生成以及切面邏輯的織入,由于使用的方式和Cglib是一樣的,因而這里并沒有對(duì)其細(xì)節(jié)進(jìn)行過多描述。