Spring AOP源码02 - 代理的创建

Spring AOP 的实现

Spring AOP 不同于 AspectJ 的 AOP 实现,是在 runtime,通过代理原本的 object 来实现的。
由于 Spring IOC 的 container 的存在,编程过程中是通过container 间接地访问对象,Spring 可以将原本的object 替换为 proxy ,而不侵入原本的代码。
Proxy 有两种产生方式,通过 Java dynamic proxy 和 CGLIB 。本章只涉及 dyanmic proxy 的实现方法。 (dynamic proxy 的基础不在本章范围内)

ProxyFactory

ProxyFactory 提供了手动创建代理的方法。是比较好的一个分析 Proxy 生成过程的切入点。通过设置需要被代理的object 以及对应的advisors 就可以生成相应的代理。它和被代理的object 是一一对应的关系。

// 创建代理示例
ProxyFactory factory = new ProxyFactory();
// 设置target object
factory.setTarget(myBusinessInterfaceImpl);
// 设置interface 及 advice/advisor
factory.setInterface(MyBusinessInterface);
factory.addAdvice(myMethodInterceptor);
factory.addAdvisor(myAdvisor);
MyBusinessInterface tb = (MyBusinessInterface) factory.getProxy();

其结构也很简单,通过继承 ProxyCreatorSupport ,实现了通用的一些代理的配置以及对Advisor, Advice, interfaces 等的管理

Spring AOP源码02 - 代理的创建_第1张图片
ProxyFactory.png

Proxy 配置和管理

配置主要由 ProxyConfig 完成,Advise/Advisor的注册管理则定义在Advised 里。

ProxyConfig

定义了下列参数。

    private boolean proxyTargetClass = false;
    private boolean optimize = false;
    boolean opaque = false;
    boolean exposeProxy = false;
    private boolean frozen = false;
  • proxyTargateClass. 是否使用CGLIB

  • optimize. 是否采用CGLIB 的优化

  • opaque. 是否允许生成的proxy 被cast 成 Advised ——— 通过Advised 可以知道该proxy 的切面等信息

  • exposeProxy. 是否要把当前proxy 暴露在threadlocal 中。从而可以通过AopContext.currentProxy() 获取该proxy。一个使用场景是,如果希望在被proxy的class中调用proxy的方法,则需要开启此功能,从threadlocal 中获取proxy。

  • frozen. 是否允许继续修改配置,可以通过将其设置为 true 来避免被意外修改。

Advised

Advised 和被代理的object 是一一对应的关系,定义了一些列管理加于被代理object 上的proxy 的方法 —— 管理interfaces, advices, advisors 等

  • ProxyConfig 中的参数的获取
  • Proxied Interface 的管理
  • Targate Source 的管理
  • Advice List 的管理
  • Advisor List 的管理

TargateSource

我们并不直接访问被代理的对象,而是通过TargateSource来访问。TargateSource 封装了被proxy 的object, 提供了对proxied object 的间接访问。这让我们可以不透明地替换下面实际的proxied object。

public interface TargetSource extends TargetClassAware {

    Class getTargetClass();

    boolean isStatic();

    Object getTarget() throws Exception;

    void releaseTarget(Object target) throws Exception;
}

通常用SingletonTargetSource 访问固定 proxied object 就可以了。

AdvisedSupport

上述两个配置由 AdvisedSupport 合起来提供一个convenience implementation

public class AdvisedSupport extends ProxyConfig implements Advised {}

实现细节上,AdvisedSupport 默认使用SingletonTargetSource

advice 添加的时候会被转化为 DefaultPointcutAdvisor,对所有的class/method 都生效。

另外会有对Introduction advice 的一些处理。例如会将 introduction interface 加到 proxied interfce 里。

生成 Proxy

ProxyFactory 将配置和管理的工作都交给了 AdvisedSupport ,而将具体的生成的代理的工作 delegate 给了 AopProxy
生成 proxy 的入口如下

public Object getProxy() {
    return createAopProxy().getProxy();
}

public interface AopProxy {

    Object getProxy();

    Object getProxy(ClassLoader classLoader);
}

AopProxy 两种实现,有基于Java dynamic proxy 的实现 ——JdkDynamicAopProxy 和基于CGLIB 的实现 —— CglibAopProxy

DefaultAopProxyFactory

具体AopProxy 实现会经由工厂类 DefaultAopProxyFactory 决定,通过判断 config 的 optimize, proxyTargetClass, 以及proxied interfaces 来判断用那个一 AopProxy

    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
        if (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);
        }
    }

JdkDynamicAopProxy

JdkDynamicAopProxy 是实际生成proxy 的地方
JdkDynamicAopProxy 实现 InvocationHandler, 用Java dynamic proxy生成代理

Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);

Proxied Interfaces

而proxiedInterfaces 由AopProxyUtils.completeProxiedInterfaces(AdvisedSupport advised, boolean decoratingProxy) 生成,除了我们添加到ProxyFactory 的interface 之外,还会添加三个特殊的 interface, SpringProxy, Advised, DecoratingProxy

SpringProxy - 空interface, 用来标记该object 是spring 生成的 proxy

Advised - 令proxy 也能访问到创建它的proxy 信息,如果 ProxyConfig.opaque = true 则不添加这个 interface。

DecoratingProxy - 令AOP 外部的 package 也能检查 proxy 上的 interface

AdvisedDecoratingProxy 上的方法的调用会被拦截下来,具体实现视AopProxy 的实现而定。

invoke()

invoke()JdkDynamicAopProxy 的核心方法,调用的拦截,转发都是在这里完成。

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    ...

    try {
        ...

        /*
        拦截对 DecoratingProxy 和 Advised 方法的调用
         */
        else if (method.getDeclaringClass() == DecoratingProxy.class) {
            return AopProxyUtils.ultimateTargetClass(this.advised);
        }
        else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
                method.getDeclaringClass().isAssignableFrom(Advised.class)) {
            return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
        }

        Object retVal;

        /*
        在threadlocal 中暴露当前proxy
         */
        if (this.advised.exposeProxy) {
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }

        /*
        从TargetSource 中获取object
         */
        target = targetSource.getTarget();
        if (target != null) {
            targetClass = target.getClass();
        }

        /*
        创建interceptor 链并调用
         */
        List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

        if (chain.isEmpty()) {
            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
            retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
        }
        else {
            invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
            retVal = invocation.proceed();
        }

        /*
        如果返回值为该object, 则尝试返回 proxy。
        以及 null 检查
         */
        Class returnType = method.getReturnType();
        if (retVal != null && retVal == target &&
                returnType != Object.class && returnType.isInstance(proxy) &&
                !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
            retVal = proxy;
        }
        else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
            throw new AopInvocationException(
                    "Null return value from advice does not match primitive return type for: " + method);
        }
        return retVal;
    }
    /*
    最后恢复threadlocal 中之前的proxy
     */
    finally {
        if (target != null && !targetSource.isStatic()) {
            // Must have come from TargetSource.
            targetSource.releaseTarget(target);
        }
        if (setProxyContext) {
            // Restore old proxy.
            AopContext.setCurrentProxy(oldProxy);
        }
    }
}
 
 

拦截链

不管是 dynamic proxy 还是 cglib 都只是实现代码“织入“的手段。而真正的逻辑还是定义在拦截链上。

AdvisorChainFactory

getInterceptorsAndDynamicInterceptionAdvice 返回条件可能符合当前调用的所有Advisor。

基本逻辑是遍历所有注册的advisor,能用pointcut 过滤掉的都先过滤掉,然后用 Advice adapter 转化成MethodInterceptor

注意由于ProxyFactory 并不会在生成proxy 之前,对注册的advisor 先做一次过滤,所以实际每次调用都会都会进行这样的遍历,所以在注册advisor 的时候需要留意,不要将对当前对象无效的advisor 注册进来。

public interface AdvisorChainFactory {

    List getInterceptorsAndDynamicInterceptionAdvice(Advised config, Method method, Class targetClass);
}
 
 

AdvisorChainFactory 只有 DefaultAdvisorChainFactory 一个实现。

public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable {

    @Override
    public List getInterceptorsAndDynamicInterceptionAdvice(
            Advised config, Method method, Class targetClass) {

        List interceptorList = new ArrayList(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) {
                PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
                /*
                PointcutAdvisor 的情况下,先用其 ClassFilter 筛一下
                 */
                if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
                    /*
                    使用 Advice Adapter 转化 PointcutAdvisor 中的 advice
                     */
                    MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                    MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
                    /*
                    用 MethodFilter 再筛一遍
                     */
                    if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
                        /*
                        static 的 advisor 的interceptor 现在已经可以直接放入拦截链里了
                        但如果还需要 runtime 的检查 (检查调用时传入的 arguments), 
                        则需要将 InterceptorAndDynamicMethodMatcher 将interceptor 和 method matcher wrap 起来供runtime 检查用
                        这也是runtime 的 pointcut 性能较差的原因
                         */
                        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));
                        }
                    }
                }
            }
            /*
            IntroductionAdvisor 则简单取出 interceptor 即可
             */
            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));
                }
            }
            /*
            其他(用户自定义的) advisor
             */
            else {
                Interceptor[] interceptors = registry.getInterceptors(advisor);
                interceptorList.addAll(Arrays.asList(interceptors));
            }
        }

        return interceptorList;
    }
    ...
}
 
 

ReflectiveMethodInvocation

ReflectiveMethodInvocation 将一次调用和上面的拦截链组合起来

public Object proceed() throws Throwable {
    /*
    拦截链遍历完,调用原本的方法
     */
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        return invokeJoinpoint();
    }

    /*
    获取并调用拦截器的 invoke() 方法,传入自身
    而拦截器中,执行了自身逻辑之后由会调用 MethodInvocation.proceed() 方法,
    从而递归地实现对拦截链的遍历
     */
    Object interceptorOrInterceptionAdvice =
            this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
        /*
        做runtime 的 MethodMatcher 检查
         */
        InterceptorAndDynamicMethodMatcher dm =
                (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
        if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
            return dm.interceptor.invoke(this);
        }
        else {
            return proceed();
        }
    }
    else {
        return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    }
}

至此整个拦截调用,用了一种很巧妙的方法,将advice代码的执行时间交给了拦截器自己决定。这种方法灵活度更高也更容易实现。而不是通过维护拦截链顺序,比如将before advice 放在原方法调用前,after returing 放在调用链后。

总结

  1. Spring AOP runtime 的代码织入有两种方式,Java dynamic proxy 和 cglib。代码织入方式和 AOP 的实现调用无关。

  2. AOP 后的方法调用每次都会遍历过滤所有的advisor,所以不要注册无效的advisor。

  3. 调用链中的 Interceptor 通过改变 MethodInvocation.invoke() 的位置来改变切入时机。ReflectiveMethodInvocation 封装方法调用,递归地调用拦截器。

你可能感兴趣的:(Spring AOP源码02 - 代理的创建)