在上一篇aop源码分析时,我们已经分析了一个bean被代理的详细过程,参考:https://www.cnblogs.com/yangxiaohui227/p/13266014.html
本次主要是分析目标方法的执行过程: 测试代码在git : https://gitee.com/yangxioahui/aopdemo.git
主要代码如下:
public interface Calc { Integer add(int num1,int num2); } @Component public class MyMath implements Calc { public Integer add(int num1,int num2){ return num1+num2; } } @Aspect @Component public class MyAspectJ { @Pointcut(" execution(* com.yang.xiao.hui.aop.MyMath.*(..))") private void pointcut(){} @Before(value = "pointcut()") public void before(JoinPoint joinPoint){ System.out.println("before。。。。。"); } @After(value = "pointcut()") public void after(JoinPoint joinPoint){ System.out.println("after。。。。"); } @AfterReturning(value = "pointcut()") public void afterReturning(){ System.out.println("afterReturning。。。"); } @AfterThrowing(value = "pointcut()") public void afterThrowing(JoinPoint joinPoint){ System.out.println("afterThrowing。。。。"); } @Around(value ="pointcut()") public void around(ProceedingJoinPoint joinPoint){ System.out.println("around-before。。。。"); try { Object proceed = joinPoint.proceed(); System.out.println("around-after_return。。。"); } catch (Throwable throwable) { System.out.println("around-throw。。。"+throwable.getMessage()); } System.out.println("around-after。。。"); } } @Configuration @ComponentScan("com.yang.xiao.hui.aop") @EnableAspectJAutoProxy() public class App { public static void main( String[] args ) { ApplicationContext ctx = new AnnotationConfigApplicationContext(App.class); Calc myMath = (Calc)ctx.getBean("myMath"); myMath.add(3,5); System.out.println(ctx.getBean("myMath").getClass()); } }
测试: MyMath 类的add 方法执行过程,debug 调试:
上一篇源码分析,我们已经分析过,最终会被JdkDynamicAopProxy 的invoke方法调用,下面分析下该方法:
@Override @Nullable public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object oldProxy = null; boolean setProxyContext = false; TargetSource targetSource = this.advised.targetSource; //里面封装了被代理对象,也就是MyMath Object target = null; //被代理对象 try { if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) { //处理equals方法 // The target does not implement the equals(Object) method itself. return equals(args[0]); } else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) { //处理Hashcode 方法 // The target does not implement the hashCode() method itself. return hashCode(); } else if (method.getDeclaringClass() == DecoratingProxy.class) {//显然,我们的方法定义所在的类是Calc // There is only getDecoratedClass() declared -> dispatch to proxy config. return AopProxyUtils.ultimateTargetClass(this.advised); }
//this.advised.opaque 这个值是说代理类能否强转为Advised,flase是可以强转,在代理对象创建源码时分析过了,代理对象确实实现了Advised接口
//method.getDeclaringClass().isInterface() 我们的目标方法定义所在类是Calc,确实是一个接口,但该接口没有实现Advised,所以下面方法不会进入
else 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); //这里是直接反射调用方法: method.invoke(target, args); } Object retVal; if (this.advised.exposeProxy) { //@EnableAspectJAutoProxy 注解的一个属性,为true时,就会将代理对象 // Make invocation available if necessary. oldProxy = AopContext.setCurrentProxy(proxy);//将当前的代理对象存到ThreadLocal中 setProxyContext = true; } // Get as late as possible to minimize the time we "own" the target, // in case it comes from a pool. target = targetSource.getTarget(); //获取被代理类的实例,在这里是MyMath的实例 Class<?> targetClass = (target != null ? target.getClass() : null); //在这里是com.yang.xiao.hui.aop.MyMath // Get the interception chain for this method. 将advisors封装成MethodInterceptor,在代理对象源码的博客介绍过,@before等注解标注的方法会被封装成advisor,所以这里取出来,封装一下,下面会详细分析该方法 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. Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); //如果没有拦截器,获取实际参数,反射调用目标方法就行了 retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse); ////这里是直接反射调用方法: method.invoke(target, args); } else { // We need to create a method invocation... MethodInvocation 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 != Object.class && returnType.isInstance(proxy) && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) { //特殊情况,责任链调用的返回值就是被代理对象(target),而方法的返回类型要求的是代理对象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; } else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) { //如果方法的返回类型不是void,并且是基本类型,那么,如果执行调用后,拿到的返回值是空,就抛异常 throw new AopInvocationException( "Null return value from advice does not match primitive return type for: " + method); } return retVal;//返回得到的结果 } finally { if (target != null && !targetSource.isStatic()) { //如果目标代理对象不为空,同时每次调用targetSource.getTarget()返回的对象不同,也就是非单例的情况下需要释放目标对象 // Must have come from TargetSource. targetSource.releaseTarget(target); } if (setProxyContext) { // Restore old proxy. AopContext.setCurrentProxy(oldProxy); //方法调用完毕,将ThreadLocal中的代理对象设置回之前的那个 } } }
//通过上面的分析,目标方法在执行时,主要分两步,取得拦截链,调用拦截链:
先分析: List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); 其中AdvisedSupport: advised拥有被代理对象和advisors,在代理对象创建源码分析时,有分析过
下面分析获取chain的过程:
@Override public List<Object> getInterceptorsAndDynamicInterceptionAdvice( Advised config, Method method, @Nullable Class<?> targetClass) { // This is somewhat tricky... We have to process introductions first, // but we need to preserve order in the ultimate list. AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance(); Advisor[] advisors = config.getAdvisors(); // config 就是AdvisedSupport,它拥有advisors,在代理对象创建过程中分析过 List<Object> interceptorList = new ArrayList<>(advisors.length); //要将advisor转成方法拦截器,才能起到拦截的作用 Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());//被代理类 Boolean hasIntroductions = null; for (Advisor advisor : advisors) { if (advisor instanceof PointcutAdvisor) { //根据advisor的类型不一样,转成MethodInterceptor 逻辑也不一样 // Add it conditionally. PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
//config.isPreFiltered()都是返回true,代表advisors是否已经是过滤过的了
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {//主要通过切入点表达式再次校验目标类是否需要被切入 MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();// 如果根据切入点表达式判断了类需要被切入,那之后就要判断方法是否需要切入,因为一个类有很多方法,并不是所有方法都需要被切入 boolean match; if (mm instanceof IntroductionAwareMethodMatcher) { //根据方法匹配器的类型,使用不同发匹配方式 if (hasIntroductions == null) { hasIntroductions = hasMatchingIntroductions(advisors, actualClass); } match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions); } else { match = mm.matches(method, actualClass); } if (match) { MethodInterceptor[] interceptors = registry.getInterceptors(advisor); //如果advisor 匹配上了,那就要封装成方法拦截器 if (mm.isRuntime()) { /mm的类型主要有2种,一种是动态方法匹配器,永远返回true,一种是静态方法匹配器,永远返回false // 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)); //将所有符合要求的interceptors 存起来 } } } } else if (advisor instanceof 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; }
上面的方法主要是根据advisor的类型,使用不同的方法匹配器,看看目标的方法是否可以使用该advisor,是的话,就封装成MethodInterceptor,看看封装的逻辑:registry.getInterceptors(advisor);
@Override public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException { List<MethodInterceptor> interceptors = new ArrayList<>(3); Advice advice = advisor.getAdvice(); if (advice instanceof MethodInterceptor) { interceptors.add((MethodInterceptor) advice); } for (AdvisorAdapter adapter : this.adapters) { //三种适配器: MethodBeforeAdviceAdapter/ AfterReturningAdviceAdapter/ThrowsAdviceAdapter 看看哪个匹配上,就用哪一种适配器来封装成拦截器 if (adapter.supportsAdvice(advice)) interceptors.add(adapter.getInterceptor(advisor)); } } if (interceptors.isEmpty()) { throw new UnknownAdviceTypeException(advisor.getAdvice()); } return interceptors.toArray(new MethodInterceptor[0]); }
//advisor封装成interceptor的一个例子:
拦截器链获取分析完毕了,那么,我们接下来分析下,责任链的执行:
之后我们看看:invocation.proceed();
public Object proceed() throws Throwable {
//刚开始currentInterceptorIndex=-1 // We start with an index of -1 and increment early. if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { //如果最后一个拦截器执行完毕后,就直接反射调用目标方法 return invokeJoinpoint(); //method.invoke(target, args); } 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; Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass()); if (dm.methodMatcher.matches(this.method, 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); //如果是静态的匹配的,就直接调用目标方法 } }
debug调试调用过程:
先看看我们的链条都有哪些:
总共有六个拦截器:
最后总结:
springboot对aop的自动装配机制:我们在springboot项目中,没有自己给启动类贴上@EnableAspectJAutoProxy 注解,aop一样生效,原理是有个配置类:
默认值如下:
我们可以在yml中配置相应的属性: