1. 程式人生 > >Spring技術內幕:Spring AOP的實現原理(三)

Spring技術內幕:Spring AOP的實現原理(三)

dede ide configure ida mini == src min dem

生成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 [email protected] 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 [email protected] 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 [email protected] 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技術內幕:Spring AOP的實現原理(三)