您的位置:首页 > 运维架构

aop源码解析四-代理方法的调用

2017-07-27 21:03 513 查看
JdkDynamicAopProxy
实现了
InvocationHandler
接口 那么方法的实现我们看下
invoke
方法

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;

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.
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
}
else {
// 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);
}
}
}


实现
AfterThrowing``AfterReturning``After``Arond``Before
这些切面方法的调用是通过责任链来实现的 把这些切面方法组装成一个责任链 然后循环调用
AfterXXX
类切面是怎么实现在方法调用后实现的
Before
又是怎么实现在方法调用前调用的 是我们感兴趣的地方

构造责链

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;
}

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;
}


advised
是构造的
proxyFactory
对象
getInterceptorsAndDynamicInterceptionAdvice
方法把
method
作为缓存的key缓存
method
所对应的责任链 能够节省时间的开销

我们前面提到的那些切面都是
PointcutAdvisor
类型的切面 根据切点信息过滤 判断是否应该对该目标方法增强 最后返回的责任链大概是这样的


注意图中的切面的顺序 这是很重要一点 对于方法的执行时刻来说是至关重要的一点 这个顺序在寻找出
advisor
的时候就已经排好顺序了

如果责任链是空的就直接调用目标方法 如果非空的话 构造一个
ReflectiveMethodInvocation
对象 这个对象其实就是一个工具类(责任链对象) 是相关信息的封装 这样的实现能让方法看起来更简洁 看下
ReflectiveMethodInvocation
proceed
方法

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);
}
}


责任链的执行方式就是不断的调用责任链条中子节点的方法 同时把责任链对象自己传递进去 这样就可以在子节点方法中循环调用 使链条一个接一个的调用 一般通过下标的方式记录执行的子节点的位置 目标方法总是最后一个调用(可不是最后一个执行!!!) 这样可能就给读者一个困惑 目标方法最后一个调用 那么那些
afterxxx
切面是怎么实现的呢? 我们后面会介绍到

下面是切面所对应的
invoke
方法

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

//AfterReturningAdviceInterceptor
public Object invoke(MethodInvocation mi) throws Throwable {
Object retVal = mi.proceed();
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}

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

//AspectJAroundAdvice
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);
}

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


这是我按顺序列出的切面的调用 顺序为

AfterThrowing

AfterReturning

After

Around

Before

如果我们对一个方法加了这5个方法增强 那么我们来分析一下执行的流程:

AspectJAfterThrowingAdvice##invoke
用了
try{}catch(){}
的结构 看到这里是不是觉得有种焕然大悟的感觉 实现就是这么简单 在
try
结构体中调用责任链结构体的
proceed
方法 执行下一个方法 如果有异常抛出的话 会被
catch
结构体捕获到

AfterReturningAdviceInterceptor##invoke
方法先调用责任链结构体的
proceed
方法 执行下一个方法 剩下的方法入栈 直到
proceed
方法取到返回值的时候出栈继续执行 这样就解决了在方法返回后执行的问题 在取到目标方法返回值后调用
AfterReturningAdvice
afterReturning(xxx)
方法

public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
if (shouldInvokeOnReturnValueOf(method, returnValue)) {
invokeAdviceMethod(getJoinPointMatch(), returnValue, null);
}
}


AspectJAfterAdvice#invoke
方法用了
try{}finnally{}
结构体 在
try
结构体中继续调用下一个责任链的子节点 在
finally
结构体中调用增强方法

AspectJAroundAdvice##invoke
方法相对复杂一些 我们需要在方法的执行前后实现增强 那么责任链的执行就需要我们去推动 spring需要提供一些参数供我们使用 例如
ProceedingJoinPoint
ProceedingJoinPoint
构造方法中传递的是责任链结构体 这样就可以继续推动责任链的执行 而不会中断
AspectJAroundAdvice##invoke
方法实现中直接调用了增强方法 而不是像其他切面一样 在
invoke
方法中调用
mi.proceed(xxx)
方法 这样一来 环绕通知作用在目标方法前面的增强就早于前置通知执行 环绕增强方法中的调用的
proceed()
会让责任链向下一个节点执行 剩下的方法体入栈

MethodBeforeAdviceInterceptor#invoke
方法是在目标方法前执行的
invoke
方法先调用了切面增强方法然后再让责任链继续执行

如果只有这5个增强方法的话 那么
MethodBeforeAdviceInterceptor#invoke
方法体中
mi.proceed()
方法就执行到责任链的结束了 这个时候就会调用目标方法了 如果有异常的话 会被
AfterThrowing
通知捕获到

目标方法执行完就会执行环绕通知中的后半部分代码 环绕通知执行完就会执行
After
通知的
finally{}
结构体 执行后置通知增强 后置通知执行完就会执行
AfterReturning
入的剩余的方法体

这些就是代理方法的调用过程 也算是解决了心中的一个疑点 当然还有很大一部分内容没有涉及 例如方法参数的绑定等 就不再介绍了 干兴趣的可以自己debug探索
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  源码 aop spring sp