写点什么

一文给你讲清楚 BeanFactory 和 FactoryBean 的关联与区别

  • 2023-09-21
    广东
  • 本文字数:2656 字

    阅读完需:约 9 分钟

一文给你讲清楚BeanFactory 和 FactoryBean 的关联与区别

本文分享自华为云社区 《BeanFactory 和 FactoryBean 的关联与区别》,作者:战斧。

一、概括性的回答


两者其实都是 Spring 提供的接口,如下


public interface FactoryBean<T> {	T getObject() throws Exception;	Class<?> getObjectType();	boolean isSingleton();}
复制代码


public interface BeanFactory {	String FACTORY_BEAN_PREFIX = "&";	Object getBean(String name) throws BeansException;	<T> T getBean(String name, Class<T> requiredType) throws BeansException;	<T> T getBean(Class<T> requiredType) throws BeansException;	Object getBean(String name, Object... args) throws BeansException;	<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;	boolean containsBean(String name);	boolean isSingleton(String name) throws NoSuchBeanDefinitionException;	boolean isPrototype(String name) throws NoSuchBeanDefinitionException;	boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;	boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;	Class<?> getType(String name) throws NoSuchBeanDefinitionException;	String[] getAliases(String name);}
复制代码


BeanFactory 就是我们常说的 Spring 容器,其内包含着大量的 Bean,我们可以从 BeanFactory 获取到想要的 Bean,或者查询 Bean 的一些信息。


而 FactoryBean 则是众多 Bean 里的一种,只不过这种 Bean 是一种辅助 Bean 或者说中间人,它的作用是为你提供另一个/一些 Bean。



两者一个比较形象的比喻就是 BeanFactory 就是一家工厂,我们可以通过提供物品名字,从工厂中得到各式各样的物品,比如桌椅板凳,键盘鼠标 等等。而除此之外,我们还能获取一种比较特殊的物品——生产线(FactoryBean),一般情况下,我们获取生产线当然不是为了它本身,而是为了利用生产线生产出产品,所以当你提供生产线的名字,得到的其实是生产线生产的产品。当然,如果你就是想取这个生产线本身,那你提供的名字就得是 “&” + 生产线名。

二、FactoryBean

FactoryBean 示例


我们先来看一下 FactoryBean 的基础用法,简而言之就是实现 FactoryBean 接口,然后重写其中的 getObject 方法,如下:


public class ConfigLoaderFactoryBean implements FactoryBean<ConfigLoader> {    private String configLocation;
public void setConfigLocation(String configLocation) { this.configLocation = configLocation; }
@Override public ConfigLoader getObject() throws Exception { if (configLocation.startsWith("file:")) { LocalConfigLoader configLoader = new LocalConfigLoader(); configLoader.setFilePath(configLocation.substring(5)); return configLoader; } else if (configLocation.startsWith("http:")) { RemoteConfigLoader configLoader = new RemoteConfigLoader(); configLoader.setServerUrl(configLocation); return configLoader; } else { throw new IllegalArgumentException("Unsupported config location: " + configLocation); } }
@Override public Class<?> getObjectType() { return ConfigLoader.class; }}
复制代码


然后把这个 factoryBean 放入容器中,你可以采用 xml 或者 @Bean 等形式注入。


<bean id="configLoader" class="com.example.ConfigLoaderFactoryBean">    <property name="configLocation" value="http://example.com/config.json"/></bean
复制代码

FactoryBean 的必要性


我们上面介绍过,FactoryBean 其实相当于一个中间人,我们获取它,往往不是需要它本身,而是希望通过它获得另一个 Bean,自然的我们会产生疑问,为什么要多此一举?如果我们通过它是为了获得另一个 Bean,那么为什么不直接实例化另一个 Bean 然后放入 Spring 容器呢?比如在方法上使用 @Bean 注解。



这种想法无可厚非,主要是因为 factoryBean 接口的诞生更早,所以早期很多的结构采用了这种方式。后续有了 @Bean 注解以后,在方法上使用 @Bean 注解也能实现复杂 Bean 的创建了。


那是不是所有情况都能使用 @Bean 来替代 factoryBean 呢?比如我们想每次获取的 Bean 都是实时的,又比如我们需要一个计时器 Bean,但你注入的 Bean 都被固定了,只有通过工厂,才能每次获取都能得到一个实时的新 Bean。同样的,使用 factoryBean 还有一个懒加载的作用,对于某些复杂的 Bean 能在获取时再进行实例化。

三、BeanFactory

BeanFactory 与 ApplicationContext


提及 BeanFactory,自然而然的我们会想到 Spring 的重要特性 IOC,IOC 要求有一个能管理所有 Bean 的管家,而管家需要一个盛放这些 Bean 的容器,这个容器就是 BeanFactory。



尽管我们在日常项目中,使用的容器是具有更全功能的 ApplicationContext,但 ApplicationContext 也是 BeanFactory 的子接口,其除了单纯的容器功能外,还有配置元信息,应用事件机制,资源管理等功能,所以我们可以说 ApplicationContext 是 BeanFactory 的增强版本。

BeanFactory 的使用


在早期的 spring 项目中,我们经常会在代码中指定使用某种 BeanFactory ,并且使用如下方式去加载资源。


 //读取核心的配置文件ClassPathResource resource = new ClassPathResource("MyContext.xml");BeanFactory BeanFactory = new XmlBeanFactory(resource);
复制代码


顾名思义 XmlBeanFactory 就是能够读取并解析 xml 资源,解析出各种 Bean 后存入自身,而在后期,springboot 的大规模使用后,其内置的工厂可以解析 xml、properties 以及注解等多种配置来源。


当然,其实 Spring 本身就有相当的自动化程度,比如当我们在启动类上使用。


@ImportResource(location = {"classpath:MyContext.xml"})
复制代码


它也能导入内容,并根据资源后缀是否为".groovy"判断是使用 GroovyBeanDefinitionReader.class 还是 XmlBeanDefinitionReader.class,对资源解析完成后,把 Bean 定义注册进 BeanFactory 中。

四、总结


我们应当发现了:BeanFactory 和 FactoryBean 除了名字相似、都能包含一些 Bean 实例之外,其实没有什么相同的地方。前者是 SpringIOC 的核心,是存放一切 Bean 的容器;后者只不过是对复杂 Bean 的一种包装,比如我们常用的 myBatis 组件,针对各个 mapper 级接口生成的 Bean 实例,就是以 FactoryBean 的形式存在 Spring 容器中的。


点击关注,第一时间了解华为云新鲜技术~

发布于: 刚刚阅读数: 2
用户头像

提供全面深入的云计算技术干货 2020-07-14 加入

生于云,长于云,让开发者成为决定性力量

评论

发布
暂无评论
一文给你讲清楚BeanFactory 和 FactoryBean 的关联与区别_spring_华为云开发者联盟_InfoQ写作社区