Spring擴展點之FactoryBean接口

  • 2019 年 10 月 4 日
  • 筆記

首先看一下接口定義

  public interface FactoryBean<T> {        /**       * 返回對象實例       */      @Nullable      T getObject() throws Exception;        /**       * 返回對象類型,       */      @Nullable      Class<?> getObjectType();        /**       * 該工廠管理的對象是否為單例?       */      default boolean isSingleton() {          return true;      }    }

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

FactoryBean的註冊

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

  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名稱都默認為FactoryBean

  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對象的方法:

  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技術的重點,簡單回顧一下

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