博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring AOP的实现原理(四)
阅读量:2062 次
发布时间:2019-04-29

本文共 13200 字,大约阅读时间需要 44 分钟。

4、目标方法的调用

如果没有拦截器会对目标对象方法直接调用。对于JDKDynamicAopProxy代理对象是通过AopUtils使用反射机制实现的。在这个调用方法中首先得到调用方法的反射对象,然后使用invoke启动对方法反射对象的调用。源码如下:

/**     * Invoke the given target via reflection, as part of an AOP method invocation.     * @param target the target object     * @param method the method to invoke     * @param args the arguments for the method     * @return the invocation result, if any     * @throws Throwable if thrown by the target method     * @throws org.springframework.aop.AopInvocationException in case of a reflection error     */    public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args)            throws Throwable {        // Use reflection to invoke the method.        try {            ReflectionUtils.makeAccessible(method);            return method.invoke(target, args);        }        catch (InvocationTargetException ex) {            // Invoked method threw a checked exception.            // We must rethrow it. The client won't see the interceptor.            throw ex.getTargetException();        }        catch (IllegalArgumentException ex) {            throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" +                    method + "] on target [" + target + "]", ex);        }        catch (IllegalAccessException ex) {            throw new AopInvocationException("Could not access method [" + method + "]", ex);        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

5、AOP拦截器的调用

下面进入AOP的核心部分,Aop是怎样完成对目标的增强的。这些都封装在Aop拦截器链中,由一个具体的拦截器完成。
无论是使用JDKDynamicAopProxy还是使用CglibAopProxy创建代理对象最终对AOP拦截链的调用都是在ReflectiveMethodInvocation中通过proceed方法实现的。在proceed方法中逐个运行拦截器的拦截方法。在运行拦截器的拦截方法之前需要对代理方法完成一个匹配,通过这个匹配判断来决定拦截器是否满足切面增强的要求。具体代码如下:

public Object proceed() throws Throwable {        //  We start with an index of -1 and increment early.        // 从索引为-1的拦截器开始调用,并按序递增        // 如果拦截器链里的拦截器迭代调用完毕,这里开始调用target函数,这个函数是通过反射机制完成        // 具体在AopUtils.invokeJoinpointUsingReflection方法中完成        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {            return invokeJoinpoint();        }        // 这里沿着定义好的interceptorOrInterceptionAdvice链进行处理        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.            // 前面分析的Pointcut,这里是触发匹配的地方,如果定义的Pointcut匹配,那么这个advice将会得到执行            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.                // 如果不匹配,proceed会递归调用,知道所有的拦截器被运行                return proceed();            }        }        else {            // It's an interceptor, so we just invoke it: The pointcut will have            // been evaluated statically before this object was constructed.            // 如果是一个拦截器,直接调用这个interceptor对应的方法            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);        }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

这时我们会有疑问,这些advisor是怎样从配置文件中获得并配置到proxy的拦截器链中,我们使用的advisor通知时怎样起作用的,让我们带着这些问题继续往下看。

6、配置通知器
在整个AopProxy代理对象拦截回调过程中,先回到ReflectionMethodInvocation类的proceed方法,在这个方法里,可以看到得到了配置的interceptorOrInterceptionAdvice,如下所示:

Object interceptorOrInterceptionAdvice =                this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
  • 1
  • 2

interceptorOrInterceptionAdvice是获得的拦截器,他通过拦截器机制对目标对象进行增强。这个拦截器来自interceptorsAndDynamicMethodMatchers。具体来说,他是interceptorsAndDynamicMathers持有的List中的一个元素。关于如何配置拦截器的问题就转化为了List中的拦截器元素是从哪里来的,在哪里配置的问题。接着对invoke调用进行回放,回到JDKDynamicAopProxy中的invoke方法中,可以看到这个List中的interceptors是从哪个调用中获取的。对于CglibAopProxy,也有类似过程,只不过这个过程是在DynamicAdvisedInterceptor的intercept回调中实现的,如下所示:

List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method,targetClass);
  • 1

从上面的代码可以看出,获取intercptors的操作是由advised对象完成的,这个advised是一个AdvisedSupport对象,从AdvisedSupport类中可以看到getInterceptorsAndDynamicInterceptionAdvice的实现。在这个方法中取得了拦截器链,再取得拦截器链的时候,为了提高拦截器链的效率,还为这个拦截器链这是了缓存。

/**     * Determine a list of {@link org.aopalliance.intercept.MethodInterceptor} objects     * for the given method, based on this configuration.     * @param method the proxied method     * @param targetClass the target class     * @return List of MethodInterceptors (may also include InterceptorAndDynamicMethodMatchers)     */    public List getInterceptorsAndDynamicInterceptionAdvice(Method method, Class targetClass) {        // 这里使用cache,利用cache去获取已有的inteceptor链,但是第一次还是需要自己动手生成的。这个inteceptor链的生成        // 是由advisorChainFactory完成的,在这里使用的是DefaultAdvisorChainFactory        MethodCacheKey cacheKey = new MethodCacheKey(method);        List cached = this.methodCache.get(cacheKey);        if (cached == null) {            cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(                    this, method, targetClass);            this.methodCache.put(cacheKey, cached);        }        return cached;    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

在 DefaultAdvisorChainFactory中实现了interceptor链的获取过程,在这个过程中,首先设置了一个List,其长度是配置的通知器的个数来决定的,这个配置时在XML中对ProxyFactoryBean做的interceptNames属性的配置,然后,DefaultAdvisorChainFactory会通过一个AdvisorAdapterRegistry来实现拦截器的注册。AdvisorAdapterRegistry对advice通知的织入功能起了很大作用。有了AdvisorAdapterRegistry注册器,利用他来对ProxyFactoryBean配置中得到的通知进行适配,从而得到相应的拦截器,再把他前面设置好的List中去,完成所谓的拦截器注册过程。在拦截器适配和注册过程完成以后,List中的拦截器会被JDK生成的AopProxy代理对象的invoke方法或者CGLIB代理对象的intercept拦截方法获得,并启动拦截器的invoke方法调用,最终触发通知的切面增强。

下面看看DefaultAdvisorChainFactory是怎样生成拦截器链的:

/** * A simple but definitive way of working out an advice chain for a Method, * given an {@link Advised} object. Always rebuilds each advice chain; * caching can be provided by subclasses. * * @author Juergen Hoeller * @author Rod Johnson * @author Adrian Colyer * @since 2.0.3 */@SuppressWarnings("serial")public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable {
public List 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. // advisor链已经在config中持有了,这里可以直接使用 List interceptorList = new ArrayList(config.getAdvisors().length); boolean hasIntroductions = hasMatchingIntroductions(config, targetClass); 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(targetClass)) { // 拦截器链是通过AdvisorAdapterRegistry来加入的,这个AdvisorAdapterRegistry MethodInterceptor[] interceptors = registry.getInterceptors(advisor); MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher(); if (MethodMatchers.matches(mm, method, targetClass, 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(targetClass)) { Interceptor[] interceptors = registry.getInterceptors(advisor); interceptorList.addAll(Arrays.asList(interceptors)); } } else { Interceptor[] interceptors = registry.getInterceptors(advisor); interceptorList.addAll(Arrays.asList(interceptors)); } } return interceptorList; }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
/**     * Determine whether the Advisors contain matching introductions.     */    // 判断Advisors是否符合要求    private static boolean hasMatchingIntroductions(Advised config, Class targetClass) {        for (int i = 0; i < config.getAdvisors().length; i++) {            Advisor advisor = config.getAdvisors()[i];            if (advisor instanceof IntroductionAdvisor) {                IntroductionAdvisor ia = (IntroductionAdvisor) advisor;                if (ia.getClassFilter().matches(targetClass)) {                    return true;                }            }        }        return false;    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

在ProxyFactoryBean的getObject方法中对adviosr进行初始化,从XML配置中获取了advisor通知器。下面看下在ProxyFactoryBean拦截器链的初始化中获取advisor通知器

/**     * Create the advisor (interceptor) chain. Aadvisors that are sourced     * from a BeanFactory will be refreshed each time a new prototype instance     * is added. Interceptors added programmatically through the factory API     * are unaffected by such changes.     */    private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {        if (this.advisorChainInitialized) {            return;        }        if (!ObjectUtils.isEmpty(this.interceptorNames)) {            if (this.beanFactory == null) {                throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +                        "- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames));            }            // Globals can't be last unless we specified a targetSource using the property...            if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) &&                    this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {                throw new AopConfigException("Target required after globals");            }            // Materialize interceptor chain from bean names.            for (String name : this.interceptorNames) {                if (logger.isTraceEnabled()) {                    logger.trace("Configuring advisor or advice '" + name + "'");                }                if (name.endsWith(GLOBAL_SUFFIX)) {                    if (!(this.beanFactory instanceof ListableBeanFactory)) {                        throw new AopConfigException(                                "Can only use global advisors or interceptors with a ListableBeanFactory");                    }                    addGlobalAdvisor((ListableBeanFactory) this.beanFactory,                            name.substring(0, name.length() - GLOBAL_SUFFIX.length()));                }                else {                    // If we get here, we need to add a named interceptor.                    // We must check if it's a singleton or prototype.                    Object advice;                    if (this.singleton || this.beanFactory.isSingleton(name)) {                        // Add the real Advisor/Advice to the chain.                        // 这里是取得advisor的地方,是通过BeanFactory取得的                        // 把interceptorNames这个List中interceptor名字交给                        // BeanFactory,然后通过调用BeanFactory的getBean去获取                        advice = this.beanFactory.getBean(name);                    }                    else {                        // It's a prototype Advice or Advisor: replace with a prototype.                        // Avoid unnecessary creation of prototype bean just for advisor chain initialization.                        advice = new PrototypePlaceholderAdvisor(name);                    }                    addAdvisorOnChainCreation(advice, name);                }            }        }        this.advisorChainInitialized = true;    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55

advisor通知器的取得时委托给IOC容器完成的,但是在ProxyFactoryBean中是如何获得IOC容器,然后通过回调IOC容器的getBean方法来得到需要的通知advisor?在这里大家可以回顾下IOC容器的原理。

未完待续……

转载地址:http://yfhlf.baihongyu.com/

你可能感兴趣的文章
kubectl 创建 Pod 背后到底发生了什么?
查看>>
Kube-scheduler 源码分析(二):调度程序启动前逻辑
查看>>
kubernetes 1.15 有哪些让人眼前一亮的新特性?
查看>>
云原生周报:第 3 期
查看>>
深入理解 Linux Cgroup 系列(三):内存
查看>>
7月最新Java微服务资料
查看>>
Linux 指令
查看>>
wi10优化
查看>>
windows console 颜色设置
查看>>
VC unicode下Cstring转char*
查看>>
MFC ListBox使用
查看>>
Linux 使用grep筛选多个条件
查看>>
H264 NALU分析(sps,pps,关键帧,非关键帧)
查看>>
Windows文本加载wscite的使用
查看>>
浏览器主页被篡改修复
查看>>
FFmpeg - 新老接口对比问题
查看>>
Windows下MinGW编译ffmpeg库
查看>>
SDL在windows下使用 - 显示YUV
查看>>
三种方式YUV420转RGB24/BGR24,实测可用
查看>>
Windows下使用VS2015编译openssl库
查看>>