1.Spring AOP源码分析(三)
1.JDK
如果创建的是JdkDynamicAopProxy,那么当执行目标类的时候,会进入到JdkDynamicAopProxy#invoke。因为JdkDynamicAopProxy本身也是一个InvocationHandler,并实现了invoke方法。
org.springframework.aop.framework.JdkDynamicAopProxy#invoke:
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;
//1.获取目标源
TargetSource targetSource = this.advised.targetSource;
Class<?> targetClass = null;
Object target = null;
try {
//2.目标类如果没有实现equals或hashCode,则调用代理类实现的
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
return hashCode();
}
//3.可能有多层代理,返回真正的目标类
else if (method.getDeclaringClass() == DecoratingProxy.class) {
return AopProxyUtils.ultimateTargetClass(this.advised);
}
//4.直接通过反射执行方法
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
//5.如果expose-proxy为true,则暴露代理对象
if (this.advised.exposeProxy) {
//向AopContext中设置当前代理对象,可以通过AopContext.currentProxy调用
//可解决某个类中一个方法调用另一个方法,无法执行拦截的问题
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
//6.获取目标对象
target = targetSource.getTarget();
if (target != null) {
targetClass = target.getClass();
}
//7.获取适合当前方法的拦截器,通过ClassFilter和MethodMatcher进行匹配,然后缓存,下次直接从缓存中获取
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
//8.如果拦截器为空,则直接执行目标方法
if (chain.isEmpty()) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
//通过反射执行目标方法
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
//9.创建一个方法调用器,并将拦截器链传入当中
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
//10.执行拦截器链
retVal = invocation.proceed();
}
//11.获取方法返回值类型
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
//如果方法返回值为this,即return this,则直接将代理对象赋值给返回值
retVal = proxy;
}
//12.如果返回值是基本数据类型,但是返回了null,则抛出异常
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 {
//13.如果每次不是需要相同的target,则需要释放
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
//14.回滚proxy
if (setProxyContext) {
AopContext.setCurrentProxy(oldProxy);
}
}
}
基于JDK动态代理的方式,首先是一轮判断,如果目标类没有实现equals或hashCode,那么在调用这两个方法的时候会调用代理类实现的方法,如果目标类本身就是代理类,那么就需要不断的剥离,拿到真正的目标类,最后一个就是直接执行ProxyConfig的方法;然后就是根据exposeProxy属性判断是否需要暴露当前的Proxy,暴露之后,可以通过AopContext.currentProxy进行调用;然后获取当前目标类可以使用的拦截器,这里也会通过ClassFilter和MethodMatcher进行匹配,然后缓存起来,下次直接从缓存中取,这里还包含一个转换,使用的适配器模式;拿到调用链之后,创建ReflectiveMethodInvocatin,并调用proceed方法,执行拦截器链;最后根据方法返回类型返回结果。
这里核心的就是获取Interceptor和执行Interceptor。
1.获取Interceptor
org.springframework.aop.framework.DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice:
@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, Class<?> targetClass) {
List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
//1.registry为DefaultAdvisorAdapterRegistry类型,适配器模式,将非Interceptor的Advice转为Interceptor
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
//2.遍历通知器列表
for (Advisor advisor : config.getAdvisors()) {
if (advisor instanceof PointcutAdvisor) {
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
//3.调用ClassFilter对Bean类型进行匹配,无法匹配说明当前通知器不适用于这个bean
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
//4.将advisor中的advice转成相应的拦截器
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
//5.通过方法匹配器对目标方法进行匹配
if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
//6.若isRuntime为true,则表明MethodMatch运行时需要做一些检测
if (mm.isRuntime()) {
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}
else if (advisor instanceof IntroductionAdvisor) {
//7.IntroductionAdvisor类型的通知器,仅需进行类级别的匹配即可
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
return interceptorList;
}
首先是一个适配器模式,将Advice转为Interceptor。
org.springframework.aop.framework.adapter.DefaultAdvisorAdapterRegistry#DefaultAdvisorAdapterRegistry:
//注册默认的适配器,将Advice转为Interceptor
public DefaultAdvisorAdapterRegistry() {
//处理MethodBeforeAdvice
registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
//处理AfterReturningAdvice
registerAdvisorAdapter(new AfterReturningAdviceAdapter());
//处理MethodBeforeAdvice的异常
registerAdvisorAdapter(new ThrowsAdviceAdapter());
}
这里只注册了前置处理和后置返回,那其他的三个为什么不需要适配器,原因很简单,看下类图:
可以看到其他的三个通知都是MethodInterceptor的子类,该类提供了一个invoke方法, 这个方法就是每个通知具体的执行逻辑,所以对于没有实现该接口的类,都必须通过适配器模式进行转换。
转换完成之后就很简单了,就是遍历所有的Advisor,根据joinpoint的ClassFilter和MethodMatcher进行匹配,匹配合格的则根据Advisor获取Inteceptor,并返回。
2.执行Interceptor
org.springframework.aop.framework.ReflectiveMethodInvocation#proceed:
@Override
public Object proceed() throws Throwable {
//1.拦截器执行完成之后,就执行目标方法,通过一个索引进行计数
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
//2.执行目标方法
return invokeJoinpoint();
}
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
//3.动态匹配目标方法
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
//4.匹配失败,忽略当前拦截器,执行下一个拦截器
return proceed();
}
}
else {
//5.执行拦截器
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
proceed是AOP执行的核心方法,起到一个分发的作用。通过一个索引计算通知是否执行完了,决定是否可以执行目标方法。一般情况下都是走第5步,这一步执行的invoke方法其实就是之前的Interceptor的方法,并把当前的MethodInvocation作为参数传递。
org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor#invoke:
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
//执行前置通知逻辑
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
//通过MethodInvocation调用下一个拦截器,若所有拦截器执行完成,则执行目标方法
return mi.proceed();
}
org.springframework.aop.aspectj.AspectJMethodBeforeAdvice#before:
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
//调用通知方法
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
这里调用了一个getJoinPointMatch方法,获取连接点匹配器JoinPointMatch。这个接口提供了两个方法:matches和getParameterBindings,见名知意,matches用于判断连接点是否匹配,getParameterBindings用于返回通知的方法参数。
org.springframework.aop.aspectj.AbstractAspectJAdvice#invokeAdviceMethod:
protected Object invokeAdviceMethod(JoinPointMatch jpMatch, Object returnValue, Throwable ex) throws Throwable {
//调用通知方法,并向其传递参数
return invokeAdviceMethodWithGivenArgs(argBinding(getJoinPoint(), jpMatch, returnValue, ex));
}
这里调用了一个argBinding方法,很明显是用来通知方法的参数绑定的。对于目前的五种通知来说,通知方法也就包含以下几种参数:普通参数、JointPoint、返回参数、异常参数。
org.springframework.aop.aspectj.AbstractAspectJAdvice#invokeAdviceMethodWithGivenArgs:
protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
//通过反射调用通知方法
return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
}
public void before(){
System.out.println("前置通知");
}
这就是一个前置通知的执行,有了方法参数、通知方法、切面,然后通过反射执行,然后再回到proceed方法继续执行其他通知。其他的通知都差不多,只是通知和目标方法的顺序不同。
当所有的Interceptor执行之后,调用invokeJoinpoint执行目标方法。
org.springframework.aop.framework.ReflectiveMethodInvocation#invokeJoinpoint:
protected Object invokeJoinpoint() throws Throwable {
return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
}
org.springframework.aop.support.AopUtils#invokeJoinpointUsingReflection:
public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args)
throws Throwable {
ReflectionUtils.makeAccessible(method);
return method.invoke(target, args);
}
非常简单,通过反射执行目标方法,然后再回滚去执行之前未完成的通知。
2.CGLIB
如果proxy-target-class为true,或者目标类没有实现接口,那么就会使用CglibAopProxy。CglibAopProxy内置了一些内部类,用于处理方法的执行。
org.springframework.aop.framework.CglibAopProxy.DynamicAdvisedInterceptor:
private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {
private final AdvisedSupport advised;
public DynamicAdvisedInterceptor(AdvisedSupport advised) {
this.advised = advised;
}
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Class<?> targetClass = null;
Object target = null;
try {
//1.是否需要暴露当前代理
if (this.advised.exposeProxy) {
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
target = getTarget();//通过TargetSource获取目标对象
if (target != null) {
targetClass = target.getClass();
}
//2.将Advice转为Interceptor
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = methodProxy.invoke(target, argsToUse);
}
else {
//3.这是ReflectiveMethodInvocation的子类,是一个内部类
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null) {
releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
这个内部类实现了MethodInterceptor接口,重写了interceptor方法,当代理类执行目标方法的时候就会进入这个方法,这个方法的整体实现和JdkDynamicAopProxy#invoke方法基本一致,主要的区别在于这里使用的CglibMethodInvocation,这个类是ReflectiveMethodInvocation的子类。
org.springframework.aop.framework.CglibAopProxy.CglibMethodInvocation:
private static class CglibMethodInvocation extends ReflectiveMethodInvocation {
private final MethodProxy methodProxy;
private final boolean publicMethod;
public CglibMethodInvocation(Object proxy, Object target, Method method, Object[] arguments,
Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers, MethodProxy methodProxy) {
super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers);
this.methodProxy = methodProxy;
this.publicMethod = Modifier.isPublic(method.getModifiers());
}
//执行目标方法
@Override
protected Object invokeJoinpoint() throws Throwable {
if (this.publicMethod) {
return this.methodProxy.invoke(this.target, this.arguments);
}
else {
return super.invokeJoinpoint();
}
}
}
这个类只重写了invokeJoinpoint方法,那也就意味着CglibMethodInvocation调用的proceed方法是ReflectiveMethodInvocation中的方法,也就是和JdkDynamicAopProxy调用的一模一样了。
主要的区别在于目标方法的,如果是public修饰符的方法,则直接通过MethodProxy去执行,否则也是调用ReflectiveMethodInvocation中的invokeJoinpoint执行。
总结一下:
1.分发通知执行的核心方法是一样的,都是
ReflectiveMethodInvocation#proceed。2.JDK的
invoke和CGLIB的interceptor整体流程基本一致。是否需要暴露代理、从TargetSource获取target、将Advice转为Interceptor、执行通知、执行目标方法、处理返回值。3.目标方法的执行稍有不同,JDK是使用
ReflectiveMethodInvocation#invokeJoinpoint,CGLIB是使用CglibMethodInvocation#invokeJoinpoint。