我们看看在Spring AOP中拦截器链是怎样被调用的,也就是Proxy模式是怎样起作用的,或者说Spring是怎样为我们提供AOP功能的;
在JdkDynamicAopProxy中生成Proxy对象的时候:
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
这里的this参数对应的是InvocationHandler对象,这里我们的JdkDynamicAopProxy实现了这个接口,也就是说当Proxy对象的函数被调用的时候,这个InvocationHandler的invoke方法会被作为回调函数调用,下面我们看看这个方法的实现:
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 { // Try special rules for equals() method and implementation of the // Advised AOP configuration interface. if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) { // What if equals throws exception!? // This class implements the equals(Object) method itself. return equals(args[0]) ? Boolean.TRUE : Boolean.FALSE; } if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) { // This class implements the hashCode() method itself. return new Integer(hashCode()); } if (Advised.class == method.getDeclaringClass()) { // service invocations on ProxyConfig with the proxy config return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args); } Object retVal = null; if (this.advised.exposeProxy) { // make invocation available if necessary oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true; } // May be <code>null</code>. Get as late as possible to minimize the time we "own" the target, // in case it comes from a pool. // 这里是得到目标对象的地方,当然这个目标对象可能来自于一个实例池或者是一个简单的JAVA对象 target = targetSource.getTarget(); if (target != null) { targettargetClass = target.getClass(); } // get the interception chain for this method // 这里获得定义好的拦截器链 List chain = this.advised.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice( this.advised, proxy, 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 = advised.getMethodInvocationFactory().getMethodInvocation( // proxy, method, targetClass, target, args, chain, advised); // 如果有拦截器的设定,那么需要调用拦截器之后才调用目标对象的相应方法 // 这里通过构造一个ReflectiveMethodInvocation来实现,下面我们会看这个ReflectiveMethodInvocation类 invocation = new ReflectiveMethodInvocation( proxy, target, method, args, targetClass, chain); // proceed to the joinpoint through the interceptor chain // 这里通过ReflectiveMethodInvocation来调用拦截器链和相应的目标方法 retVal = invocation.proceed(); } // massage return value if necessary if (retVal != null && retVal == target && method.getReturnType().isInstance(proxy)) { // 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; } return retVal; } finally { if (target != null && !targetSource.isStatic()) { // must have come from TargetSource targetSource.releaseTarget(target); } if (setProxyContext) { // restore old proxy AopContext.setCurrentProxy(oldProxy); } } }
我们先看看目标对象方法的调用,这里是通过AopUtils的方法调用 - 使用反射机制来对目标对象的方法进行调用:
public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args) throws Throwable { // Use reflection to invoke the method. // 利用放射机制得到相应的方法,并且调用invoke try { if (!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers())) { method.setAccessible(true); } return method.invoke(target, args); } catch (InvocationTargetException ex) { // Invoked method threw a checked exception. // We must rethrow it. The client won't see the interceptor. throw ex.getTargetException(); } catch (IllegalArgumentException ex) { throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" + method + "] on target [" + target + "]", ex); } catch (IllegalAccessException ex) { throw new AopInvocationException("Couldn't access method: " + method, ex); } }
对拦截器链的调用处理是在ReflectiveMethodInvocation里实现的:
public Object proceed() throws Throwable { // We start with an index of -1 and increment early. // 这里直接调用目标对象的方法,没有拦截器的调用或者拦截器已经调用完了,这个currentInterceptorIndex的初始值是0 if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size()) { 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. // 这里获得相应的拦截器,如果拦截器可以匹配的上的话,那就调用拦截器的invoke方法 InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) { return dm.interceptor.invoke(nextInvocation()); } else { // Dynamic matching failed. // Skip this interceptor and invoke the next in the chain. // 如果拦截器匹配不上,那就调用下一个拦截器,这个时候拦截器链的位置指示后移并迭代调用当前的proceed方法 this.currentInterceptorIndex++; 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(nextInvocation()); } }
这里把当前的拦截器链以及在拦截器链的位置标志都clone到一个MethodInvocation对象了,作用是当前的拦截器执行完之后,会继续沿着得到这个拦截器链执行下面的拦截行为,也就是会迭代的调用上面这个proceed:
private ReflectiveMethodInvocation nextInvocation() throws CloneNotSupportedException { ReflectiveMethodInvocation invocation = (ReflectiveMethodInvocation) clone(); invocation.currentInterceptorIndex = this.currentInterceptorIndex + 1; invocation.parent = this; return invocation; }
这里的nextInvocation就已经包含了当前的拦截链的基本信息,我们看到在Interceptor中的实现比如TransactionInterceptor的实现中:
public Object invoke(final MethodInvocation invocation) throws Throwable { ......//这里是TransactionInterceptor插入的事务处理代码,我们会在后面分析事务处理实现的时候进行分析 try { //这里是对配置的拦截器链进行迭代处理的调用 retVal = invocation.proceed(); } ......//省略了和事务处理的异常处理代码 ,也是TransactionInterceptor插入的处理 else { try { Object result = ((CallbackPreferringPlatformTransactionManager) getTransactionManager()).execute(txAttr, new TransactionCallback() { public Object doInTransaction(TransactionStatus status) { //这里是TransactionInterceptor插入对事务处理的代码 TransactionInfo txInfo = prepareTransactionInfo(txAttr, joinpointIdentification, status); //这里是对配置的拦截器链进行迭代处理的调用,接着顺着拦截器进行处理 try { return invocation.proceed(); } ......//省略了和事务处理的异常处理代码 ,也是TransactionInterceptor插入的处理 } 从上面的分析我们看到了Spring AOP的基本实现,比如Spring怎样得到Proxy,怎样利用JAVA Proxy以及反射机制对用户定义的拦截器链进行处理。
相关推荐
Spring-Aop源码实现
Java spring AOP源码
一、适合人群 1、具备一定Java编程基础,初级开发者 ...(需要知道原理的请看spring aop源码,此处不做赘述) 3、可在现有源码上快速进行功能扩展 4、spring boot,mybatis,druid,spring aop的使用
Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。Spring AOP:通过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理的任何对象...
AOP流程源码分析-SpringAOP中定义的类图AOP流程源码分析-SpringAOP中定义的类图AOP流程源码分析-SpringAOP中定义的类图AOP流程源码分析-SpringAOP中定义的类图AOP流程源码分析-SpringAOP中定义的类图AOP流程源码分析...
1.Spring入门和IOC介绍 2.对象依赖 3.AOP入门 4.JDBCTemplate和Spring事务 5.Spring事务原理 6.Spring事务的一个线程安全问题 7.IOC再回顾和面试题 8.AOP再回顾
下面我们接着来看AOP的源码实现。 有关于AOP,我们在面试中也被无数次问到,AOP是什么?AOP有什么作用与优势?AOP在项目中是如何用到的? 这些还都是比较简单的,有些可能会问你AOP的实现是怎样的? 哪怕...
Spring AOP(面向切面编程)作为Spring框架的一个重要部分,为Java开发者提供了一个...通过对Spring AOP源码的深入分析,我们可以更好地理解其内部工作原理,从而在实际开发中更加灵活和高效地使用这一强大的编程范式。
spring aop 源码解析
Java流行框架源码分析:Spring源码、SpringBoot源码、SpringAOP源码、SpringSecurity源码、SpringSecurity OAuth2源码、JDK源码、Netty源码
NULL 博文链接:https://zhang-yingjie-qq-com.iteye.com/blog/319927
Spring AOP源码笔记
Spring AOP实现,项目源码,Myeclipse直接导入可用,本人根据教程编写,测试通过。
Spring Aop 源码流程.doc
Spring源码最难问题:当Spring AOP遇上循环依赖.docx
spring-aop 源码电子书,本人根据spring-aop的源码整理生成的pdf ,方便在kindle上阅读
Spring Aop 引用 源码
spring-aop-4.2.4.RELEASE-sources.jar;spring框架源码
本文深入分析了Spring AOP的实现机制,让读者能够更好地理解和应用这一强大的编程范式。 Spring AOP是基于代理模式实现的,主要包括动态代理、通知(Advice)、切点(Pointcut)、切面(Aspect)和连接点(Join ...
spring AOP源码解读以及对应代码的解说