spring aop实现原理

     Java是面向对象的编程语言,整个程序的执行是方法纵向的调用完成,Aop是面向切面的编程思想,是对面向对象的一个补充。Aop面向切面的思想是针对方法进行编程,依赖动态代理来实现对方法执行的前后注入业务逻辑。简而言之,spring aop是面向切面的编程思想,辅佐以动态代理的实现来完成。
    下面以ProxyFactoryBean的getObject为切入点,来分析spring aop的实现原理。

获取通知器链

     从ProxyFactoryBean的getObject方法中可以看到,initializeAdvisorChain初始化通知器链,这个是通过读取interceptorNames的配置属性获取的,然后把获取到的所有通知器添加到通知器链中,这里是按配置的顺序进行添加的。最后是把所有通知器链保存到advisors属性中。

public Object getObject() throws BeansException {
        //从ProxyFactoryBean的配置中获取所有的advisor信息
        initializeAdvisorChain();
        if (isSingleton()) {
            //获取代理对象
            return getSingletonInstance();
        }

        // ...
}


private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
        if (!ObjectUtils.isEmpty(this.interceptorNames)) {
            // ...

            for (String name : this.interceptorNames) {
                if (name.endsWith(GLOBAL_SUFFIX)) {
                    addGlobalAdvisors((ListableBeanFactory) this.beanFactory,
                            name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
                }
                else {
                    Object advice;
                    if (this.singleton || this.beanFactory.isSingleton(name)) {
                        //这里从spring ioc容器中获取通知bean
                        advice = this.beanFactory.getBean(name);
                    }
                    else {
                        advice = new PrototypePlaceholderAdvisor(name);
                    }
                    //把获取到的通知添加到通知器链中,这里是按序添加的
                    addAdvisorOnChainCreation(advice);
                }
            }
        }

        this.advisorChainInitialized = true;
}
代理对象的生成

     aop代理对象的生成是委托给AopProxy来进行代理对象的生成。

private synchronized Object getSingletonInstance() {
        if (this.singletonInstance == null) {
            //生成一个aop代理对象
            this.singletonInstance = getProxy(createAopProxy());
        }
        return this.singletonInstance;
}

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {

    @Override
    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
        //配置了isProxyTargetClass属性或者没有实现接口就使用ObjenesisCglibAopProxy去生成代理对象,否则就使用JdkDynamicAopProxy生成代理对象
        if (!NativeDetector.inNativeImage() &&
                (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))) {
            Class<?> targetClass = config.getTargetClass();
            if (targetClass == null) {
                throw new AopConfigException("TargetSource cannot determine target class: " +
                        "Either an interface or a target is required for proxy creation.");
            }
            if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
                return new JdkDynamicAopProxy(config);
            }
            return new ObjenesisCglibAopProxy(config);
        }
        else {
            return new JdkDynamicAopProxy(config);
        }
    }
}

     这里可以看到,spring把代理对象的生成是交给了AopProxy接口,通过AopProxy来解耦了代理对象的生成。在配置了isOptimize或isProxyTargetClass的时候,并且目标对象不是实现接口的形式,就采用ObjenesisCglibAopProxy来生成代理对象,否则就使用JdkDynamicAopProxy去生成代理对象。对于代理对象这里是动态代理设计模式的使用,对于动态代理对象这里不进行解释,以JdkDynamicAopProxy为例来看看代理对象的生成过程。

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
    @Override
    public Object getProxy(@Nullable ClassLoader classLoader) {
        if (logger.isTraceEnabled()) {
            logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
        }
        return Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this);
    }
}

     在代理模式中,Proxy生成代理对象的时候,需要传入类加载器、目标对象实现的接口和触发器。代理对象生成后,对目标对象所有的方法调用都会交给InvocationHandler进行处理,都会触发InvovationHandler接口invoke方法的调用。JdkDynamicAopProxy实现了InvocationHandler接口,所以这里在生成代理对象的时候,把自己作为InvocationHandler参数传进去了。

     以上是为实现spring aop进行的基础处理和铺垫:
  • 读取配置的通知器到advisors通知器链中
  • 代理对象的生成
     接下来看看在实际方法调用的过程中,aop是怎么对运行的方法进行拦截处理的。对目标方法的调用最终都会转交给InvocationHandler的invoke方法的处理,以这个为入口进行分析。
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        try {
            // ...

            //获取通知器链
            List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
            if (chain.isEmpty()) {
                //如果通知器链为空,直接执行目标方法
                Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
            }
            else {
                //通知器链不为空,包装成ReflectiveMethodInvocation进行调用
                MethodInvocation invocation =
                        new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                // Proceed to the joinpoint through the interceptor chain.
                retVal = invocation.proceed();
            } 
            return retVal;
        }
}

     这里是先获取当前方法的通知器链,然后把通知器链包装成ReflectiveMethodInvocation进行调用。

通知器链如何获取
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;
    }

public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable {

    @Override
    public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
            Advised config, Method method, @Nullable Class<?> targetClass) {

        AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
        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) {
                // Add it conditionally.
                PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
                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
                        MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                        if (mm.isRuntime()) {
                            for (MethodInterceptor interceptor : interceptors) {
                                //然后把包装后的通知和方法匹配器包装起来放到拦截器链中
                                interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
                            }
                        }
                        else {
                            interceptorList.addAll(Arrays.asList(interceptors));
                        }
                    }
                }
            }
        }

        return interceptorList;
    }
}

     可以看到在获取通知器链的时候,是使用DefaultAdvisorChainFactory来进行获取的。

  • 在初始化通知器链的时候,已经把配置的通知器添加到通知器链中了。
  • 根据通知器链,通过MethodMatcher来判断通知器对当前方法是否匹配
  • 对于匹配的通知器,这里把通知器和MethodMatcher包装成InterceptorAndDynamicMethodMatcher转换成MethodInterceptor添加到拦截器链中。
看看通知器适配成拦截器的过程

     DefaultAdvisorAdapterRegistry是用来把advisor转换成MethodInterceptor。

public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {

    public DefaultAdvisorAdapterRegistry() {
        registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
        registerAdvisorAdapter(new AfterReturningAdviceAdapter());
        registerAdvisorAdapter(new ThrowsAdviceAdapter());
    }
    
    @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) {
            if (adapter.supportsAdvice(advice)) {
                interceptors.add(adapter.getInterceptor(advisor));
            }
        }
        if (interceptors.isEmpty()) {
            throw new UnknownAdviceTypeException(advisor.getAdvice());
        }
        return interceptors.toArray(new MethodInterceptor[0]);
    }
}

     在DefaultAdvisorAdapterRegistry实例化的时候,添加了3个适配器,由这3个适配器来具体完成对不同的advisor完成Interceptor转换。下面以MethodBeforeAdviceAdapter来分析:

class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {

    @Override
    public boolean supportsAdvice(Advice advice) {
        return (advice instanceof MethodBeforeAdvice);
    }

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

public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {

    @Override
    @Nullable
    public Object invoke(MethodInvocation mi) throws Throwable {
        this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
        return mi.proceed();
    }

}

     适配器把Advisor转换成MethodBeforeAdviceInterceptor拦截器。

获取完拦截器,看看在方法调用实际运行的时候,拦截器链是怎么起作用的。
MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
retVal = invocation.proceed();

public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable {
    
    public Object proceed() throws Throwable {
        //如果通知器链为空,直接调用目标方法
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            return invokeJoinpoint();
        }

        //这里从通知器链开始处进行调用
        Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
        if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
            
            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 {
                //拦截器不匹配的话,沿着拦截器链调用下一个拦截器
                return proceed();
            }
        }
        else {
            
            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
        }
    }
}

     沿着拦截器链开始,一个个遍历执行拦截器中的所有拦截器,这里就是前面从通知器适配转换的MethodBeforeAdviceInterceptor拦截器等。

public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {

    @Override
    @Nullable
    public Object invoke(MethodInvocation mi) throws Throwable {
        this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
        return mi.proceed();
    }

}

     这里就回到了我们自己写的业务通知逻辑。cglib生成的代理对象执行过程和jdk执行过程没有太大的区别。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 230,563评论 6 544
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 99,694评论 3 429
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 178,672评论 0 383
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 63,965评论 1 318
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 72,690评论 6 413
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 56,019评论 1 329
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 44,013评论 3 449
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 43,188评论 0 290
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 49,718评论 1 336
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 41,438评论 3 360
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 43,667评论 1 374
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 39,149评论 5 365
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 44,845评论 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 35,252评论 0 28
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 36,590评论 1 295
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 52,384评论 3 400
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 48,635评论 2 380

推荐阅读更多精彩内容