FactoryBean使用及真实应用场景分享

 更新时间:2026年05月31日 09:56:35   作者:起名困难综合症  
这段文章详细介绍了FactoryBean在Spring中的应用,包括其定义、使用方法以及在Spring Boot中的实例,同时,探讨了如何利用FactoryBean整合MyBatis,简化了MyBatis与Spring的集成过程,通过FactoryBean,第三方库可以被优雅地加载到Spring容器中,提升了系统的灵活性和可扩展性

一、FactoryBean是什么?

FactoryBean是spring提供的一个接口,可以通过它创建自定义对象工厂,将其注入spring容器后,会将其本身和其所要创建的bean一同注入容器。他和工厂模式中的工厂本质上来没有太大的区别,只不过一个是由spring 容器管理,一个是使用者自己管理。

FactoryBean中有三个方法如下:

public interface FactoryBean<T> {

	/**
	 * The name of an attribute that can be
	 * {@link org.springframework.core.AttributeAccessor#setAttribute set} on a
	 * {@link org.springframework.beans.factory.config.BeanDefinition} so that
	 * factory beans can signal their object type when it can't be deduced from
	 * the factory bean class.
	 * @since 5.2
	 */
	String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";


	/**
	 返回我们所要创建的bean
	 * 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}
	 * 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})
	 * @throws Exception in case of creation errors
	 * @see FactoryBeanNotInitializedException
	 */
	@Nullable
	T getObject() throws Exception;

	/**
	返回我们要创建bean的class类型
	 * Return the type of object that this FactoryBean creates,
	 * or {@code null} if not known in advance.
	 * <p>This allows one to check for specific types of beans without
	 * instantiating objects, for example on autowiring.
	 * <p>In the case of implementations that are creating a singleton object,
	 * this method should try to avoid singleton creation as far as possible;
	 * it should rather estimate the type in advance.
	 * For prototypes, returning a meaningful type here is advisable too.
	 * <p>This method can be called <i>before</i> this FactoryBean has
	 * been fully initialized. It must not rely on state created during
	 * initialization; of course, it can still use such state if available.
	 * <p><b>NOTE:</b> Autowiring will simply ignore FactoryBeans that return
	 * {@code null} here. Therefore, it is highly recommended to implement
	 * this method properly, using the current state of the FactoryBean.
	 * @return the type of object that this FactoryBean creates,
	 * or {@code null} if not known at the time of the call
	 * @see ListableBeanFactory#getBeansOfType
	 */
	@Nullable
	Class<?> getObjectType();

	/**
	是否为单例
	 * Is the object managed by this factory a singleton? That is,
	 * will {@link #getObject()} always return the same object
	 * (a reference that can be cached)?
	 * <p><b>NOTE:</b> If a FactoryBean indicates to hold a singleton object,
	 * the object returned from {@code getObject()} might get cached
	 * by the owning BeanFactory. Hence, do not return {@code true}
	 * unless the FactoryBean always exposes the same reference.
	 * <p>The singleton status of the FactoryBean itself will generally
	 * be provided by the owning BeanFactory; usually, it has to be
	 * defined as singleton there.
	 * <p><b>NOTE:</b> This method returning {@code false} does not
	 * necessarily indicate that returned objects are independent instances.
	 * An implementation of the extended {@link SmartFactoryBean} interface
	 * may explicitly indicate independent instances through its
	 * {@link SmartFactoryBean#isPrototype()} method. Plain {@link FactoryBean}
	 * implementations which do not implement this extended interface are
	 * simply assumed to always return independent instances if the
	 * {@code isSingleton()} implementation returns {@code false}.
	 * <p>The default implementation returns {@code true}, since a
	 * {@code FactoryBean} typically manages a singleton instance.
	 * @return whether the exposed object is a singleton
	 * @see #getObject()
	 * @see SmartFactoryBean#isPrototype()
	 */
	default boolean isSingleton() {
		return true;
	}

}

二、使用

在使用FactoryBean的时候,大多数是于spring提供的其他接口一起使用

1.创建我们需要的bean及其builder

代码如下(示例):

@Data
public class Customize {

    private String id;

    private String name;

    private int age;

    private String address;

    private String phone;
}

public class CustomizeBuilder {

    private Customize customize;

    public CustomizeBuilder builder() {
        customize = new Customize();
        return this;
    }

    public CustomizeBuilder id(String id) {
        customize.setId(id);
        return this;
    }

    public CustomizeBuilder name(String name) {
        customize.setName(name);
        return this;
    }

    public CustomizeBuilder age(int age) {
        customize.setAge(age);
        return this;
    }

    public CustomizeBuilder address(String address) {
        customize.setAddress(address);
        return this;
    }

    public CustomizeBuilder phone(String phone) {
        customize.setPhone(phone);
        return this;
    }

    public Customize build() {
        return customize;
    }
}

2.创建FactoryBean的实例

实现了InitializingBean 的 afterPropertiesSet()方法,该方法将在实现类的属性加载完毕后调用。

代码如下(示例):

@Component
public class CustomizeFactoryBean implements FactoryBean<Customize> , InitializingBean {

    private Customize customize;

    @Override
    public Customize getObject() throws Exception {
        return customize;
    }

    @Override
    public Class<?> getObjectType() {
        return Customize.class;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        if (customize == null){
            customize= new CustomizeBuilder().builder()
                    .id("1")
                    .name("sun")
                    .age(18)
                    .address("beijing")
                    .phone("123456789")
                    .build();
        }
    }
}

之后我们在测试类中进行测试

@SpringBootTest
class SpringBeanApplicationTests {
    @Autowired
    private Customize customize;
    @Autowired
    private CustomizeFactoryBean customizeFactoryBean;
    @Test
    public void contextLoads() throws Exception {
        System.out.println(customizeFactoryBean);
        System.out.println(customizeFactoryBean.getObject());
        System.out.println(customize);
    }
}

输出:

com.agp.springbean.factorybean.CustomizeFactoryBean@5a592c70
Customize(id=1, name=sun, age=18, address=beijing, phone=123456789)
Customize(id=1, name=sun, age=18, address=beijing, phone=123456789)

对springboot进行调试得到注入FactoryBean工厂得到的默认对象就是其要创建的对象,可以通过&+factoryBeanName得到真实的bean工厂


整合mybatis

上述我们虽然通过@Component 将工厂注入到spring容器中,但是他真正的用法却不是这样。因为想要注册一个bean我们可以通过很多种方式去完成。这种方法明显是比较麻烦的,官方也不推荐使用spring相关注解注入。

下面来看看mybatis-spring是如何将spring整合mybatis的。

mybatis是如何运行的?

mybatis的核心组件是 SqlSession,我们所有的sql操作都要使用这个接口完成。sqlSession又是由SqlSessionFactory构建的。通过build方法创建出了SqlSessionFactory,即得到SqlSession。

具体解析过程这里不做介绍

public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
    try {
      // 传入配置文件,创建一个XMLConfigBuilder类
      XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
      // 分两步:
      // 1、解析配置文件,得到配置文件对应的Configuration对象
      // 2、根据Configuration对象,获得一个DefaultSqlSessionFactory
      return build(parser.parse());
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
      ErrorContext.instance().reset();
      try {
        reader.close();
      } catch (IOException e) {
      }
    }
  }

由上述代码可知,只要我们拥有了SqlSessionFactory就拥有了mybatis的所有能力,剩下的就是怎么把SqlSessionFactory集成到spring中

在mybatis-spring中有这样的一个Factorybean

public class SqlSessionFactoryBean
    implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ContextRefreshedEvent>{
	private SqlSessionFactory sqlSessionFactory;
....

  @Override
  public void afterPropertiesSet() throws Exception {
    notNull(dataSource, "Property 'dataSource' is required");
    notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
    state((configuration == null && configLocation == null) || !(configuration != null && configLocation != null),
        "Property 'configuration' and 'configLocation' can not specified with together");

    this.sqlSessionFactory = buildSqlSessionFactory();
  }
    @Override
  public SqlSessionFactory getObject() throws Exception {
    if (this.sqlSessionFactory == null) {
      afterPropertiesSet();
    }

    return this.sqlSessionFactory;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public Class<? extends SqlSessionFactory> getObjectType() {
    return this.sqlSessionFactory == null ? SqlSessionFactory.class : this.sqlSessionFactory.getClass();
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public boolean isSingleton() {
    return true;
  }
}

通过了buildSqlSessionFactory()来创建了SqlSessionFactory(),具体细节不做介绍。相信到了这里在结合我们在使用spring结合mybatis时的配置,大家都应该能了解如何使用了,通过xml或者javaConfig的方式就SqlSessionFactoryBean加入到spring容器中将第三方的mybatis 集成到容器中,然后使用mybatis了

总结

FactoryBean主要是用来在spring初始化的过程中创建bean的工厂,个人理解它更像一个插件的接口。可以将第三方的类优雅的加载到spring容器中。可能还有其他功能有待开发

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Java的System.getProperty()方法获取大全

    Java的System.getProperty()方法获取大全

    这篇文章主要介绍了Java的System.getProperty()方法获取大全,罗列了System.getProperty()方法获取各类信息的用法,具有一定的参考借鉴价值,需要的朋友可以参考下
    2014-12-12
  • JavaAPI的使用方法详解

    JavaAPI的使用方法详解

    这篇文章主要介绍了JavaAPI的使用方法详解,还是比较不错的,这里分享给大家,供需要的朋友参考。
    2017-11-11
  • SpringBoot中application.properties、application.yaml、application.yml区别

    SpringBoot中application.properties、application.yaml、applicati

    本文主要介绍了SpringBoot中application.properties、application.yaml、application.yml区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-04-04
  • Java学习笔记之面向对象编程精解

    Java学习笔记之面向对象编程精解

    看名字它是注重对象的。当解决一个问题的时候,面向对象会把事物抽象成对象的概念,就是说这个问题里面有哪些对象,然后给对象赋一些属性和方法,然后让每个对象去执行自己的方法,问题得到解决
    2021-09-09
  • Java字符编码简介_动力节点Java学院整理

    Java字符编码简介_动力节点Java学院整理

    这篇文章主要介绍了Java字符编码简介,本文主要包括以下几个方面:编码基本知识,Java,系统软件,url,工具软件等,感兴趣的朋友一起看看吧
    2017-08-08
  • java实现模仿斗地主发牌

    java实现模仿斗地主发牌

    这篇文章主要为大家详细介绍了java实现模仿斗地主发牌,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-12-12
  • 基于SpringAop中JoinPoint对象的使用说明

    基于SpringAop中JoinPoint对象的使用说明

    这篇文章主要介绍了基于SpringAop中JoinPoint对象的使用说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-06-06
  • Java实现图片转换PDF文件的示例代码

    Java实现图片转换PDF文件的示例代码

    这篇文章主要介绍了Java实现图片转换PDF文件的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-09-09
  • Netty分布式抽象编码器MessageToByteEncoder逻辑分析

    Netty分布式抽象编码器MessageToByteEncoder逻辑分析

    这篇文章主要介绍了Netty分布式抽象编码器MessageToByteEncoder的抽象逻辑分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-03-03
  • 探索jedis连接池预热优化高并发

    探索jedis连接池预热优化高并发

    这篇文章主要为大家介绍了jedis连接池预热优化高并发深入探索示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-10-10

最新评论