Spring擴展點之FactoryBean接口

前言

首先看一下接口定義緩存

public interface FactoryBean<T> {

    /**
     * 返回對象實例
     */
    @Nullable
    T getObject() throws Exception;

    /**
     * 返回對象類型,
     */
    @Nullable
    Class<?> getObjectType();

    /**
     * 該工廠管理的對象是否爲單例?
     */
    default boolean isSingleton() {
        return true;
    }

}

由接口定義能夠看出來,實現這個接口的bean不是主要功能,getObject()建立的對象纔是重點。那麼在這咱們就能夠猜到了,能夠是使用FactoryBean建立一些實例化過程比較複雜的beanpost

FactoryBean的註冊

FactoryBean的處理邏輯在AbstractBeanFactory.doGetBean方法內ui

protected <T> T doGetBean(
            final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
            throws BeansException {
        //獲取bean名稱
        final String beanName = transformedBeanName(name);
        Object bean;
			  //省略部份內容
            //這裏就是FactoryBean的相關處理,下面會展開說
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
			 //省略部份內容

        return (T) bean;
    }

看一下具體的邏輯,這裏須要注意Spring關於bean的name有個潛規則,凡是以&開頭的bean名稱都默認爲FactoryBeanthis

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

	  // 若是beanName以工廠引用&開頭
    if (BeanFactoryUtils.isFactoryDereference(name)) {
        if (beanInstance instanceof NullBean) {
            return beanInstance;
        }
        // 若是name以&開頭,而beanInstance不是FactoryBean類型,則拋異常
        if (!(beanInstance instanceof FactoryBean)) {
            throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
        }
    }

    // 若是beanInstance不是FactoryBean類型,則直接返回beanInstance
    // 或者name以&開頭,也直接返回beanInstance,說明咱們就想獲取FactoryBean實例
    if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
        return beanInstance;
    }

    Object object = null;
    if (mbd == null) {
        object = getCachedObjectForFactoryBean(beanName);
    }
    if (object == null) {
        // 此時beanInstance是FactoryBean類型,而name又不是以&開頭; 這是咱們示例工程的狀況,也是最普通、用的最多的狀況
        // 將beanInstance強轉成FactoryBean類型
        FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
        // 從緩存中獲取咱們須要的實例對象
        if (mbd == null && containsBeanDefinition(beanName)) {
            mbd = getMergedLocalBeanDefinition(beanName);
        }
        boolean synthetic = (mbd != null && mbd.isSynthetic());
        // 調用FactoryBean的getObject方法建立咱們須要的實例對象
        object = getObjectFromFactoryBean(factory, beanName, !synthetic);
    }
    return object;
}

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) {
                //經過factory.getObject獲取
                object = doGetObjectFromFactoryBean(factory, beanName);
                Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
                if (alreadyThere != null) {
                    object = alreadyThere;
                }
                else {
                    if (shouldPostProcess) {
                        if (isSingletonCurrentlyInCreation(beanName)) {
                            // Temporarily return non-post-processed object, not storing it yet..
                            return object;
                        }
                        beforeSingletonCreation(beanName);
                        try {
                            object = postProcessObjectFromFactoryBean(object, beanName);
                        }
                        catch (Throwable ex) {
                            throw new BeanCreationException(beanName,
                                    "Post-processing of FactoryBean's singleton object failed", ex);
                        }
                        finally {
                            afterSingletonCreation(beanName);
                        }
                    }
                    if (containsSingleton(beanName)) {
                        //將獲取到的對象放到factoryBeanObjectCache單例緩存map進行存儲
                        this.factoryBeanObjectCache.put(beanName, object);
                    }
                }
            }
            return object;
        }
    }
    else {
        //非單例的處理,直接經過factory.getObejct獲取,而後再返回給用戶
        Object object = doGetObjectFromFactoryBean(factory, beanName);
        if (shouldPostProcess) {
            try {
                object = postProcessObjectFromFactoryBean(object, beanName);
            }
            catch (Throwable ex) {
                throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
            }
        }
        return object;
    }
}

生成bean對象的方法:prototype

private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
      throws BeanCreationException {

   Object object;
   try {
      if (System.getSecurityManager() != null) {
         AccessControlContext acc = getAccessControlContext();
         try {
            object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) 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) {
      if (isSingletonCurrentlyInCreation(beanName)) {
         throw new BeanCurrentlyInCreationException(
               beanName, "FactoryBean which is currently in creation returned null from getObject");
      }
      object = new NullBean();
   }
   return object;}

Spring的實現

Spring中實現這個接口的bean有不少,可是咱們最熟悉也是最重要的就是在我以前文章中提到過得ProxyFactoryBean這個bean是實現AOP技術的重點,簡單回顧一下吧 1code

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 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;
	}

1

相關文章
相關標籤/搜索