Spring AOP实现原理解析

Spring AOP

相关概念

  • AOP:Aspect-Oriented Programming,是一种新的模块化机制,用来描述分散在对象、类或者函数中的横切关注点。
  • Join Point:程序流中被分割为一个个代码单元,单元之间的点即为Join Point。如程序调用栈中,可以按照各个方法将代码执行流分割为一个个方法单元,那么方法调用前后都是Join Point。
  • Advice:模块化内容,也是增强逻辑本身。
  • Introduction:引介增强,向Target引入新的属性或者方法
  • PointCut:关注点,将要织入Advice的Join Point的集合。
  • Advisor:增强与关注点的结合,Advice+PointCut/Introduction+PointCut
  • MethodInterceptor:Advice的子类,在Spring AOP中,各类Advice最终都会封装为MethodInterceptor,其invoke方法中封装了Target和Advice的相对执行顺序
  • MethodInvocation:Joinpoint的子类,指对一个方法的调用。

支撑技术

JDK动态代理与CGLIB动态代理

实现原理

Spring AOP的主要工作就是将Advice和Target结合生成代理对象(不同的是AspectJ是在字节码层面织入的,JVM类加载的就是经过增强的对象,而不需要代理模式)。其主要逻辑可大体拆分为两部分:

  1. 获取Advice、Target等相关配置信息
  2. 生成代理对象

以ProxyFactoryBean开始分析,这个FactoryBean的getObject()方法即可获取代理对象。

public Object getObject() throws BeansException {
        //初始化Advisor链
        initializeAdvisorChain();
        //生成代理对象
        if (isSingleton()) {
            return getSingletonInstance();
        }
        else {
            if (this.targetName == null) {
                logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +
                        "Enable prototype proxies by setting the 'targetName' property.");
            }
            return newPrototypeInstance();
        }
    }

《Spring AOP实现原理解析》
这是ProxyFactoryBean的继承关系图,其中AdvisedSupport父类主要持有Advice相关配置信息,ProxyCreatorSupport父类主要负责代理类的实际生成工作。

配置信息获取与初始化

ProxyFactoryBean中配置信息的获取是经由IOC容器获取的,ProxyFactoryBean有一个属性为interceptorNames,需要在IOC容器中配置设置。在此基础上,在调用getObject()方法时,进行Advisor链的初始化。

Advisor链的初始化主要分两步:

  1. 注册器包装
  2. 添加入链表

其中注册器包装由适配器注册器GlobalAdvisorAdapterRegistry类将IOC配置中的interceptor对象类型(可能是Advisor,或者Advice等)包装为Advisor类型,并过滤不支持的类型。添加入链表的操作和链表的持有交给了父类AdvisedSupport来完成。

包装代码:

public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
    //Bean可以是直接定义好的含有PointCut的Advisor
        if (adviceObject instanceof Advisor) {
            return (Advisor) adviceObject;
        }
        if (!(adviceObject instanceof Advice)) {
            throw new UnknownAdviceTypeException(adviceObject);
        }
        Advice advice = (Advice) adviceObject;
        //可以是Advice的子类MethodInterceptor类型
        if (advice instanceof MethodInterceptor) {
            // So well-known it doesn't even need an adapter.
            return new DefaultPointcutAdvisor(advice);
        }
        //也可以是各类Advice,如果有适配器支持即可封装,后两者封装的都是默认的PointCutAdvisor。
        for (AdvisorAdapter adapter : this.adapters) {
            // Check that it is supported.
            if (adapter.supportsAdvice(advice)) {
                return new DefaultPointcutAdvisor(advice);
            }
        }
        throw new UnknownAdviceTypeException(advice);
    }
生成代理对象

在父类AdvisedSupport持有了Advisor链表之后,下一步即可进行代理对象的生成工作,这一步交给父类ProxyCreatorSupport来完成,该类持有DefaultAopProxyFactory代理工厂,并通过该工厂生产代理对象。主要有两种代理对象生成方式:

  1. JDK代理
  2. CGLIB代理

通常目标类是接口的情况下使用JDK代理。其中JDK代理由JdkDynamicAopProxy类支持,CGLIB代理由CglibAopProxy支持。

JdkDynamicAopProxy类实现了InvocationHandler接口,在其Invoke方法里实现了Advice的织入。

invoke方法里有两个重要的地方:MethodInterceptor链的生成和增强方法的调用逻辑

MethodInterceptor链的生成
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

这一步由DefaultAdvisorChainFactory支持,该工厂方法用于从Advisor链生成某个方法的MethodInterceptor链。这里主要有两部分内容:

  1. 拆出Advisor里的PointCut用于方法的匹配和过滤
  2. 拆出Advisor里的Advice,根据Advice的实际类型来创建对应的MethodInterceptor,并加入链表

前面我们讲到GlobalAdvisorAdapterRegistry将IOC容器中的InterceptorNames对应的Bean封装为Advisor,后来,从Advisor拆出Advice并依据其类型创建对应的MethodInterceptor

@Override
    public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
        List<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>(3);
        Advice advice = advisor.getAdvice();
        //如果本身就是子类型MethodInterceptor,向下转型即可
        if (advice instanceof MethodInterceptor) {
            interceptors.add((MethodInterceptor) advice);
        }
        //如果只是Advice类型,通过各类AdvisorAdapter适配器来创建
        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()]);
    }

以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();
        //从Advisor中拆出Advice后重新封装为MethodBeforeAdviceInterceptor
        return new MethodBeforeAdviceInterceptor(advice);
    }

}

具体封装逻辑如下:

public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {

    private MethodBeforeAdvice advice;

    /** * Create a new MethodBeforeAdviceInterceptor for the given advice. * @param advice the MethodBeforeAdvice to wrap */
    public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
        Assert.notNull(advice, "Advice must not be null");
        this.advice = advice;
    }
//BeforeAdvice的执行逻辑封装在这里
//MethodInvocation为一个Joinpoint,表示将要被调用的方法,这里先执行了
//BeforeAdvice的before逻辑,再继续执行Joinpoint
    @Override
    public Object invoke(MethodInvocation mi) throws Throwable {
        this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
        return mi.proceed();
    }

}
增强方法的调用
if (chain.isEmpty()) {
    // We can skip creating a MethodInvocation: just invoke the target directly
    // Note that the final invoker must be an InvokerInterceptor so we know it does
    // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
    retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
}
else {
    // We need to create a method invocation...
    invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
    // Proceed to the joinpoint through the interceptor chain.
    retVal = invocation.proceed();
}

这一步即实际的方法调用逻辑,当该方法的Advisor链为空时,直接通过反射调用该方法。如果不为空,通过ReflectiveMethodInvocation的proceed()方法调用。ReflectiveMethodInvocation重写了MethodInvacation的proceed()方法:

@Override
    public Object proceed() throws Throwable {
        // We start with an index of -1 and increment early.
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        //直到MethodInterceptor链都执行了,才直接调用当前MethodInvocation执行
            return invokeJoinpoint();
        }
//不然则进入MethodInterceptor的执行逻辑,这里是动态PointCut匹配
        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.
            //MethodInterceptor的执行逻辑
            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
        }
    }

这里ReflectiveMethodInvocation实际上代表了一个Joinpoint的调用,但是其内部包含了一个MethodInterceptor链,即各类增强逻辑。各类增强逻辑有多个,有前也右后,其前后顺序封装在各MethodInterceptor的invoke方法里了(如前面所写的MethodBeforeAdviceInterceptor),invoke方法里对MethodInvocation的递归调用使得多个MethodInterceptor的循环得以进行,非常巧妙。

关于CGLIB的增强逻辑,是在CallBack中设置了默认的DynamicAdvisedInterceptor,其intercept方法中封装的逻辑与JDK代理的invoke方法封装的逻辑大同小异,不再赘述。

总结

spring aop首先从IOC容器中获取Advice或者MethodInterceptor等,将其封装为Advisor(这一步主要目的是将Advice与PointCut相结合),最后在JDK Proxy和CGLIB Proxy的回调方法中应用PointCut匹配具体方法,并将Advisor中的Advice按类型封装为MethodInterceptor应用到目标方法的调用MethodInvocation上去。

Spring 技术内幕

    原文作者:AOP
    原文地址: https://blog.csdn.net/john_lw/article/details/80925657
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞