Spring中的FactoryBean与ObjectFactory详解

 更新时间:2023年12月20日 09:16:29   作者:Brain_L  
这篇文章主要介绍了Spring中的FactoryBean与ObjectFactory详解,FactoryBean是一种特殊的bean,本身又是个工厂,实现了FactoryBean的bean会被注册到容器中,需要的朋友可以参考下

FactoryBean

public interface FactoryBean<T> {
    //获取对象
    T getObject() throws Exception;
    //获取对象类型
    Class<?> getObjectType();
    //是否单例,默认true
    default boolean isSingleton() {
		return true;
	}
}

FactoryBean是一种特殊的bean,本身又是个工厂,实现了FactoryBean的bean会被注册到容器中。

ObjectFactory

public interface ObjectFactory<T> {
   //获取对象
   T getObject() throws BeansException;
}

ObjectFactory就是个对象工厂。

示例对比

public class Cat {
    public Cat() {
        System.out.println("调用了Cat构造器");
    }
}
@Component
public class MyFactoryBean implements FactoryBean<Dog> {
    @Override
    public Dog getObject() throws Exception {
        return new Dog();
    }
    @Override
    public Class<?> getObjectType() {
        return Dog.class;
    }
    @Override
    public boolean isSingleton() {
        return true;
    }
}

MyFactoryBean用来生成Dog对象。

public class Cat {
    public Cat() {
        System.out.println("调用了Cat构造器");
    }
}
@Component
public class MyObjectFactory implements ObjectFactory<Cat> {
    @Override
    public Cat getObject() throws BeansException {
        return new Cat();
    }
}

MyObjectFactory用来生成Cat对象。

System.out.println(ctx.getBean("myFactoryBean"));
System.out.println(ctx.getBean("myFactoryBean"));
System.out.println(ctx.getBean("&myFactoryBean"));
System.out.println(((MyObjectFactory)ctx.getBean("myObjectFactory")).getObject());
//输出:
调用了Dog构造器
com.brain.demo.factory.Dog@58c1da09
com.brain.demo.factory.Dog@58c1da09
com.brain.demo.factory.MyFactoryBean@2b2954e1
调用了Cat构造器
com.brain.demo.factory.Cat@58d6e55a

ObjectFactory没啥说的,就是对象工厂,通过getObject获取对象。

重点看下FactoryBean。MyFactoryBean本身作为bean(“myFactoryBean”)被扫描进容器中,即singletonObjects。当通过getBean或者@Autowired等方式需要获得bean时,调用getObject或者从缓存中获取所需的对象。

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
      @Nullable 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);
   //这个地方获得到bean("myFactoryBean")
   if (sharedInstance != null && args == null) {
      if (logger.isTraceEnabled()) {
         if (isSingletonCurrentlyInCreation(beanName)) {
            logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
                  "' that is not fully initialized yet - a consequence of a circular reference");
         }
         else {
            logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
         }
      }
      //这里进行了转换
      bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
   }
}
protected Object getObjectForBeanInstance(
      Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
   // Don't let calling code try to dereference the factory if the bean isn't a factory.
   //判断name是否是&开头的,代表是FactoryBean
   if (BeanFactoryUtils.isFactoryDereference(name)) {
      if (beanInstance instanceof NullBean) {
         return beanInstance;
      }
      if (!(beanInstance instanceof FactoryBean)) {
         throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
      }
      if (mbd != null) {
         mbd.isFactoryBean = true;
      }
      return beanInstance;
   }
   // 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.
   //不是FactoryBean,就是普通的bean,返回
   if (!(beanInstance instanceof FactoryBean)) {
      return beanInstance;
   }
   Object object = null;
   if (mbd != null) {
      mbd.isFactoryBean = true;
   }
   else {
      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());
      //调用FactoryBean的getObject方法获取bean
      object = getObjectFromFactoryBean(factory, beanName, !synthetic);
   }
   return object;
}
protected Object getCachedObjectForFactoryBean(String beanName) {
        //factoryBeanObjectCache就是用来存放FactoryBean getObject生成的对象,此时还不包含我们需要的bean
		return this.factoryBeanObjectCache.get(beanName);
}
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
   //单例且singletonObjects中已经加载了FactoryBean
   if (factory.isSingleton() && containsSingleton(beanName)) {
      synchronized (getSingletonMutex()) {
         //第一次进来是获取不到的
         Object object = this.factoryBeanObjectCache.get(beanName);
         if (object == null) {
            //调用getObject,此时生成了Dog实例,打印“调用了Dog构造器”
            object = doGetObjectFromFactoryBean(factory, beanName);
            // Only post-process and store if not put there already during getObject() call above
            // (e.g. because of circular reference processing triggered by custom getBean calls)
            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 {
                     //调用postProcessAfterInitialization,如果有AOP,此时生成代理对象
                     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)) {
                  //将Dog放到缓存中,下次就可以取到了
                  this.factoryBeanObjectCache.put(beanName, object);
               }
            }
         }
         return object;
      }
   }
   else {
      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;
   }
}

而要获取MyFactoryBean就要通过“&myFactoryBean”才能获取,getObjectForBeanInstance时通过BeanFactoryUtils.isFactoryDereference判断beanName是不是以&开头的,如果是,并且是FactoryBean类型的,则直接返回。

总结

FactoryBean本身作为bean保存在singletonObjects,beanName和普通bean一样,首字母小写(如果你没指定的话)。

如果直接通过beanName获取到的是FactoryBean通过getObject生成的对象,生成的对象保存在factoryBeanObjectCache中,便于下次获取时不用再调用getObject。

如果想获取FactoryBean本身,需要通过&beanName来获取,容器根据前缀&和是否是FactoryBean,来从singletonObjects中获取bean。

ObjectFactory是一个普通工程,通过getObject生成对象,不会像上面进行缓存。

到此这篇关于Spring中的FactoryBean与ObjectFactory详解的文章就介绍到这了,更多相关FactoryBean与ObjectFactory内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • JAVA编程实现TCP网络通讯的方法示例

    JAVA编程实现TCP网络通讯的方法示例

    这篇文章主要介绍了JAVA编程实现TCP网络通讯的方法,简单说明了TCP通讯的原理并结合具体实例形式分析了java实现TCP通讯的步骤与相关操作技巧,需要的朋友可以参考下
    2017-08-08
  • Java TreeSet 添加失败的解决

    Java TreeSet 添加失败的解决

    这篇文章主要介绍了Java TreeSet 添加失败的解决,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-09-09
  • java设计模式笔记之代理模式

    java设计模式笔记之代理模式

    这篇文章主要为大家详细介绍了java设计模式之代理模式笔记,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-10-10
  • JavaWeb实现文件上传下载功能实例解析

    JavaWeb实现文件上传下载功能实例解析

    这篇文章主要为大家详细介绍了JavaWeb中的文件上传和下载功能的实现,在Web应用系统开发中,文件上传和下载功能是非常常用的功能,需要的朋友可以参考下
    2015-08-08
  • 解决mybatis三表连接查询数据重复的问题

    解决mybatis三表连接查询数据重复的问题

    这篇文章主要介绍了解决mybatis三表连接查询数据重复的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-01-01
  • SpringBoot--Banner的定制和关闭操作

    SpringBoot--Banner的定制和关闭操作

    这篇文章主要介绍了SpringBoot--Banner的定制和关闭操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2018-05-05
  • SpringBoot中整合MyBatis-Plus-Join使用联表查询的实现

    SpringBoot中整合MyBatis-Plus-Join使用联表查询的实现

    本文主要介绍了SpringBoot中整合MyBatis-Plus-Join使用联表查询的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-03-03
  • springboot网站应用使用第三方qq登录的实现过程

    springboot网站应用使用第三方qq登录的实现过程

    这篇文章主要介绍了springboot网站应用使用第三方qq登录,本文通过实例图文相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-09-09
  • SpringBoot条件注解@Conditional详细解析

    SpringBoot条件注解@Conditional详细解析

    这篇文章主要介绍了SpringBoot条件注解@Conditional详细解析,@Conditional是Spring4.0提供的一个用于条件装配的注解,其定义了一个Condition的数组,只有当数组所有的条件都满足的时候,组件才会被导入容器,需要的朋友可以参考下
    2023-11-11
  • SpringBoot 使用定时任务(SpringTask)的详细步骤

    SpringBoot 使用定时任务(SpringTask)的详细步骤

    Cron 表达式非常灵活,可以满足各种定时任务的需求,但需要注意的是,Cron 表达式只能表示固定的时间点,无法处理复杂的时间逻辑,本文给大家介绍SpringBoot 使用定时任务(SpringTask)的详细步骤,感兴趣的朋友一起看看吧
    2024-02-02

最新评论