【Spring】DefaultListableBeanFactory 详解

DefaultListableBeanFactory 详解

DefaultListableBeanFactory 是 Spring IoC 容器的最核心实现,它提供了完整的 Bean 定义注册、依赖注入和生命周期管理功能。几乎所有 Spring 应用最终都依赖于这个类(包括 ApplicationContext 内部)。

一、核心作用

1. Bean 注册中心

  • 维护 Bean 名称到 BeanDefinition 的映射
  • 支持别名管理
  • 存储 Bean 的元数据(作用域、依赖、属性等)

2. 依赖注入引擎

  • 解析构造函数参数
  • 通过 setter/字段注入依赖
  • 处理循环依赖(三级缓存机制)
  • 支持自动装配(byName, byType, constructor)

3. 生命周期管理

  • 实例化 Bean
  • 执行初始化方法(@PostConstruct, InitializingBean, init-method)
  • 管理单例 Bean 的缓存
  • 调用销毁方法(@PreDestroy, DisposableBean, destroy-method)

4. 扩展点管理

  • 管理 BeanFactoryPostProcessor(容器级后置处理器)
  • 管理 BeanPostProcessor(Bean 级后置处理器)
  • 支持 PropertyEditorRegistrarTypeConverter

二、与其他 BeanFactory 的关系

java 复制代码
// 继承关系
BeanFactory (基础接口)
    ↑
ListableBeanFactory (可枚举)
    ↑
ConfigurableBeanFactory (可配置)
    ↑
AutowireCapableBeanFactory (可自动装配)
    ↑
DefaultListableBeanFactory (完整实现)

关键区别

  • BeanDefinitionRegistry :只有 DefaultListableBeanFactory 实现了此接口,支持 动态注册 Bean
  • ApplicationContext:内部持有 DefaultListableBeanFactory 实例,提供额外功能(事件、资源、AOP 等)

三、核心 API 与使用示例

1. 编程式创建容器

java 复制代码
// 1. 创建工厂实例
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

// 2. 创建 BeanDefinition
GenericBeanDefinition definition = new GenericBeanDefinition();
definition.setBeanClass(UserService.class);
definition.setScope(BeanDefinition.SCOPE_SINGLETON);

// 3. 设置属性(相当于 <property name="userDao" ref="userDao"/>)
MutablePropertyValues props = new MutablePropertyValues();
props.addPropertyValue("userDao", new RuntimeBeanReference("userDao"));
definition.setPropertyValues(props);

// 4. 注册 BeanDefinition
beanFactory.registerBeanDefinition("userService", definition);

// 5. 注册依赖的 Bean
beanFactory.registerBeanDefinition("userDao", 
    BeanDefinitionBuilder.genericBeanDefinition(UserDao.class).getBeanDefinition());

// 6. 获取 Bean 实例
UserService userService = beanFactory.getBean("userService", UserService.class);

2. 动态注册 Bean(高级用法)

java 复制代码
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

// 方式一:使用 BeanDefinitionBuilder
BeanDefinitionBuilder builder = BeanDefinitionBuilder
    .genericBeanDefinition(UserService.class)
    .addPropertyReference("userDao", "userDao")
    .setScope(BeanDefinition.SCOPE_PROTOTYPE)
    .setInitMethodName("init")
    .setDestroyMethodName("cleanup");

beanFactory.registerBeanDefinition("userService", builder.getBeanDefinition());

// 方式二:直接实现 FactoryBean
BeanDefinitionBuilder factoryBeanBuilder = BeanDefinitionBuilder
    .genericBeanDefinition(MyFactoryBean.class);
beanFactory.registerBeanDefinition("myBean", factoryBeanBuilder.getBeanDefinition());

3. 手动处理后置处理器

java 复制代码
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

// 注册 BeanFactoryPostProcessor(必须在 refresh 前)
PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
beanFactory.addBeanFactoryPostProcessor(configurer);

// 注册 BeanPostProcessor(必须在 getBean 前)
beanFactory.addBeanPostProcessor(new AutowiredAnnotationBeanPostProcessor());
beanFactory.addBeanPostProcessor(new CommonAnnotationBeanPostProcessor());

// 预实例化所有单例 Bean
beanFactory.preInstantiateSingletons();

4. 从现有配置创建

java 复制代码
// 从 XML 创建
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
reader.loadBeanDefinitions("classpath:applicationContext.xml");

// 从注解配置创建(需要额外依赖)
AnnotatedBeanDefinitionReader annotatedReader = new AnnotatedBeanDefinitionReader(beanFactory);
annotatedReader.register(AppConfig.class);

// 扫描包
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(beanFactory);
scanner.scan("com.example.service");

四、核心方法速查

方法 作用 示例
registerBeanDefinition() 注册 Bean 定义 factory.registerBeanDefinition("user", beanDef)
getBean() 获取 Bean 实例 factory.getBean(UserService.class)
containsBeanDefinition() 检查是否包含 Bean factory.containsBeanDefinition("user")
getBeansOfType() 按类型获取所有 Bean factory.getBeansOfType(DataSource.class)
getBeanDefinitionNames() 获取所有 Bean 名称 factory.getBeanDefinitionNames()
preInstantiateSingletons() 预初始化所有单例 factory.preInstantiateSingletons()
destroySingletons() 销毁所有单例 factory.destroySingletons()
registerSingleton() 注册已存在的单例对象 factory.registerSingleton("user", userObj)
addBeanPostProcessor() 添加 Bean 后置处理器 factory.addBeanPostProcessor(processor)

五、应用场景

1. 测试场景(精确控制)

java 复制代码
public class MyServiceTest {
    private DefaultListableBeanFactory factory;
    
    @Before
    public void setup() {
        factory = new DefaultListableBeanFactory();
        // 仅注册需要的 Bean,避免加载整个上下文
        factory.registerBeanDefinition("myService", 
            BeanDefinitionBuilder.genericBeanDefinition(MyService.class)
                .addPropertyReference("dao", "mockDao")
                .getBeanDefinition());
        
        // 注册 Mock 对象
        factory.registerSingleton("mockDao", Mockito.mock(MyDao.class));
    }
}

2. 动态插件系统

java 复制代码
// 根据运行时条件动态注册 Bean
if (featureEnabled) {
    beanFactory.registerBeanDefinition("featureService",
        BeanDefinitionBuilder.genericBeanDefinition(FeatureService.class).getBeanDefinition());
}

3. 框架集成

java 复制代码
// 在自定义框架中嵌入 Spring IoC
public class MyFramework {
    private final DefaultListableBeanFactory beanFactory;
    
    public MyFramework() {
        this.beanFactory = new DefaultListableBeanFactory();
        // 自动扫描框架内部的 Bean
        new ClassPathBeanDefinitionScanner(beanFactory)
            .scan("com.myframework.internal");
    }
}

4. 性能优化(延迟加载)

java 复制代码
// 只加载必要的 Bean,避免 ApplicationContext 的额外开销
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions("core-beans.xml");

// 按需加载其他模块
if (needModuleA) {
    reader.loadBeanDefinitions("module-a-beans.xml");
}

六、与 ApplicationContext 的对比

特性 DefaultListableBeanFactory ApplicationContext
事件发布 ❌ 不支持 ✅ 支持 ApplicationEvent
资源访问 ❌ 基础支持 ✅ 统一 Resource 接口
AOP 集成 ❌ 需手动添加处理器 ✅ 自动集成
注解支持 ❌ 需手动注册处理器 ✅ 自动支持
国际化 ❌ 不支持 ✅ 支持 MessageSource
启动速度 ⚡ 更快(功能少) ⚡ 稍慢(功能多)
内存占用 📊 更小 📊 更大
易用性 🛠️ 需手动配置 🎯 开箱即用

核心建议:除非有特殊需求(如性能优化、动态注册、框架集成),否则优先使用 ApplicationContext。

七、注意事项

1. 生命周期管理

java 复制代码
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();

// 错误:忘记调用 preInstantiateSingletons()
factory.registerBeanDefinition(...);
// 此时单例 Bean 还未初始化!

// 正确:手动触发初始化
factory.preInstantiateSingletons();

// 错误:不管理容器关闭
// 应用结束时可能导致资源泄漏

// 正确:调用销毁方法
factory.destroySingletons(); // 销毁所有单例
// 或在 Web 环境中注册 ShutdownHook

2. 后置处理器必须手动注册

java 复制代码
// ApplicationContext 会自动检测并注册,但 DefaultListableBeanFactory 不会!

// 必须手动添加常用处理器
factory.addBeanPostProcessor(new AutowiredAnnotationBeanPostProcessor()); // 处理 @Autowired
factory.addBeanPostProcessor(new CommonAnnotationBeanPostProcessor());    // 处理 @Resource @PostConstruct
factory.addBeanPostProcessor(new ApplicationContextAwareProcessor(...));  // 处理 Aware 接口
factory.addBeanPostProcessor(new AnnotationConfigUtils());                // 处理 @Configuration

// 否则注解不会生效!

3. 循环依赖处理

java 复制代码
// DefaultListableBeanFactory 支持三级缓存解决单例循环依赖
// 但 prototype 作用域的 Bean 循环依赖会抛出异常

// 示例:A 依赖 B,B 依赖 A(单例:✅ 支持)
factory.registerBeanDefinition("a", 
    BeanDefinitionBuilder.genericBeanDefinition(A.class)
        .addPropertyReference("b", "b")
        .getBeanDefinition());

factory.registerBeanDefinition("b", 
    BeanDefinitionBuilder.genericBeanDefinition(B.class)
        .addPropertyReference("a", "a")
        .getBeanDefinition());

factory.preInstantiateSingletons(); // 正常完成

4. 线程安全

  • Bean 注册阶段:非线程安全,应在单线程中完成所有注册
  • Bean 获取阶段:线程安全,支持并发访问
java 复制代码
// 推荐做法:在应用启动时完成所有注册
public class MyApp {
    private static final DefaultListableBeanFactory factory;
    
    static {
        factory = new DefaultListableBeanFactory();
        // 所有注册操作在这里完成
        initializeFactory();
    }
    
    public static BeanFactory getBeanFactory() {
        return factory; // 返回后只读
    }
}

5. 内存泄漏风险

java 复制代码
// 错误:频繁创建新的 Factory
public void processRequest() {
    DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
    // ... 加载大量 Bean
} // 无法被 GC,因为单例 Bean 持有引用

// 正确:复用工厂或使用 ApplicationContext(自动管理)

6. 配置元数据丢失

java 复制代码
// 直接注册单例实例会丢失配置信息
UserService service = new UserService();
factory.registerSingleton("userService", service);
// ✅ 速度快
// ❌ 无法应用 BeanPostProcessor
// ❌ 无法处理依赖注入
// ❌ 无法调用生命周期方法

// 推荐:通过 BeanDefinition 注册
BeanDefinition definition = BeanDefinitionBuilder
    .genericBeanDefinition(UserService.class)
    .getBeanDefinition();
factory.registerBeanDefinition("userService", definition);
// ✅ 完整生命周期支持

7. 与 Environment 集成

java 复制代码
// DefaultListableBeanFactory 没有 Environment
// 需要手动设置才能使用占位符 ${...}

StandardEnvironment env = new StandardEnvironment();
factory.setBeanExpressionResolver(new StandardBeanExpressionResolver());

// 手动添加 PropertySource
MutablePropertySources propertySources = env.getPropertySources();
propertySources.addLast(new MapPropertySource("custom", Map.of("db.url", "jdbc:...")));

// 使用 PropertySourcesPlaceholderConfigurer
PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
configurer.setEnvironment(env);
configurer.postProcessBeanFactory(factory); // 必须在所有 Bean 注册后调用

八、高级技巧

1. Bean 定义继承

java 复制代码
// 创建父定义
AbstractBeanDefinition parentDef = BeanDefinitionBuilder
    .genericBeanDefinition(BaseService.class)
    .setAbstract(true) // 标记为抽象
    .getBeanDefinition();
factory.registerBeanDefinition("baseService", parentDef);

// 创建子定义并继承
BeanDefinition childDef = BeanDefinitionBuilder
    .genericBeanDefinition(UserService.class)
    .setParentName("baseService") // 继承父配置
    .getBeanDefinition();
factory.registerBeanDefinition("userService", childDef);

2. 自定义作用域

java 复制代码
// 注册自定义作用域
factory.registerScope("tenant", new TenantScope());

// 使用自定义作用域
BeanDefinition definition = BeanDefinitionBuilder
    .genericBeanDefinition(TenantConfig.class)
    .setScope("tenant")
    .getBeanDefinition();
factory.registerBeanDefinition("tenantConfig", definition);

3. 依赖排序

java 复制代码
// 使用 @DependsOn 或手动设置
BeanDefinition definition = BeanDefinitionBuilder
    .genericBeanDefinition(DatabaseService.class)
    .setDependsOn("configService", "logService") // 确保顺序
    .getBeanDefinition();

九、总结建议

使用 DefaultListableBeanFactory 的场景

  • ✅ 需要动态注册/卸载 Bean的插件系统
  • ✅ 对启动性能有极致要求的轻量级应用
  • ✅ 编写单元测试时精确控制容器内容
  • ✅ 开发底层框架需要嵌入 IoC 能力
  • ✅ 需要绕过 ApplicationContext 的某些默认行为

不要使用 DefaultListableBeanFactory 的场景

  • ❌ 标准 Web 应用(用 ApplicationContext)
  • ❌ 需要 AOP、事务、事件等高级功能
  • ❌ 希望自动处理注解配置
  • ❌ 项目规模较大,需要统一资源管理

最终建议:在 99% 的场景下使用 ApplicationContext,只有当你明确知道需要绕过它的某些限制时,才考虑使用 DefaultListableBeanFactory。

相关推荐
while(1){yan}2 分钟前
SpringAOP
java·开发语言·spring boot·spring·aop
longxibo2 分钟前
mysql数据快速导入doris
android·大数据·python·mysql
专注于大数据技术栈3 分钟前
java学习--Collection
java·开发语言·学习
heartbeat..3 分钟前
Spring 全局上下文实现指南:单机→异步→分布式
java·分布式·spring·context
浙江巨川-吉鹏5 分钟前
【城市地表水位连续监测自动化系统】沃思智能
java·后端·struts·城市地表水位连续监测自动化系统·地表水位监测系统
zero.cyx12 分钟前
javaweb(AI)-----后端
java·开发语言
鹿角片ljp13 分钟前
Java深入理解MySQL数据库操作
java·mysql·adb
NE_STOP15 分钟前
SpringBoot集成shiro
java
RemainderTime17 分钟前
从零搭建Spring Boot3.x生产级单体脚手架项目(JDK17 + Nacos + JWT + Docker)
java·spring boot·架构
听风吹雨yu18 分钟前
YoloV11的pt模型转rknn模型适用于RK3588等系列
linux·python·yolo·开源·rknn