Spring AOP 源码分析 part4 :拦截器的实现

来源:互联网 发布:python pdf 文字水印 编辑:程序博客网 时间:2024/05/17 22:51

Spring AOP的核心是动态代理,那么动态代理核心是什么呢?
动态代理有两个核心:1可以动态的生成代理对象;2在回调方法invoke中,我们做的一些额外的操作,这个也是可以是动态。
即动态的生成代理对象以及动态的执行额外的操作。

代码:

@Override    public Object invoke(Object proxy, Method method, Object[] args)            throws Throwable {        doBefore();        method.invoke(target, args);        doAfter() ;        return null;    }

Dobefore 和doafter的具体实现时未定的,所以这个地方可以写接口方法,具体是实现根据具体情况而确定,这有点类似于模板设计模式,具体是实现有子类来完成。

在上一篇博客中我们已经分析了SpringAOP生成动态代理对象的过程。Spring Aop中定义的通知就是我们动态执行的额外操作。
我们这一节就是分析这些通知是什么时候执行的。

在web编程中,我们都使用过拦截器,其实拦截器就是一种面向切面编程的表现方式。在spring Aop中,通知的执行,最终是转为拦截器执行的。所以在配置中我们使用interceptName来配置通知,这个单词还是用的拦截器的英文单词。
这一节涉及到类比较多,尽量将清楚。

先看动态代理的invoke方法,我们假设此方法所在的类为:
JdkDynamicAopProxy我们主要看这两行:

1、取得通知器链
List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

2、通知器链不为空 进行后面的执行
MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); // Proceed to the joinpoint through the interceptor chain.
Object retVal = invocation.proceed();

一、取得通知器链

This.advised 这个就是AdvisedSupport ,这个类是的实例是在生成JdkDynamicAopProxy对象传过来的。并且AdvisedSupport 里面存有通知器链。

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, 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;    }

我们看这个取得通知器链的方法,里面还使用了缓存。 这个取得通知器链的过程又使用了变量advisorChainFactory,
AdvisorChainFactory advisorChainFactory = new DefaultAdvisorChainFactory();

那现在就要去看这个通知器链工厂了DefaultAdvisorChainFactory

@Override    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);        Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());        boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);        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(actualClass)) {                    MethodInterceptor[] interceptors = registry.getInterceptors(advisor);                    MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();                    if (MethodMatchers.matches(mm, method, actualClass, 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(actualClass)) {                    Interceptor[] interceptors = registry.getInterceptors(advisor);                    interceptorList.addAll(Arrays.asList(interceptors));                }            }            else {                Interceptor[] interceptors = registry.getInterceptors(advisor);                interceptorList.addAll(Arrays.asList(interceptors));            }        }

现在先总结一下,就是在invoke方法被触发调用之后,会先获取通知器链,这个通知器链由AdvisedSupport持有,又需要通过默认的通知器链工厂生成。

我们继续看通知器链工厂里面做了哪些事情:

AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
通知器注册类
这个通知器注册类实际上是:

static void reset() {        instance = new DefaultAdvisorAdapterRegistry();    }

DefaultAdvisorAdapterRegistry
这个通知器注册类的作用是根据通知器,返回拦截器数组。
我们看源码方法:

@Override    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()]);    }

核心的一句:
interceptors.add(adapter.getInterceptor(advisor));
就是添加一个通知器。
具体一点:我们是要将通知器添加进拦截器数组。
我们需要一个适配,需要将通知器适配为拦截器。
通知器适配器就应运而生了:AdvisorAdapter
我们看下这个通知器适配器,他是一个接口:
AdvisorAdapter
boolean supportsAdvice(Advice advice);
取得对应通知器的方法拦截器
MethodInterceptor getInterceptor(Advisor advisor);

他正好有一个抽象方法将通知器转为拦截器。
他有三个实现:
MethodBeforeAdviceAdapter
AfterReturningAdviceAdapter
ThrowsAdviceAdapter

看下第一个:MethodBeforeAdviceAdapter

@Override    public MethodInterceptor getInterceptor(Advisor advisor) {        MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();        return new MethodBeforeAdviceInterceptor(advice);    }

获取通知器中的通知,将通知 适配为对应拦截器

因此这个时候,三个对应拦截器也诞生了:
MethodBeforeAdviceInterceptor
AfterReturningAdviceInterceptor
ThrowsAdviceInterceptor

我们先看下他们公共接口:MethodInterceptor:
他有一个回调方法:

 Object invoke(MethodInvocation invocation) throws Throwable;我们继续看一个实现:MethodBeforeAdviceInterceptor@Override    public Object invoke(MethodInvocation mi) throws Throwable {        this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );        return mi.proceed();    }

也就是当这个invoke被触发调用时,先执行通知的会调用方法,这个是前置通知,所以先执行before方法。然后再执行MethodInvocation 的proceed方法。

现在总结一下,就是通知器链工厂,在生成通知器链的时候,先将advice适配为对应拦截器,然后存放到list中。我们现在的问题是那个拦截器中的invoke什么调用。不过现在我们已经获得了拦截器链。

获得了拦截器链,还需要得到一个Advice的MethodMatcher,然后这拦截器和MethodMatcher一同封装到这个类中:
InterceptorAndDynamicMethodMatcher
类的实现一目了然:

class InterceptorAndDynamicMethodMatcher {    final MethodInterceptor interceptor;    final MethodMatcher methodMatcher;    public InterceptorAndDynamicMethodMatcher(MethodInterceptor interceptor, MethodMatcher methodMatcher) {        this.interceptor = interceptor;        this.methodMatcher = methodMatcher;    }}

我们将这个类存放到List interceptorList
最终返回。
所以通知器链工厂最终返回的通知器链是包含通知器和methodMatcher的。

二、、通知器链不为空 进行后面的执行
invocation.proceed();
看下它的实现:

@Override    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);        }    }

一个一个的取出拦截器链和对应的methodMatcher,匹配以后才执行拦截器的invoke方法。
dm.interceptor.invoke(this);
Dm就是那个封装拦截器和methodMatcher的对象。调用拦截器的invoke方法。具体是拦截器是哪一种:前置、 后置or 异常,这个是由运行时确定的。

至此AOP源码分析完毕。大结局。

0 0
原创粉丝点击