spring源碼學習之路---深入AOP(終)


                 作者:zuoxiaolong8810(左瀟龍),轉載請注明出處,特別說明:本博文來自博主原博客,為保證新博客中博文的完整性,特復制到此留存,如需轉載請注明新博客地址即可。

                上一章和各位一起看了一下springAOP的工作流程,當我們給出AOP相關的配置以后,直接從IOC容器中拿出來的就是已經加強過的bean。這說明spring在這個過程中一定做了什么。

                本章我們就一起來看一下spring是如何完成對bean的增強的,首先我們來看一下,FactoryBean接口中一個方法的定義。

public interface FactoryBean<T> {

    /**
     * Return an instance (possibly shared or independent) of the object
     * managed by this factory.
     * <p>As with a {@link BeanFactory}, this allows support for both the
     * Singleton and Prototype design pattern.
     * <p>If this FactoryBean is not fully initialized yet at the time of
     * the call (for example because it is involved in a circular reference),
     * throw a corresponding {@link FactoryBeanNotInitializedException}.
     * <p>As of Spring 2.0, FactoryBeans are allowed to return <code>null</code>
     * objects. The factory will consider this as normal value to be used; it
     * will not throw a FactoryBeanNotInitializedException in this case anymore.
     * FactoryBean implementations are encouraged to throw
     * FactoryBeanNotInitializedException themselves now, as appropriate.
     * @return an instance of the bean (can be <code>null</code>)
     * @throws Exception in case of creation errors
     * @see FactoryBeanNotInitializedException
     */
    T getObject() throws Exception;

                 getObject這個方法,就是用來獲取被這個factorybean加強后的對象的,上一章測試的過程中,最終就是調用了這個方法,來完成了對bean的加強。我們來跟蹤一下上一次測試的代碼,看看到底是在什么地方調用的。這里再次貼出來上次測試的代碼,方便解釋。

public class TestAOP {

    public static void main(String[] args) {
        ApplicationContext applicationContext = new FileSystemXmlApplicationContext("classpath:beans.xml");
        TestTarget target = (TestTarget) applicationContext.getBean("testAOP");
        target.test();
        System.out.println("------無敵分割線-----");
        target.test2();
    }
    
}

其實整個過程也就兩行代碼,第一行代碼,是我們對IOC容器的初始化,這時其實並沒有發生對bean的增強,原因就是這個時候只是完成了對ProxyFactoryBean的初始化,也就是相當於我們已經new出來了一個ProxyFactoryBean,但是此時並沒有調用接口方法,去獲得加強后的bean。

         下面我們去跟進第二行獲取testAOP的代碼,來看一下究竟。首先我們會找到AbstractApplicationContext中的getBean方法,但是這個類並不負責bean的實例化工作,而是交給了bean工廠,我們跟蹤bean工廠的方法,能找到上述第二行其實是調用了如下這個方法。

@SuppressWarnings("unchecked")
    protected <T> T doGetBean(
            final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
            throws BeansException {

        final String beanName = transformedBeanName(name);
        Object bean;

        // Eagerly check singleton cache for manually registered singletons.
        Object sharedInstance = getSingleton(beanName);
        if (sharedInstance != null && args == null) {
            if (logger.isDebugEnabled()) {
                if (isSingletonCurrentlyInCreation(beanName)) {
                    logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
                            "' that is not fully initialized yet - a consequence of a circular reference");
                }
                else {
                    logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
                }
            }
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
        }

        else {
            // Fail if we're already creating this bean instance:
            // We're assumably within a circular reference.
            if (isPrototypeCurrentlyInCreation(beanName)) {
                throw new BeanCurrentlyInCreationException(beanName);
            }

            // Check if bean definition exists in this factory.
            BeanFactory parentBeanFactory = getParentBeanFactory();
            if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
                // Not found -> check parent.
                String nameToLookup = originalBeanName(name);
                if (args != null) {
                    // Delegation to parent with explicit args.
                    return (T) parentBeanFactory.getBean(nameToLookup, args);
                }
                else {
                    // No args -> delegate to standard getBean method.
                    return parentBeanFactory.getBean(nameToLookup, requiredType);
                }
            }

            if (!typeCheckOnly) {
                markBeanAsCreated(beanName);
            }

            final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
            checkMergedBeanDefinition(mbd, beanName, args);

            // Guarantee initialization of beans that the current bean depends on.
            String[] dependsOn = mbd.getDependsOn();
            if (dependsOn != null) {
                for (String dependsOnBean : dependsOn) {
                    getBean(dependsOnBean);
                    registerDependentBean(dependsOnBean, beanName);
                }
            }

            // Create bean instance.
            if (mbd.isSingleton()) {
                sharedInstance = getSingleton(beanName, new ObjectFactory() {
                    public Object getObject() throws BeansException {
                        try {
                            return createBean(beanName, mbd, args);
                        }
                        catch (BeansException ex) {
                            // Explicitly remove instance from singleton cache: It might have been put there
                            // eagerly by the creation process, to allow for circular reference resolution.
                            // Also remove any beans that received a temporary reference to the bean.
                            destroySingleton(beanName);
                            throw ex;
                        }
                    }
                });
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            }

            else if (mbd.isPrototype()) {
                // It's a prototype -> create a new instance.
                Object prototypeInstance = null;
                try {
                    beforePrototypeCreation(beanName);
                    prototypeInstance = createBean(beanName, mbd, args);
                }
                finally {
                    afterPrototypeCreation(beanName);
                }
                bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
            }

            else {
                String scopeName = mbd.getScope();
                final Scope scope = this.scopes.get(scopeName);
                if (scope == null) {
                    throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");
                }
                try {
                    Object scopedInstance = scope.get(beanName, new ObjectFactory() {
                        public Object getObject() throws BeansException {
                            beforePrototypeCreation(beanName);
                            try {
                                return createBean(beanName, mbd, args);
                            }
                            finally {
                                afterPrototypeCreation(beanName);
                            }
                        }
                    });
                    bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                }
                catch (IllegalStateException ex) {
                    throw new BeanCreationException(beanName,
                            "Scope '" + scopeName + "' is not active for the current thread; " +
                            "consider defining a scoped proxy for this bean if you intend to refer to it from a singleton",
                            ex);
                }
            }
        }

        // Check if required type matches the type of the actual bean instance.
        if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
            throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
        }
        return (T) bean;
    }

這是一個重載方法,后面三個參數兩個為null,一個為false。下面注意,在這面這一行的時候,我們已經獲取到了實例。

Object sharedInstance = getSingleton(beanName);

            所以分支在碰到第一個if判斷時,會直接進入if塊而不是else塊,在這里提醒一下,這個是獲取的單例的bean實例,而這個sharedInstance並不是TestTarget,而是ProxyFactoryBean的實例。好了,接下來相信你已經明白了,我們該進入getObjectForBeanInstance這個方法了,來看這個方法。

protected Object getObjectForBeanInstance(
            Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {

        // Don't let calling code try to dereference the factory if the bean isn't a factory.
        if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
            throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
        }

        // Now we have the bean instance, which may be a normal bean or a FactoryBean.
        // If it's a FactoryBean, we use it to create a bean instance, unless the
        // caller actually wants a reference to the factory.
        if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
            return beanInstance;
        }

        Object object = null;
        if (mbd == null) {
            object = getCachedObjectForFactoryBean(beanName);
        }
        if (object == null) {
            // Return bean instance from factory.
            FactoryBean factory = (FactoryBean) beanInstance;
            // Caches object obtained from FactoryBean if it is a singleton.
            if (mbd == null && containsBeanDefinition(beanName)) {
                mbd = getMergedLocalBeanDefinition(beanName);
            }
            boolean synthetic = (mbd != null && mbd.isSynthetic());
            object = getObjectFromFactoryBean(factory, beanName, !synthetic);
        }
        return object;
    }

方法的剛開始是兩個衛語句,第一個判斷如果是想獲得factorybean本身,卻又不是factorybean則拋出異常,第二個則是正常的獲得factorybean。但是我們都不屬於這兩種情況。所以在經過getCachedObjectForFactoryBean獲取無果和getCachedObjectForFactoryBean獲取到bean定義以后,就進入了getObjectFromFactoryBean方法。

protected Object getObjectFromFactoryBean(FactoryBean factory, String beanName, boolean shouldPostProcess) {
        if (factory.isSingleton() && containsSingleton(beanName)) {
            synchronized (getSingletonMutex()) {
                Object object = this.factoryBeanObjectCache.get(beanName);
                if (object == null) {
                    object = doGetObjectFromFactoryBean(factory, beanName, shouldPostProcess);
                    this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));
                }
                return (object != NULL_OBJECT ? object : null);
            }
        }
        else {
            return doGetObjectFromFactoryBean(factory, beanName, shouldPostProcess);
        }
    }

進入以后,由於proxyFactorybean是單例bean,所以會進入到if塊不是else塊,接下來系統再次嘗試從cache中獲得,自然是無果。接下來依然會進入到和else一樣的方法doGetObjectFromFactoryBean,先不說這個方法,看后面,獲得以后就會放入cache,然后直接將對象返回。所以如果重復調用,下一次就會從cache當中取出來直接返回。好了,接下來我們進去doGetObjectFromFactoryBean方法。

private Object doGetObjectFromFactoryBean(
            final FactoryBean factory, final String beanName, final boolean shouldPostProcess)
            throws BeanCreationException {

        Object object;
        try {
            if (System.getSecurityManager() != null) {
                AccessControlContext acc = getAccessControlContext();
                try {
                    object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
                        public Object run() throws Exception {
                                return factory.getObject();
                            }
                        }, acc);
                }
                catch (PrivilegedActionException pae) {
                    throw pae.getException();
                }
            }
            else {
                object = factory.getObject();
            }
        }
        catch (FactoryBeanNotInitializedException ex) {
            throw new BeanCurrentlyInCreationException(beanName, ex.toString());
        }
        catch (Throwable ex) {
            throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
        }

        
        // Do not accept a null value for a FactoryBean that's not fully
        // initialized yet: Many FactoryBeans just return null then.
        if (object == null && isSingletonCurrentlyInCreation(beanName)) {
            throw new BeanCurrentlyInCreationException(
                    beanName, "FactoryBean which is currently in creation returned null from getObject");
        }

        if (object != null && shouldPostProcess) {
            try {
                object = postProcessObjectFromFactoryBean(object, beanName);
            }
            catch (Throwable ex) {
                throw new BeanCreationException(beanName, "Post-processing of the FactoryBean's object failed", ex);
            }
        }

        return object;
    }

此處判斷了一下當前是否設置了安全管理器,我們並沒有設置,所以將直接調用ProxyFactoryBean的getObject方法,也就是對bean增強的地方。下面我們着重來看一下是如何對bean進行增強的。首先我們進入到ProxyFactoryBean的getObject方法來看一下。

public Object getObject() throws BeansException {
        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();
        }
    }

此處主要是先初始化了一下通知器鏈,然后就會根據是否單例做相應的動作,我們看一下初始化通知器鏈的進行。

private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
        if (this.advisorChainInitialized) {
            return;
        }

        if (!ObjectUtils.isEmpty(this.interceptorNames)) {
            if (this.beanFactory == null) {
                throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +
                        "- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames));
            }

            // Globals can't be last unless we specified a targetSource using the property...
            if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) &&
                    this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {
                throw new AopConfigException("Target required after globals");
            }

            // Materialize interceptor chain from bean names.
            for (String name : this.interceptorNames) {
                if (logger.isTraceEnabled()) {
                    logger.trace("Configuring advisor or advice '" + name + "'");
                }

                if (name.endsWith(GLOBAL_SUFFIX)) {
                    if (!(this.beanFactory instanceof ListableBeanFactory)) {
                        throw new AopConfigException(
                                "Can only use global advisors or interceptors with a ListableBeanFactory");
                    }
                    addGlobalAdvisor((ListableBeanFactory) this.beanFactory,
                            name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
                }

                else {
                    // If we get here, we need to add a named interceptor.
                    // We must check if it's a singleton or prototype.
                    Object advice;
                    if (this.singleton || this.beanFactory.isSingleton(name)) {
                        // Add the real Advisor/Advice to the chain.
                        advice = this.beanFactory.getBean(name);
                    }
                    else {
                        // It's a prototype Advice or Advisor: replace with a prototype.
                        // Avoid unnecessary creation of prototype bean just for advisor chain initialization.
                        advice = new PrototypePlaceholderAdvisor(name);
                    }
                    addAdvisorOnChainCreation(advice, name);
                }
            }
        }

        this.advisorChainInitialized = true;
    }

可以看到,其中針對我們配置的interpretorNames進行了循環,我們並非是配置的全局通知器,所以會進入else塊,然后因為我們配置的testAdvisor默認是單例的,所以會從bean工廠中去獲取這個實例,此時TestAdvisor已經實例化完成的,我們只是去取一下而已。然后就會進入addAdvisorOnChainCreation方法。這個方法不再一一貼進來,各位有興趣的可以自己去看一下,就是把通知器加到了通知鏈當中。

              值得注意的是在這個過程中,觸發了一個這樣的方法this.advisorAdapterRegistry.wrap(next)。這個方法就是用來包裝通知器的,如果不是advisor而是advice,就會包裝一下返回。

              好了,接着剛才的過程,初始化通知器鏈完成以后,就會進入getSingletonInstance方法,這是用來獲取單例實例的,而真正的加強也是在這里發生的,我們來看一下。

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.
                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);
            this.singletonInstance = getProxy(createAopProxy());
        }
        return this.singletonInstance;
    }

此時第一次獲取,單例實例為null,所以會進入if塊,首先刷新targetSource,因為我們的Target類沒有實現targetSource接口,所以會由spring幫我們產生一個targetSource適配,這里是使用的適配器的模式,有興趣可以進去看一下,我們此處不關注這個。接下來,會去判斷代理接口,並且設置代理接口,但是我們的target未實現任何接口,所以此處interfaces仍然為空的,所以最后一步createAopProxy時,會幫我們創建cglib的proxy。最終由cglib生成代理返回。

執行下國際慣例,說完以后總要稍微總結一下,主要說幾點:

1.在IOC容器初始化的過程中,並沒有發生增強的動作,而是初始化了proxyFactoryBean。

2.如果配置中不指定,所有bean默認都是單例和非延遲加載的,也就是說所有的bean都將在第一次IOC容器初始化時全部實例化,所以上一章中所配置的三個bean都是在IOC容器初始化時進行的實例化。

3.springAOP代理有兩種方式,一種是JDK提供的動態代理,一種是cglib字節碼生成的技術,當要代理的類有實現的接口的時候,就會針對接口進行代理,否則就會采用cglib直接生成字節碼產生子類。

 

              到此處,我們已經基本上完全跟了一遍整個bean增強的過程,也大概了解了springAOP的大概原理,相信各位心中應該有個大概的印象了,其實springAOP增強的原理已經浮現出來了,接下來再研究下去,可能會收獲甚微,還是要結合平時的應用和自己的興趣去體會,始終不贊同一頭扎進去就埋頭苦干的作風。

              好了,spring源碼學習之路就圓滿結束了,雖說時間不長,但收獲甚大。各位如果有興趣,相信現在也完全有能力自己去看源碼了,以后有問題,不要找度娘了,找源碼吧。

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM