Spring IoC 容器:Bean 管理与配置文件
Spring IoC 容器:Bean 管理与配置文件
一、Spring 容器的核心概念
Spring 容器的本质是一个IoC(控制反转)容器,它颠覆了传统 “开发者手动创建对象、管理依赖” 的模式,改为由容器统一管理对象的生命周期和依赖关系(这个过程也叫 DI 依赖注入)。
Spring 容器就是 Spring 框架的 “对象管家”,它帮你自动创建、管理、组装和销毁 Java 对象(也就是 Spring 里的 Bean),你不用手动 new 对象、处理对象依赖,只需要告诉它规则就行。
简单打个比方:
把 Spring 容器比作 家里的 “智能收纳柜”:
你(开发者)只需要把 “物品清单”(注解 / 配置文件)交给收纳柜,告诉它要收纳哪些东西(Bean)、哪些东西要放在一起(依赖关系)。
收纳柜会自动把物品分类放好(创建并注册 Bean),当你需要用某个物品时(获取 Bean),它直接递到你手上,不用你自己翻找;
当你不需要这些物品了(容器关闭),收纳柜还会自动把它们整理好收起来(销毁 Bean),全程不用你操心。
1. 容器的核心接口
Spring 容器有两个核心层级接口,你可以把它们理解为 “容器的不同版本”:
BeanFactory:最基础的容器接口,提供了 IoC 容器的最核心功能(如获取 Bean、Bean 生命周期管理),是 Spring 容器的底层实现,特点是懒加载。
补:Spring 中的懒加载,是容器创建 Bean 时的一种加载策略,简单说就是 “什么时候用,什么时候才创建” 即 容器启动不创建,首次使用才创建,和默认的 “容器一启动就创建所有 Bean” 。
ApplicationContext:BeanFactory 的子接口,是更高级的容器实现,在 BeanFactory 基础上扩展了更多功能(如国际化、事件发布、资源加载),特点是饿汉式加载(容器启动时就创建所有单例 Bean),也是实际开发中最常用的容器。
常见的 ApplicationContext 实现类:
ClassPathXmlApplicationContext:从类路径加载 XML 配置文件创建容器。
AnnotationConfigApplicationContext:从注解配置类(@Configuration)创建容器(主流方式)。
FileSystemXmlApplicationContext:从文件系统路径加载 XML 配置文件。
二、Spring 容器的核心功能
1. Bean 的创建与注册
容器会根据配置(XML / 注解 / Java 配置)创建 Bean,并将其注册到容器中。
示例:注解方式创建容器并注册 Bean
// 1. 定义一个简单的 Bean
@Component // 标记为 Spring 管理的 Bean
public class UserService {
public void sayHello() {
System.out.println("Hello from Spring Container!");
}
}
// 2. 配置类(告诉容器扫描哪些包下的 Bean)
@Configuration
@ComponentScan("com.example.demo") // 扫描指定包下的@Component注解类
public class SpringConfig {
}
// 3. 启动容器并获取 Bean
public class Main {
public static void main(String[] args) {
// 创建 ApplicationContext 容器(核心步骤)
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
// 从容器中获取 Bean
UserService userService = context.getBean(UserService.class);
// 使用 Bean
userService.sayHello(); // 输出:Hello from Spring Container!
}
}
2. Bean 的生命周期管理
Spring 容器会全程管理 Bean 的生命周期,核心流程:
- 实例化 Bean(创建对象)
- 设置 Bean 的属性(依赖注入)
- 调用
BeanNameAware/ApplicationContextAware等接口方法 - 调用
BeanPostProcessor的前置处理方法 - 调用
InitializingBean的afterPropertiesSet()或自定义初始化方法(@PostConstruct) - 调用
BeanPostProcessor的后置处理方法 - Bean 就绪可使用
- 容器关闭时,调用
DisposableBean的destroy()或自定义销毁方法(@PreDestroy) - 销毁 Bean。
示例:自定义 Bean 生命周期方法
@Component
public class OrderService {
// 初始化方法(Bean 创建完成后执行)
@PostConstruct
public void init() {
System.out.println("OrderService 初始化");
}
// 销毁方法(容器关闭时执行)
@PreDestroy
public void destroy() {
System.out.println("OrderService 销毁");
}
}
3. 依赖注入(DI)
容器会自动将 Bean 依赖的其他对象注入进来,无需手动 new,常见方式:
字段注入(最简洁,推荐简单场景):
@Component
public class UserController {
@Autowired // 自动注入 UserService 实例
private UserService userService;
}
构造器注入(推荐复杂场景,更符合依赖不可变原则):
@Component
public class UserController {
private final UserService userService;
// 容器自动调用构造器注入
public UserController(UserService userService) {
this.userService = userService;
}
}
补:若用 Spring Boot 2.6+,建议配合 @RequiredArgsConstructor 替代纯字段注入(兼顾简洁和规范)开发常用的方式:
@RestController
@RequestMapping("/user")
@RequiredArgsConstructor // Lombok注解,自动生成final字段的构造器
public class UserController {
private final UserService userService; // final + 构造器注入,极简又规范
}
可选依赖 / 动态变更依赖(推荐:Setter 注入):
适用场景:
依赖可选存在(有则注入,无则用默认值),或运行中可能更换实现的场景。
例如:订单服务(OrderService)可选依赖短信通知(SmsService),没有则用邮件通知兜底;或需要动态切换支付渠道(AlipayService/WechatPayService)。
示例:
@Component
public class OrderService {
private SmsService smsService; // 可选依赖,非final
// Setter注入,支持可选依赖
@Autowired(required = false) // required=false 表示可选
public void setSmsService(SmsService smsService) {
this.smsService = smsService;
}
// 业务方法:有短信服务则发通知,无则跳过
public void createOrder(Order order) {
// 业务逻辑...
if (smsService != null) {
smsService.sendOrderNotice(order);
}
}
}
补:Setter 方法可在运行时被调用,支持动态更换依赖实现(比如从支付宝切换到微信支付)。
多实现类的依赖注入(需配合限定符)
适用场景:
一个接口有多个实现类,需要指定具体注入哪个(比如 PaymentService 有 AlipayPayment、WechatPayment 两个实现)。
方案:
构造器 / 字段 / Setter 注入都可,关键是配合 @Qualifier(指定 Bean 名称)或 @Resource(按名称注入)。
示例(构造器 + @Qualiier):
// 接口
public interface PaymentService {
void pay(Order order);
}
// 实现类1
@Component("alipay") // 指定Bean名称
public class AlipayPayment implements PaymentService {
@Override
public void pay(Order order) {
System.out.println("支付宝支付");
}
}
// 实现类2
@Component("wechat")
public class WechatPayment implements PaymentService {
@Override
public void pay(Order order) {
System.out.println("微信支付");
}
}
// 注入时指定实现类
@Component
public class OrderService {
private final PaymentService paymentService;
// 构造器注入 + @Qualifier 指定Bean名称
public OrderService(@Qualifier("alipay") PaymentService paymentService) {
this.paymentService = paymentService;
}
}
注入方式选择原则
优先选构造器注入:这是 Spring 官方推荐的方式,符合 “依赖注入” 的设计初衷,代码更健壮、易测试;
字段注入只用于简单场景:Controller 层可酌情使用,核心业务层尽量不用;
Setter注入仅用于可选依赖:不要把 Setter 注入当成 “替代构造器” 的方式,避免依赖可变带来的风险;
多实现类必加限定符:用 @Qualifier 或 @Resource 明确指定 Bean,避免 “NoUniqueBeanDefinitionException” 异常。
4. Bean 的作用域管理
Spring 支持为 Bean 设置不同的作用域,控制 Bean 的实例数量,常用:
singleton(默认):容器中只有一个 Bean 实例,全局共享。
prototype:每次获取 Bean 都创建新实例。
request:Web 环境下,每个 HTTP 请求创建一个实例。
session:Web 环境下,每个 HTTP 会话创建一个实例。
示例:设置 Bean 作用域
@Component
@Scope("prototype") // 原型作用域,每次getBean都新建
public class CartService {
}
三、容器的启动与关闭
启动:创建 ApplicationContext 实例时,容器会完成 Bean 的扫描、注册、实例化(单例 Bean)、依赖注入等操作。
关闭:非 Web 环境下需手动关闭容器(释放资源),Web 环境下由容器(如 Tomcat)自动关闭。
示例:手动关闭容器
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
// 使用容器...
// 手动关闭容器(触发 Bean 的销毁方法)
context.close();
}
}
四、配置文件
1、文件类型
Spring 配置文件主要分两类,核心都是 XML 格式(这是配置文件的主流形式):
核心配置文件(Bean 定义)
最基础的配置文件,用于注册 Bean、配置依赖注入、指定扫描规则等,文件名通常是 applicationContext.xml(约定俗成,也可自定义)。
环境配置文件(属性配置)
用于存放常量(如数据库连接信息、端口号),常见格式:
.properties(键值对格式,最传统)
.yml/.yaml(层级格式,Spring Boot 主流,也算广义的配置文件)
2、核心配置文件详解(XML)
完整示例
<?xml version="1.0" encoding="UTF-8"?>
<!-- 根标签 + 命名空间声明(核心:beans,扩展:context、tx等) -->
<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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 1. 扫描指定包下的注解Bean(XML + 注解混合配置) -->
<context:component-scan base-package="com.example.demo"/>
<!-- 2. 加载外部属性配置文件(比如db.properties) -->
<context:property-placeholder location="classpath:db.properties"/>
<!-- 3. 手动注册Bean(id=Bean名称,class=全类名) -->
<bean id="userDao" class="com.example.demo.dao.UserDaoImpl"/>
<!-- 4. 注册Bean并注入依赖(构造器注入) -->
<bean id="userService" class="com.example.demo.service.UserServiceImpl">
<!-- ref 引用另一个Bean的id -->
<constructor-arg ref="userDao"/>
</bean>
<!-- 5. 注册Bean并设置属性(Setter注入 + 读取外部配置) -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<!-- value 直接赋值,${} 读取外部properties中的值 -->
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
</beans>
标签说明
| 标签 / 配置 | 作用 |
|---|---|
<beans> |
根标签,所有配置都包裹在里面,声明命名空间和 xsd 约束 |
<bean> |
注册单个 Bean,id是 Bean 唯一标识,class是类的全限定名 |
<constructor-arg> |
构造器注入依赖,ref引用其他 Bean,value赋值基本类型 |
<property> |
Setter 注入依赖,name对应 Setter 方法名(如 setUrl→url),value/ref赋值 |
<context:component-scan> |
开启注解扫描,base-package指定扫描的包路径(混合配置核心) |
<context:property-placeholder> |
加载外部.properties 文件,支持${key}读取值 |
加载配置文件
// 方式1:从类路径加载(最常用)
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 方式2:从文件系统绝对路径加载
// ApplicationContext context = new FileSystemXmlApplicationContext("D:/project/applicationContext.xml");
// 获取Bean
UserService userService = context.getBean("userService", UserService.class);
3、属性配置文件(.properties/.yml)
这类文件用于存放可配置的常量,解耦代码中的硬编码,常见于数据库连接、服务端口等配置。
properties 格式(传统)
文件名:db.properties
# 数据库连接配置
jdbc.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8
jdbc.username=root
jdbc.password=123456
jdbc.driverClassName=com.mysql.cj.jdbc.Driver
yml 格式(Spring Boot 主流)
文件名:application.yml(层级结构,更简洁)
# 服务器配置
server:
port: 8080
servlet:
context-path: /demo
# 数据库配置
spring:
datasource:
url: jdbc:mysql://localhost:3306/test
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
加载属性配置文件
XML 中:通过 <context:property-placeholder> 加载(见上文 XML 示例);
Spring Boot 中:自动加载 resources 下的 application.properties/application.yml,无需手动配置。
4、使用场景
| 配置文件类型 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| XML 核心配置 | 配置与代码分离、老项目兼容 | 繁琐、编译期不校验、维护成本高 | Spring 老项目、需要跨团队共享配置 |
| .properties | 简单易上手、兼容性好 | 层级结构不清晰、重复配置多 | 简单配置、老项目 |
| .yml | 层级清晰、简洁、支持复杂结构 | 对格式敏感(空格 / 缩进) | Spring Boot 新项目、复杂配置 |
总结
- Spring 容器的核心是 IoC 容器,核心接口为
BeanFactory(基础)和ApplicationContext(常用),负责统一管理 Bean 的生命周期。 - 容器的核心能力包括:Bean 的创建 / 注册、依赖注入(DI)、生命周期管理、作用域控制。
- 实际开发中优先使用
AnnotationConfigApplicationContext(注解配置),Bean 的注入推荐构造器注入,作用域默认使用 singleton,需多实例时用 prototype。
更多推荐




所有评论(0)