Spring aop 分析之一
分析Spring之前先看一个demo, 以对AOP有一个直观的了解:
package com.test.aop; import java.lang.reflect.Method; import org.springframework.aop.MethodBeforeAdvice; import org.springframework.aop.framework.ProxyFactory; public class TestAOP { public static void main(String[] args) { ProxyFactory f = new ProxyFactory(); // 设置代理目标 f.setTarget(new Hello()); // 设置一个前置通知 f.addAdvice(new MethodBeforeAdvice() { @Override public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println("start hello aop....."); } }); // 取得代理对象 IHello h = (IHello) f.getProxy(); h.hello(); } } interface IHello { public void hello(); } class Hello implements IHello { @Override public void hello() { System.out.println("hello aop"); } }
执行结果:
start hello aop.....
hello aop
二:
上述demo中IHello接口类型是通过
IHello h = (IHello) f.getProxy(); 方式获取的,f.getProxy()做了什么处理,
来看下getProxy()方法:
可以看出, 创建的AopProxy对象可能是 Cglib2AopProxy, JdkDynamicAopProxy, ProxyFactory .
这里只关注 JdkDynamicAopProxy
public Object getProxy() { return getProxy(ClassUtils.getDefaultClassLoader()); } 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); }
注:
Class[] proxiedInterfaces= AopProxyUtils.completeProxiedInterfaces(this.advised); // 这里获取的proxiedInterfaces 包含了IHello接口
Return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); //返回的对象实现了 proxiedInterfaces 中的接口, 而proxiedInterfaces中包含IHello接口, 故可以被转换成 IHello类型
接下去看看调用代理对象的 hello方法时会做什么:
当调用hello()时会进入到下面的invoke函数
/** * Implementation of <code>InvocationHandler.invoke</code>. * <p>Callers will see exactly the exception thrown by the target, * unless a hook method throws an exception. */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { MethodInvocation invocation = null; Object oldProxy = null; boolean setProxyContext = false; TargetSource targetSource = this.advised.targetSource; Class targetClass = null; Object target = null; try { Object retVal = null; target = targetSource.getTarget(); if (target != null) { targetClass = target.getClass(); } // Get the interception chain for this method. List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); // 得到拦截器链 if (chain.isEmpty()) { // 如果拦截器链为空, 就直接通过java反射调用目标对象的方法 retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args); } else { invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); retVal = invocation.proceed(); // 先执行拦截器链,等所有拦截器执行完后再执行目标对象方法 } if (retVal != null && retVal == target && method.getReturnType().isInstance(proxy) && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) { retVal = proxy; } return retVal; } finally { if (target != null && !targetSource.isStatic()) { // Must have come from TargetSource. targetSource.releaseTarget(target); } if (setProxyContext) { // Restore old proxy. AopContext.setCurrentProxy(oldProxy); } } }
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
retVal = invocation.proceed(); // 这里是怎么来执行拦截器的, 从ReflectiveMethodInvocation构造函数可以知道,invocation实例持有一个拦截器链
通过 invocation.proceed() 方法又是如何遍历拦截器的呢?
来看proceed方法:
public Object proceed() throws Throwable { // We start with an index of -1 and increment early. // currentInterceptorIndex 当前拦截器执行索引, 如果已执行完毕所有拦截器, 则调用目标对象方法 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); // 将this作为参数传入interceptor.invoke, interceptor中有一个通知, 执行完通知后,又会调用proceed方法, 这样就形成一个递归调用过程, 直到所有处理器都便利完成 } 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. return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); } }
最后以一个demo来 说明拦截器和MethodInvocation 之间相互调用过程
package com.test.aop; import java.util.ArrayList; import java.util.List; public class Test { public String test() { return "hello test"; } public static void main(String[] args) { // 创建通知1 Advice advice1 = new Advice() { @Override public void advice() { System.out.println("advice1...."); } }; // 创建通知2 Advice advice2 = new Advice() { @Override public void advice() { System.out.println("advice2...."); } }; // 创建拦截器链 List<Interceptor> interceptorList = new ArrayList<Interceptor>(); interceptorList.add(new Interceptor(advice1)); interceptorList.add(new Interceptor(advice2)); // 创建目标对象 Test target = new Test(); // 创建Invocation Invocation invocation = new Invocation(interceptorList, target); Object ret = invocation.proceed(); // start System.out.println(ret); } } /** * 模拟拦截器 * */ class Interceptor { private Advice advice; public Interceptor(Advice advice) { this.advice = advice; } public Object invoke(Invocation invocation) { advice.advice(); // 先执行通知 return invocation.proceed(); } } /** * 模拟通知 * */ interface Advice { public void advice(); } /** * 模拟调用 * */ class Invocation { private int interceptorIndex = -1; // 当前拦截器链索引 private List<Interceptor> interceptorList; // 持有的拦截器链 private Test target; public Invocation(List<Interceptor> interceptorList, Test target) { this.interceptorList = interceptorList; this.target = target; } public Object proceed() { if (++interceptorIndex >= interceptorList.size()) { return target.test(); } Interceptor interceptor = interceptorList.get(interceptorIndex); return interceptor.invoke(this);// 将当前实例作为invoke参数传入 } }
执行结果:
advice1....
advice2....
hello test