当前位置: 首页 > news >正文

深入理解 Spring 中的 XmlBeanFactory 原理及实践

1. 什么是 IoC 容器?——Spring 的核心理念

在进入 XmlBeanFactory 之前,我们需要首先理解一个重要的核心概念:IoC(Inversion of Control,控制反转)

什么是 IoC?

IoC 是一种软件设计原则,它将对象的创建和依赖管理交由容器负责,从而降低代码之间的耦合度,提高程序的可测试性与可维护性。

在传统的 Java 应用中,类通常通过 new 关键字实例化依赖类,如下所示:

public class UserService {private UserRepository userRepository = new UserRepository();
}

在 IoC 思维下,对象的创建交由容器完成,类仅声明所依赖的组件,由容器负责注入:

public class UserService {private UserRepository userRepository;public void setUserRepository(UserRepository userRepository) {this.userRepository = userRepository;}
}

容器则通过配置将依赖注入进来。这种方式即是 IoC 的典型体现。

IoC 容器的核心职责

  • 管理对象的生命周期

  • 管理对象之间的依赖关系

  • 提供统一的配置方式(如 XML、注解、JavaConfig)

Spring 就是 Java 世界中最知名的 IoC 容器框架之一。

2. BeanFactory 接口解析 —— IoC 容器的灵魂

在 Spring 中,IoC 容器的顶层抽象就是 org.springframework.beans.factory.BeanFactory 接口。

BeanFactory 是什么?

BeanFactory 是 Spring IoC 容器的最基础接口,定义了容器的基本行为,例如:

  • getBean(String name):获取指定名称的 Bean 实例。

  • containsBean(String name):判断容器中是否包含某个 Bean。

  • isSingleton(String name):判断是否为单例。

public interface BeanFactory {Object getBean(String name) throws BeansException;<T> T getBean(String name, Class<T> requiredType) throws BeansException;boolean containsBean(String name);boolean isSingleton(String name);// ...
}

为什么了解 BeanFactory 很重要?

所有更高级的 Spring 容器(如 ApplicationContext)都基于 BeanFactory 构建,理解 BeanFactory 是理解 Spring IoC 的基础。

 

3. 初识 XmlBeanFactory —— 定义与功能概览

什么是 XmlBeanFactory?

XmlBeanFactory 是 Spring 框架早期版本中通过 XML 文件配置 Bean 的一种实现,它实现了 BeanFactory 接口,能够读取 XML 文件中定义的 Bean 元素并创建相应的实例。

@Deprecated
public class XmlBeanFactory extends DefaultListableBeanFactory {public XmlBeanFactory(Resource resource) throws BeansException {this(resource, null);}public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {super(parentBeanFactory);XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);reader.loadBeanDefinitions(resource);}
}

从上面的源码可知:

  • XmlBeanFactory 继承自 DefaultListableBeanFactory

  • 使用 XmlBeanDefinitionReader 解析 XML 文件

  • 加载 BeanDefinition 并注册到当前容器

为什么还要了解 XmlBeanFactory?

尽管该类已在 Spring 3.1 之后被标记为废弃,但其原理仍然是 ApplicationContext 的重要基础。

4. 配置 XML 文件中的 Bean —— 结构与常见属性详解

要使用 XmlBeanFactory,首先需要编写 XML 配置文件来定义 Bean。Spring 通过读取这些 XML 文件来构建 BeanDefinition 并生成 Bean 实例。

基本结构

一个标准的 Spring XML 配置文件的基本结构如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="userService" class="com.example.service.UserService"/></beans>

常见属性说明

1. idname
  • id:用于唯一标识 Bean 实例。

  • name:可以为 Bean 提供多个别名。

<bean id="myBean" name="alias1,alias2" class="com.example.MyClass"/>
2. class

用于指定该 Bean 的全限定类名,是 Spring 创建实例的依据。

<bean id="userDao" class="com.example.dao.UserDao"/>
3. scope

定义 Bean 的作用域,常见值有:

  • singleton(默认):整个容器中只有一个实例。

  • prototype:每次调用都会创建一个新的实例。

<bean id="counter" class="com.example.Counter" scope="prototype"/>
4. init-methoddestroy-method

用于定义 Bean 初始化和销毁时要调用的方法。

<bean id="resourceManager" class="com.example.ResourceManager" init-method="init" destroy-method="cleanup"/>
5. depends-on

声明当前 Bean 依赖于其他 Bean,需要先初始化依赖的 Bean。

<bean id="beanA" class="com.example.BeanA" depends-on="beanB"/>
6. autowire

定义自动装配的方式:

  • byName

  • byType

  • constructor

  • no(默认)

<bean id="orderService" class="com.example.OrderService" autowire="byType"/>

属性注入(Property Injection)

通过 <property> 子元素设置属性值:

<bean id="userService" class="com.example.service.UserService"><property name="userRepository" ref="userRepository"/>
</bean><bean id="userRepository" class="com.example.repository.UserRepository"/>

构造函数注入(Constructor Injection)

<bean id="userService" class="com.example.service.UserService"><constructor-arg ref="userRepository"/>
</bean>

 

5. 使用 XmlBeanFactory 加载 Bean 的实践示例

了解了 XML 配置的基础后,我们就可以使用 XmlBeanFactory 实际加载这些配置并获取 Bean 实例了。下面是详细的步骤和示例。

步骤一:准备 XML 配置文件

创建一个名为 beans.xml 的文件,内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="userRepository" class="com.example.repository.UserRepository"/><bean id="userService" class="com.example.service.UserService"><property name="userRepository" ref="userRepository"/></bean></beans>

步骤二:创建 Bean 类

UserRepository 类:

package com.example.repository;public class UserRepository {public void save() {System.out.println("User saved.");}
}

UserService 类:

package com.example.service;import com.example.repository.UserRepository;public class UserService {private UserRepository userRepository;public void setUserRepository(UserRepository userRepository) {this.userRepository = userRepository;}public void registerUser() {System.out.println("Registering user...");userRepository.save();}
}

步骤三:使用 XmlBeanFactory 加载配置并使用 Bean

import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
import com.example.service.UserService;public class MainApp {public static void main(String[] args) {XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("beans.xml"));UserService userService = (UserService) factory.getBean("userService");userService.registerUser();}
}

输出结果

Registering user...
User saved.

注意事项

  • XmlBeanFactory 会在调用 getBean 时才真正实例化 Bean,这被称为 延迟加载(Lazy Loading)

  • 如果配置错误(如 ID 拼写错误、类未找到),会在调用 getBean 时抛出异常。

6. XmlBeanFactory 的生命周期管理机制

在 Spring 框架中,每个 Bean 都拥有一个清晰的生命周期管理流程。XmlBeanFactory 作为最基础的容器,同样支持完整的 Bean 生命周期控制机制。理解这个生命周期对于正确地管理资源、初始化逻辑、释放内存等非常重要。

Bean 生命周期的阶段概览

一个 Bean 在容器中的典型生命周期如下:

  1. 实例化(Instantiation)

  2. 属性注入(Populate Properties)

  3. Aware 接口回调(如 BeanNameAware、BeanFactoryAware 等)

  4. BeanPostProcessor 前置处理

  5. 初始化方法执行(包括 InitializingBean 和 init-method)

  6. BeanPostProcessor 后置处理

  7. Bean 可用阶段

  8. 销毁阶段(包括 DisposableBean 和 destroy-method)

1. 实例化阶段

当调用 getBean() 方法时,XmlBeanFactory 首先根据 BeanDefinition 创建对象实例。此过程通过 Java 的反射机制完成:

Object bean = beanClass.getDeclaredConstructor().newInstance();

2. 属性注入

容器会将 XML 中通过 <property><constructor-arg> 指定的依赖注入到 Bean 中。

<bean id="userService" class="com.example.UserService"><property name="userRepository" ref="userRepository"/>
</bean>

对应的 Java 注入过程是通过反射调用 setUserRepository() 方法。

3. Aware 接口回调

如果 Bean 实现了如下接口之一,容器将会在实例化后回调相应方法:

  • BeanNameAware:注入 Bean 的名称

  • BeanFactoryAware:注入当前的 BeanFactory 实例

  • ApplicationContextAware:注入 ApplicationContext(需要 ApplicationContext 支持)

public class MyBean implements BeanNameAware {public void setBeanName(String name) {System.out.println("Bean name is: " + name);}
}

4. BeanPostProcessor(前置处理)

如果注册了 BeanPostProcessor,容器会在 Bean 初始化前调用 postProcessBeforeInitialization() 方法。

public Object postProcessBeforeInitialization(Object bean, String beanName) {// 可对 bean 做增强处理,如代理、日志等return bean;
}

5. 初始化方法执行

初始化方法有两种:

  • 实现 InitializingBean 接口的 afterPropertiesSet() 方法

  • XML 配置中的 init-method 属性指定的方法

public class ResourceBean implements InitializingBean {public void afterPropertiesSet() throws Exception {System.out.println("Bean 初始化完成");}
}<!-- XML 配置 -->
<bean id="resourceBean" class="com.example.ResourceBean" init-method="init"/>

6. BeanPostProcessor(后置处理)

Bean 初始化完成后,会再次进入 postProcessAfterInitialization() 方法,为 Bean 提供最后的扩展点。

public Object postProcessAfterInitialization(Object bean, String beanName) {return bean;
}

7. Bean 使用阶段

此时 Bean 已完成初始化并可正常使用,由业务代码或容器进行调用。

8. Bean 销毁阶段

当容器关闭时,销毁流程开始。XmlBeanFactory 支持两种销毁方式:

  • 实现 DisposableBean 接口的 destroy() 方法

  • XML 中通过 destroy-method 指定的方法

public class ResourceBean implements DisposableBean {public void destroy() throws Exception {System.out.println("Bean 被销毁");}
}<!-- XML 配置 -->
<bean id="resourceBean" class="com.example.ResourceBean" destroy-method="cleanup"/>

⚠️ 注意:只有单例 Bean 的销毁方法才会被调用,原型作用域的 Bean 容器不会管理其销毁。

 

7. XmlBeanFactory 与 ApplicationContext 的深入比较

随着 Spring 发展,ApplicationContext 成为了主流的 IoC 容器,而 XmlBeanFactory 被逐渐淘汰。本节将从多个角度比较两者之间的异同。

基本定义对比

特性XmlBeanFactoryApplicationContext
接口继承BeanFactoryBeanFactory + 多个接口
延迟加载否(默认预加载单例 Bean)
国际化支持是(MessageSource)
事件机制支持事件发布机制
自动 BeanPostProcessor否(需手动注册)
支持资源访问部分完整资源访问封装(ResourceLoader)
推荐使用否(已废弃)是(主流容器)

示例对比:加载方式

使用 XmlBeanFactory
XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("beans.xml"));
MyService service = factory.getBean("myService", MyService.class);
使用 ApplicationContext
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
MyService service = context.getBean("myService", MyService.class);

生命周期差异

XmlBeanFactory 仅在调用 getBean() 时才创建 Bean,因此它具有 延迟加载(Lazy Initialization) 特性。而 ApplicationContext 会在启动时预加载所有非懒加载的单例 Bean。

这种行为差异带来如下影响:

  • XmlBeanFactory:适合资源紧张场景或按需初始化

  • ApplicationContext:启动时可能较慢,但能提前发现配置错误,且提供完整生命周期管理

BeanPostProcessor 自动注册

XmlBeanFactory 中,如果你定义了 BeanPostProcessor,需要手动调用 addBeanPostProcessor() 方法进行注册。而在 ApplicationContext 中,这些后处理器会自动被注册并应用。

XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("beans.xml"));
factory.addBeanPostProcessor(new CustomBeanPostProcessor());

国际化支持

ApplicationContext 实现了 MessageSource 接口,支持基于 messages.properties 文件的国际化功能,这在 XmlBeanFactory 中是不支持的。

String message = context.getMessage("welcome.message", null, Locale.CHINA);

事件发布机制

ApplicationContext 提供了事件发布和监听机制,可以发布自定义事件并监听容器内部事件,如 ContextRefreshedEvent。

context.publishEvent(new CustomEvent(this, "Hello World"));

资源访问封装

ApplicationContext 提供了统一的资源访问方式(如文件、URL、classpath等),而 XmlBeanFactory 仅限于 Resource 接口,不如前者强大灵活。

小结

对比点XmlBeanFactoryApplicationContext
是否推荐❌ 不推荐✅ 强烈推荐
生命周期支持✅ 有限支持✅ 完整支持
是否自动注册 BeanPostProcessor❌ 否✅ 是
是否支持事件机制❌ 否✅ 是
是否支持国际化❌ 否✅ 是
是否支持注解扫描、配置类❌ 否✅ 是(@Configuration, @ComponentScan 等)

从实践角度来看,除非特殊场景下进行底层定制或学习目的,推荐始终使用 ApplicationContext 作为 Spring 应用的主要容器。

8. 源码深度解析:XmlBeanFactory 的核心类与方法

XmlBeanFactory 是 Spring 框架中最早期的 XML 配置 Bean 容器实现,其继承体系如下:

XmlBeanFactory → DefaultListableBeanFactory → AbstractAutowireCapableBeanFactory → AbstractBeanFactory → FactoryBeanRegistrySupport → DefaultSingletonBeanRegistry

每一层都负责不同的职责。接下来我们逐层分析 XmlBeanFactory 及其核心功能实现源码。


8.1 类定义与构造器

源码路径(Spring 5.0 前):

@Deprecated
public class XmlBeanFactory extends DefaultListableBeanFactory {private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);public XmlBeanFactory(Resource resource) throws BeansException {this(resource, null);}public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {super(parentBeanFactory);this.reader.loadBeanDefinitions(resource);}
}
说明:
  1. XmlBeanFactory 实际上是 DefaultListableBeanFactory 的一个装饰器,它添加了 XML 配置加载能力。

  2. 使用 XmlBeanDefinitionReader 加载 XML 配置。

  3. loadBeanDefinitions 方法负责解析 Resource(如 ClassPathResource)中定义的 XML。


8.2 XmlBeanDefinitionReader 类

此类负责读取 XML 并将其转换为 BeanDefinition

核心方法:

public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {return loadBeanDefinitions(new EncodedResource(resource));
}public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {InputStream inputStream = encodedResource.getResource().getInputStream();InputSource inputSource = new InputSource(inputStream);return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
doLoadBeanDefinitions
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {Document doc = doLoadDocument(inputSource, resource);return registerBeanDefinitions(doc, resource);
}
  1. doLoadDocument():使用 DocumentLoader(默认是 DefaultDocumentLoader) 解析 XML 为 DOM。

  2. registerBeanDefinitions():调用 BeanDefinitionDocumentReader 对 DOM 结构进行 Bean 注册。


8.3 BeanDefinitionDocumentReader 与 BeanDefinitionParserDelegate

这些类处理 XML DOM 并将 <bean> 元素解析为 BeanDefinition

DefaultBeanDefinitionDocumentReader

核心方法:

public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {Element root = doc.getDocumentElement();BeanDefinitionParserDelegate delegate = createDelegate(readerContext, root);parseBeanDefinitions(root, delegate);
}
parseBeanDefinitions
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {NodeList nl = root.getChildNodes();for (int i = 0; i < nl.getLength(); i++) {Node node = nl.item(i);if (node instanceof Element) {Element ele = (Element) node;if (delegate.isDefaultNamespace(ele)) {parseDefaultElement(ele, delegate);} else {delegate.parseCustomElement(ele);}}}
}
  • 如果是默认命名空间(如 <bean>),则调用 parseDefaultElement

  • 否则调用 parseCustomElement(如 AOP、context 等命名空间)。


8.4 BeanDefinition 构建过程

进入 <bean> 元素的处理:

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.readerContext.getRegistry());
}

最终将 BeanDefinition 放入 BeanFactory 的注册表中。


8.5 Bean 注册表结构

最终注册的 Bean 存储在 DefaultListableBeanFactory 中的两个核心结构:

private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
private final List<String> beanDefinitionNames = new ArrayList<>();

当调用 getBean("xxx") 时,流程如下:

  1. beanDefinitionMap 获取对应的 BeanDefinition

  2. 如果是单例,尝试从缓存中获取,否则创建

  3. 实例化对象(反射)

  4. 注入属性(依赖注入)

  5. 执行初始化方法和 Aware 接口

  6. 返回实例

 

9. Spring 如何解析 XML 配置文件?Schema 与命名空间的工作机制

除了基本的 <bean> 元素,Spring 配置文件常见的还有如 <context:component-scan><aop:config> 等自定义标签。这些元素是通过 Spring 的 命名空间扩展机制(NamespaceHandler)实现的。

本章将揭示 Spring 如何通过 XSD 文件、NamespaceHandler 和 BeanDefinitionParser 机制解析复杂 XML。


9.1 XML 命名空间结构解析

Spring XML 文件顶部通常包含如下命名空间定义:

<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
核心含义:
  • xmlns:定义 XML 的命名空间。

  • xsi:schemaLocation:指定 XSD 文件位置。

  • Spring 使用 NamespaceHandler 对每个命名空间注册对应的解析器。


9.2 NamespaceHandler 的加载

META-INF/spring.handlers

Spring 使用 Java 的 SPI 机制加载 XML 命名空间处理器。

http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler
http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler
  • 当解析 <context:component-scan> 时,Spring 会通过 URI 匹配加载 ContextNamespaceHandler

NamespaceHandler 初始化流程:
  1. 解析 XML 根节点元素(如 <context:component-scan>

  2. 查找命名空间 URI

  3. 使用 NamespaceHandlerResolver 查找对应类

  4. 实例化并调用 NamespaceHandler.init() 注册子标签解析器


9.3 BeanDefinitionParser 的作用

每个标签由具体的 BeanDefinitionParser 实现类处理。例如:

  • <context:component-scan> 对应 ComponentScanBeanDefinitionParser

  • <aop:config> 对应 ConfigBeanDefinitionParser

public BeanDefinition parse(Element element, ParserContext parserContext) {String basePackage = element.getAttribute("base-package");// 解析并注册 beanDefinitionClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(...);scanner.scan(basePackage);
}

9.4 自定义标签支持流程小结:

Spring 解析 XML 自定义标签的完整流程:

读取 XML → 分析命名空间 URI → spring.handlers → NamespaceHandler → 注册 BeanDefinitionParser → 解析标签 → 注册 BeanDefinition

9.5 示例:解析 context 命名空间

XML:

<context:component-scan base-package="com.example.service" />

解析流程:

  1. 识别命名空间 http://www.springframework.org/schema/context

  2. spring.handlers 找到对应类 ContextNamespaceHandler

  3. ContextNamespaceHandler.init() 注册 ComponentScanBeanDefinitionParser

  4. 解析标签属性 base-package

  5. 使用 ClassPathBeanDefinitionScanner 扫描路径并注册 Bean

10. 深入理解 BeanDefinition —— 容器中的元数据核心

BeanDefinition 是 Spring IoC 容器的基石,代表了容器中一个 bean 的抽象描述,它是 Spring 用于内部管理 bean 的元数据结构。

本章将深入探讨 BeanDefinition 的定义、结构、用途及扩展方式,帮助读者真正理解容器初始化和实例化过程中的核心逻辑。


10.1 BeanDefinition 的接口与实现

Spring 中 BeanDefinition 是一个接口,主要实现类有:

  • GenericBeanDefinition

  • RootBeanDefinition

  • ChildBeanDefinition

  • AnnotatedGenericBeanDefinition

常用的是 GenericBeanDefinition,在基于 XML 或注解的配置中常被使用。

接口定义如下:

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {String getBeanClassName();void setBeanClassName(String beanClassName);String getScope();void setScope(String scope);boolean isLazyInit();void setLazyInit(boolean lazyInit);String[] getDependsOn();void setDependsOn(String[] dependsOn);boolean isAutowireCandidate();void setAutowireCandidate(boolean autowireCandidate);// 更多配置项...
}

10.2 核心字段说明

字段含义
beanClassNamebean 的类全名
scope单例 (singleton) 或原型 (prototype)
lazyInit是否延迟初始化
dependsOn本 bean 所依赖的其他 bean 名称
propertyValues注入的属性集合
constructorArgumentValues构造函数参数
initMethodName初始化方法名
destroyMethodName销毁方法名

10.3 BeanDefinitionHolder 与 BeanDefinitionReaderUtils

Spring 中不仅用 BeanDefinition 表示一个 bean,还通过 BeanDefinitionHolder 将其包装:

public class BeanDefinitionHolder {private final BeanDefinition beanDefinition;private final String beanName;private final String[] aliases;// 构造器、getters...
}

BeanDefinitionReaderUtils 则负责将定义注册到 BeanFactory 中:

public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) {registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());
}

10.4 从 XML 到 BeanDefinition 的转换示例

以如下 XML 为例:

<bean id="userService" class="com.example.UserService" scope="singleton" lazy-init="true"><property name="userDao" ref="userDao" />
</bean>

Spring 将其解析为如下 BeanDefinition 对象:

GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setBeanClassName("com.example.UserService");
bd.setScope(BeanDefinition.SCOPE_SINGLETON);
bd.setLazyInit(true);MutablePropertyValues pvs = new MutablePropertyValues();
pvs.add("userDao", new RuntimeBeanReference("userDao"));
bd.setPropertyValues(pvs);

10.5 BeanDefinition 注册时机

Spring 加载 XML 配置时,解析器最终会调用:

BeanDefinitionRegistry.registerBeanDefinition(beanName, beanDefinition);

注册到容器的 bean 名称与定义会保存在:

// DefaultListableBeanFactory.java
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();

此时 bean 尚未实例化,仅完成元数据注册。


10.6 BeanDefinition 与容器启动流程的关系

BeanDefinition 的生命周期大致如下:

  1. 加载配置(XML、注解等)

  2. 解析为 DOM 或扫描 Class 文件

  3. 生成 BeanDefinition

  4. 注册到 BeanFactory

  5. 容器调用 getBean() 时触发创建


10.7 自定义 BeanDefinition 示例

可以编程方式定义并注册一个 Bean:

DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setBeanClass(MyBean.class);
bd.setScope("singleton");factory.registerBeanDefinition("myBean", bd);
MyBean myBean = (MyBean) factory.getBean("myBean");

这对于动态创建 Bean 非常实用,例如通过反射加载类。

 

11. XmlBeanFactory 的最佳实践与常见陷阱

尽管 XmlBeanFactory 在 Spring 早期版本中广泛使用,但随着 Spring Framework 的演进,它已被标记为 @Deprecated。然而,在理解 Spring IoC 原理的学习阶段,它仍具有重要的参考价值。本章将从最佳实践与常见陷阱两个方面,为读者梳理 XmlBeanFactory 的使用策略。


11.1 最佳实践汇总

1)仅用于学习目的或轻量型场景

XmlBeanFactory 更适合用于:

  • 学习 Spring IoC 初始化流程

  • 实验项目或轻量容器(如工具类加载)

  • 非 Web 场景或与 ApplicationContext 脱离的容器环境

2)加载资源时使用 ClassPathResource 或 FileSystemResource

推荐方式:

Resource resource = new ClassPathResource("beans.xml");
XmlBeanFactory factory = new XmlBeanFactory(resource);

避免硬编码路径或使用未受支持的 URL 资源。

3)与 BeanFactoryPostProcessor 搭配使用

在初始化 BeanFactory 后,可以使用 BeanFactoryPostProcessor 扩展或修改 BeanDefinition:

factory.addBeanPostProcessor(new CustomBeanPostProcessor());
4)定义清晰的生命周期回调方法

使用 init-methoddestroy-method 明确指定生命周期钩子:

<bean id="example" class="com.Example" init-method="init" destroy-method="cleanup" />
5)关注 Scope 与依赖注入合理性

明确指定 singletonprototype,并确保依赖注入方式与 Bean 的生命周期一致。


11.2 常见陷阱与规避方式

1)多次实例化导致资源浪费

错误方式:

XmlBeanFactory factory1 = new XmlBeanFactory(resource);
XmlBeanFactory factory2 = new XmlBeanFactory(resource); // 再次实例化

问题:每次实例化都重新解析 XML,效率低下。

✅ 解决:保持单例模式下的 BeanFactory 实例。


2)未处理 IoC 生命周期导致异常

如果某些 bean 依赖于容器级初始化顺序,而未使用 depends-on 明确顺序,可能导致初始化失败。

✅ 解决:添加 depends-on 明确依赖。

<bean id="dataSource" class="com.DataSource" />
<bean id="userDao" class="com.UserDao" depends-on="dataSource" />

3)Bean 定义重复导致覆盖或冲突
<bean id="userService" class="com.UserService" />
<bean id="userService" class="com.AnotherUserService" />

可能抛出异常或悄然覆盖。

✅ 解决:确保每个 bean 的 ID 唯一。


4)Resource 加载失败导致异常
Resource resource = new FileSystemResource("config/missing.xml");

文件不存在会导致 FileNotFoundException

✅ 解决:使用 try-catch 捕获并处理异常,或通过 ClassPathResource 确保路径正确。


5)误用 ApplicationContext 扩展功能

XmlBeanFactory 不支持事件发布、国际化、AOP 注解、@Value 等特性。

✅ 建议:在生产项目中使用 ClassPathXmlApplicationContext 替代。


11.3 XmlBeanFactory 的生命周期易错点

  • Bean 的初始化顺序未明确 => 添加 depends-on

  • 单例/原型混用 => 保证注入时按需调整作用域或使用 ObjectFactory

  • 销毁方法未触发 => 使用 registerShutdownHook() 或显式 destroy()

((DisposableBean) bean).destroy();

11.4 替代方案建议

随着 Spring 的发展,推荐使用 ApplicationContext 作为默认容器,特别是:

  • ClassPathXmlApplicationContext

  • AnnotationConfigApplicationContext

  • GenericApplicationContext

这些容器提供更多功能与扩展性。


小结

实践建议
是否适合生产使用?❌ 不推荐
是否适合学习使用?✅ 强烈推荐
是否支持完整容器功能?❌ 功能受限
是否线程安全?✅ 多数情况下线程安全

XmlBeanFactory 是理解 Spring IoC 的经典入口,但实际开发应优先使用更现代的 ApplicationContext 系列容器。

http://www.xdnf.cn/news/1195885.html

相关文章:

  • 数据结构第1问:什么是数据结构?
  • Java 大视界 -- Java 大数据机器学习模型在电商客户细分与精准营销活动策划中的应用(367)
  • 【牛客网C语言刷题合集】(四)
  • PostgreSQL并发控制
  • 机器学习鸢尾花案例
  • KingbaseES聚焦产品上线
  • docker与k8s的容器数据卷
  • 自由学习记录(74)
  • 多租户Kubernetes集群架构设计实践——隔离、安全与弹性扩缩容
  • MYSQL--再谈间隙锁和临键锁
  • RabbitMq 常用命令和REST API
  • 商品中心—1.B端建品和C端缓存
  • Python-初学openCV——图像预处理(四)——滤波器
  • 命令行和neovim的git操作软件-lazygit
  • sealos 方式安装k8s5节点集群
  • 自动标注软件X-AnyLabeling的使用教程
  • 基于动态增强的 LLM 置信度方法研究
  • C语言中:形参与实参的那些事
  • [SAP ABAP] ALV报表练习4
  • Matlab自学笔记六十五:解方程的数值解法(代码速成)
  • 文件IO——bmp图像处理
  • 磁悬浮轴承转子不平衡质量控制策略设计:原理、分析与智能实现
  • 基于java的在线教育平台管理系统、在线学习系统的设计与实现
  • 零基础学习性能测试第三章:jmeter性能组件应用(事件,并发,定时器)
  • 哈尔滨←→南昌的铁路要道
  • AWD的攻击和防御手段
  • idea中无法删除模块,只能remove?
  • 2025年7月26日训练日志
  • 最优估计准则与方法(4)最小二乘估计(LS)_学习笔记
  • 幸福网咖订座点餐小程序的设计与实现