1548 字
8 分钟
Spring中的BeanFactory与FactoryBean
BeanFactory
BeanFactory是一个工厂接口,是一个负责生产和管理bean的一个工厂。BeanFactory是工厂的顶层接口,是IOC容器的核心接口,BeanFactory定义了管理Bean的通用方法,如getBean和containsBean等,它的职责包括:
- Bean实例化: 根据XML注解等创建Bean对象。
- 依赖注入: 自动将Bean所需的依赖注入进去。
- 生命周期管理: 管理Bean的初始化,销毁等生命周期方法。
- 延迟加载: 默认采用懒加载策略,只有在调用getBean()时才创建Bean实例。
- Bean获取: 提供getBean()方法来获取Bean实例。
BeanFactory只是一个接口,不是IOC容器的具体实现,所以Spring容器给出了很多种实现,如XmlBeanFactory、AnnotationConfigApplicationContext,ApplicationContext等。
BeanFactory 的常见实现类
Spring 提供了多种 BeanFactory 的实现,每种实现都有其特定的使用场景:
DefaultListableBeanFactory
最常用的完整实现,支持完整的Bean生命周期管理:
import org.springframework.beans.factory.support.DefaultListableBeanFactory;import org.springframework.beans.factory.support.RootBeanDefinition;
public class BeanFactoryExample { public static void main(String[] args) { DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
// 手动注册Bean定义 RootBeanDefinition beanDefinition = new RootBeanDefinition(MyService.class); factory.registerBeanDefinition("myService", beanDefinition);
// 获取Bean MyService service = factory.getBean("myService", MyService.class); service.doSomething(); }}
class MyService { public void doSomething() { System.out.println("Service is working!"); }}
XmlBeanFactory(已废弃)
基于XML配置的BeanFactory实现,Spring 5.x后已废弃,推荐使用ApplicationContext:
// 传统用法(不推荐)// XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("beans.xml"));
// 现代替代方案import org.springframework.context.support.ClassPathXmlApplicationContext;
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");MyService service = context.getBean("myService", MyService.class);
StaticListableBeanFactory
静态Bean工厂,适用于Bean集合固定的场景:
import org.springframework.beans.factory.support.StaticListableBeanFactory;
StaticListableBeanFactory factory = new StaticListableBeanFactory();factory.addBean("myService", new MyService());factory.addBean("anotherService", new AnotherService());
MyService service = factory.getBean("myService", MyService.class);
ApplicationContext实现类
作为BeanFactory的高级实现,提供更多企业级特性:
// 注解配置import org.springframework.context.annotation.AnnotationConfigApplicationContext;
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
// XML配置import org.springframework.context.support.ClassPathXmlApplicationContext;
ClassPathXmlApplicationContext xmlContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// Web环境import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
AnnotationConfigWebApplicationContext webContext = new AnnotationConfigWebApplicationContext();webContext.register(WebConfig.class);
实际应用示例
结合Bean定义构建器的完整示例:
import org.springframework.beans.factory.support.BeanDefinitionBuilder;import org.springframework.beans.factory.support.DefaultListableBeanFactory;
public class CustomBeanFactoryDemo { public static void main(String[] args) { DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
// 使用BeanDefinitionBuilder构建复杂Bean BeanDefinitionBuilder builder = BeanDefinitionBuilder .rootBeanDefinition(DatabaseService.class) .addPropertyValue("url", "jdbc:mysql://localhost:3306/mydb") .addPropertyValue("username", "root") .setScope("singleton") .setLazyInit(true);
factory.registerBeanDefinition("dbService", builder.getBeanDefinition());
// 懒加载验证 System.out.println("Bean定义已注册,但未实例化");
DatabaseService dbService = factory.getBean("dbService", DatabaseService.class); System.out.println("现在Bean被实例化了"); }}
class DatabaseService { private String url; private String username;
// getters and setters public void setUrl(String url) { this.url = url; } public void setUsername(String username) { this.username = username; }
public void connect() { System.out.println("连接到: " + url + " 用户: " + username); }}
BeanFactory 与 ApplicationContext 的区别
- 预实例化策略
- BeanFactory:单例默认懒加载。
- ApplicationContext:默认预实例化单例(提高启动后首次访问的吞吐)。
- 扩展能力
- ApplicationContext 额外提供国际化、事件发布、AOP自动代理、资源模式解析等企业特性。
- 适用场景
- BeanFactory:资源受限、极致冷启动、强控制懒加载/条件加载。
- ApplicationContext:大多数应用优先选择。
- 调优提示
- 需要懒加载时,可结合ApplicationContext + @Lazy 或者使用ObjectProvider/Provider按需获取。
FactoryBean
在Spring中,所有的Bean都是由BeanFactory管理的(IOC容器), 这个FactoryBean不是简单的Bean,而是一个能生产或者修饰对象生成的工厂Bean,它的实现与设计模式中的工厂模式和修饰器模式类似。
FactoryBean 的作用
- 将“复杂对象的创建逻辑”封装到工厂Bean中,对外暴露的是“产品对象”而不是工厂本身。
- 常用于:动态代理(AOP/远程代理)、框架桥接(如MyBatis的SqlSessionFactoryBean)、复杂构建(连接池、客户端SDK)。
核心接口方法
- getObject(): 返回实际产品对象(对外暴露的Bean)。
- getObjectType(): 返回产品类型,便于类型匹配与自动装配。
- isSingleton(): 决定产品是否为单例(影响缓存与生命周期)。
获取“产品”还是“工厂本身”
- 普通名:context.getBean(“beanName”) 获取的是产品对象(getObject返回值)。
- 带&前缀:context.getBean(“&beanName”) 获取的是FactoryBean自身。
- 命名规则:注册名为 x 的 FactoryBean,会对外暴露“产品”名为 x,“工厂自身”为 &x。
最小可运行示例
// 一个业务产品public class ApiClient { private final String endpoint; public ApiClient(String endpoint) { this.endpoint = endpoint; } public String call(String path) { return "GET " + endpoint + path; }}
// FactoryBean 实现import org.springframework.beans.factory.FactoryBean;import org.springframework.beans.factory.InitializingBean;import org.springframework.util.Assert;
public class ApiClientFactoryBean implements FactoryBean<ApiClient>, InitializingBean { private String endpoint; public void setEndpoint(String endpoint) { this.endpoint = endpoint; }
@Override public ApiClient getObject() { // 可在此放入复杂构建/代理/缓存等逻辑 return new ApiClient(endpoint); }
@Override public Class<?> getObjectType() { return ApiClient.class; }
@Override public boolean isSingleton() { return true; }
@Override public void afterPropertiesSet() { Assert.hasText(endpoint, "endpoint must not be empty"); }}
// Java 配置注册 FactoryBeanimport org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;
@Configurationpublic class AppConfig { @Bean(name = "apiClient") public ApiClientFactoryBean apiClientFactoryBean() { ApiClientFactoryBean fb = new ApiClientFactoryBean(); fb.setEndpoint("https://api.example.com"); return fb; }}
// 取产品与取工厂本身import org.springframework.context.ApplicationContext;import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Demo { public static void main(String[] args) { ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class); ApiClient client = ctx.getBean("apiClient", ApiClient.class); // 产品 ApiClientFactoryBean fb = ctx.getBean("&apiClient", ApiClientFactoryBean.class); // 工厂本身 System.out.println(client.call("/ping")); }}
常见坑与最佳实践
- getObjectType 切勿返回 null:尽量返回接口/具体类型,便于按类型注入与AOT分析。
- isSingleton 与产品生命周期:单例将被容器缓存;非单例每次getBean都会重新创建产品。
- 懒加载与预实例化:在ApplicationContext中,如希望延迟创建可使用@Lazy或将FactoryBean产品设为非单例。
- 自动装配歧义:按类型注入时,注入到的是产品类型而非FactoryBean;需要注入工厂本身时使用@Qualifier(“&name”)或@Resource(name=“&name”)。
- 原型产品与循环依赖:原型产品不参与循环依赖的三级缓存提前暴露,避免在原型链路中引入循环依赖。
- 命名规范:确保文档/注释标明“&”语义,避免团队误用。
什么时候用哪一个?
- 仅需容器功能:优先ApplicationContext(功能更全,默认预实例化)。
- 需要懒加载到极致:考虑BeanFactory或在ApplicationContext中对关键Bean标注@Lazy。
- 对象构建复杂/需代理/外部SDK桥接:使用FactoryBean封装构建细节,对外仅暴露产品。
小结
- BeanFactory 是IoC容器的最小抽象;ApplicationContext在其上增强了企业级特性。
- FactoryBean 是“创建Bean的Bean”,对外暴露产品;使用“&name”获取工厂本身。
- 合理利用FactoryBean可显著简化复杂对象创建,并保持应用装配的清晰与解耦。