故事场景:购买你的座驾
BeanFactory
— “高性能发动机套件”
BeanFactory
就像一个高性能的发动机核心套件。
-
• 你得到的是什么:
你从工厂订购了一套“引擎核心”(BeanFactory
)。你得到的是一个箱子,里面装着引擎、活塞、变速器等最核心的部件。它具备了驱动汽车所需的一切基本能力(Bean的实例化和依赖注入)。 -
• 它的特点 (懒加载):
这个引擎套件送到你家车库时,它并不会自动点火启动。它只是静静地待在那里。只有当你第一次坐进驾驶舱,拧动点火钥匙的那一刻(调用getBean()
),引擎才会“轰”的一声被组装并启动起来。 -
• 它缺少什么:
它只有引擎。没有车身、没有轮胎、没有空调(AOP)、没有导航系统(国际化)、没有车载音响(事件发布)。你只有最核心的动力单元,如果你想把它变成一辆能开上路的车,你得自己动手去整合所有其他部件。 -
• 谁会用它?
只有那些资源极其有限(比如在内存极小的嵌入式设备上)或者需要极致启动速度的“骨灰级玩家”,才会选择从一个引擎套件开始构建。
ApplicationContext
— “出厂即顶配的豪华轿车”
ApplicationContext
则是一辆从工厂里直接开出来的、功能完备的豪华轿车。
-
• 你得到的是什么:
你订购了一辆“豪华轿车”。这辆车的核心,正是那款高性能引擎(ApplicationContext
继承了BeanFactory
),但工厂已经为它装配好了一切。 -
• 它的特点 (饿汉式加载):
当这辆车被交付到你家门口时(Spring容器启动时),工厂已经对它进行了全面的质检。引擎早已点火预热,所有系统都已经自检完毕,随时可以出发。这确保了你一上车就能立刻开走,并且所有潜在的装配问题都在出厂前就已暴露并解决了。 -
• 它多了什么?(核心区别)
除了强大的引擎 (BeanFactory
的功能) 之外,这辆“豪华轿车”还配备了:-
• 智能悬挂系统 (
AOP
): 能根据路况自动调整,提供平稳的驾乘体验。 -
• 多语言导航系统 (
国际化
): 能用不同语言为你指路。 -
• 行车警报系统 (
事件发布
): 轮胎气压低、油量不足时会自动提醒你。 -
• 后备箱和储物格 (
资源加载
): 可以方便地存取地图、工具等各种资源。
-
故事总结:
特性 | BeanFactory
(发动机套件) | ApplicationContext
(豪华整车) |
本质关系 | 核心/基础 | 扩展/高级
( |
加载策略 | 懒加载
(第一次用才启动) | 饿汉式加载
(出厂时就已启动) |
功能集 | 基础
(只有Bean管理) | 全面
(Bean管理 + AOP, I18N, 事件等) |
核心比喻 | 只提供最核心的引擎 | 提供一辆功能完备的汽车 |
一句话总结 | 我是Spring的心脏,但只是个零件。 | 我是Spring的完整形态,拿来就能开。 |
结论与现代实践:
在任何现代的Spring应用(尤其是Spring Boot)中,我们几乎总是与ApplicationContext
打交道。BeanFactory
更多的是作为底层的基础设施存在。ApplicationContext
提供的“开箱即用”的丰富功能和“启动时故障检测”的饿汉式加载模式,对于构建复杂的企业级应用来说,是不可或缺的。
技术解析与代码示例
核心关系:继承与扩展
ApplicationContext
继承自 BeanFactory
接口。你可以把 ApplicationContext
看作是 BeanFactory
的一个“超集”或“加强版”。它包含了 BeanFactory
的所有功能,并在此基础上提供了大量额外的企业级特性。
特性 | BeanFactory | ApplicationContext |
本质 |
Spring IoC容器的根接口,最基础的容器。 | BeanFactory
的子接口,功能更全面的容器。 |
Bean加载 | 懒加载 (Lazy)
:默认情况下,Bean在第一次被调用 ( | 饿汉式 (Eager)
:默认情况下,容器启动时就创建所有单例Bean。 |
提供功能 |
基础的Bean生命周期管理、依赖注入。 |
包含 |
代码示例:懒加载 vs 饿汉式
我们将通过代码直观地看到这两种加载策略的区别。
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
// 一个简单的Bean,它的构造函数会打印信息,以便我们观察创建时机
class MyBean {
public MyBean() {
System.out.println(">>> MyBean object has been created!");
}
}
// Spring的配置类
@Configuration
class AppConfig {
@Bean
public MyBean myBean() {
return new MyBean();
}
}
public class FactoryVsContextDemo {
public static void main(String[] args) {
System.out.println("--- 1. 演示 ApplicationContext (饿汉式加载) ---");
// 1. 创建 ApplicationContext 容器
// 注意观察控制台输出!
System.out.println("Context is about to be created.");
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
System.out.println("Context has been created.");
// **你会发现,"MyBean object has been created!" 在这里已经被打印出来了!**
// **这证明了 ApplicationContext 在启动时就 eagerly 创建了所有单例Bean。**
System.out.println("Now, let's get the bean...");
MyBean beanFromContext = context.getBean(MyBean.class);
System.out.println("Got bean from context: " + beanFromContext);
System.out.println("\n" + "---".repeat(20) + "\n");
// BeanFactory 接口没有直接的注解实现类,通常我们使用其实现,但其行为是懒加载
// 为了方便,我们知道 ApplicationContext 本身就是一个 BeanFactory
System.out.println("--- 2. 演示 BeanFactory 的概念 (懒加载) ---");
System.out.println("ApplicationContext is also a BeanFactory.");
BeanFactory factory = context; // 向上转型
// 假如我们有一个真正的、纯粹的 BeanFactory 实现(如 XmlBeanFactory,但已废弃),
// 那么 Bean 的创建会延迟到 getBean() 调用时。
// ApplicationContext 默认行为是饿汉式,但我们可以通过注解 @Lazy 来模拟懒加载
System.out.println("For a lazy-loaded bean (or a pure BeanFactory), the creation happens only when you call getBean().");
System.out.println("Since our context already created the bean, getting it again won't re-create it.");
MyBean beanFromFactory = factory.getBean(MyBean.class);
System.out.println("Got bean from factory: " + beanFromFactory);
}
}
代码结论:
-
•
ApplicationContext
在new AnnotationConfigApplicationContext(AppConfig.class)
这一行执行时,就会立即创建MyBean
的实例。 -
•
BeanFactory
的核心思想(懒加载)是在调用getBean()
时才去创建MyBean
的实例。