前言

  • 上一章节介绍了AOP代理对象的创建,那么实际方法的运行是通过代理对象来操作的,本章节将介绍代理对象方法的执行过程

  • AopProxy它有两个子类,所以不同代理对象方法执行过程是不一样的

    • JdkDynamicAopProxy是基于 JDKAOP 代理实现类
    • ObjenesisCglibAopProxy是基于 CGLIBAOP 的代理实现类

解析

1、JdkDynamicAopProxy

  • 我们知道JDK的动态代理是通过Proxy,InvocationHandler来实现的,所以抓住这两个点来分析这个JdkDynamicAopProxy

  • 先看一下JdkDynamicAopProxy这个类的继承关系,可以看到这个类实现了InvocationHandler接口,所以关注里面的invoke方法,同时还继承了AopProxy接口,这个接口的作用是返回对应的代理对象

  • 下面是JdkDynamicAopProxy的主体代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {

private static final long serialVersionUID = 5531744639992436476L;

private static final Log logger = LogFactory.getLog(JdkDynamicAopProxy.class);

/** Config used to configure this proxy */
private final AdvisedSupport advised;

/**
* Is the {@link #equals} method defined on the proxied interfaces?
*/
private boolean equalsDefined;

/**
* Is the {@link #hashCode} method defined on the proxied interfaces?
*/
private boolean hashCodeDefined;


/**
* Construct a new JdkDynamicAopProxy for the given AOP configuration.
* @param config the AOP configuration as AdvisedSupport object
* @throws AopConfigException if the config is invalid. We try to throw an informative
* exception in this case, rather than let a mysterious failure happen later.
*/
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(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
}
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

/**
* Finds any {@link #equals} or {@link #hashCode} method that may be defined
* on the supplied set of interfaces.
* @param proxiedInterfaces the interfaces to introspect
*/
private void findDefinedEqualsAndHashCodeMethods(Class<?>[] proxiedInterfaces) {
for (Class<?> proxiedInterface : proxiedInterfaces) {
Method[] methods = proxiedInterface.getDeclaredMethods();
for (Method method : methods) {
if (AopUtils.isEqualsMethod(method)) {
this.equalsDefined = true;
}
if (AopUtils.isHashCodeMethod(method)) {
this.hashCodeDefined = true;
}
if (this.equalsDefined && this.hashCodeDefined) {
return;
}
}
}
}


/**
* Implementation of {@code InvocationHandler.invoke}.
* <p>Callers will see exactly the exception thrown by the target,
* unless a hook method throws an exception.
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;

TargetSource targetSource = this.advised.targetSource;
Class<?> targetClass = null;
Object target = null;

try {
// 如果被代理的目标对象要执行的方法是equal则执行JdkDynamicAopProxy(即代理对象的equal)方法
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
// 如果被代理的目标对象要执行的方法是hashCode则执行JdkDynamicAopProxy(即代理对象的hashCode)方法
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;
// 有时候目标对象内部的自我调用将无法实施切面中的增强则需要通过此属性暴露代理
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}

// May be null. Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
target = targetSource.getTarget();
if (target != null) {
targetClass = target.getClass();
}

// Get the interception chain for this method.
// 获取当前方法的拦截器链
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);
// 如果没有发现任何拦截器那么直接调用切点方法
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// We need to create a method invocation...
// 将拦截器封装在ReflectiveMethodInvocation,以便于使用其proceed进行链接表用拦截器
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);
}
}
}

...
  • 关注invoke方法,根据上面代码可以看到如果执行的是equals或者hashCode方法则执行JdkDynamicAopProxy里面对应的内部方法,然后就是获取当前获取当前方法的拦截器链,对于没有拦截器的方法直接调用原有方法,有拦截器的方法会构造ReflectiveMethodInvocation,并沿着拦截器链进行调用。整个调用链的入口在其proceed方法中

    • 1、获取当前方法的拦截器链

      • this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);方法,这个方法做了一下缓存处理,因为那些方法需要执行代理都是之前写好固定的

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, 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;
        }
      • 继续跟进this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass);方法,可以看到这边就是一个拦截器的过滤,可以看到主体逻辑是循环Advisor通过切点匹配MethodMatchers.matches(mm, method, actualClass, hasIntroductions)

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48
        49
        50
        51
        52
        53
        54
        55
        56
        57
        58
        /**
        * 其实这边就是一个拦截器的过滤,我们在生产环境中,我们一般会用正则表达来定义切点(expression),
        * 因为并不是每个方法都需要切,会影响性能,所以matches这个方法很重要
        *
        * @param config the AOP configuration in the form of an Advised object
        * @param method the proxied method
        * @param targetClass the target class (may be {@code null} to indicate a proxy without
        * target object, in which case the method's declaring class is the next best option)
        * @return
        */
        @Override
        public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
        Advised config, Method method, Class<?> targetClass) {

        // This is somewhat tricky... We have to process introductions first,
        // but we need to preserve order in the ultimate list.
        // 先定义了一个拦截链的List大小最大为我们传入advisor的个数
        List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
        Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
        boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
        AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();

        for (Advisor advisor : config.getAdvisors()) {
        if (advisor instanceof PointcutAdvisor) {
        // Add it conditionally.
        PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
        if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
        MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
        MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
        if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
        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 {
        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;
        }
    • 2、对于没有拦截器的方法直接调用原有方法

      • 如果上面获取的chainisEmpty(),下面就是直接调用method.invoke(target, args);方法

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        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);
        // 如果没有发现任何拦截器那么直接调用切点方法
        retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
        }

        public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args) throws Throwable {
        // 使用反射执行方法
        try {
        ReflectionUtils.makeAccessible(method);
        return method.invoke(target, args);
        }
        catch (InvocationTargetException ex) {
        // Invoked method threw a checked exception.
        // We must rethrow it. The client won't see the interceptor.
        throw ex.getTargetException();
        }
        catch (IllegalArgumentException ex) {
        throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" +
        method + "] on target [" + target + "]", ex);
        }
        catch (IllegalAccessException ex) {
        throw new AopInvocationException("Could not access method [" + method + "]", ex);
        }
        }
    • 3、有拦截器的方法会构造ReflectiveMethodInvocation执行proceed()方法

      • 如果上面获取的chainisNotEmpty(),就需要执行相应拦截器的方法了,可以看到是封装了一个ReflectiveMethodInvocation对象,然后执行其proceed()方法

        1
        2
        3
        4
        5
        6
        7
        8
        else {
        // We need to create a method invocation...
        // 将拦截器封装在ReflectiveMethodInvocation,以便于使用其proceed进行链接表用拦截器
        invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
        // Proceed to the joinpoint through the interceptor chain.
        // 执行拦截器链
        retVal = invocation.proceed();
        }
      • 进入invocation.proceed();方法,可以看到这里使用了一个拦截器链的操作,从索引为-1的拦截器开始,并递增,如果拦截器迭代调用完成,则调用目标方法

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        @Override
        public Object proceed() throws Throwable {
        // We start with an index of -1 and increment early.
        // 执行完所有增强后执行切点方法,从索引为-1的拦截器开始,并递增,如果拦截器迭代调用完成,则调用目标方法
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        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;
        if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
        return dm.interceptor.invoke(this);
        }
        else {
        // Dynamic matching failed.
        // Skip this interceptor and invoke the next in the chain.
        // 不匹配则跳过这个拦截器调用下一个
        return proceed();
        }
        }
        else {
        // It's an interceptor, so we just invoke it: The pointcut will have
        // been evaluated statically before this object was constructed.
        // 这是一个拦截器,直接调用它,将this作为参数传递以保证当前实例中调用链的执行
        return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
        }
        }

2、ObjenesisCglibAopProxy

  • 先看一下ObjenesisCglibAopProxy这个类的继承关系
  • Cglib调用方法的核心逻辑在DynamicAdvisedInterceptorintercept方法中,和jdk方式实现代理的invoke方法大同小异
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {

private final AdvisedSupport advised;

public DynamicAdvisedInterceptor(AdvisedSupport advised) {
this.advised = advised;
}

@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Class<?> targetClass = null;
Object target = null;
try {
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// May be null. Get as late as possible to minimize the time we
// "own" the target, in case it comes from a pool...
target = getTarget();
if (target != null) {
targetClass = target.getClass();
}
// 获取拦截器链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
// Check whether we only have one InvokerInterceptor: that is,
// no real advice, but just reflective invocation of the target.
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
// 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);
retVal = methodProxy.invoke(target, argsToUse);
}
else {
// We need to create a method invocation...
// 进入链
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null) {
releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
  • 关注retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();这行代码,这里构造了CglibMethodInvocation查看这个类,然后执行proceed()方法,可以发现这个类继承了ReflectiveMethodInvocation这个类,所以这里的proceed()方法和我们上面jdk动态代理执行的proceed()方法是一样的

总结

参考

  • 《Spring 源码深度解析》