BeanFactory
Spring的BeanFactory是IoC容器的核心接口,理解其原理和周边概念对掌握Spring框架至关重要。下面我将详细讲解BeanFactory,并提供一些常见的面试题及参考答案。
BeanFactory 详解
1. BeanFactory 的角色与核心职责
BeanFactory是Spring框架中非常核心的一个顶层接口(即无父接口),它是Bean的工厂,主要职责就是生产Bean,实现了简单工厂的设计模式,即通过调用getBean
并传入标识来生产一个Bean。
作为Spring IoC(控制反转)容器的核心实现,BeanFactory负责管理所有Bean的生命周期和依赖关系。其核心能力包括:
创建Bean:根据配置(如XML、注解)或编程方式实例化Bean对象。
管理Bean:存储Bean的定义信息(
BeanDefinition
)和创建好的Bean实例。获取Bean:通过
getBean(String name)
等方法从容器中获取Bean实例。依赖注入(DI):自动解析并建立Bean之间的依赖关系。
2. 核心实现类
BeanFactory有多个实现类,每个工厂有不同的职责。其中最强大、最核心的是 DefaultListableBeanFactory
,Spring底层就是使用该实现工厂来生产Bean的。它提供了完整的Bean管理能力,是许多高级容器(如ApplicationContext
)的底层核心。
早期常用的XmlBeanFactory
在Spring 3.1之后已被弃用,现在可以通过DefaultListableBeanFactory
结合XmlBeanDefinitionReader
来实现类似功能。
3. BeanFactory 与 ApplicationContext 的关系
这是一个高频面试点。ApplicationContext
是BeanFactory
的子接口,在继承其所有Bean工厂功能的基础上,增加了大量企业级特性。
它们的核心区别如下表所示:
对比维度 | BeanFactory | ApplicationContext |
---|---|---|
功能定位 | 基础的IoC容器,Bean的“生产工厂” | 高级应用上下文,BeanFactory的超集 |
Bean加载时机 | 延迟加载:只有在调用 | 立即加载:容器启动时就会预实例化所有非延迟加载的单例Bean,有助于提前发现配置错误。 |
企业级功能 | 仅提供基本的IoC和DI功能。 | 提供了国际化、事件发布/监听、更便捷的AOP集成、资源访问等丰富功能。 |
使用场景 | 在资源敏感、追求极致轻量的环境中(如移动设备)可能被考虑。 | 绝大多数现代Spring应用的标准选择,功能全面。 |
一个形象的比喻是:BeanFactory就像汽车制造厂,只负责造车(创建Bean);而ApplicationContext则像4S店,它不仅从工厂拿车,还提供销售、保养、上牌等一站式服务(即各种企业级功能)。
4. BeanDefinition:Bean的“蓝图”
BeanDefinition
(Bean定义)是理解BeanFactory如何工作的关键。它主要负责存储Bean的定义信息,决定Bean的生产方式。你可以把它看作建造Bean的“蓝图”或“配方”。
当Spring容器启动时,它会读取配置文件(如XML中的<bean>
标签)或扫描注解(如@Component
),将这些配置信息解析成一个或多个BeanDefinition
对象,并注册到BeanFactory中(通常是一个名为beanDefinitionMap
的Map结构)。后续BeanFactory就是根据这些BeanDefinition
来实例化和装配Bean的。
核心面试题与参考答案
以下是一些关于BeanFactory的常见面试题及其答案,可以帮助你巩固理解和准备面试。
1. BeanFactory 和 FactoryBean 有什么区别?
这是最容易混淆的两个概念,它们的区别是本质性的。
对比项 | BeanFactory | FactoryBean |
---|---|---|
角色 | IoC容器的核心接口,是管理所有Bean的“大管家”。 | 一个特殊的Bean,是由BeanFactory管理的对象。 |
功能 | 是一个工厂,也是一个容器,负责所有Bean的创建、存储和管理。 | 是一个工厂,但只负责定制单个(或一种)复杂Bean的创建逻辑。 |
获取方式 | 直接通过 | 通过 |
简单总结:BeanFactory是容器级的接口,而FactoryBean是Bean级的接口。FactoryBean提供了一种扩展机制,当某个Bean的实例化过程非常复杂,无法用简单配置表达时,可以通过实现FactoryBean
接口来自定义创建逻辑,例如MyBatis-Spring中的SqlSessionFactoryBean
。
2. 简述 Spring IoC 容器的加载过程
IoC容器的加载过程非常精细,可以概括为以下几个核心阶段:
资源定位与加载:容器(如
ApplicationContext
)启动,定位配置文件(如XML)或注解配置类。解析与注册BeanDefinition:解析配置信息,将每个
<bean>
或@Component
注解的类解析成一个BeanDefinition
对象,然后将其注册(put)到容器的beanDefinitionMap
中。此时Bean还处于“定义态”。BeanFactoryPostProcessor处理:调用所有
BeanFactoryPostProcessor
的后置处理方法。这是第一个重要的扩展点,允许修改已有的Bean定义信息(例如,解析属性文件中的占位符${}
)。实例化Bean:容器遍历
beanDefinitionMap
,对非延迟加载的单例Bean进行实例化。这个过程包括:实例化:通过反射调用构造方法创建对象实例(“纯净态”Bean,属性未注入)。
依赖注入:根据配置,将Bean所依赖的其他Bean或值注入到属性中。
Aware接口回调:如果Bean实现了
BeanNameAware
、BeanFactoryAware
等接口,则回调相应方法,将容器信息注入给Bean。
BeanPostProcessor处理:这是第二个重要的扩展点。在Bean初始化方法(如
@PostConstruct
、InitializingBean
的afterPropertiesSet
)调用前后,会调用BeanPostProcessor
进行干预。Spring AOP的动态代理就是在此阶段生成的。初始化与投入使用:调用Bean的初始化方法,然后将完整的Bean放入单例池( singleton pool ),此时Bean处于“成熟态”,可供应用程序使用。
销毁:容器关闭时,对实现了
DisposableBean
接口的Bean调用destroy
方法,执行清理工作。
3. Spring 有哪些重要的扩展点?
Spring提供了丰富的扩展点,其中最核心的两个是:
BeanFactoryPostProcessor:允许在BeanFactory标准初始化之后、但任何Bean实例化之前,读取和修改Bean的定义信息(
BeanDefinition
)。例如,PropertySourcesPlaceholderConfigurer
处理${...}
占位符就是通过它实现的。BeanPostProcessor:允许在Bean实例化之后、初始化回调方法执行之前/之后,对Bean实例本身进行增强或包装。这是Spring AOP实现动态代理的基石。
其他常见扩展点还包括Aware
系列接口(用于让Bean感知容器)、生命周期回调方法(@PostConstruct
, @PreDestroy
)等。
4. Spring Bean 的作用域有哪些?
Spring容器中的Bean可以分为以下几种作用域:
singleton(默认):每个IoC容器中只有一个Bean实例。
prototype:每次请求(调用
getBean()
)都会创建一个新的Bean实例。request:在一次HTTP请求中,一个Bean定义对应一个实例(仅Web环境可用)。
session:在一个HTTP Session中,一个Bean定义对应一个实例(仅Web环境可用)。
application:在一个ServletContext生命周期内,一个Bean定义对应一个实例(仅Web环境可用)。
websocket:在一个WebSocket生命周期内,一个Bean定义对应一个实例(仅Web环境可用)。
希望这份详细的讲解和面试题汇总能帮助你深入理解Spring的BeanFactory。如果你对某个特定方面还有疑问,我们可以继续深入探讨。