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) —— 根据名称获取 Bean
  • getBean(Class<T> requiredType) —— 根据类型获取 Bean
  • containsBean(String name) —— 判断是否包含某个 Bean
  • isSingleton(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 容器与工厂模式关系图 经典工厂模式 抽象工厂(接口) ↓ 实现 具体工厂(创建产品) ↓ 返回 产品对象 演进 Spring IoC 容器 BeanFactory(抽象工厂) ↓ 实现 DefaultListableBeanFactory ↓ 管理 Bean 定义 + 依赖注入 核心差异 工厂模式:手动管理产品创建 产品类型固定,扩展需改工厂 无生命周期管理 IoC 容器:自动管理 Bean 创建 通过配置动态扩展,无需改代码 完整的生命周期回调

从这张图可以看得很清楚: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 的时候,可以想想背后那个默默工作的「超级工厂」——它正在用工厂模式的思想,帮你管理着整个应用的对象生态。


公众号:蓝海资料掘金营,微信deep3321