码迷,mamicode.com
首页 > 编程语言 > 详细

Spring技术内幕:Spring AOP的实现原理(四)

时间:2015-07-05 11:10:32      阅读:1001      评论:0      收藏:0      [点我收藏+]

标签:spring   aop   原理   源码   

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

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

这时我们会有疑问,这些advisor是怎样从配置文件中获得并配置到proxy的拦截器链中,我们使用的advisor通知时怎样起作用的,让我们带着这些问题继续往下看。
6、配置通知器
在整个AopProxy代理对象拦截回调过程中,先回到ReflectionMethodInvocation类的proceed方法,在这个方法里,可以看到得到了配置的interceptorOrInterceptionAdvice,如下所示:

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

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

List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method,targetClass);

从上面的代码可以看出,获取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<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class targetClass) {
        // 这里使用cache,利用cache去获取已有的inteceptor链,但是第一次还是需要自己动手生成的。这个inteceptor链的生成
        // 是由advisorChainFactory完成的,在这里使用的是DefaultAdvisorChainFactory
        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;
    }

在 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<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.
        // advisor链已经在config中持有了,这里可以直接使用
        List<Object> interceptorList = new ArrayList<Object>(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;
    }
}
    /**
     * 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;
    }

在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;
    }

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

Spring技术内幕:Spring AOP的实现原理(四)

标签:spring   aop   原理   源码   

原文地址:http://blog.csdn.net/fuyuwei2015/article/details/46759365

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!