SpringAOP-代理对象调用拦截器

代理对象创建好后,其实最终的拦截工作都是交给了MethodInvocation来做的,MethodInvocation有2个重要实现类ReflectiveMethodInvocation、CglibMethodInvocation

1、JDK代理对象的拦截器链创建交给:ReflectiveMethodInvocation
2、Cglib代理对象的拦截器链创建交给:CglibMethodInvocation,其中CglibMethodInvocation继承了ReflectiveMethodInvocation

注意拦截器链的创建是在代理对象被执行的时候绑定,不是代理对象创建时绑定的。

当我们代理对象生成后执行目标方法,先被JDK代理的invoke方法拦截,或者被Cglib的intercept方法拦截。在invoke和intercept方法内部会生成拦截器链,然后一层层调用拦截器,并且这种调用不是通过for循环的方式,而是通过职责链的模式调用。

下面是invoke方法和intercept方法创建拦截器链的代码

//JDK生成拦截器链,chain参数是拦截器集合
MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);

//Cglib生成拦截器链,chain参数是拦截器集合
CglibMethodInvocation invocation = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy);

//执行拦截器链
retVal = invocation.proceed();//职责链模式

其中拦截器集合chain的获取是通过ProxyCreatorSupport.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass)来得到的

getInterceptorsAndDynamicInterceptionAdvice里面就是根据切面的类型,分为"切点切面"和"引介切面",如果是"切点切面"就通过方法层面匹配符合切点表达式的通知,如果是引介切面,就通过类的层面找到符合类型规则的通知。关于这两种类型的切面可以参考我的这篇文章切点切面和引介切面

这里关于MethodInvocation接口以及的父类子类,并关于getInterceptorsAndDynamicInterceptionAdvice方法是如何获取拦截器集合做简单介绍

一、MethodInvocation

1、MethodInvocation的父类

public interface Joinpoint {
    //执行拦截器链
    Object proceed() throws Throwable;
  	......
}
public interface Invocation extends Joinpoint {
    //获取参数,例如方法的参数
    Object[] getArguments();
}
public interface MethodInvocation extends Invocation {
    //返回正在被调用的方法,也就是Method
    Method getMethod();
}

2、MethodInvocation的子类

ReflectiveMethodInvocation是Jdk使用的,CglibMethodInvocation是Cglib使用的,并CglibMethodInvocation还继承了ReflectiveMethodInvocation

2.1、ReflectiveMethodInvocation 拦截器链

public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable {
	protected final Object proxy; // 代理对象
    protected final Object target; // 目标对象,持有目标对象是为了通过Method调用目标对象方法。
    protected final Method method; // 被拦截的方法
    ......
    protected final List<?> interceptorsAndDynamicMethodMatchers;//拦截器集合
    private int currentInterceptorIndex = -1;//当前拦截器所在集合中的下标

    //1、Spring内部使用的类
    protected ReflectiveMethodInvocation(Object proxy, @Nullable Object target, Method method, @Nullable Object[] arguments,
            @Nullable Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {

        this.proxy = proxy;
        this.target = target;
        this.targetClass = targetClass;
        // 找到桥接方法,作为最后执行的方法。
        this.method = BridgeMethodResolver.findBridgedMethod(method);
        // 对参数进行适配
        this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments);

        this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
    }
    。。。。。。

    //2、这里是递归调用的方式,执行所有的拦截器
    @Override
    public Object proceed() throws Throwable {
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            //调用了目标方法,执行到这说明拦截器链到了链尾
            return invokeJoinpoint();
        }

        //获取集合中的MethodInterceptor,注意这里++在前
        Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);

        //InterceptorAndDynamicMethodMatcher它是Spring内部使用的一个类。很简单,就是把MethodInterceptor实例和MethodMatcher放在了一起。看看在advisor chain里面是否能够匹配上
        if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
            InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
            
            // 匹配拦截器是否适用于这个目标方法 
            if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
                return dm.interceptor.invoke(this);
            } else {
                //不匹配跳过此拦截器,执行下一个拦截器,递归调用。
                return proceed();
            }
        } else {
            // 直接执行此拦截器。说明之前已经匹配好了,只有匹配上的方法才会被拦截进来的
            // 这里传入this就是传入了ReflectiveMethodInvocation,从而形成了一个链条了
            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
        }
    }
    
    //执行Method方法
    protected Object invokeJoinpoint() throws Throwable {
        //通过目标对象target,执行目标对象的method的方法
        return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
    }
}

2.2、CglibMethodInvocation 拦截器链

CglibMethodInvocation因为继承了ReflectiveMethodInvocation,所以拥有父类所具备的能力,只是多了一个methodProxy属性

private static class CglibMethodInvocation extends ReflectiveMethodInvocation {  
 
    @Nullable  
    private final MethodProxy methodProxy;//代理方法,这个是什么
  
    public CglibMethodInvocation(Object proxy, Object target, Method method,  
            Object[] arguments, Class<?> targetClass,  
            List<Object> interceptorsAndDynamicMethodMatchers, MethodProxy methodProxy) {  
  
        super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers);  
        
        //做出了特殊处理,methodProxy是特有的参数,表示被CGLIB拦截的时候的类
        //MethodProxy:为生成代理类对方法的代理引用,使用MethodProxy比直接调用JDK本身的Method直接执行方法效率会有提升。
        //MethodProxy有两个重要的方法:invoke和invokeSuper。
        //method.getDeclaringClass用来判断当前这个方法是哪个类的方法。
        //若该方法是public方法 且method不是Object类的方法,且method不是equals,且method不是hashCode,且 method不是toString方法,返回methodProxy对象。
        this.methodProxy = (Modifier.isPublic(method.getModifiers()) 
        		&& method.getDeclaringClass() != Object.class 
                && !AopUtils.isEqualsMethod(method) 
                && !AopUtils.isHashCodeMethod(method) 
                && !AopUtils.isToStringMethod(method) ?  
                methodProxy : null);  
    }  
  
    @Override  
    protected Object invokeJoinpoint() throws Throwable {  
        if (this.methodProxy != null) {  
            //如果符合上述条件,调用methodProxy去执行目标方法。(使用FastClass调用)
            return this.methodProxy.invoke(this.target, this.arguments);  
        }  
        else {  
            return super.invokeJoinpoint();  
        }  
    }  
}

二、getInterceptorsAndDynamicInterceptionAdvice

获取符合规则的拦截器

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
	MethodCacheKey cacheKey = new MethodCacheKey(method);
	List<Object> cached = this.methodCache.get(cacheKey);//尝试用缓存里面拿
	if (cached == null) {
		//重点在这里
		cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass);
		this.methodCache.put(cacheKey, cached);
	}
	return cached;
}
@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Advised config, Method method, @Nullable Class<?> targetClass) {

	//通过单例方式创建DefaultAdvisorAdapterRegistry实例,DefaultAdvisorAdapterRegistry是advisor的适配器,主要用来处理advisor-切面
	AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();

	//获取所有的Advisor-切面,切面 = 切点 + 通知,这里的通知,我们就可以把他看做拦截器
	//注意这里的通知是什么时候塞进去的,是在后置处理器调用wrapIfNecessary方法,拿到符合规则的切面塞进去的,
	//所以这里的切面是过滤过一次的。
	Advisor[] advisors = config.getAdvisors();

	//返回可用适用的"通知"
	List<Object> interceptorList = new ArrayList<>(advisors.length);
	Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
	Boolean hasIntroductions = null;

	//遍历所有切面
	for (Advisor advisor : advisors) {

		if (advisor instanceof PointcutAdvisor) {//如果是"切点切面"类型,切点切面是方法层级的匹配规则。
			PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;

			//判断目标方法是否符合切点的规则
			if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
				MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
				boolean match;
				if (mm instanceof IntroductionAwareMethodMatcher) {//如果是AspectJ都是走这种匹配
					if (hasIntroductions == null) {
						hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
					}
					match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
				} else {
					match = mm.matches(method, actualClass);
				}

				//如果切点的MethodMatcher都匹配这个method,拿到切面里面的"通知"
				if (match) {
					MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
					。。。。
					interceptorList.addAll(Arrays.asList(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;
}

本文引至:https://www.cnblogs.com/chenxingyang/p/15559346.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

信仰_273993243

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值