13、工厂模式进阶:Spring IoC容器与工厂模式的关系、BeanFactory与ApplicationContext
聊到工厂模式,很多人第一反应就是那个经典的「简单工厂」或者「工厂方法」。但说实话,真正让我对工厂模式有深刻理解的,是第一次接触 Spring 的 IoC 容器。那时候我刚从传统 Java EE 转过来,看到配置文件里一堆 <bean> 标签,心里还在嘀咕:这不就是个大型工厂吗?
嗯,后来我才明白,Spring 的 IoC 容器本质上就是工厂模式的「终极进化版」。它把对象的创建、组装、生命周期管理全都包揽了。今天我们就来拆解一下,BeanFactory 和 ApplicationContext 到底是怎么玩转工厂模式的。
13.1 工厂模式在 Spring 中的体现
先问一个问题:为什么 Spring 要搞一个 IoC 容器?说白了,就是为了解耦。传统开发中,你 new 一个对象,这个对象就跟你绑死了。想换实现?改代码吧。而工厂模式的核心思想就是「把创建对象的逻辑抽出来」,Spring 把这个思路推到了极致。
我个人习惯把 Spring IoC 容器理解成一个「超级工厂」——它不只能创建对象,还能管理对象之间的依赖关系。你看下面这个例子:
// 传统工厂模式
public class ServiceFactory {
public static UserService createUserService() {
return new UserServiceImpl(new UserDaoImpl());
}
}
// Spring IoC 容器
@Configuration
public class AppConfig {
@Bean
public UserService userService() {
return new UserServiceImpl(userDao());
}
@Bean
public UserDao userDao() {
return new UserDaoImpl();
}
}
看到区别了吗?传统工厂你得手动管理依赖,Spring 容器会自动帮你注入。我在项目中遇到过好几次,团队里有人把 Bean 的创建逻辑散落在各个工具类里,结果维护起来简直噩梦。后来统一用 Spring 管理,清爽多了。
13.2 BeanFactory:最朴素的工厂
BeanFactory 是 Spring IoC 容器的根接口。它定义了最基本的 IoC 功能——说白了就是「给我一个 Bean,别管我怎么造的」。
它的核心方法就几个:
getBean(String name)—— 根据名称获取 BeangetBean(Class<T> requiredType)—— 根据类型获取 BeancontainsBean(String name)—— 判断是否包含某个 BeanisSingleton(String name)—— 判断 Bean 是否为单例
你看,这跟工厂模式里的「产品创建接口」是不是一模一样?BeanFactory 就是那个抽象工厂,具体的实现类(比如 DefaultListableBeanFactory)负责真正的创建逻辑。
关键点:BeanFactory 采用的是「懒加载」策略。也就是说,只有当你调用 getBean() 时,它才会去创建对象。这在某些场景下能节省资源,但第一次调用时会有性能开销。
我曾经在一个高并发项目里踩过这个坑。系统启动时一切正常,结果第一个请求进来,响应时间直接飙到 3 秒——就是因为 BeanFactory 在懒加载。后来换成 ApplicationContext 的预加载机制,问题就解决了。
13.3 ApplicationContext:增强版工厂
ApplicationContext 是 BeanFactory 的子接口。它继承了 BeanFactory 的所有能力,还加了一堆「外挂」:
- 国际化支持 —— 通过 MessageSource 实现
- 事件发布机制 —— 观察者模式的经典应用
- 资源访问 —— 统一处理文件、类路径等资源
- AOP 集成 —— 面向切面编程的基础
说白了,ApplicationContext 就是一个「全能型工厂」。它不只能创建对象,还能帮你处理对象运行时的各种需求。
这里有个表格,可以直观对比两者的区别:
| 特性 | BeanFactory | ApplicationContext |
|---|---|---|
| 加载策略 | 懒加载 | 预加载(默认) |
| 事件机制 | 不支持 | 支持 |
| 国际化 | 不支持 | 支持 |
| AOP 支持 | 需手动集成 | 原生支持 |
| 使用场景 | 嵌入式、资源受限环境 | 企业级应用 |
我的建议:除非你是在做嵌入式开发或者对内存极度敏感,否则直接用 ApplicationContext。它带来的便利性远超那点内存开销。
13.4 从工厂模式角度看 IoC 容器
我们来画一张图,看看 Spring IoC 容器和经典工厂模式的关系:
从这张图可以看得很清楚:Spring 的 IoC 容器并没有抛弃工厂模式,而是在它的基础上做了「超集」扩展。BeanFactory 对应工厂模式中的抽象工厂接口,而具体的实现类(比如 XmlBeanFactory、AnnotationConfigApplicationContext)就是具体工厂。
13.5 实战中的选择
说了这么多理论,到底什么时候用 BeanFactory,什么时候用 ApplicationContext?
我个人的经验是:
- 嵌入式环境(比如 Android、IoT 设备)—— 用 BeanFactory,省内存
- 标准 Web 应用 —— 用 ApplicationContext,省心
- 需要事件机制 —— 必须用 ApplicationContext
- 需要 AOP —— 必须用 ApplicationContext
避坑指南:我曾经在一个微服务项目里,为了「性能优化」强行用 BeanFactory 替换了 ApplicationContext。结果后面需要加事件监听时,发现 BeanFactory 根本不支持,最后不得不重构。所以,除非你有非常明确的理由,否则别瞎折腾。
13.6 小结
工厂模式和 Spring IoC 容器的关系,说白了就是「继承与发扬」。工厂模式提供了「如何创建对象」的思路,Spring 把这个思路做成了工业级的解决方案。BeanFactory 是那个朴素的「基础工厂」,ApplicationContext 则是「全能工厂」。
你想想看,如果没有工厂模式的思想,Spring 的 IoC 容器可能就不会设计成现在这样。反过来,Spring 的成功也让工厂模式有了更丰富的内涵。这就是理论和实践相互促进的最好例子。
嗯,下次你在用 @Autowired 注入 Bean 的时候,可以想想背后那个默默工作的「超级工厂」——它正在用工厂模式的思想,帮你管理着整个应用的对象生态。