Spring从2.5版本开始引入注解配置,到Spring Boot时代注解几乎成了唯一选择,很多新入行的开发者甚至没写过一行XML配置。但这并不意味着XML已经死亡,大量遗留系统仍在运行,某些企业级场景中XML依然是首选方案。理解两种配置方式的原理与适用边界,是每个Spring开发者的必修课。

XML配置的实现原理与现状
XML配置是Spring最早支持的配置方式,它的核心入口是ClassPathXmlApplicationContext或FileSystemXmlApplicationContext。容器启动时,Spring会通过XmlBeanDefinitionReader解析XML文件,将<bean>标签解析成BeanDefinition对象,再由容器统一实例化和管理。整个解析过程基于DTD或XSD约束,Spring的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="userService" class="com.example.service.UserService">
<property name="userDao" ref="userDao"/>
</bean>
<bean id="userDao" class="com.example.dao.UserDao"/>
</beans>XML的优势在于配置与代码完全分离。修改依赖关系、替换实现类、调整注入属性都不需要重新编译,只需替换配置文件即可生效,这在某些需要运维人员介入、不允许频繁发版的环境中非常实用。此外,XML对第三方Jar包中的类特别友好,因为你无法修改别人的源码来添加@Component注解,只能通过外部配置声明Bean。
当然XML的缺点也很明显:配置冗长,一个Bean需要多行标签,依赖关系复杂时可读性急剧下降;缺乏编译期检查,类名写错只能在启动时发现;IDE支持虽然完善,但重构时XML中的全限定类名不会自动同步更新,容易留下隐患。
注解配置的机制与常用注解详解
注解配置的基础是@Configuration和@Component两大体系。@Component及其派生注解(@Service、@Repository、@Controller)负责声明Bean,@Autowired负责完成依赖注入,@Configuration类则扮演了XML文件的角色。Spring解析配置类时依赖AnnotationConfigApplicationContext,通过ClassPathBeanDefinitionScanner扫描指定包路径下的注解,同样生成BeanDefinition。
与上面XML等价的注解写法如下:
// 声明为Spring组件,由容器扫描注册
@Service
public class UserService {
private final UserDao userDao;
// 构造器注入,官方推荐方式
@Autowired
public UserService(UserDao userDao) {
this.userDao = userDao;
}
}
@Repository
public class UserDao {
}如果想实现与XML完全一致的外部化声明,也可以使用Java配置类,这种方式兼具类型安全和集中管理的优点:
@Configuration
public class AppConfig {
@Bean
public UserDao userDao() {
return new UserDao();
}
@Bean
public UserService userService() {
return new UserService(userDao());
}
}注解方式的优点突出:配置即代码,享受编译期类型检查;重构安全,IDE可以精确追踪所有引用;代码量少,与业务代码贴合紧密。缺点则是配置散落在各个类中,全局视角不如XML直观,而且修改配置必须重新编译打包。另外@Autowired的按类型匹配在存在多个候选Bean时需要配合@Qualifier使用,初学者容易在此踩坑。
多维度对比:可读性、性能与维护成本
从可读性角度看,注解在小规模项目中优势明显,一眼就能看出类的职责和依赖;但项目变大后,Bean之间的依赖关系分散在上百个类文件里,想梳理某个模块的整体装配结构反而困难,这时XML或@Configuration集中配置的全局视图更有价值。
从启动性能看,两者差异不大。XML解析和注解扫描最终都会生成BeanDefinition,耗时差异主要体现在解析阶段,注解扫描需要遍历字节码读取元数据,XML则需要解析文档树。在实际项目中,这部分开销相对于Bean实例化本身通常可以忽略,不必作为选择依据。
从维护成本看,注解明显占优。版本升级、批量重构、静态分析工具支持,注解方式都更友好。XML还有一个容易被忽视的问题:XSD文件的加载依赖网络或本地缓存,某些离线环境下会遇到解析超时,需要额外配置spring-beans.xsd的本地映射。
| 对比维度 | XML配置 | 注解配置 |
|---|---|---|
| 类型安全 | 无编译期检查 | 编译期即可校验 |
| 配置修改 | 改文件即可,无需编译 | 需重新编译打包 |
| 第三方类接入 | 天然支持 | 需Java配置类桥接 |
| 全局视图 | 集中清晰 | 分散在各类中 |
| 代码量 | 冗长 | 简洁 |
| 与Spring Boot契合度 | 低 | 高,事实标准 |
如何选择:分场景给出建议
对于新项目,尤其是基于Spring Boot的项目,注解配置是毫无悬念的选择。自动配置、条件装配、 starter机制全部围绕注解体系构建,强行引入XML只会增加理解成本。
对于遗留系统的维护,如果原有架构基于XML,建议采取渐进式策略:新模块使用注解,通过@ImportResource引入旧的XML配置文件,让两种方式共存,避免一次性改造带来的风险。示例如下:
@Configuration
@ImportResource("classpath:legacy-beans.xml")
public class HybridConfig {
// 该配置类同时注册注解Bean和XML中声明的Bean
}还有几类特殊场景XML仍然不可替代:一是需要在不重启或极少发版的前提下调整Bean装配的运维型系统;二是引入无法修改源码且没有starter支持的第三方库;三是团队规范要求配置与代码严格分离的合规性场景。此外,AOP切面、事务边界等横切逻辑,历史上常用<aop:config>和<tx:advice>声明,如今可以完全用@Aspect和@Transactional替代,这属于注解的舒适区。
总结来说,XML配置并非过时的弃子,而是特定场景下的务实工具。理解它的原理依然有价值,因为在阅读老代码、排查Bean装配问题时,这些知识会直接派上用场。技术选型的原则很简单:默认用注解,遇到集中管理、外部化装配、第三方接入等需求时,再考虑XML或Java配置类,三者混用也完全合法,Spring容器对它们一视同仁。
Spring XML配置注解配置Spring依赖注入修改时间:2026-09-02 10:24:44