Spring AOP源码分析(四)Spring AOP的JDK动态代理

[size=medium]本篇文章将会介绍上一个例子中的源码执行情况,从中熟悉整个SpringAOP的一些概念和接口设计。

首先整个SpringAOP的分两大过程。
第一个过程:根据xml文件或者注解中配置的拦截信息,生成相应的代理对象,这个代理对象包含了对应的拦截器。
第二个过程:执行所拦截的方法时,就是调用代理对象的执行逻辑,完成各种拦截。

本文章先对第二个过程进行源码解析。
对第一个过程先做简单概述,如果拦截的类的对应方法是接口方法,则使用JDK的Proxy进行代理对象的创建否则使用CGLIB进行代理对象的创建。

本工程采用的之前文章所给出案例链接:[url]http://www.iteye.com/topic/336873[/url]
[/size]
[size=medium]简单概述如下:
拦截类:TestAspect[/size]

public void doAfter(JoinPoint jp) {
System.out.println("log Ending method: "
+ jp.getTarget().getClass().getName() + "."
+ jp.getSignature().getName());
}

public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
long time = System.currentTimeMillis();
Object retVal = pjp.proceed();
time = System.currentTimeMillis() - time;
System.out.println("process time: " + time + " ms");
return retVal;
}

public void doBefore(JoinPoint jp) {
System.out.println("log Begining method: "
+ jp.getTarget().getClass().getName() + "."
+ jp.getSignature().getName());
}

public void doThrowing(JoinPoint jp, Throwable ex) {
System.out.println("method " + jp.getTarget().getClass().getName()
+ "." + jp.getSignature().getName() + " throw exception");
System.out.println(ex.getMessage());
}

xml的配置:

<aop:config>
<aop:aspect id="TestAspect" ref="aspectBean">

<!-- 配置com.spring.service包下所有类或接口的所有方法 -->
<aop:pointcut id="businessService"
expression="execution(* com.lg.aop.service.*.*(..))" />
<aop:before pointcut-ref="businessService" method="doBefore"/>
<aop:after pointcut-ref="businessService" method="doAfter"/>
<aop:around pointcut-ref="businessService" method="doAround"/>
<aop:after-throwing pointcut-ref="businessService" method="doThrowing" throwing="ex"/>
</aop:aspect>
</aop:config>

[size=medium]建立单元测试类:[/size]

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "file:src/main/webapp/WEB-INF/mvc-servlet.xml")
public class AOPTest {

@Autowired
private AService aService;
@Autowired
private BServiceImpl bServiceImpl;

@Test
public void testAOP(){
aService.barA();
bServiceImpl.fooB();
}

}

[size=medium]运行,效果如下:[/size]

log Begining method: com.lg.aop.service.impl.AServiceImpl.barA
AServiceImpl.barA()
process time: 0 ms
log Ending method: com.lg.aop.service.impl.AServiceImpl.barA
log Begining method: com.lg.aop.service.BServiceImpl.fooB
BServiceImpl.fooB()
process time: 12 ms
log Ending method: com.lg.aop.service.BServiceImpl.fooB

[size=medium]接下来就是分析这一过程。
首先我们会看到:此时的AService不再是它的实现者AServiceImpl,而是一个代理对象。
由于barA()是接口方法,所以会选择使用JDK的Proxy进行代理对象的创建。如下在JdkDynamicAopProxy中:[/size]

@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);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

[size=medium]来看下Proxy.newProxyInstance(classLoader, proxiedInterfaces, this)(详情见上一篇文章[url]http://lgbolgger.iteye.com/blog/2117215[/url])这个代码就是创建代理对象,第一个参数指定classLoader,第二个参数指定代理对象要实现的接口,第三个对象那个是InvocationHandler类型。来看下InvocationHandler:[/size]

public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;

[size=medium]一个代理对象和一个InvocationHandler绑定,当执行代理对象的方法时,就会去执行InvocationHandler的invoke(Object proxy, Method method, Object[] args)方法,在该方法中你可以选择相应的处理或者不执行代理对象的method方法。
JdkDynamicAopProxy继承了InvocationHandler,所以上文中在创建代理对象时传的参数是this,即这个代理对象的方法的执行拦截情况全部在JdkDynamicAopProxy的invoke(Object proxy, Method method, Object[] args)方法中。
我们先来了解下JdkDynamicAopProxy的一些属性:[/size]

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
/** Config used to configure this proxy */
private final AdvisedSupport advised;

private boolean equalsDefined;
private boolean hashCodeDefined;
//略
}

[size=medium]最关键的就是这个AdvisedSupport advised属性,它包含了我们在xml中配置的拦截信息,同时还包含了这个JdkDynamicAopProxy要代理的接口及其实现类,对于本文来说就是AService和AServiceImpl。JdkDynamicAopProxy可以根据这些配置信息来创建一个代理对象实现拦截,同时又可以执行AServiceImpl本身的业务方法。

AdvisedSupport有两个重要的内容:TargetSource和List<Advisor> advisors和List<Class<?>> interfaces。
TargetSource是目标类型和目标对象的包裹,在这里是AServiceImpl类和AServiceImpl对象。
List<Class<?>> interfaces:包含了目标类型实现的接口,在这里就是AService
List<Advisor> advisors:这里包含了我们在xml文件中配置的所有信息。这一部分是每个AdvisedSupport所共享的信息,而前面两个是每个AdvisedSupport所独有的信息。

在详细看下AdvisedSupport:[/size]

public class AdvisedSupport extends ProxyConfig implements Advised

[size=medium]接口Advised:主要包含TargetSource和List<Advisor> advisors和List<Class<?>> interface
ProxyConfig:则是对要产生的代理对象的一些配置,如下:[/size]

public class ProxyConfig implements Serializable {

/** use serialVersionUID from Spring 1.2 for interoperability */
private static final long serialVersionUID = -8409359707199703185L;


private boolean proxyTargetClass = false;

private boolean optimize = false;

boolean opaque = false;

boolean exposeProxy = false;

private boolean frozen = false;
}

[size=medium]其中proxyTargetClass:表示是否强制使用CGLIB进行代理对象的创建
exposeProxy :表示是否暴漏代理对象,实现线程内共享,这里又是使用ThreadLocal模式。
他们分别对应xml配置中的[/size]

<aop:config expose-proxy="false" proxy-target-class="false">
</aop:config>

[size=medium]继续回到AdvisedSupport ,对于它的List<Advisor> advisors则分别对应xml中的配置:[/size]

<aop:before pointcut-ref="businessService1" method="doBefore" />
<aop:after pointcut-ref="businessService2" method="doAfter"/>
<aop:around pointcut-ref="businessService2" method="doAround"/>
<aop:after-throwing pointcut-ref="businessService1" method="doThrowing" throwing="ex"/>

[size=medium]则产生的Advisor如下:每一个都是AspectJPointcutAdvisor对象,该对象所包含的内容如下:[/size]

private final AbstractAspectJAdvice advice;
private final Pointcut pointcut;
private Integer order;

[size=medium]分别和xml配置中的内容相对应,在xml中你还可以指定order值,用来排序,这个顺序关系到这些拦截方法的执行顺序,之后我们会详细分析这个拦截器链的执行情况。
如aop:before产生的AspectJPointcutAdvisor的AbstractAspectJAdvice 为AspectJMethodBeforeAdvice,Pointcut 为ComposablePointcut。具体的内容已在上文中接口说明中给出了说明。

至此xml中的配置对应到AdvisedSupport基本上简单的了解了,这些内容的创建都是为下文方法的拦截做准备。
下面继续回到JdkDynamicAopProxy,来看看拦截过程,即调用代理对象的方法,然后被拦截到代理对象的InvocationHandler的invoke方法,JdkDynamicAopProxy的invoke方法如下:[/size]

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 {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
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;

//我们关注的重点1
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();
}
//关注的重点2
// 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.
//关注的重点3
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
}
else {
//关注的重点4
// We need to create a method invocation...
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.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);
}
}
}

[size=medium]关注的重点1:this.advised.exposeProxy即我们在xml文件中所配置的<aop:config expose-proxy="false">。如果配置为true,默认false,则意味着在该线程内将会暴露proxy代理对象,实现共享,即在该线程中的任何地方都可以都可以取到proxy代理对象。具体是由ThreadLocal设计模式来实现的,可以见我的另一篇博客对ThreadLocal设计模式的分析([url]http://lgbolgger.iteye.com/blog/2117216[/url]),来看下AopContext:[/size]

private static final ThreadLocal<Object> currentProxy = new NamedThreadLocal<Object>("Current AOP proxy");

public static Object currentProxy() throws IllegalStateException {
Object proxy = currentProxy.get();
if (proxy == null) {
throw new IllegalStateException(
"Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available.");
}
return proxy;
}

static Object setCurrentProxy(Object proxy) {
Object old = currentProxy.get();
if (proxy != null) {
currentProxy.set(proxy);
}
else {
currentProxy.remove();
}
return old;
}

[size=medium]AopContext内部使用了一个ThreadLocal<Object> currentProxy,它的两个方法都是静态方法,任何线程都可以调用这两个方法,当线程一调用setCurrentProxy方法时,AopContext的currentProxy就会去操作线程一内部的数据,当线程二调用setCurrentProxy方法时,AopContext的currentProxy就会去操作线程二内部的数据,互不干扰。这种情况不会引起多线程争抢资源数据的情况,同时实现了在某个线程中实现的数据的共享,而不用在某个线程中来回的传递参数。这就是ThreadLocal的设计模式,对于ThreadLocal<Object> currentProxy这样的类型属性,它仅仅是操作调用currentProxy的方法的当前线程的工具类,仅此而已。

继续,这样的话就可以实现了在本线程中共享proxy代理对象,这就意味着我们在我们自定义的advice上通过AopContext可以获取到当前的代理对象。
关注的重点2:根据我们的目标类和方法找到对应的拦截器链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
它内部是通过advised的一个this.advisorChainFactory来实现这一过程,advisorChainFactory默认为DefaultAdvisorChainFactory,实现过程如下:[/size]

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<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
boolean hasIntroductions = hasMatchingIntroductions(config, targetClass);
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(targetClass)) {
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
if (MethodMatchers.matches(mm, method, targetClass, 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(targetClass)) {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
return interceptorList;
}

[size=medium]上述过程分了三种情况来获取对应的Interceptor拦截器,config.getAdvisors()是我们在xml文件中所配置的所有的拦截情况,对于这些所有的拦截情况:

当Advisor为PointcutAdvisor类型的时:
这是我们本工程的配置的拦截,每个拦截都有pointcut,针对这种情况,首先判断该PointcutAdvisor的ClassFilter是否拦截了targetClass,若拦截则需继续判断PointcutAdvisor的MethodMatcher是否拦截targetClass的method方法。如果也拦截了,就需要将PointcutAdvisor的adice添加进去,则继续判断这个PointcutAdvisor的MethodMatcher是否是动态变化的,若是则需要将interceptor进一步包装成InterceptorAndDynamicMethodMatcher然后添加进去。

当Advisor为IntroductionAdvisor类型的时候:
IntroductionAdvisor应用在类上,不需要判断是否拦截了相应的方法。IntroductionAdvisor只有一个ClassFilter。此时仅仅去判断下是否拦截相应的类即可。

其他情况:
直接获取相应的interceptor。

我们来看下根据Advisor来获取对应的MethodInterceptor方法:[/size]

public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
List<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>(3);
Advice advice = advisor.getAdvice();
if (advice instanceof MethodInterceptor) {
interceptors.add((MethodInterceptor) advice);
}
for (AdvisorAdapter adapter : this.adapters) {
if (adapter.supportsAdvice(advice)) {
interceptors.add(adapter.getInterceptor(advisor));
}
}
if (interceptors.isEmpty()) {
throw new UnknownAdviceTypeException(advisor.getAdvice());
}
return interceptors.toArray(new MethodInterceptor[interceptors.size()]);
}

[size=medium]首先是判断advisor.getAdvice()是否已实现了MethodInterceptor,如AspectJAfterAdvice、AspectJAfterThrowingAdvice等。
然后又是利用适配器模式,将不用的advice封装成对应的MethodInterceptor。如MethodBeforeAdviceAdapter,默认硬编码注册了三个[/size]

public DefaultAdvisorAdapterRegistry() {
registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
registerAdvisorAdapter(new AfterReturningAdviceAdapter());
registerAdvisorAdapter(new ThrowsAdviceAdapter());
}

[size=medium]看下MethodBeforeAdviceAdapter:[/size]

class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {

@Override
public boolean supportsAdvice(Advice advice) {
return (advice instanceof MethodBeforeAdvice);
}

@Override
public MethodInterceptor getInterceptor(Advisor advisor) {
MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
return new MethodBeforeAdviceInterceptor(advice);
}

}

[size=medium]这就是典型的适配器模式,当Advice为MethodBeforeAdvice时,就会封装成MethodBeforeAdviceInterceptor。

至此获取MethodInterceptor链的过程就完成了,回到List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);即List<Object>是一系列的MethodInterceptor构成的。

继续看JdkDynamicAopProxy的invoke拦截方法:

关注重点3:在获取MethodInterceptor链后,如果为空,则没有拦截器直接执行目标对象的方法。retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);中的target对于本工程来说就是AServiceImpl,所以此方法的本质就是利用反射执行AServiceImpl的method方法。如下:[/size]

public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args)
throws Throwable {

// Use reflection to invoke the method.
try {
ReflectionUtils.makeAccessible(method);
return method.invoke(target, args);
}
//略

}

[size=medium]关注的重点4: 有了拦截器链后,就构造一个ReflectiveMethodInvocation来完成这一个调用过程。
首先说下接口情况:ReflectiveMethodInvocation实现了ProxyMethodInvocation,ProxyMethodInvocation继承了MethodInvocation,
MethodInvocation继承了Invocation,
Invocation继承了Joinpoint,此时的Joinpoint是AOP联盟定义的接口。
aspectj也有一个类似的JoinPoint,这两个是不一样的。
Joinpoint:能够得到目标对象,同时指定了对目标对象的处理方法[/size]

//定义了一个proceed()方法,来处理这些拦截器链的调用过程
Object proceed() throws Throwable;
//返回目标对象,针对本工程就是AServiceImpl
Object getThis();

[size=medium]Invocation:能够获取方法参数,此时方法可以是构造方法也可以是一般方法[/size]

Object[] getArguments();

[size=medium]MethodInvocation:能够获取方法而不是构造方法,ConstructorInvocation才是获取构造方法,所以有了MethodInvocation就可以执行目标对象的方法了。[/size]

Method getMethod();

[size=medium]ProxyMethodInvocation:能够获取代理代理对象,这个在Around通知时发挥作用,稍后会看到。[/size]

Object getProxy();

[size=medium]此时ReflectiveMethodInvocation就拥有以下数据:[/size]

protected final Object proxy;
protected final Object target;
protected final Method method;
protected Object[] arguments;
private final Class<?> targetClass;
protected final List<?> interceptorsAndDynamicMethodMatchers;

[size=medium]
interceptorsAndDynamicMethodMatchers则是由重点2中得出的拦截器链传给ReflectiveMethodInvocation的。然后看下ReflectiveMethodInvocation作为一个Joinpoint的proceed方法的执行过程:[/size]

public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
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.
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}

[size=medium]首先就是this.currentInterceptorIndex,它是ReflectiveMethodInvocation的一个属性,从-1开始:[/size]

private int currentInterceptorIndex = -1;

[size=medium]当currentInterceptorIndex达到this.interceptorsAndDynamicMethodMatchers.size() - 1时,拦截器链执行完毕了,就去执行目标对象的方法。invokeJoinpoint()方法就是上文我们所说的通过反射进行目标方法的调用。

继续看,拿出一个interceptorOrInterceptionAdvice,判断它是不是InterceptorAndDynamicMethodMatcher类型,这个类型在获取拦截器链的时候遇见了,我们再次回顾下:[/size]

for (Advisor advisor : config.getAdvisors()) {
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(targetClass)) {
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
//重点在这里重点在这里重点在这里重点在这里重点在这里
if (MethodMatchers.matches(mm, method, targetClass, 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));
}
}
}
}
//略

[size=medium]因为InterceptorAndDynamicMethodMatcher的MethodMatcher是可变的,所以在执行前仍要进行判断一次,符合的话就执行InterceptorAndDynamicMethodMatcher中所包含的MethodInterceptor。不符合的话跳过本次拦截器,继续执行下一个拦截器。

当拦截器是MethodInterceptor,则是执行这个拦截器。
然后我们来看下具体有哪些拦截器链,以及具体是怎样的执行过程:

我们会看到会有如下5个拦截器,依次是:
ExposeInvocationInterceptor、MethodBeforeAdviceInterceptor、AspectJAfterAdvice、AspectJAroundAdvice、AspectJAfterThrowingAdvice。

首先看第一个ExposeInvocationInterceptor:
它是Spring自动帮我们添加的,它不属于InterceptorAndDynamicMethodMatcher类型,即不再进行判断是否符合当前函数。
看下它的invoke方法的内容:[/size]

public Object invoke(MethodInvocation mi) throws Throwable {
MethodInvocation oldInvocation = invocation.get();
invocation.set(mi);
try {
return mi.proceed();
}
finally {
invocation.set(oldInvocation);
}
}

[size=medium]其中MethodInvocation mi始终是刚创建的ReflectiveMethodInvocation对象,它包含了一切要执行的信息。invocation则是一个ThreadLocal类型,如下:[/size]

private static final ThreadLocal<MethodInvocation> invocation =
new NamedThreadLocal<MethodInvocation>("Current AOP method invocation");

[size=medium]这里使用了ThreadLocal模式,将ReflectiveMethodInvocation对象这一重要对象存进当前线程的map集合中(ThreadLocal模式参见 [url]http://lgbolgger.iteye.com/blog/2117216[/url]),实现线程内ReflectiveMethodInvocation对象这一重要数据的共享,这就意味着我们在自定义的advice中可以通过invocation来获取ReflectiveMethodInvocation对象这一重要数据。
同时ExposeInvocationInterceptor的currentInvocation方法用于获取当前线程的ReflectiveMethodInvocation对象[/size]

public static MethodInvocation currentInvocation() throws IllegalStateException {
MethodInvocation mi = invocation.get();
if (mi == null)
throw new IllegalStateException(
"No MethodInvocation found: Check that an AOP invocation is in progress, and that the " +
"ExposeInvocationInterceptor is upfront in the interceptor chain. Specifically, note that " +
"advices with order HIGHEST_PRECEDENCE will execute before ExposeInvocationInterceptor!");
return mi;
}

[size=medium]ExposeInvocationInterceptor即分析完了,此时ExposeInvocationInterceptor的invoke函数还没有执行完毕,然后就嵌套执行ReflectiveMethodInvocation对象的proceed方法,
获取下一个拦截器MethodBeforeAdviceInterceptor,并且判断类型也属于InterceptorAndDynamicMethodMatcher类型的(我们自定义的几个都不属于),
和ExposeInvocationInterceptor一样,直接执行,看下MethodBeforeAdviceInterceptor的invoke函数:[/size]

public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
return mi.proceed();
}

[size=medium]先会执行我们在xml文件中配置好的advice,即我们自定义的doBefore方法,这就是前置通知。然后继续嵌套执行ReflectiveMethodInvocation对象的proceed方法,轮到了AspectJAfterAdvice的invoke方法:[/size]

@Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
finally {
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}

[size=medium]它的执行顺序则是先去执行后面的内容,当都执行完毕了才返回来执行这个advice。这就是后置通知。继续嵌套执行ReflectiveMethodInvocation对象的proceed方法,来到了AspectJAroundAdvice的invoke方法:[/size]

public Object invoke(MethodInvocation mi) throws Throwable {
if (!(mi instanceof ProxyMethodInvocation)) {
throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
}
ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
JoinPointMatch jpm = getJoinPointMatch(pmi);
return invokeAdviceMethod(pjp, jpm, null, null);
}


protected ProceedingJoinPoint lazyGetProceedingJoinPoint(ProxyMethodInvocation rmi) {
return new MethodInvocationProceedingJoinPoint(rmi);
}

[size=medium]lazyGetProceedingJoinPoint(pmi)就是将ReflectiveMethodInvocation对象作为一个ProxyMethodInvocation封装成一个MethodInvocationProceedingJoinPoint,如下:[/size]


public MethodInvocationProceedingJoinPoint(ProxyMethodInvocation methodInvocation) {
Assert.notNull(methodInvocation, "MethodInvocation must not be null");
this.methodInvocation = methodInvocation;
}

[size=medium]这个就是环绕通知,我们看下这通知我们所写的具体内容:[/size]

public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
long time = System.currentTimeMillis();
Object retVal = pjp.proceed();
time = System.currentTimeMillis() - time;
System.out.println("process time: " + time + " ms");
return retVal;
}

[size=medium]这里面有一个很重要的信息ProceedingJoinPoint pjp,它决定了ReflectiveMethodInvocation的执行链是否继续执行下去,所以pjp.proceed()的本质仍然是调用ReflectiveMethodInvocation的proceed()方法,来继续下面拦截器的执行,也可以选择不执行,则拦截器链的执行就会终止了,会从不断嵌套的proceed函数中不断返回。
这里将会执行到我们自定义的上面的doAround方法,当执行到pjp.proceed()时,又会返还到
ReflectiveMethodInvocation的proceed()执行下一个拦截器,来到AspectJAfterThrowingAdvice,它的invoke方法为:[/size]

public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
catch (Throwable t) {
if (shouldInvokeOnThrowing(t)) {
invokeAdviceMethod(getJoinPointMatch(), null, t);
}
throw t;
}
}

[size=medium]即先执行后面的拦截器,但后面的拦截器执行过程中出现异常时才会发挥该拦截器的作用。继续执行后面的拦截器,发现已经没了,则终于轮到目标对象的方法了,目标方法执行完毕后,返回上一个proceed的嵌套即AspectJAfterThrowingAdvice的invoke方法,发现没有抛出异常,则继续返回到上一个proceed嵌套,即AspectJAroundAdvice,即我们自定义的doAround中这一行代码Object retVal = pjp.proceed()返回了,继续完成我们自定义的doAround函数,完成后再返回上一个proceed嵌套,来到AspectJAfterAdvice,则开始执行这个advice的处理工作,即我们自定义的doAfter方法。再返回上一个proceed嵌套,来到MethodBeforeAdviceInterceptor,发现已经执行完毕继续返回上一个嵌套来到ExposeInvocationInterceptor,继续完成余下的工作,至此整个拦截过程就分析完毕了。在此过程中一个重要的参数就是我们配置的拦截器的顺序,顺序不同时执行过程就不一样,我们可以通过在xml配置中指定,下面附上我画的拦截器链的执行流程图。[/size]

[img]http://dl2.iteye.com/upload/attachment/0101/2557/6f7a57c4-9d1d-35a0-8743-456f2ba2cc00.png[/img]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值