私の他の Spring ソースコード分析: https://blog.csdn.net/caicongyang/category_2139981.html
核となるアイデア:
アドバイザー
ポイントカット
クラスフィルター
メソッドマッチャー
アドバイス --> メソッドインターセプター
全体的なプロセス:
作成中の Bean --> インスタンス化後、メソッドは一致するアドバイザをすべて検索します --> メソッドがプロキシ ペアで実行されるときに、ProxyFactory を使用してプロキシ オブジェクトを生成します
--> 現在呼び出されているメソッドに基づいて、一致するアドバイザをすべて検索します --> > 対応するアドバイス ロジックを実行します。
1. cglib ダイナミック プロキシと jdk ダイナミック プロキシ
要点: インターフェイスには jdk を使用し、他のインターフェイスには cglib を使用します
2.@EnableAspectJAutoProxy
AnnotationAwareAspectJAutoProxyCreator を Bean ファクトリに追加します。
AnnotationAwareAspectJAutoProxyCreator は、AbstractAutoProxyCreator を継承し、BeanPostProcess です。初期化後のメソッド postProcessAfterInitialization で、初期 Bean に一致するアドバイスがあるかどうかが判断されます。存在する場合は、ProxyFactory プロキシ オブジェクトが生成されます。
その中で、AnnotationAwareAspectJAutoProxyCreator は findCandidateAdvisors() を書き換えて、すべての Advisor タイプを検索し、@Before およびその他のアノテーションをあらゆる側面から解析して Advisor オブジェクトを取得します。
3.プロキシファクトリー
ProxyFactory は Spring の動的プロキシのカプセル化です。JdkDynamicAopProxy
クラスの invoke メソッドは、一致する Advisor をフィルタリングして除外し、それを Interceptor に適応させ、それを責任のチェーンにカプセル化し、MethodInvocation の continue() メソッドで再帰呼び出しを行います。クラス;
CglibAopProxy にも同様のロジックがあります。
JdkDynamicAopProxyの呼び出しメソッドは以下のとおりです。
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
// 拿到被代理对象
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
// 如果接口中没有定义equals()方法,那么则直接调用,不走代理
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
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...
// 也是直接调用Advised接口中的方法,不走代理逻辑
// 其实就是利用代理对象获取ProxyFactory中的信息
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
// 如果ProxyFactory的exposeProxy为true,则将代理对象设置到currentProxy这个ThreadLocal中去
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.
// 被代理对象和代理类
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// Get the interception chain for this method.
// 代理对象在执行某个方法时,根据方法筛选出匹配的Advisor,并适配成Interceptor
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.
// 如果没有Advice,则直接调用对应方法
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
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.
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) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}