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


    生成SingleTon代理对象在getSingleTonInstance方法中完毕,这种方法时ProxyFactoryBean生成AopProxy对象的入口。代理对象会封装对target目标对象的调用。也就是说针对target对象的方法调用行为会被这里生成的代理对象所拦截。

    详细的生成过程是首先读取ProxyFactoryBean配置,为生成代理对象做好准备。Spring通过AopProxy类来详细生成代理对象。对于getSingleTonInstance方法中生成代理对象的步骤例如以下:

    /**
         * Return the singleton instance of this class's proxy object,
         * lazily creating it if it hasn't been created already.
         * @return the shared singleton proxy
         */
        private synchronized Object getSingletonInstance() {
            if (this.singletonInstance == null) {
                this.targetSource = freshTargetSource();
                if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
                    // Rely on AOP infrastructure to tell us what interfaces to proxy.
                    // 依据AOP框架来推断须要代理的接口
                    Class targetClass = getTargetClass();
                    if (targetClass == null) {
                        throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");
                    }
                    // 这里设置代理对象的接口
                    setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
                }
                // Initialize the shared singleton instance.
                super.setFrozen(this.freezeProxy);
                // 这里会使用ProxyFactoryBean来生成须要的proxy对象
                this.singletonInstance = getProxy(createAopProxy());
            }
            return this.singletonInstance;
        }
    /**
         * Return the proxy object to expose.
         * <p>The default implementation uses a {@code getProxy} call with
         * the factory's bean class loader. Can be overridden to specify a
         * custom class loader.
         * @param aopProxy the prepared AopProxy instance to get the proxy from
         * @return the proxy object to expose
         * @see AopProxy#getProxy(ClassLoader)
         */
        protected Object getProxy(AopProxy aopProxy) {
            return aopProxy.getProxy(this.proxyClassLoader);
        }

    这里出现了AopProxy对象类型,Spring利用AOPProxy接口类把AOP代理对象的实现与框架其它部分有效隔离开来。

    AopProxy接口有两个子类实现,一个Cglib2AopProxy,还有一个是JdkDynamicProxy。
    详细代理对象的生成是在ProxyFactoryBean的基类AdvisedSupport中实现,借助AopProxyFactory完毕,这个对象要么从JDK中生成,要么借助CGLIB获得。

    以下看看ProxyCreatorSupport中是怎样生成代理对象的。

        /**
         * Subclasses should call this to get a new AOP proxy. They should <b>not</b>
         * create an AOP proxy with {@code this} as an argument.
         */
        protected final synchronized AopProxy createAopProxy() {
            if (!this.active) {
                activate();
            }
            // 通过AopProxyFactory取得AopProxy,这个AopProxyFactory是在初始化函数中定义的,使用的是DefaultAopProxyFactory
            return getAopProxyFactory().createAopProxy(this);
        }

    AopProxy代理对象的生成有两种方式。假设目标对象是接口类使用JDK来生成,否则Spring会使用CGLIB来生成目标的代理对象。

    以下看看在DefaultAopProxyFactory是怎样生成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()) {
                    return new JdkDynamicAopProxy(config);
                }
                return CglibProxyFactory.createCglibProxy(config);
            }
            else {
                return new JdkDynamicAopProxy(config);
            }
        }

    在AopProxy代理对象的生成过程中。首先要从AdviseSupport对象中取得配置的目标对象。AOP完毕的是切面应用对目标应用对象的增强。假设这里没有配置目标对象会直接抛出异常。一般而言,默认方式是使用JDK来产生AopProxy代理对象,但假设配置的目标对象不是接口类的实现,会使用CGLIB来产生AopProxy代理对象;在使用CGLIB来产生AopProxy代理对象时,由于CGLIB是第三方类库,本身不在JDK基类库中,全部须要在classPath中正确配置,以便可以载入和利用。在Spring中。使用JDK和CGLIB来生成AopProxy代理对象的工作,是由JdkDynamicAopProxy和CglibProxyFactory来完毕。


    4、JDK生成AopProxy对象(接口实现类)
    通过上面我们已经知道生成AopProxy对象有两种方式,以下看下类图:
    这里写图片描写叙述
    我们先看下JdkDynamicAopProxy是怎样生成AopProxy对象的:

        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);
            // 调用JDK生成Proxy
            return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
        }

    5、CGLIB生成AopProxy对象(非接口实现类)

        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); } } // Validate the class, writing log messages as necessary. validateClassIfNecessary(proxySuperClass); // Configure CGLIB Enhancer... // 来自advised的IOC配置。比方使用AOP的DynamicAdvisedInterceptor 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); // 通过设置DynamicAdvisedInterceptor拦截器来完毕AOP功能,getCallBacks方法例如以下: // Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised) 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); // Generate the proxy class and create a proxy instance. Object proxy; if (this.constructorArgs != null) { proxy = enhancer.create(this.constructorArgTypes, this.constructorArgs); } else { proxy = enhancer.create(); } return proxy; } catch (CodeGenerationException ex) { throw new AopConfigException("Could not generate CGLIB subclass of class [" + this.advised.getTargetClass() + "]: " + "Common causes of this problem include using a final class or a non-visible class", ex); } catch (IllegalArgumentException ex) { throw new AopConfigException("Could not generate CGLIB subclass of class [" + this.advised.getTargetClass() + "]: " + "Common causes of this problem include using a final class or a non-visible class", ex); } catch (Exception ex) { // TargetSource.getTarget() failed throw new AopConfigException("Unexpected AOP exception", ex); } }

    四、Spring AOP拦截器调用的实现
    1、设计原理
    在Spring AOP通过JDK的Proxy方式或CGLIB方式生成代理对象的时候,相关的拦截器已经配置到代理对象中去了,拦截器在代理对象中起作用是通过对这些方法的回调来完毕的。
    假设使用JDK的Proxy来生成代理对象,那么须要InvocationHandler来设置拦截器回调,而假设使用CGLIB来生成代理对象。通过DynamicAdvisedInterceptor来完毕回调。
    2、JdkDynamicAopProxy的invoke拦截
    在JDKDynamicAopProxy生成代理对象时,他的AopProxy代理对象生成调用:

    Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);

    this指的是InvocationHandler对象,InvocationHandler是JDK定义反射类的一个接口。这个接口定义了invoke方法,此方法为回调方法。

    通过invoke的详细实现。来完毕对目标对象方法调用的拦截器或者功能增强工作。

    在这种方法中。包括一个完整的拦截器链对目标对象的拦截过程。比方获取拦截器链中的拦截器进行配置。逐个执行拦截器链里的拦截器增强,知道最后的目标对象方法的执行。以下看下invoke的源代码

        /**
         * Implementation of {@code InvocationHandler.invoke}.
         * <p>Callers will see exactly the exception thrown by the target,
         * unless a hook method throws an exception.
         */
        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 {
                if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
                    // The target does not implement the equals(Object) method itself.
                    return equals(args[0]);
                }
                if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
                    // The target does not implement the hashCode() method itself.
                    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) {
                    // 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 = targetSource.getTarget();
                if (target != null) {
                    targetClass = target.getClass();
                }
                // Get the interception chain for this method.
                // 获得定义好的拦截器
                List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
                // Check whether we have any advice. If we don't, we can fallback on direct
                // reflective invocation of the target, and avoid creating a MethodInvocation.
                // 假设没有拦截器直接调用target的相应方法
                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();
                }
                // Massage return value if necessary.
                Class<?> returnType = method.getReturnType();
                if (retVal != null && retVal == target && returnType.isInstance(proxy) &&
                        !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
                    // Special case: it returned "this" and the return type of the method
                    // is type-compatible. Note that we can't help if the target sets
                    // a reference to itself in another returned object.
                    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);
                }
            }
        }

    3、CglibAopProxy的intercept拦截器
    使用CglibAopProxy生成AopProxy对象时候。对于AOP拦截器调用。回调的是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;
                    // Check whether we only have one InvokerInterceptor: that is,
                    // no real advice, but just reflective invocation of the target.
                    if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
                        // 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 = methodProxy.invoke(target, args);
                    }
                    else {
                        // We need to create a method invocation...
                        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);
                    }
                }
            }
  • 相关阅读:
    物联网与边缘计算的融合
    在【自我认知】大学,你可能永远毕不了业
    Spring Security实现短信验证码登录
    线上课程
    【技术人成长】公众号
    大数据是阿猫阿狗都能玩的吗
    机器不能代替你思考
    如何缓解需求沟通中的鸡同鸭讲
    如何成为一个更渊博的技术人
    招聘季,聊聊那些古怪的候选人
  • 原文地址:https://www.cnblogs.com/lytwajue/p/7279015.html
Copyright © 2020-2023  润新知