aop源码解析四-代理方法的调用
来源:互联网 发布:suse 软件源 编辑:程序博客网 时间:2024/06/08 08:00
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
方法
//AspectJAfterThrowingAdvicepublic Object invoke(MethodInvocation mi) throws Throwable { try { return mi.proceed(); } catch (Throwable t) { if (shouldInvokeOnThrowing(t)) { invokeAdviceMethod(getJoinPointMatch(), null, t); } throw t; } }//AfterReturningAdviceInterceptorpublic Object invoke(MethodInvocation mi) throws Throwable { Object retVal = mi.proceed(); this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis()); return retVal; }//AspectJAfterAdvicepublic 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源码解析四-代理方法的调用
- AOP代理类中调用带有annotation的私有方法
- AOP源码解析(四)寻找匹配的增强器
- AOP源码解析(五)获取代理
- aop源码解析辅助-jdk动态代理
- AOP源码解析(二)创建AOP代理
- Spring源码分析----建立AopProxy代理对象和AOP拦截器的调用
- Spring AOP代理机制以及方法调用在同一个类的另一个方法的问题
- AOP 动态代理 的 源码分析
- Spring源码解析之四 ------ AOP原理和源码分析
- AOP源码解析(一)实现动态代理
- spring 源码探索 -- aop 标签解析和创建代理
- Spring AOP:被代理类的构造函数和调用自身类方法的注意点
- Spring基于注解形式的 AOP的原理流程及源码解析(四)
- spring AOP中自身方法调用无法应用代理解决办法
- spring 代理对象方法增强源码解析
- Castle AOP 系列(二):对接口方法调用的拦截(有源码)
- Castle AOP 系列(一):对类方法调用的拦截(有源码)
- C++中的多态和多态对象模型
- 报错修改:Tomcat version 7.0 only supports J2EE 1.2, 1.3, 1.4, and Java EE 5 and 6 Web
- 二进制枚举的实现
- 蓝桥杯 算法训练—— 最大乘积问题
- 一种新的单片机调试方法
- aop源码解析四-代理方法的调用
- 《Drools7.0.0.Final规则引擎教程》第4章 4.3 日历
- Java Heap
- hihocoder1181(fleury)
- aop源码解析辅助-jdk动态代理
- 处理大并发之五 使用libevent利器bufferevent
- python_反射
- 网口扫盲三:以太网芯片MAC和PHY的关系
- centos7 网卡配置及bond配置