博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Spring AOP 多个切点实现:JdkDynamicAopProxy

Posted on 2019-05-23 11:39  徐自勉  阅读(3975)  评论(0编辑  收藏  举报

Spring Aop 的底层生成代理类i的实现除 jdk的动态代理技术外,还用到了Cglib,不过在封装两者的设计原理上相差不大,只是底层工具不同而已。

本文只分析JdkDynamicAopProxy 是如何为一个目标方法执行织入多个切点,也就是将原本可能需要多个“代理类“实现的业务放到一个代理类中(JdkDynamicAopProxy)完成。

JdkDynamicAopProxy 本身就是一个JDK代理的InvocationHandler,spring 在调用其getProxy()方法返回一个代理类对象时:

public Object getProxy(ClassLoader classLoader) {
        if (logger.isDebugEnabled()) {
            logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
        }
        Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
        findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
        return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    }
Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); 传入的 Handler 就是this,也就是 一个 JdkDynamicAopProxy 对象。所以代理的业务就在 JdkDynamicAopProxy
invoke()方法上。
 1 /**
 2      * Implementation of <code>InvocationHandler.invoke</code>.
 3      * <p>Callers will see exactly the exception thrown by the target,
 4      * unless a hook method throws an exception.
 5      */
 6     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 7         MethodInvocation invocation;
 8         Object oldProxy = null;
 9         boolean setProxyContext = false;
10 
11         TargetSource targetSource = this.advised.targetSource;
12         Class targetClass = null;
13         Object target = null;
14 
15         try {
16             if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
17                 // The target does not implement the equals(Object) method itself.
18                 return equals(args[0]);
19             }
20             if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
21                 // The target does not implement the hashCode() method itself.
22                 return hashCode();
23             }
24             if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
25                     method.getDeclaringClass().isAssignableFrom(Advised.class)) {
26                 // Service invocations on ProxyConfig with the proxy config...
27                 return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
28             }
29 
30             Object retVal;
31 
32             if (this.advised.exposeProxy) {
33                 // Make invocation available if necessary.
34                 oldProxy = AopContext.setCurrentProxy(proxy);
35                 setProxyContext = true;
36             }
37 
38             // May be null. Get as late as possible to minimize the time we "own" the target,
39             // in case it comes from a pool.
40             target = targetSource.getTarget();
41             if (target != null) {
42                 targetClass = target.getClass();
43             }
44 
45             // Get the interception chain for this method.
46             List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
47 
48             // Check whether we have any advice. If we don't, we can fallback on direct
49             // reflective invocation of the target, and avoid creating a MethodInvocation.
50             if (chain.isEmpty()) {
51                 // We can skip creating a MethodInvocation: just invoke the target directly
52                 // Note that the final invoker must be an InvokerInterceptor so we know it does
53                 // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
54                 retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
55             }
56             else {
57                 // We need to create a method invocation...
58                 invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
59                 // Proceed to the joinpoint through the interceptor chain.
60                 retVal = invocation.proceed();
61             }
62 
63             // Massage return value if necessary.
64             if (retVal != null && retVal == target && method.getReturnType().isInstance(proxy) &&
65                     !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
66                 // Special case: it returned "this" and the return type of the method
67                 // is type-compatible. Note that we can't help if the target sets
68                 // a reference to itself in another returned object.
69                 retVal = proxy;
70             }
71             return retVal;
72         }
73         finally {
74             if (target != null && !targetSource.isStatic()) {
75                 // Must have come from TargetSource.
76                 targetSource.releaseTarget(target);
77             }
78             if (setProxyContext) {
79                 // Restore old proxy.
80                 AopContext.setCurrentProxy(oldProxy);
81             }
82         }
83     }
invoke方法中的红色加粗代码就是重点部分:

List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
该行代码是构建代理链,获取到目标方法需要增强的一系列业务代理对象。

invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
通过将目标方法和 多个业务代理对象 创建成一个
ReflectiveMethodInvocation,来实际完成 执行目标方法时执行一些拦截器,也就是代理业务。


retVal = invocation.proceed();
该行代码开始执行代理业务和目标方法。

下面是
ReflectiveMethodInvocation 的 proceed方法代码:
 1 public Object proceed() throws Throwable {
 2         //    We start with an index of -1 and increment early.
 3         if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
 4             return invokeJoinpoint();
 5         }
 6 
 7         Object interceptorOrInterceptionAdvice =
 8             this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
 9         if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
10             // Evaluate dynamic method matcher here: static part will already have
11             // been evaluated and found to match.
12             InterceptorAndDynamicMethodMatcher dm =
13                 (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
14             if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
15                 return dm.interceptor.invoke(this);
16             }
17             else {
18                 // Dynamic matching failed.
19                 // Skip this interceptor and invoke the next in the chain.
20                 return proceed();
21             }
22         }
23         else {
24             // It's an interceptor, so we just invoke it: The pointcut will have
25             // been evaluated statically before this object was constructed.
26             return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
27         }
28     }

可以看到proceed()方法通过从interceptorsAndDynamicMethodMatchers(list)集合中取出拦截器,拦截器是在前面创建ReflectiveMethodInvocation对象时传入的chain,

通过判断拦截器集合中所有拦截器是否执行完,未执行完这递归调用proceed()方法,执行完则执行目标方法。

 

以上就是JdkDynamicAopProxy实现多个拦截器拦截目标方法的动态代理业务。