前面我们分析了 Spring AOP 实现中得到 Proxy 对象的过程,下面我们看看在 Spring AOP 中拦截器链是怎样被调用的,也就是 Proxy 模式是怎样起作用的,或者说 Spring 是怎样为我们提供 AOP 功能的;在 JdkDynamicAopProxy 中生成 Proxy 对象的时候:
代码语言:javascript复制1return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
这里的 this 参数对应的是 InvocationHandler 对象,这里我们的 JdkDynamicAopProxy 实现了这个接口,也就是说当 Proxy 对象的函数被调用的时候,这个 InvocationHandler 的 invoke 方法会被作为回调函数调用,下面我们看看这个方法的实现:
代码语言:javascript复制 1public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
2 MethodInvocation invocation = null;
3 Object oldProxy = null;
4 boolean setProxyContext = false;
5
6 TargetSource targetSource = this.advised.targetSource;
7 Class targetClass = null;
8 Object target = null;
9
10 try {
11 // Try special rules for equals() method and implementation of the
12 // Advised AOP configuration interface.
13
14 if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
15 // What if equals throws exception!?
16 // This class implements the equals(Object) method itself.
17 return equals(args[0]) ? Boolean.TRUE : Boolean.FALSE;
18 }
19 if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
20 // This class implements the hashCode() method itself.
21 return new Integer(hashCode());
22 }
23 if (Advised.class == method.getDeclaringClass()) {
24 // service invocations on ProxyConfig with the proxy config
25 return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
26 }
27
28 Object retVal = null;
29
30 if (this.advised.exposeProxy) {
31 // make invocation available if necessary
32 oldProxy = AopContext.setCurrentProxy(proxy);
33 setProxyContext = true;
34 }
35
36 // May be <code>null</code>. Get as late as possible to minimize the time we "own" the target,
37 // in case it comes from a pool.
38 // 这里是得到目标对象的地方,当然这个目标对象可能来自于一个实例池或者是一个简单的 JAVA 对象
39 target = targetSource.getTarget();
40 if (target != null) {
41 targetClass = target.getClass();
42 }
43
44 // get the interception chain for this method
45 // 这里获得定义好的拦截器链
46 List chain = this.advised.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this.advised, proxy, 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 // 如果没有设定拦截器,那么我们就直接调用目标的对应方法
51 if (chain.isEmpty()) {
52 // We can skip creating a MethodInvocation: just invoke the target directly
53 // Note that the final invoker must be an InvokerInterceptor so we know it does
54 // nothing but a reflective operation on the target, and no hot swapping or fancy proxying
55 retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
56 } else {
57 // We need to create a method invocation...
58 // invocation = advised.getMethodInvocationFactory().getMethodInvocation(
59 // proxy, method, targetClass, target, args, chain, advised);
60 // 如果有拦截器的设定,那么需要调用拦截器之后才调用目标对象的相应方法
61 // 这里通过构造一个 ReflectiveMethodInvocation 来实现,下面我们会看这个 ReflectiveMethodInvocation 类
62 invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
63
64 // proceed to the joinpoint through the interceptor chain
65 // 这里通过 ReflectiveMethodInvocation 来调用拦截器链和相应的目标方法
66 retVal = invocation.proceed();
67 }
68
69 // massage return value if necessary
70 if (retVal != null && retVal == target && method.getReturnType().isInstance(proxy)) {
71 // Special case: it returned "this" and the return type of the method is type-compatible
72 // Note that we can't help if the target sets
73 // a reference to itself in another returned object.
74 retVal = proxy;
75 }
76 return retVal;
77 } finally {
78 if (target != null && !targetSource.isStatic()) {
79 // must have come from TargetSource
80 targetSource.releaseTarget(target);
81 }
82
83 if (setProxyContext) {
84 // restore old proxy
85 AopContext.setCurrentProxy(oldProxy);
86 }
87 }
88}
我们先看看目标对象方法的调用,这里是通过 AopUtils 的方法调用 - 使用反射机制来对目标对象的方法进行调用:
代码语言:javascript复制 1public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args) throws Throwable {
2
3 // Use reflection to invoke the method.
4 // 利用放射机制得到相应的方法,并且调用 invoke
5 try {
6 if (!Modifier.isPublic(method.getModifiers()) ||
7 !Modifier.isPublic(method.getDeclaringClass().getModifiers())) {
8 method.setAccessible(true);
9 }
10 return method.invoke(target, args);
11 } catch (InvocationTargetException ex) {
12 // Invoked method threw a checked exception.
13 // We must rethrow it. The client won't see the interceptor.
14 throw ex.getTargetException();
15 } catch (IllegalArgumentException ex) {
16 throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" method "] on target [" target "]", ex);
17 } catch (IllegalAccessException ex) {
18 throw new AopInvocationException("Couldn't access method: " method, ex);
19 }
20}
对拦截器链的调用处理是在 ReflectiveMethodInvocation 里实现的:
代码语言:javascript复制 1public Object proceed() throws Throwable {
2 // We start with an index of -1 and increment early.
3 // 这里直接调用目标对象的方法,没有拦截器的调用或者拦截器已经调用完了,这个 currentInterceptorIndex 的初始值是 0
4 if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size()) {
5 return invokeJoinpoint();
6 }
7
8 Object interceptorOrInterceptionAdvice = 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 // 这里获得相应的拦截器,如果拦截器可以匹配的上的话,那就调用拦截器的 invoke 方法
13 InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
14 if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
15 return dm.interceptor.invoke(nextInvocation());
16 } else {
17 // Dynamic matching failed.
18 // Skip this interceptor and invoke the next in the chain.
19 // 如果拦截器匹配不上,那就调用下一个拦截器,这个时候拦截器链的位置指示后移并迭代调用当前的 proceed 方法
20 this.currentInterceptorIndex ;
21 return proceed();
22 }
23 }
24 else {
25 // It's an interceptor, so we just invoke it: The pointcut will have
26 // been evaluated statically before this object was constructed.
27 return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(nextInvocation());
28 }
29}
这里把当前的拦截器链以及在拦截器链的位置标志都 clone 到一个 MethodInvocation 对象了,作用是当前的拦截器执行完之后,会继续沿着得到这个拦截器链执行下面的拦截行为,也就是会迭代的调用上面这个 proceed:
代码语言:javascript复制1private ReflectiveMethodInvocation nextInvocation() throws CloneNotSupportedException {
2 ReflectiveMethodInvocation invocation = (ReflectiveMethodInvocation) clone();
3 invocation.currentInterceptorIndex = this.currentInterceptorIndex 1;
4 invocation.parent = this;
5 return invocation;
6}
这里的 nextInvocation 就已经包含了当前的拦截链的基本信息,我们看到在 Interceptor 中的实现比如 TransactionInterceptor 的实现中:
代码语言:javascript复制 1public Object invoke(final MethodInvocation invocation) throws Throwable {
2 ...//这里是 TransactionInterceptor 插入的事务处理代码,我们会在后面分析事务处理实现的时候进行分析
3 try {
4 //这里是对配置的拦截器链进行迭代处理的调用
5 retVal = invocation.proceed();
6 }
7 ...//省略了和事务处理的异常处理代码 ,也是 TransactionInterceptor 插入的处理
8 else {
9 try {
10 Object result = ((CallbackPreferringPlatformTransactionManager) getTransactionManager.execute(txAttr, new TransactionCallback() {
11 public Object doInTransaction(TransactionStatus status) {
12 //这里是 TransactionInterceptor 插入对事务处理的代码
13 TransactionInfo txInfo = prepareTransactionInfo(txAttr, joinpointIdentification, status);
14 //这里是对配置的拦截器链进行迭代处理的调用,接着顺着拦截器进行处理
15 try {
16 return invocation.proceed();
17 }
18 ...//省略了和事务处理的异常处理代码 ,也是 TransactionInterceptor 插入的处理
19}
从上面的分析我们看到了 Spring AOP 的基本实现,比如 Spring 怎样得到 Proxy,怎样利用 JAVA Proxy 以及反射机制对用户定义的拦截器链进行处理。