spring aop 源码分析(二) 代理方法的执行过程分析

在上一篇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中配置相应的属性:

 

posted @ 2020-07-09 12:50  yangxiaohui227  阅读(225)  评论(0编辑  收藏  举报