zoukankan      html  css  js  c++  java
  • Spring AOP学习笔记04:AOP核心实现之创建代理

      上文中,我们分析了对所有增强器的获取以及获取匹配的增强器,在本文中我们就来分析一下Spring AOP中另一部分核心逻辑--代理的创建。这部分逻辑的入口是在wrapIfNecessary()方法中紧接着增强器的获取之后的createProxy():

    protected Object createProxy(
            Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
    
        ProxyFactory proxyFactory = new ProxyFactory();
        // 获取当前类中相关属性
        proxyFactory.copyFrom(this);
        // 决定对于给定的bean是否应该使用targetClass而不是它的接口进行代理
        if (!shouldProxyTargetClass(beanClass, beanName)) {
            // Must allow for introductions; can't just set interfaces to
            // the target's interfaces only.
            Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, this.proxyClassLoader);
            for (Class<?> targetInterface : targetInterfaces) {
                // 添加代理接口
                proxyFactory.addInterface(targetInterface);
            }
        }
    
        Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
        for (Advisor advisor : advisors) {
            // 加入增强器
            proxyFactory.addAdvisor(advisor);
        }
        // 设置要代理的类
        proxyFactory.setTargetSource(targetSource);
        // 定制代理
        customizeProxyFactory(proxyFactory);
        // 用来控制代理工厂被配置之后,是否还允许修改通知
        // 默认值为false(即在代理被配置之后,不允许修改代理的配置)
        proxyFactory.setFrozen(this.freezeProxy);
        if (advisorsPreFiltered()) {
            proxyFactory.setPreFiltered(true);
        }
    
        return proxyFactory.getProxy(this.proxyClassLoader);
    }

      对于代理类的创建及处理,Spring委托给了ProxyFactory进行处理,而在上面的函数中主要是对ProxyFactory的初始化操作,为真正的代理创建做准备,初始化包括如下内容:

    • 获取当前中的属性;
    • 添加代理接口;
    • 封装Advisor并加入到ProxyFactory中;
    • 设置要代理的类;
    • 对代理工厂进行定制化处理,供子类实现;
    • 进行获取代理操作;

      其中封装Advisor并加入到ProxyFactory中以及创建代理是两个相对繁琐的过程,可以通过ProxyFactory提供的addAdvisor方法直接将增强器置入代理创建工厂中,但是将拦截器封装为增强器还是需要一定的逻辑的。

    protected Advisor[] buildAdvisors(String beanName, Object[] specificInterceptors) {
        // 解析注册的所有interceptorName
        Advisor[] commonInterceptors = resolveInterceptorNames();
    
        List<Object> allInterceptors = new ArrayList<Object>();
        if (specificInterceptors != null) {
            // 加入拦截器
            allInterceptors.addAll(Arrays.asList(specificInterceptors));
            if (commonInterceptors != null) {
                if (this.applyCommonInterceptorsFirst) {
                    allInterceptors.addAll(0, Arrays.asList(commonInterceptors));
                }
                else {
                    allInterceptors.addAll(Arrays.asList(commonInterceptors));
                }
            }
        }
        if (logger.isDebugEnabled()) {
            int nrOfCommonInterceptors = (commonInterceptors != null ? commonInterceptors.length : 0);
            int nrOfSpecificInterceptors = (specificInterceptors != null ? specificInterceptors.length : 0);
            logger.debug("Creating implicit proxy for bean '" + beanName + "' with " + nrOfCommonInterceptors +
                    " common interceptors and " + nrOfSpecificInterceptors + " specific interceptors");
        }
    
        Advisor[] advisors = new Advisor[allInterceptors.size()];
        for (int i = 0; i < allInterceptors.size(); i++) {
            // 将拦截器进行包装转化为Advisor
            advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
        }
        return advisors;
    }
    
    public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
        // 如果要封装的对象本身就是Advisor类型的那么无需再做过多处理
        if (adviceObject instanceof Advisor) {
            return (Advisor) adviceObject;
        }
        // 如果不是Advisor与Advice两种类型,则抛出异常
        if (!(adviceObject instanceof Advice)) {
            throw new UnknownAdviceTypeException(adviceObject);
        }
        Advice advice = (Advice) adviceObject;
        if (advice instanceof MethodInterceptor) {
            // 如果是MethodInterceptor类型则使用DefaultPointcutAdvisor封装
            return new DefaultPointcutAdvisor(advice);
        }
        // 如果存在Advisor的适配器那么也同样需要进行封装
        for (AdvisorAdapter adapter : this.adapters) {
            // Check that it is supported.
            if (adapter.supportsAdvice(advice)) {
                return new DefaultPointcutAdvisor(advice);
            }
        }
        throw new UnknownAdviceTypeException(advice);
    }

      因为Spring中涉及过多的拦截器、增强器、增强方法等方式来对逻辑进行增强,所以非常有必要将增强器封装成Advisor来进行代理的创建,完成了增强的封装过程,那么接下来就是最重要的一步--代理的创建与获取。

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

    1. 创建代理

    protected final synchronized AopProxy createAopProxy() {
        if (!this.active) {
            activate();
        }
        // 创建代理
        return getAopProxyFactory().createAopProxy(this);
    }
    
    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()) {
                return new JdkDynamicAopProxy(config);
            }
            return CglibProxyFactory.createCglibProxy(config);
        }
        else {
            return new JdkDynamicAopProxy(config);
        }
    }

      到这里已经完成了代理的创建了,不管我们之前是否有阅读过Spring的源码,但是应该或多或少都听说过对于Spring的代理中JDKProxy的实现CglibProxy的实现。Spring是如果选取的呢?现在我们就从源码的角度分析,看看到底Spring是如何选择代理方式的。

      从上面代码中的判断条件可以看到3个方面影响着Spring的判断:

    • optimize:用来控制通过CGLIB创建的代理是否使用激进的优化策略。除非完全了解AOP代理如何处理优化,否则不推荐用户使用这个设置。目前这个属性仅用于CGLIB代理,对于JDK动态代理(默认代理)无效。
    • proxyTargetClass:这个属性为true时,目标类本身被代理而不是目标类的接口,并且使用CGLIB方式创建代理,xml文件配置方式为:<aop:aspectj-autoproxy proxy-target-class="true"/>。
    • hasNoUserSuppliedProxyInterfaces:是否存在代理接口。

      下面是对JDK与Cglib方式的总结:

    • 如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP;
    • 如果目标对象实现了接口,可以强制使用CGLIB实现AOP;
    • 如果目标对象没有实现接口,则必须采用CGLIB方式实现AOP,Spring会自动切换;

    如何强制使用CGLIB实现AOP?

    • 添加CGLIB库,Spring_HOME/cglib/*.jar
    • 在Spring配置文件中加入<aop:aspectj-autoproxy proxy-target-class="true"/>

    JDK动态代理和CGLIB字节码生成的区别?

    • JDK动态代理只能对实现了接口的类生成代理,而不能针对类。
    • CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法,因为是继承,所以该类或方法最好不要声明成final。

    2. 获取代理

      确定了使用哪种代理方式之后便可以进行代理的创建了,Spring中主要使用了两种方式来实现代理的创建:JDK动态代理、cglib,我们一一来解析。

    2.1 JDK动态代理方式

      这里直接定位到JdkDynamicAopProxy中的getProxy():

    public Object getProxy(ClassLoader classLoader) {
        if (logger.isDebugEnabled()) {
            logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
        }
        Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
        findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
        return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    }

      JDK动态代理的使用关键是创建自定义的InvocationHandler,而InvocationHandler中包含了需要覆盖的函数getProxy,这里其实JdkDynamicAopProxy就是继承了InvocationHandler的,所以上面的方法正是完成了这个操作,并且我们还可以推断出,在JdkDynamicAopProxy中一定会有一个invoke函数,并且JdkDynamicAopProxy会把AOP的核心逻辑写在其中,找一下,一定会有这样一个函数的:

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        MethodInvocation invocation;
        Object oldProxy = null;
        boolean setProxyContext = false;
    
        TargetSource targetSource = this.advised.targetSource;
        Class<?> targetClass = null;
        Object target = null;
    
        try {
            // 处理equals方法
            if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
                return equals(args[0]);
            }
            // 处理hash方法
            if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
                return hashCode();
            }
            if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
                    method.getDeclaringClass().isAssignableFrom(Advised.class)) {
                // Service invocations on ProxyConfig with the proxy config...
                return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
            }
    
            Object retVal;
            // 有时候目标对象内部的自我调用将无法实施切面中的增强,则需要通过此属性暴露代理
            if (this.advised.exposeProxy) {
                oldProxy = AopContext.setCurrentProxy(proxy);
                setProxyContext = true;
            }
    
            target = targetSource.getTarget();
            if (target != null) {
                targetClass = target.getClass();
            }
    
            // 获取当前方法的拦截器链
            List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
    
            if (chain.isEmpty()) {
                // 如果没有任何拦截器链则直接调用切点方法
                retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
            }
            else {
                // 将拦截器封装在ReflectiveMethodInvocation,以便于使用其proceed进行链式调用拦截器
                invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                // 执行拦截器链
                retVal = invocation.proceed();
            }
    
            // 返回结果
            Class<?> returnType = method.getReturnType();
            if (retVal != null && retVal == target && 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;
        }
        finally {
            if (target != null && !targetSource.isStatic()) {
                // Must have come from TargetSource.
                targetSource.releaseTarget(target);
            }
            if (setProxyContext) {
                // Restore old proxy.
                AopContext.setCurrentProxy(oldProxy);
            }
        }
    }

      上面的invoke()函数最主要的工作就是创建了一个拦截器链,并使用ReflectiveMethodInvocation类进行了链的封装,而在ReflectiveMethodInvocation类的proceed方法中实现了拦截器的逐一调用,那么我们就继续来探究,在proceed方法中是怎么实现诸如前置增强在目标方法前调用以及后置增强在目标方法后调用的逻辑的。

    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;
            if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
                return dm.interceptor.invoke(this);
            }
            else {
                // 若未匹配则不执行拦截器,调用拦截器链中下一个
                return proceed();
            }
        }
        else {
            // 普通拦截器,直接调用。将this作为参数传入以保证当前实例中调用链的执行
            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
        }
    }

      ReflectiveMethodInvocation的主要职责是维护一个链式调用的计数器,记录着当前调用链的位置,以便链可以有序地进行下去。其实在这个方法中并没有我们设想的维护各种增强的顺序,但是细心的读者可能会发现,这部分工作其实是委托给了各个增强器来实现,前面有说到。

    2.2 Cglib方式

      完成CGLIB代理的类是委托给CglibAopProxy类去实现的,我们来一探究竟。根据前面的分析,我们容易判断出来,CglibAopProxy的入口应该也是在getProxy():

    public Object getProxy(ClassLoader classLoader) {
        if (logger.isDebugEnabled()) {
            logger.debug("Creating CGLIB proxy: target source is " + this.advised.getTargetSource());
        }
    
        try {
            Class<?> rootClass = this.advised.getTargetClass();
            Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");
    
            Class<?> proxySuperClass = rootClass;
            if (ClassUtils.isCglibProxyClass(rootClass)) {
                proxySuperClass = rootClass.getSuperclass();
                Class<?>[] additionalInterfaces = rootClass.getInterfaces();
                for (Class<?> additionalInterface : additionalInterfaces) {
                    this.advised.addInterface(additionalInterface);
                }
            }
    
            // 验证Class
            validateClassIfNecessary(proxySuperClass);
    
            // 创建及配置CGLIB Enhancer
            Enhancer enhancer = createEnhancer();
            if (classLoader != null) {
                enhancer.setClassLoader(classLoader);
                if (classLoader instanceof SmartClassLoader &&
                        ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
                    enhancer.setUseCache(false);
                }
            }
            enhancer.setSuperclass(proxySuperClass);
            enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
            enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
            enhancer.setStrategy(new MemorySafeUndeclaredThrowableStrategy(UndeclaredThrowableException.class));
            enhancer.setInterceptDuringConstruction(false);
            // 设置拦截器
            Callback[] callbacks = getCallbacks(rootClass);
            Class<?>[] types = new Class<?>[callbacks.length];
            for (int x = 0; x < types.length; x++) {
                types[x] = callbacks[x].getClass();
            }
            enhancer.setCallbackFilter(new ProxyCallbackFilter(
                    this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
            enhancer.setCallbackTypes(types);
            enhancer.setCallbacks(callbacks);
    
            // 生成代理类及创建代理对象
            Object proxy;
            if (this.constructorArgs != null) {
                proxy = enhancer.create(this.constructorArgTypes, this.constructorArgs);
            }
            else {
                proxy = enhancer.create();
            }
    
            return proxy;
        }
        catch (CodeGenerationException ex) {
            catch若干异常。。。
        }
    }

      上面的函数中就是一个完整创建Enhancer的过程,详细可以参考Enhancer的文档,这里最重要的是通过getCallbacks()方法设置拦截器链。

    private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
        // 对于expose-proxy属性的处理
        boolean exposeProxy = this.advised.isExposeProxy();
        boolean isFrozen = this.advised.isFrozen();
        boolean isStatic = this.advised.getTargetSource().isStatic();
    
        // 将拦截器封装在DynamicAdvisedInterceptor中
        Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
    
        // Choose a "straight to target" interceptor. (used for calls that are
        // unadvised but can return this). May be required to expose the proxy.
        Callback targetInterceptor;
        if (exposeProxy) {
            targetInterceptor = isStatic ?
                    new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :
                    new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource());
        }
        else {
            targetInterceptor = isStatic ?
                    new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :
                    new DynamicUnadvisedInterceptor(this.advised.getTargetSource());
        }
    
        // 将拦截器加入到callback中
        Callback targetDispatcher = isStatic ?
                new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp();
    
        Callback[] mainCallbacks = new Callback[] {
                aopInterceptor,  // for normal advice
                targetInterceptor,  // invoke target without considering advice, if optimized
                new SerializableNoOp(),  // no override for methods mapped to this
                targetDispatcher, this.advisedDispatcher,
                new EqualsInterceptor(this.advised),
                new HashCodeInterceptor(this.advised)
        };
    
        Callback[] callbacks;
    
        // If the target is a static one and the advice chain is frozen,
        // then we can make some optimisations by sending the AOP calls
        // direct to the target using the fixed chain for that method.
        if (isStatic && isFrozen) {
            Method[] methods = rootClass.getMethods();
            Callback[] fixedCallbacks = new Callback[methods.length];
            this.fixedInterceptorMap = new HashMap<String, Integer>(methods.length);
    
            // TODO: small memory optimisation here (can skip creation for methods with no advice)
            for (int x = 0; x < methods.length; x++) {
                List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(methods[x], rootClass);
                fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(
                        chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());
                this.fixedInterceptorMap.put(methods[x].toString(), x);
            }
    
            // Now copy both the callbacks from mainCallbacks
            // and fixedCallbacks into the callbacks array.
            callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length];
            System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length);
            System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length);
            this.fixedInterceptorOffset = mainCallbacks.length;
        }
        else {
            callbacks = mainCallbacks;
        }
        return callbacks;
    }

      在getCallback()中Spring考虑了很多情况,有很多的细节,但是我们阅读源码是没有必要也没有那么多精力把每一个细节都弄明白的,重点是抓住主干即可。这里只需要理解最常用的,比如将advised属性封装在DynamicAdvisedInterceptor并加入在callbacks中,这么做的目的是什么呢?在CGLIB中对于方法的拦截是通过将自定义的拦截器(实现了MethodInterceptor接口的类)加入Callback中并在调用代理时直接激活拦截器中的intercept()方法来实现的,而在getCallback()方法中正好有这一部分功能的实现,DynamicAdvisedInterceptor继承自MethodInterceptor,加入Callback中后,在再次调用代理时会直接调用其intercept()方法,由此推断,对于CGLIB方式实现的代理,其核心逻辑应该是在DynamicAdvisedInterceptor中的intercept()方法中的:

    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        Object oldProxy = null;
        boolean setProxyContext = false;
        Class<?> targetClass = null;
        Object target = null;
        try {
            if (this.advised.exposeProxy) {
                // Make invocation available if necessary.
                oldProxy = AopContext.setCurrentProxy(proxy);
                setProxyContext = true;
            }
            // May be null. Get as late as possible to minimize the time we
            // "own" the target, in case it comes from a pool...
            target = getTarget();
            if (target != null) {
                targetClass = target.getClass();
            }
            // 获取拦截器链
            List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
            Object retVal;
            if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
                // 如果拦截器链为空则直接激活原方法
                retVal = methodProxy.invoke(target, args);
            }
            else {
                // 链式调用
                retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
            }
            retVal = processReturnType(proxy, target, method, retVal);
            return retVal;
        }
        finally {
            if (target != null) {
                releaseTarget(target);
            }
            if (setProxyContext) {
                // Restore old proxy.
                AopContext.setCurrentProxy(oldProxy);
            }
        }
    }

      这里的实现与JDK动态代理方式实现代理中的invoke方法大同小异,都是首先构造拦截器链,然后封装此链进行串联调用,不同的是在JDK动态代理的方式中是直接构造ReflectiveMethodInvocation,而在cglib中则是使用CglibMethodInvocation,其是继承自ReflectiveMethodInvocation,但是proceed()方法并没有重写。

    3. 总结

      本文着重分析了Spring AOP实现原理中代理对象的创建过程,在bean的初始化过程中会执行Spring的后置处理器,这里会去判断这个bean是否需要增强,如果需要则会根据Aspect中定义的增强信息,对指定bean进行增强,也就是创建一个代理对象。对代理对象的创建有两种方式,一种是通过JDK动态代理的方式,另一种是通过cglib的方式。

  • 相关阅读:
    在日志中记录Java异常信息的正确姿势
    基于Spring Boot架构的前后端完全分离项目API路径问题
    Spring生态简介
    WebSocket协议入门介绍
    Spring Boot程序正确停止的姿势
    python 中 __init__方法
    python中的if __name__ == 'main'
    python 类和实例
    内建模块 datetime使用
    内建模块collections的使用
  • 原文地址:https://www.cnblogs.com/volcano-liu/p/13020422.html
Copyright © 2011-2022 走看看