- 浏览: 236551 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
shuhucy:
必须赞啊,源码理解的很深,解决一个困扰两天的问题
Spring AOP源码分析(八)SpringAOP要注意的地方 -
sealinesu:
精彩
Spring事务源码分析(一)Spring事务入门 -
whlt20090509:
"WEB-INF/view目录下有一个简单的hell ...
SpringMVC源码总结(一)HandlerMapping和HandlerAdapter入门 -
hai0378:
兄台 算我一个,最近在研究dubbo motan 及 zk ...
ZooKeeper源码研究寻求小伙伴 -
zpkbtzmbw:
看懂了,原理
SpringMVC源码总结(五)Tomcat的URIEncoding、useBodyEncodingForURI和CharacterEncodingFilter
本篇文章将会介绍上一个例子中的源码执行情况,从中熟悉整个SpringAOP的一些概念和接口设计。
首先整个SpringAOP的分两大过程。
第一个过程:根据xml文件或者注解中配置的拦截信息,生成相应的代理对象,这个代理对象包含了对应的拦截器。
第二个过程:执行所拦截的方法时,就是调用代理对象的执行逻辑,完成各种拦截。
本文章先对第二个过程进行源码解析。
对第一个过程先做简单概述,如果拦截的类的对应方法是接口方法,则使用JDK的Proxy进行代理对象的创建否则使用CGLIB进行代理对象的创建。
本工程采用的之前文章所给出案例链接:http://www.iteye.com/topic/336873
简单概述如下:
拦截类:TestAspect
xml的配置:
建立单元测试类:
运行,效果如下:
接下来就是分析这一过程。
首先我们会看到:此时的AService不再是它的实现者AServiceImpl,而是一个代理对象。
由于barA()是接口方法,所以会选择使用JDK的Proxy进行代理对象的创建。如下在JdkDynamicAopProxy中:
来看下Proxy.newProxyInstance(classLoader, proxiedInterfaces, this)(详情见上一篇文章http://lgbolgger.iteye.com/blog/2117215)这个代码就是创建代理对象,第一个参数指定classLoader,第二个参数指定代理对象要实现的接口,第三个对象那个是InvocationHandler类型。来看下InvocationHandler:
一个代理对象和一个InvocationHandler绑定,当执行代理对象的方法时,就会去执行InvocationHandler的invoke(Object proxy, Method method, Object[] args)方法,在该方法中你可以选择相应的处理或者不执行代理对象的method方法。
JdkDynamicAopProxy继承了InvocationHandler,所以上文中在创建代理对象时传的参数是this,即这个代理对象的方法的执行拦截情况全部在JdkDynamicAopProxy的invoke(Object proxy, Method method, Object[] args)方法中。
我们先来了解下JdkDynamicAopProxy的一些属性:
最关键的就是这个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:
接口Advised:主要包含TargetSource和List<Advisor> advisors和List<Class<?>> interface
ProxyConfig:则是对要产生的代理对象的一些配置,如下:
其中proxyTargetClass:表示是否强制使用CGLIB进行代理对象的创建
exposeProxy :表示是否暴漏代理对象,实现线程内共享,这里又是使用ThreadLocal模式。
他们分别对应xml配置中的
继续回到AdvisedSupport ,对于它的List<Advisor> advisors则分别对应xml中的配置:
则产生的Advisor如下:每一个都是AspectJPointcutAdvisor对象,该对象所包含的内容如下:
分别和xml配置中的内容相对应,在xml中你还可以指定order值,用来排序,这个顺序关系到这些拦截方法的执行顺序,之后我们会详细分析这个拦截器链的执行情况。
如aop:before产生的AspectJPointcutAdvisor的AbstractAspectJAdvice 为AspectJMethodBeforeAdvice,Pointcut 为ComposablePointcut。具体的内容已在上文中接口说明中给出了说明。
至此xml中的配置对应到AdvisedSupport基本上简单的了解了,这些内容的创建都是为下文方法的拦截做准备。
下面继续回到JdkDynamicAopProxy,来看看拦截过程,即调用代理对象的方法,然后被拦截到代理对象的InvocationHandler的invoke方法,JdkDynamicAopProxy的invoke方法如下:
关注的重点1:this.advised.exposeProxy即我们在xml文件中所配置的<aop:config expose-proxy="false">。如果配置为true,默认false,则意味着在该线程内将会暴露proxy代理对象,实现共享,即在该线程中的任何地方都可以都可以取到proxy代理对象。具体是由ThreadLocal设计模式来实现的,可以见我的另一篇博客对ThreadLocal设计模式的分析(http://lgbolgger.iteye.com/blog/2117216),来看下AopContext:
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,实现过程如下:
上述过程分了三种情况来获取对应的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方法:
首先是判断advisor.getAdvice()是否已实现了MethodInterceptor,如AspectJAfterAdvice、AspectJAfterThrowingAdvice等。
然后又是利用适配器模式,将不用的advice封装成对应的MethodInterceptor。如MethodBeforeAdviceAdapter,默认硬编码注册了三个
看下MethodBeforeAdviceAdapter:
这就是典型的适配器模式,当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方法。如下:
关注的重点4: 有了拦截器链后,就构造一个ReflectiveMethodInvocation来完成这一个调用过程。
首先说下接口情况:ReflectiveMethodInvocation实现了ProxyMethodInvocation,ProxyMethodInvocation继承了MethodInvocation,
MethodInvocation继承了Invocation,
Invocation继承了Joinpoint,此时的Joinpoint是AOP联盟定义的接口。
aspectj也有一个类似的JoinPoint,这两个是不一样的。
Joinpoint:能够得到目标对象,同时指定了对目标对象的处理方法
Invocation:能够获取方法参数,此时方法可以是构造方法也可以是一般方法
MethodInvocation:能够获取方法而不是构造方法,ConstructorInvocation才是获取构造方法,所以有了MethodInvocation就可以执行目标对象的方法了。
ProxyMethodInvocation:能够获取代理代理对象,这个在Around通知时发挥作用,稍后会看到。
此时ReflectiveMethodInvocation就拥有以下数据:
interceptorsAndDynamicMethodMatchers则是由重点2中得出的拦截器链传给ReflectiveMethodInvocation的。然后看下ReflectiveMethodInvocation作为一个Joinpoint的proceed方法的执行过程:
首先就是this.currentInterceptorIndex,它是ReflectiveMethodInvocation的一个属性,从-1开始:
当currentInterceptorIndex达到this.interceptorsAndDynamicMethodMatchers.size() - 1时,拦截器链执行完毕了,就去执行目标对象的方法。invokeJoinpoint()方法就是上文我们所说的通过反射进行目标方法的调用。
继续看,拿出一个interceptorOrInterceptionAdvice,判断它是不是InterceptorAndDynamicMethodMatcher类型,这个类型在获取拦截器链的时候遇见了,我们再次回顾下:
因为InterceptorAndDynamicMethodMatcher的MethodMatcher是可变的,所以在执行前仍要进行判断一次,符合的话就执行InterceptorAndDynamicMethodMatcher中所包含的MethodInterceptor。不符合的话跳过本次拦截器,继续执行下一个拦截器。
当拦截器是MethodInterceptor,则是执行这个拦截器。
然后我们来看下具体有哪些拦截器链,以及具体是怎样的执行过程:
我们会看到会有如下5个拦截器,依次是:
ExposeInvocationInterceptor、MethodBeforeAdviceInterceptor、AspectJAfterAdvice、AspectJAroundAdvice、AspectJAfterThrowingAdvice。
首先看第一个ExposeInvocationInterceptor:
它是Spring自动帮我们添加的,它不属于InterceptorAndDynamicMethodMatcher类型,即不再进行判断是否符合当前函数。
看下它的invoke方法的内容:
其中MethodInvocation mi始终是刚创建的ReflectiveMethodInvocation对象,它包含了一切要执行的信息。invocation则是一个ThreadLocal类型,如下:
这里使用了ThreadLocal模式,将ReflectiveMethodInvocation对象这一重要对象存进当前线程的map集合中(ThreadLocal模式参见 http://lgbolgger.iteye.com/blog/2117216),实现线程内ReflectiveMethodInvocation对象这一重要数据的共享,这就意味着我们在自定义的advice中可以通过invocation来获取ReflectiveMethodInvocation对象这一重要数据。
同时ExposeInvocationInterceptor的currentInvocation方法用于获取当前线程的ReflectiveMethodInvocation对象
ExposeInvocationInterceptor即分析完了,此时ExposeInvocationInterceptor的invoke函数还没有执行完毕,然后就嵌套执行ReflectiveMethodInvocation对象的proceed方法,
获取下一个拦截器MethodBeforeAdviceInterceptor,并且判断类型也属于InterceptorAndDynamicMethodMatcher类型的(我们自定义的几个都不属于),
和ExposeInvocationInterceptor一样,直接执行,看下MethodBeforeAdviceInterceptor的invoke函数:
先会执行我们在xml文件中配置好的advice,即我们自定义的doBefore方法,这就是前置通知。然后继续嵌套执行ReflectiveMethodInvocation对象的proceed方法,轮到了AspectJAfterAdvice的invoke方法:
它的执行顺序则是先去执行后面的内容,当都执行完毕了才返回来执行这个advice。这就是后置通知。继续嵌套执行ReflectiveMethodInvocation对象的proceed方法,来到了AspectJAroundAdvice的invoke方法:
lazyGetProceedingJoinPoint(pmi)就是将ReflectiveMethodInvocation对象作为一个ProxyMethodInvocation封装成一个MethodInvocationProceedingJoinPoint,如下:
这个就是环绕通知,我们看下这通知我们所写的具体内容:
这里面有一个很重要的信息ProceedingJoinPoint pjp,它决定了ReflectiveMethodInvocation的执行链是否继续执行下去,所以pjp.proceed()的本质仍然是调用ReflectiveMethodInvocation的proceed()方法,来继续下面拦截器的执行,也可以选择不执行,则拦截器链的执行就会终止了,会从不断嵌套的proceed函数中不断返回。
这里将会执行到我们自定义的上面的doAround方法,当执行到pjp.proceed()时,又会返还到
ReflectiveMethodInvocation的proceed()执行下一个拦截器,来到AspectJAfterThrowingAdvice,它的invoke方法为:
即先执行后面的拦截器,但后面的拦截器执行过程中出现异常时才会发挥该拦截器的作用。继续执行后面的拦截器,发现已经没了,则终于轮到目标对象的方法了,目标方法执行完毕后,返回上一个proceed的嵌套即AspectJAfterThrowingAdvice的invoke方法,发现没有抛出异常,则继续返回到上一个proceed嵌套,即AspectJAroundAdvice,即我们自定义的doAround中这一行代码Object retVal = pjp.proceed()返回了,继续完成我们自定义的doAround函数,完成后再返回上一个proceed嵌套,来到AspectJAfterAdvice,则开始执行这个advice的处理工作,即我们自定义的doAfter方法。再返回上一个proceed嵌套,来到MethodBeforeAdviceInterceptor,发现已经执行完毕继续返回上一个嵌套来到ExposeInvocationInterceptor,继续完成余下的工作,至此整个拦截过程就分析完毕了。在此过程中一个重要的参数就是我们配置的拦截器的顺序,顺序不同时执行过程就不一样,我们可以通过在xml配置中指定,下面附上我画的拦截器链的执行流程图。
首先整个SpringAOP的分两大过程。
第一个过程:根据xml文件或者注解中配置的拦截信息,生成相应的代理对象,这个代理对象包含了对应的拦截器。
第二个过程:执行所拦截的方法时,就是调用代理对象的执行逻辑,完成各种拦截。
本文章先对第二个过程进行源码解析。
对第一个过程先做简单概述,如果拦截的类的对应方法是接口方法,则使用JDK的Proxy进行代理对象的创建否则使用CGLIB进行代理对象的创建。
本工程采用的之前文章所给出案例链接:http://www.iteye.com/topic/336873
简单概述如下:
拦截类:TestAspect
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>
建立单元测试类:
@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(); } }
运行,效果如下:
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
接下来就是分析这一过程。
首先我们会看到:此时的AService不再是它的实现者AServiceImpl,而是一个代理对象。
由于barA()是接口方法,所以会选择使用JDK的Proxy进行代理对象的创建。如下在JdkDynamicAopProxy中:
@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); }
来看下Proxy.newProxyInstance(classLoader, proxiedInterfaces, this)(详情见上一篇文章http://lgbolgger.iteye.com/blog/2117215)这个代码就是创建代理对象,第一个参数指定classLoader,第二个参数指定代理对象要实现的接口,第三个对象那个是InvocationHandler类型。来看下InvocationHandler:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
一个代理对象和一个InvocationHandler绑定,当执行代理对象的方法时,就会去执行InvocationHandler的invoke(Object proxy, Method method, Object[] args)方法,在该方法中你可以选择相应的处理或者不执行代理对象的method方法。
JdkDynamicAopProxy继承了InvocationHandler,所以上文中在创建代理对象时传的参数是this,即这个代理对象的方法的执行拦截情况全部在JdkDynamicAopProxy的invoke(Object proxy, Method method, Object[] args)方法中。
我们先来了解下JdkDynamicAopProxy的一些属性:
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable { /** Config used to configure this proxy */ private final AdvisedSupport advised; private boolean equalsDefined; private boolean hashCodeDefined; //略 }
最关键的就是这个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:
public class AdvisedSupport extends ProxyConfig implements Advised
接口Advised:主要包含TargetSource和List<Advisor> advisors和List<Class<?>> interface
ProxyConfig:则是对要产生的代理对象的一些配置,如下:
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; }
其中proxyTargetClass:表示是否强制使用CGLIB进行代理对象的创建
exposeProxy :表示是否暴漏代理对象,实现线程内共享,这里又是使用ThreadLocal模式。
他们分别对应xml配置中的
<aop:config expose-proxy="false" proxy-target-class="false"> </aop:config>
继续回到AdvisedSupport ,对于它的List<Advisor> advisors则分别对应xml中的配置:
<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"/>
则产生的Advisor如下:每一个都是AspectJPointcutAdvisor对象,该对象所包含的内容如下:
private final AbstractAspectJAdvice advice; private final Pointcut pointcut; private Integer order;
分别和xml配置中的内容相对应,在xml中你还可以指定order值,用来排序,这个顺序关系到这些拦截方法的执行顺序,之后我们会详细分析这个拦截器链的执行情况。
如aop:before产生的AspectJPointcutAdvisor的AbstractAspectJAdvice 为AspectJMethodBeforeAdvice,Pointcut 为ComposablePointcut。具体的内容已在上文中接口说明中给出了说明。
至此xml中的配置对应到AdvisedSupport基本上简单的了解了,这些内容的创建都是为下文方法的拦截做准备。
下面继续回到JdkDynamicAopProxy,来看看拦截过程,即调用代理对象的方法,然后被拦截到代理对象的InvocationHandler的invoke方法,JdkDynamicAopProxy的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; //我们关注的重点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); } } }
关注的重点1:this.advised.exposeProxy即我们在xml文件中所配置的<aop:config expose-proxy="false">。如果配置为true,默认false,则意味着在该线程内将会暴露proxy代理对象,实现共享,即在该线程中的任何地方都可以都可以取到proxy代理对象。具体是由ThreadLocal设计模式来实现的,可以见我的另一篇博客对ThreadLocal设计模式的分析(http://lgbolgger.iteye.com/blog/2117216),来看下AopContext:
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; }
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,实现过程如下:
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; }
上述过程分了三种情况来获取对应的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方法:
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()]); }
首先是判断advisor.getAdvice()是否已实现了MethodInterceptor,如AspectJAfterAdvice、AspectJAfterThrowingAdvice等。
然后又是利用适配器模式,将不用的advice封装成对应的MethodInterceptor。如MethodBeforeAdviceAdapter,默认硬编码注册了三个
public DefaultAdvisorAdapterRegistry() { registerAdvisorAdapter(new MethodBeforeAdviceAdapter()); registerAdvisorAdapter(new AfterReturningAdviceAdapter()); registerAdvisorAdapter(new ThrowsAdviceAdapter()); }
看下MethodBeforeAdviceAdapter:
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); } }
这就是典型的适配器模式,当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方法。如下:
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); } //略 }
关注的重点4: 有了拦截器链后,就构造一个ReflectiveMethodInvocation来完成这一个调用过程。
首先说下接口情况:ReflectiveMethodInvocation实现了ProxyMethodInvocation,ProxyMethodInvocation继承了MethodInvocation,
MethodInvocation继承了Invocation,
Invocation继承了Joinpoint,此时的Joinpoint是AOP联盟定义的接口。
aspectj也有一个类似的JoinPoint,这两个是不一样的。
Joinpoint:能够得到目标对象,同时指定了对目标对象的处理方法
//定义了一个proceed()方法,来处理这些拦截器链的调用过程 Object proceed() throws Throwable; //返回目标对象,针对本工程就是AServiceImpl Object getThis();
Invocation:能够获取方法参数,此时方法可以是构造方法也可以是一般方法
Object[] getArguments();
MethodInvocation:能够获取方法而不是构造方法,ConstructorInvocation才是获取构造方法,所以有了MethodInvocation就可以执行目标对象的方法了。
Method getMethod();
ProxyMethodInvocation:能够获取代理代理对象,这个在Around通知时发挥作用,稍后会看到。
Object getProxy();
此时ReflectiveMethodInvocation就拥有以下数据:
protected final Object proxy; protected final Object target; protected final Method method; protected Object[] arguments; private final Class<?> targetClass; protected final List<?> interceptorsAndDynamicMethodMatchers;
interceptorsAndDynamicMethodMatchers则是由重点2中得出的拦截器链传给ReflectiveMethodInvocation的。然后看下ReflectiveMethodInvocation作为一个Joinpoint的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); } }
首先就是this.currentInterceptorIndex,它是ReflectiveMethodInvocation的一个属性,从-1开始:
private int currentInterceptorIndex = -1;
当currentInterceptorIndex达到this.interceptorsAndDynamicMethodMatchers.size() - 1时,拦截器链执行完毕了,就去执行目标对象的方法。invokeJoinpoint()方法就是上文我们所说的通过反射进行目标方法的调用。
继续看,拿出一个interceptorOrInterceptionAdvice,判断它是不是InterceptorAndDynamicMethodMatcher类型,这个类型在获取拦截器链的时候遇见了,我们再次回顾下:
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)); } } } } //略
因为InterceptorAndDynamicMethodMatcher的MethodMatcher是可变的,所以在执行前仍要进行判断一次,符合的话就执行InterceptorAndDynamicMethodMatcher中所包含的MethodInterceptor。不符合的话跳过本次拦截器,继续执行下一个拦截器。
当拦截器是MethodInterceptor,则是执行这个拦截器。
然后我们来看下具体有哪些拦截器链,以及具体是怎样的执行过程:
我们会看到会有如下5个拦截器,依次是:
ExposeInvocationInterceptor、MethodBeforeAdviceInterceptor、AspectJAfterAdvice、AspectJAroundAdvice、AspectJAfterThrowingAdvice。
首先看第一个ExposeInvocationInterceptor:
它是Spring自动帮我们添加的,它不属于InterceptorAndDynamicMethodMatcher类型,即不再进行判断是否符合当前函数。
看下它的invoke方法的内容:
public Object invoke(MethodInvocation mi) throws Throwable { MethodInvocation oldInvocation = invocation.get(); invocation.set(mi); try { return mi.proceed(); } finally { invocation.set(oldInvocation); } }
其中MethodInvocation mi始终是刚创建的ReflectiveMethodInvocation对象,它包含了一切要执行的信息。invocation则是一个ThreadLocal类型,如下:
private static final ThreadLocal<MethodInvocation> invocation = new NamedThreadLocal<MethodInvocation>("Current AOP method invocation");
这里使用了ThreadLocal模式,将ReflectiveMethodInvocation对象这一重要对象存进当前线程的map集合中(ThreadLocal模式参见 http://lgbolgger.iteye.com/blog/2117216),实现线程内ReflectiveMethodInvocation对象这一重要数据的共享,这就意味着我们在自定义的advice中可以通过invocation来获取ReflectiveMethodInvocation对象这一重要数据。
同时ExposeInvocationInterceptor的currentInvocation方法用于获取当前线程的ReflectiveMethodInvocation对象
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; }
ExposeInvocationInterceptor即分析完了,此时ExposeInvocationInterceptor的invoke函数还没有执行完毕,然后就嵌套执行ReflectiveMethodInvocation对象的proceed方法,
获取下一个拦截器MethodBeforeAdviceInterceptor,并且判断类型也属于InterceptorAndDynamicMethodMatcher类型的(我们自定义的几个都不属于),
和ExposeInvocationInterceptor一样,直接执行,看下MethodBeforeAdviceInterceptor的invoke函数:
public Object invoke(MethodInvocation mi) throws Throwable { this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() ); return mi.proceed(); }
先会执行我们在xml文件中配置好的advice,即我们自定义的doBefore方法,这就是前置通知。然后继续嵌套执行ReflectiveMethodInvocation对象的proceed方法,轮到了AspectJAfterAdvice的invoke方法:
@Override public Object invoke(MethodInvocation mi) throws Throwable { try { return mi.proceed(); } finally { invokeAdviceMethod(getJoinPointMatch(), null, null); } }
它的执行顺序则是先去执行后面的内容,当都执行完毕了才返回来执行这个advice。这就是后置通知。继续嵌套执行ReflectiveMethodInvocation对象的proceed方法,来到了AspectJAroundAdvice的invoke方法:
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); }
lazyGetProceedingJoinPoint(pmi)就是将ReflectiveMethodInvocation对象作为一个ProxyMethodInvocation封装成一个MethodInvocationProceedingJoinPoint,如下:
public MethodInvocationProceedingJoinPoint(ProxyMethodInvocation methodInvocation) { Assert.notNull(methodInvocation, "MethodInvocation must not be null"); this.methodInvocation = methodInvocation; }
这个就是环绕通知,我们看下这通知我们所写的具体内容:
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; }
这里面有一个很重要的信息ProceedingJoinPoint pjp,它决定了ReflectiveMethodInvocation的执行链是否继续执行下去,所以pjp.proceed()的本质仍然是调用ReflectiveMethodInvocation的proceed()方法,来继续下面拦截器的执行,也可以选择不执行,则拦截器链的执行就会终止了,会从不断嵌套的proceed函数中不断返回。
这里将会执行到我们自定义的上面的doAround方法,当执行到pjp.proceed()时,又会返还到
ReflectiveMethodInvocation的proceed()执行下一个拦截器,来到AspectJAfterThrowingAdvice,它的invoke方法为:
public Object invoke(MethodInvocation mi) throws Throwable { try { return mi.proceed(); } catch (Throwable t) { if (shouldInvokeOnThrowing(t)) { invokeAdviceMethod(getJoinPointMatch(), null, t); } throw t; } }
即先执行后面的拦截器,但后面的拦截器执行过程中出现异常时才会发挥该拦截器的作用。继续执行后面的拦截器,发现已经没了,则终于轮到目标对象的方法了,目标方法执行完毕后,返回上一个proceed的嵌套即AspectJAfterThrowingAdvice的invoke方法,发现没有抛出异常,则继续返回到上一个proceed嵌套,即AspectJAroundAdvice,即我们自定义的doAround中这一行代码Object retVal = pjp.proceed()返回了,继续完成我们自定义的doAround函数,完成后再返回上一个proceed嵌套,来到AspectJAfterAdvice,则开始执行这个advice的处理工作,即我们自定义的doAfter方法。再返回上一个proceed嵌套,来到MethodBeforeAdviceInterceptor,发现已经执行完毕继续返回上一个嵌套来到ExposeInvocationInterceptor,继续完成余下的工作,至此整个拦截过程就分析完毕了。在此过程中一个重要的参数就是我们配置的拦截器的顺序,顺序不同时执行过程就不一样,我们可以通过在xml配置中指定,下面附上我画的拦截器链的执行流程图。
发表评论
-
Spring AOP源码分析(八)SpringAOP要注意的地方
2014-10-01 10:00 4471SpringAOP要注意的地方有很多,下面就举一个,之后想到了 ... -
Spring AOP源码分析(七)ProxyFactoryBean介绍
2014-09-28 22:03 3281这篇文章里面就要说说Spring自己的AOP,搞清楚哪种方式是 ... -
aspectj的AOP基础知识
2014-09-27 09:26 0aspectj的AOP基础知识 -
Spring AOP源码分析(六)Spring AOP配置的背后
2014-09-27 11:39 3056本篇文章主要对Spring AOP配置背后进行了哪些事情做下说 ... -
Spring AOP源码分析(五)Spring AOP的Cglib代理
2014-09-24 06:48 4282上一篇文章介绍了Spring AOP的JDK动态代理的过程,这 ... -
IntroductionAdvisor
2014-09-18 09:43 0IntroductionAdvisor asdcfs -
Spring AOP源码分析(二)JDK动态代理和CGLIB介绍
2014-09-21 07:07 3035本篇是介绍java实现代理对象的两种方法,JDK动态代理和CG ... -
Spring AOP源码分析(三)Spring AOP中的一些基本接口及其概念
2014-09-22 07:40 3867本文章对一些SpringAOP的 ... -
Spring AOP源码分析(一)AOP介绍和aspectj、SpringAOP入门
2014-09-14 10:10 3824首先说说三个名词,面向对象、面向接口编程、面向切面编程(Asp ...
相关推荐
现在让我们深入探讨JDK动态代理和Spring AOP的原理。 首先,JDK动态代理基于Java的反射机制,通过`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口来实现。Proxy类用于创建一个代理对象,...
在Spring中,AOP主要通过两种动态代理技术实现:JDK动态代理和CGLIB动态代理。 首先,让我们详细了解一下JDK动态代理。JDK动态代理基于Java的接口实现,它适用于目标对象实现了至少一个接口的情况。在运行时,JDK...
在Spring AOP的源码中,`org.springframework.aop.framework.ProxyFactoryBean`是创建代理的主要类,它会根据目标类是否有接口选择JDK动态代理或CGLIB。`org.aopalliance.intercept.MethodInterceptor`接口定义了...
哪怕没有看过源码的同学也应该知道,AOP是通过动态代理实现的,动态代理又分为两个部分:JDK动态代理和CGLIB动态代理 确实,Spring也就是通过这两种方式来实现AOP相关功能,下面就通过源码来简单求证下
Spring AOP使用两种主要的代理技术:JDK动态代理和CGLIB动态代理。JDK动态代理适用于接口的场景,而CGLIB则用于没有实现接口的情况。在这两种情况下,代理对象都会持有目标对象的引用,并在其上调用方法。具体来说:...
本篇将详细讲解Spring中的AOP实现,特别是JDK动态代理的应用。 首先,我们要了解什么是AOP(Aspect Oriented Programming,面向切面编程)。AOP是一种编程范式,旨在解决应用程序中分散的、横切关注点的问题,如...
Spring AOP支持不同的代理策略,包括JDK动态代理和CGLIB代理。如果被代理的类没有实现接口,Spring AOP会采用CGLIB来生成代理对象。CGLIB(Code Generation Library)是一个开源的代码生成库,它允许运行时在内存中...
Spring AOP基于代理实现,可以使用接口代理(JDK动态代理)或类代理(CGLIB)。 7. CGLIB: CGLIB是Spring AOP默认的代理库,用于生成目标类的子类,从而实现方法拦截。当目标类没有实现接口时,Spring会使用CGLIB...
本篇将详细探讨JDK动态代理和Spring AOP,以及它们在实际应用中的作用。 首先,JDK动态代理是Java提供的一种在运行时创建代理对象的技术。它允许我们在不修改原有类的基础上,为已有接口添加额外的功能。动态代理的...
在 Spring 中,AOP 的实现主要依赖于代理模式,有两种代理方式:JDK 动态代理和 CGLIB 动态代理。 JDK 动态代理是基于接口的,它要求被代理的目标对象必须实现至少一个接口。Spring 使用 `java.lang.reflect.Proxy`...
- 分析JDK动态代理的源码,可以了解其内部如何生成代理类和调用处理程序的工作机制。 - Spring AOP的源码解析有助于理解其是如何创建代理、匹配切点并执行相应通知的过程。 5. **工具应用**: - JDK动态代理和...
Spring AOP 的底层实现技术 --- Jdk 动态代理原理 JDK 动态代理是 Spring AOP 的底层实现技术,允许开发者在运行期创建接口的代理实例。在 JDK 1.3 以后,JDK 动态代理技术提供了实现 AOP 的绝好底层技术。JDK 动态...
代理则是Spring AOP用来实现切面功能的对象,它可以是JDK动态代理或CGLIB代理。 Spring AOP的实现主要基于两种代理:JDK动态代理和CGLIB代理。JDK动态代理适用于实现了接口的类,它通过反射创建一个代理类来实现...
动态代理则是Spring AOP实现的核心技术之一,它允许我们在运行时创建具有额外行为的对象。下面将详细阐述Spring AOP的配置以及动态代理的实现。 一、Spring AOP基础知识 1. **什么是AOP**:AOP是一种编程范式,...
Java流行框架源码分析:Spring源码、SpringBoot源码、SpringAOP源码、SpringSecurity源码、SpringSecurity OAuth2源码、JDK源码、Netty源码
有两种代理类型:JDK动态代理和CGLIB代理。前者用于接口,后者用于无接口的类。 九、源码解析 Spring AOP的源码主要集中在`org.springframework.aop`和`org.springframework.aop.framework`两个包下。`org.spring...
Spring 框架中 JDK 动态代理和 CGLIB 动态代理是 Spring AOP 中一个非常重要的知识点。Spring AOP 框架会根据实际情况选择使用 JDK 的动态代理还是 CGLIB 的动态代理。 JDK 动态代理是 Java 自带的动态代理机制,它...
Spring AOP提供了两种代理方式:JDK动态代理和CGLIB代理。JDK动态代理用于目标对象实现接口的情况,而CGLIB代理则用于目标对象没有实现接口的情况。Spring默认使用JDK动态代理,但如果目标对象没有实现接口,它会...
2. **动态代理**:Spring AOP 的默认代理方式是动态代理,它包括JDK动态代理和CGLIB代理。当目标对象实现了至少一个接口时,Spring将使用JDK的动态代理机制。JDK动态代理通过实现InvocationHandler接口,并在运行时...
JDK代理适用于那些实现了接口的类,而CGLIB代理则适用于没有实现接口的类。 引介(Introduction)是Spring AOP的一个特性,允许在通知对象中声明并实现它们原本未实现的额外接口。通过`@DeclareParents`注解可以...