java開發(fā)AOP基礎(chǔ)JdkDynamicAopProxy
1.示例代碼
public class Main {
public static void main(String[] args) {
//1. 創(chuàng)建被代理對象
Cat cat = new Cat();
System.out.println("--------------------");
//2. 創(chuàng)建Spring 代理工廠對象 ProxyFactory
// ProxyFactory 是Config + Factory 的存在,持有Aop操作所有的生產(chǎn)資料
ProxyFactory proxyFactory = new ProxyFactory(cat);
//3. 添加方法攔截器
MyPointcut pointcut = new MyPointcut();
proxyFactory.addAdvisor(new DefaultPointcutAdvisor(pointcut, new MethodInterceptor01()));
proxyFactory.addAdvisor(new DefaultPointcutAdvisor(pointcut, new MethodInterceptor02()));
//4. 獲取代理對象
Animal proxy = (Animal) proxyFactory.getProxy();
proxy.eat();
System.out.println("--------------------");
proxy.go();
}
}
結(jié)果,只有eat()方法被加強了:
--------------------
methodInterceptor01 begin
MethodInterceptor02 begin
貓貓 吃 貓糧!
MethodInterceptor02 end
methodInterceptor01 end
--------------------
貓貓 跑跑~!
切點:
- 1)匹配所有類
- 2)匹配eat()方法
public class MyPointcut implements Pointcut {
@Override
public ClassFilter getClassFilter() {
return new ClassFilter() {
@Override
public boolean matches(Class<?> clazz) {
return true;
}
};
}
@Override
public MethodMatcher getMethodMatcher() {
return new MethodMatcher() {
@Override
public boolean matches(Method method, Class<?> targetClass) {
if(method.getName().equals("eat")) {
return true;
}
return false;
}
@Override
public boolean isRuntime() {
return false;
}
@Override
public boolean matches(Method method, Class<?> targetClass, Object... args) {
return false;
}
};
}
}2.ProxyFactory#getProxy()
public Object getProxy() {
//主要分析 JdkDynamicAopProxy, 假設(shè) createAopProxy 返回的就是 JdkDynamicAopProxy
return createAopProxy().getProxy();
}
2.1 ProxyCreatorSupport#createAopProxy
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}

/**
* config 就是我們的ProxyFactory對象,咱們說過 ProxyFactory
* 它是一個配置管理對象,保存著 創(chuàng)建 代理對象所有的生產(chǎn)資料呢。
*/
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
//條件一:config.isOptimize() 暫且不管
//條件二:config.isProxyTargetClass() true 強制使用cglib 動態(tài)代理
//條件三:hasNoUserSuppliedProxyInterfaces(config)
// 說明被代理對象 沒有實現(xiàn)任何接口,沒有辦法使用JDK動態(tài)代理,只能使用cglib動態(tài)代理
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.");
}
//條件成立:說明targetClass是接口 或者 已經(jīng)是被代理過的類型了,只能使用Jdk動態(tài)代理
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
//執(zhí)行到else 什么情況? targetClass 是實現(xiàn)了接口情況下,
// 會走這個分支!咱們大多數(shù)情況都是 面向接口 編程,所以主要分析 JdkDynamicAopProxy
return new JdkDynamicAopProxy(config);
}
}2.2 JdkDynamicAopProxy#getProxy()
@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());
}
// 獲取需要代理的接口數(shù)組
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
// 查找當前所有的需要代理的接口,看看 是否有
// equals 方法 和 hashcode 方法,如果有,就打個標記。
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
// classLoader :類加載器
// proxiedInterfaces :生成的代理類 需要 實現(xiàn)的接口集合
// this? : JdkDynamicAopProxy 該類 實現(xiàn)了 InvocationHandler 接口
// 該方法最終會返回一個 代理類 對象。
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}生成的代理類類似于下面所示:
public final class $proxy0 extends Proxy implements Animal {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;
public $proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void eat() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}所有方法最后都經(jīng)由InvocationHandler#invoke進行處理
3.調(diào)用流程JdkDynamicAopProxy#invoke

/**
* Implementation of {@code InvocationHandler.invoke}.
* <p>Callers will see exactly the exception thrown by the target,
* unless a hook method throws an exception.
* * @param proxy 代理對象
* * @param method 目標對象的方法
* * @param args 目標對象方法對應(yīng)的參數(shù)
*/
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
// 獲取到創(chuàng)建ProxyFactory時 提供的 target
TargetSource targetSource = this.advised.targetSource;
// 真正的target 的一個引用
Object target = null;
try {
// 條件成立,說明代理類實現(xiàn)的哪些接口 沒有定義equals方法,
// 并且當前method 是 equals方法的話,就使用JdkDynamicAopProxy 提供的 equals方法。
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
// 條件成立,說明代理類實現(xiàn)的哪些接口 沒有定義hashCode方法,
// 并且當前method 是 hashCode方法的話,就使用JdkDynamicAopProxy 提供的 equals方法。
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// Service invocations on ProxyConfig with the proxy config...
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
// 保存返回值
Object retVal;
//this.advised.exposeProxy 如果是true,
// 就要把當前這個代理對象,暴漏 到Aop上下文內(nèi)。
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
// 根據(jù)targetSource拿到真正的目標對象
target = targetSource.getTarget();
// 獲取到目標對象的 class
Class<?> targetClass = (target != null ? target.getClass() : null);
// Get the interception chain for this method.
// 其實 這里是最關(guān)鍵的地方,查找適合該方法的 所有方法攔截器。
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// Check whether we have any advice. If we don't, we can fallback on direct
// reflective invocation of the target, and avoid creating a MethodInvocation.
if (chain.isEmpty()) {
// We can skip creating a MethodInvocation: just invoke the target directly
// Note that the final invoker must be an InvokerInterceptor so we know it does
// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
// 直接調(diào)用目標對象的目標方法。
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
// 說明有匹配當前method的方法攔截器,所以要做增強處理了。
else {
// We need to create a method invocation...
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
// 核心!注釋 :ReflectiveMethodInvocation
retVal = invocation.proceed();
}
// Massage return value if necessary.
// 方法 返回值類型
Class<?> returnType = method.getReturnType();
// 如果目標方法 返回 目標對象,這里 做個替換,返回 代理對象。
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// Special case: it returned "this" and the return type of the method
// is type-compatible. Note that we can't help if the target sets
// a reference to itself in another returned object.
retVal = proxy;
}
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 {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// 將 上次設(shè)置的proxy 再次 設(shè)置回去到 AopContext中。
// 因為當前代理對象的方法已經(jīng)完事了,需要回到再上一層邏輯了,
// 這里是一個恢復現(xiàn)場的邏輯。
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}3.1獲取目標方法的攔截器
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
/**
* 該方法的目的,就是查找出來適合當前方法 增強!
* @param config ProxyFactory,它掌握著AOP的所有資料呢
* @param method 目標對象的方法
* @param targetClass 目標對象的類型
*/
@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, @Nullable Class<?> targetClass) {
// This is somewhat tricky... We have to process introductions first,
// but we need to preserve order in the ultimate list.
//AdvisorAdapterRegistry 接口有兩個作用,一個作用是
// 可以向里面注冊 AdvisorAdapter 適配器
// 適配器目的:1. 將非Advisor 類型的 增強,包裝成為Advisor
// 2. 將Advisor 類型的增強 提取出來對應(yīng) MethodInterceptor
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
// 獲取出來 ProxyFactory 內(nèi)部 持有的 增強信息
// 1. addAdvice()
// 2. AddAdvisor() 最終 在ProxyFactory 內(nèi) 都會包裝成 Advisor 的。
Advisor[] advisors = config.getAdvisors();
List<Object> interceptorList = new ArrayList<>(advisors.length);
// 真實的目標對象類型
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
Boolean hasIntroductions = null;
for (Advisor advisor : advisors) {
//條件成立:說明當前advisor是包含 切點 信息的,
// 所以 這個if內(nèi)部的邏輯,就是做匹配算法。
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
// 轉(zhuǎn)換成 可以獲取到切點信息的接口。
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
// 條件二:成立,說明當前被代理對象的class 匹配
// 當前 Advisor 成功,這一步 只是class 匹配成功。
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 = true,靜態(tài)匹配成功。
match = mm.matches(method, actualClass);
}
//靜態(tài)匹配成功的話,再檢查是否需要 運行時匹配。
if (match) {
// 提取出來 advisor內(nèi)持有的攔截器信息
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
// 是否運行時匹配?
if (mm.isRuntime()) {
// Creating a new object instance in the getInterceptors() method
// isn't a problem as we normally cache created chains.
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
// 將當前advisor內(nèi)部的方法攔截器 追加到 interceptorList
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));
}
}
// 說明當前 Advisor 匹配全部class 全部 method
else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
// 返回所有匹配當前method的方法攔截器
return interceptorList;
}DefaultAdvisorAdapterRegistry#getInterceptors
@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);
}
for (AdvisorAdapter adapter : this.adapters) {
if (adapter.supportsAdvice(advice)) {
interceptors.add(adapter.getInterceptor(advisor));
}
}
if (interceptors.isEmpty()) {
throw new UnknownAdviceTypeException(advisor.getAdvice());
}
return interceptors.toArray(new MethodInterceptor[0]);
}public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {
private final List<AdvisorAdapter> adapters = new ArrayList<>(3);
/**
* Create a new DefaultAdvisorAdapterRegistry, registering well-known adapters.
*/
public DefaultAdvisorAdapterRegistry() {
registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
registerAdvisorAdapter(new AfterReturningAdviceAdapter());
registerAdvisorAdapter(new ThrowsAdviceAdapter());
}以MethodBeforeAdviceAdapter為例
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#invoke
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
return mi.proceed();
}
3.2 調(diào)用ReflectiveMethodInvocation#proceed
@Override
@Nullable
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
//條件成立:說明方法攔截器 全部都已經(jīng)調(diào)用過了。
// 接下來 需要執(zhí)行 目標對象的目標方法。
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
// 調(diào)用連接點
return invokeJoinpoint();
}
// 獲取下一個方法攔截器
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
// 條件成立:說明 方法攔截器 需要做 運行時匹配,很少用到運行時匹配。
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
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 {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
// 大部分情況,咱們都是執(zhí)行else 。
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
// 讓當前方法攔截器執(zhí)行,并且將 this 傳遞了 進去,this? MethodInvocation
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}總結(jié)
- 1)ProxyFactory是所有核心要素的匯集地,包括被代理對象、增強器Advisor
- 2)JdkDynamicAopProxy作為InvocationHandler是所有方法調(diào)用的入口
- 3)調(diào)用鏈路
step1.JdkDynamicAopProxy#invoke
獲取匹配該方法的攔截器鏈;
調(diào)用ReflectiveMethodInvocation;
step2.ReflectiveMethodInvocation#proceed
根據(jù)currentInterceptorIndex逐個進行調(diào)用;
最終調(diào)用至被代理的方法;
step3.MethodInterceptor#invoke(this),這里的this就是ReflectiveMethodInvocation
AspectJAroundAdvice、AspectJMethodBeforeAdvice、AspectJAfterAdvicestep4.最后反射調(diào)用至被代理的方法
以上就是java開發(fā)AOP基礎(chǔ)JdkDynamicAopProxy的詳細內(nèi)容,更多關(guān)于java AOP JdkDynamicAopProxy的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Spring Data JPA自動生成表時列順序混亂的最新解決辦法
文章主要介紹了Spring Boot 3.3.5版本中SpringDataJPA自動生成表時列順序混亂的問題,以及如何通過替換Hibernate實現(xiàn)來解決這個問題,感興趣的朋友跟隨小編一起看看吧2024-11-11
java實現(xiàn)大文件導出的實現(xiàn)與優(yōu)化
這篇文章主要為大家詳細介紹了java實現(xiàn)大文件導出的實現(xiàn)與優(yōu)化的相關(guān)資料,文中的示例代碼講解詳細,對我們深入了解java有一定的幫助,感興趣的小伙伴可以了解下2023-11-11
Java Socket+多線程實現(xiàn)多人聊天室功能
這篇文章主要為大家詳細介紹了Java Socket+多線程實現(xiàn)多人聊天室功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-07-07
設(shè)計模式之中介者模式_動力節(jié)點Java學院整理
這篇文章主要為大家詳細介紹了設(shè)計模式之中介者模式的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-08-08
如何在mybatis中向BLOB字段批量插入數(shù)據(jù)
這篇文章主要介紹了如何在mybatis中向BLOB字段批量插入數(shù)據(jù)的相關(guān)知識,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧2020-10-10
SpringBoot基于Swagger2構(gòu)建API文檔過程解析
這篇文章主要介紹了SpringBoot基于Swagger2構(gòu)建API文檔過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2019-11-11

