那些年背过的题:FactoryBean和BeanFactory对比

416 阅读5分钟

FactoryBeanBeanFactory是Spring框架中两个不同的概念,它们在功能和用途上有所区别。下面我们详细对比一下这两个概念。

1. FactoryBean概述

FactoryBean是一个接口,用于定义创建复杂bean的逻辑。它允许开发者自定义bean实例化过程。

核心方法:

  • Object getObject() throws Exception:返回由FactoryBean创建的bean实例。
  • Class<?> getObjectType():返回所创建bean实例的类型。
  • boolean isSingleton():指示由FactoryBean创建的bean实例是否为单例。

使用场景:

  • 创建复杂对象:当某个bean的创建过程非常复杂时,可以使用FactoryBean来封装复杂的创建逻辑。
  • 第三方库集成:通过FactoryBean可以方便地将第三方库中的对象集成到Spring上下文中。
  • 动态代理:在AOP或其他需要动态代理的场景中,常使用FactoryBean来创建代理对象。

示例:

public class MyFactoryBean implements FactoryBean<MyBean> {
    @Override
    public MyBean getObject() throws Exception {
        // 创建并返回MyBean实例
        return new MyBean();
    }

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

    @Override
    public boolean isSingleton() {
        return true; // 返回true表示单例,false表示多例
    }
}

2. BeanFactory概述

BeanFactory是Spring IoC容器的根接口,它提供了最基本的容器功能,负责管理bean的生命周期和依赖注入。

核心方法:

  • Object getBean(String name):根据bean的名字获取实例。
  • <T> T getBean(Class<T> requiredType):根据bean的类型获取实例。
  • boolean containsBean(String name):检查容器中是否包含指定名称的bean。

使用场景:

  • 基础IoC容器BeanFactory是Spring中最基础的IoC容器,用于加载、配置和管理bean。
  • 资源受限环境:在资源受限的环境(如移动设备或嵌入式系统)中,BeanFactory是一种轻量级的选择。
  • 延迟初始化:相比于ApplicationContextBeanFactory通常不预先实例化所有单例bean,而是按需进行实例化,从而实现延迟初始化。

示例:

BeanFactory beanFactory = new ClassPathXmlApplicationContext("applicationContext.xml");
MyBean myBean = (MyBean) beanFactory.getBean("myBean");

3. 对比总结

特性FactoryBeanBeanFactory
主要功能自定义bean创建逻辑管理bean的生命周期和依赖注入
核心接口方法getObject()getObjectType()isSingleton()getBean()containsBean(), 等
使用场景创建复杂bean、集成第三方库、动态代理基础IoC容器、资源受限环境、延迟初始化
获取实例方式普通bean:由FactoryBean创建的对象通过bean名称或类型获取
是否为容器

总结

  • FactoryBean:用于定制bean的创建过程,适合生成复杂对象或需要动态代理的场景。
  • BeanFactory:作为Spring IoC容器的基本实现,负责管理bean的生命周期和依赖注入,适用于资源受限环境和需要延迟初始化的情况。

FactoryBean注意事项:&符号

在Spring中,&符号是一个特殊的前缀,用于获取FactoryBean实例本身,而不是由FactoryBean创建的目标bean实例。下面详细说明&符号的作用和使用场景。

1. &符号的作用

当一个bean是通过实现FactoryBean接口创建的,通常情况下,从Spring容器中获取这个bean时,得到的是FactoryBean创建的目标bean实例。如果你需要直接获取FactoryBean实例本身,可以在bean名称前加上&符号。

2. 示例解析

假设有一个名为myFactoryBeanFactoryBean实现类,它创建的目标bean类型为MyBean

// FactoryBean实现类
public class MyFactoryBean implements FactoryBean<MyBean> {
    @Override
    public MyBean getObject() throws Exception {
        return new MyBean();
    }

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

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

// 目标bean类
public class MyBean {
    // Bean properties and methods
}

在Spring配置文件或Java配置中注册这个FactoryBean

Java配置:

@Configuration
public class AppConfig {
    @Bean
    public MyFactoryBean myFactoryBean() {
        return new MyFactoryBean();
    }
}

3. 获取FactoryBean本身与目标bean

获取目标bean: 默认情况下,通过bean名称获取的是FactoryBean创建的目标bean实例MyBean

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
MyBean myBean = (MyBean) context.getBean("myFactoryBean");

获取FactoryBean本身: 如果需要获取FactoryBean实例本身,则使用&前缀。

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
MyFactoryBean factoryBean = (MyFactoryBean) context.getBean("&myFactoryBean");

4. 使用场景

1. 调试和测试

在开发过程中,可能需要检查或调试FactoryBean本身的状态和行为。通过&符号获取FactoryBean实例,可以方便地进行断点调试或单元测试。

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
MyFactoryBean factoryBean = (MyFactoryBean) context.getBean("&myFactoryBean");
// 可以在此处设置断点或打印factoryBean的内部状态

2. 动态配置

有时需要在运行时修改FactoryBean的某些属性,以便其创建的目标bean符合当前需求。例如,根据外部条件(如环境变量、配置文件)在运行时调整FactoryBean的行为。

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
MyFactoryBean factoryBean = (MyFactoryBean) context.getBean("&myFactoryBean");

// 根据某些条件动态调整factoryBean的属性
if (someCondition) {
    factoryBean.setSomeProperty(newValue);
}

// 获取修改后的目标bean
MyBean myBean = (MyBean) context.getBean("myFactoryBean");

3. 延迟初始化

在某些情况下,需要延迟初始化FactoryBean或其依赖项。通过直接访问FactoryBean实例,可以手动控制其初始化过程,确保在适当的时间点进行初始化。

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
MyFactoryBean factoryBean = (MyFactoryBean) context.getBean("&myFactoryBean");

// 手动触发某些初始化逻辑
factoryBean.initializeDependencies();

// 获取目标bean
MyBean myBean = (MyBean) context.getBean("myFactoryBean");

4. 自定义初始化逻辑

有时需要在获取目标bean之前执行自定义初始化逻辑。例如,加载资源、配置连接池等操作,可以在获取目标bean之前通过FactoryBean完成。

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
MyFactoryBean factoryBean = (MyFactoryBean) context.getBean("&myFactoryBean");

// 执行自定义初始化逻辑
factoryBean.customInitialization();

// 获取经过初始化的目标bean
MyBean myBean = (MyBean) context.getBean("myFactoryBean");