源码学习之FactoryBean

 

本篇介绍一下BeanFactory的双胞胎兄弟FactoryBean.

 

FactoryBean介绍

      

我们从名称上就可以知道FactoryBean是一个bean,只不过这个是一个工厂bean,FactoryBean是spring提供的一个工厂类的接口,通过这个工厂bean可以获取我们需要的bean实例。

当我们通过getBean()来获取bean时,通过这个bean的实现类是一个工厂bean,那么它返回的对象其实是调用这个工厂bean中的getObjet()返回的内容。

FactoryBean实现

       我们看下FactoryBean中的内容:

FactoryBean:

public interface FactoryBean<T> {
    T getObject() throws Exception;

    Class<?> getObjectType();

    boolean isSingleton();
}

看到接口中只有三个方法,实现了该接口的工厂bean通过重写getObject()方法

来返回需要的实例对象。

       这样做的好处就是返回的对象完全是我们自定义的,我们可以根据自己的场景来决定需要的对象类型。

&的作用

       我们再来回顾一下BeanFactory中的内容:

public interface BeanFactory {

   /**
    * Used to dereference a {@link FactoryBean} instance and distinguish it from
    * beans <i>created</i> by the FactoryBean. For example, if the bean named
    * {@code myJndiObject} is a FactoryBean, getting {@code &myJndiObject}
    * will return the factory, not the instance returned by the factory.
    */
   String FACTORY_BEAN_PREFIX = "&";
}

 

 当时看到这里的时候,对这个还不是很理解,直到现在才明白这个前缀的作用.

工厂bean作为一个特殊的bean,当我们通过getBean()来获取bean时,获取到的实际内容是该工厂bean中的getObject(),那么我们通过什么方式来获取这个工厂bean本身呢?答案就是通过BeanFactory中的这个前缀“&”。

       举个例子:

       一个工厂bean的id 是 “test”,

通过getBean(“test”)方式获取到的就是工厂bean中getObject()返回的内容,

通过getBean(“&test”)方式获取到的就是工厂bean本身。

 

我们看下源码的中逻辑,看下它是怎么进行判断的:

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

可以看到这里的主要判断有两个:

  1. 通过beanInstance instanceof FactoryBean判断这个bean是否是工厂bean
  2. 通过BeanFactoryUtils.isFactoryDereference(name)判断beanname是否含有“&”

BeanFactoryUtils

public static boolean isFactoryDereference(String name) {
   return (name != null && name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
}

 

如果是工厂bean的子类,beanname中没有“&”:

调用factory.getObject()返回结果

如果是工厂bean的子类,beanname中含有“&”,则正常返回这个类的实例。

 

 

总结

       Factorybean是spring中的一个特殊bean,它必须实现FactoryBean接口,FactoryBean是为了给应用提供需要的对象才设计出来的,通过getObject()可以自定义返回对象的属性以适用于不同场景。

猜你喜欢

转载自blog.csdn.net/qq_23585245/article/details/89349057
今日推荐