本备忘单旨在快速梳理 Spring 框架的核心概念,从 IoC/DI 基础到 Bean 的高级管理,提供关键配置、代码示例和原理剖析,以便快速参考。
Spring 框架的设计深受两大设计原则的影响,其共同目标是 解耦。
控制反转 (Inversion of Control) 是一种核心设计思想,旨在降低代码耦合度。
依赖注入 (Dependency Injection) 是 IoC 思想的具体实现。容器会主动将某个对象所依赖的其他对象(或值)“注入”到该对象中。
setXxx() 方法注入依赖,最常用、最灵活。| 模块 (Module) | 核心功能描述 |
|---|---|
| Spring Core | (框架基石) 实现了控制反转 (IoC),是所有功能的基础。 |
| Spring AOP | (切面编程) 提供完整的面向切面编程支持,用于解耦业务与横切关注点。 |
| Spring DAO | (数据访问) 对原生 JDBC 进行了抽象和封装,简化了数据访问代码。 |
| Spring ORM | (对象关系映射) 提供对 MyBatis、Hibernate 等主流 ORM 框架的集成支持。 |
| Spring Context | (应用上下文) 提供国际化、事件传播、JNDI 等企业级服务,是框架功能的延伸。 |
| Spring Web MVC | (Web 框架) Spring 自带的、成熟的 MVC 框架,用于开发传统的 Servlet Web 应用。 |
| Spring Webflux | (响应式 Web) 完全异步、非阻塞的响应式 Web 框架,适用于高并发场景。 |
| Spring Web | (集成支持) 用于集成 Struts 等早期的第三方 Web 框架(较少使用)。 |
| 核心特性 | 说明 |
|---|---|
| 轻量 | 无论是 JAR 包大小还是运行时资源开销都非常小。 |
| 非侵入式 | 业务代码不依赖于 Spring 的特定 API,易于复用和测试。 |
| 控制反转 (IoC) | Spring 的灵魂,通过 IoC 技术促进松耦合。 |
| 面向切面 (AOP) | 允许将业务逻辑与系统服务(如事务、日志)优雅地分离。 |
| 容器 | 负责管理对象的配置、创建、装配及其完整的生命周期。 |
| 框架 | 将简单的组件通过声明式(XML 或注解)的方式组合成复杂的应用。 |
对于基础 IoC,仅需引入 spring-context 依赖。
<!-- pom.xml -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.2.9</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.13.4</version>
<scope>test</scope>
</dependency>
Bean 是由 Spring IoC 容器管理的对象,本质上是 POJO。
// src/main/java/com/example/spring6/bean/User.java
public class User {
public User() {
// Spring 默认通过无参构造器实例化
System.out.println("User 的无参数构造方法执行。");
}
}
XML 文件用于告知 Spring 容器需要管理哪些 Bean。
<!-- src/main/resources/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="userBean" class="com.example.spring6.bean.User"/>
</beans>
通过 ApplicationContext 启动 Spring 容器并获取 Bean 实例。
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
// 1. 创建 Spring 容器对象
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
// 2. 从容器中获取 Bean
// 方式一:返回 Object,需要强转
Object userBean = context.getBean("userBean");
// 方式二:无需强转 (推荐)
User user = context.getBean("userBean", User.class);
<bean> 的 id 必须唯一。Map<String, Object> 的结构(单例池)来存放单例 Bean。BeanFactory vs ApplicationContext: BeanFactory 是 IoC 容器的顶级接口,定义了基础功能。ApplicationContext 是其子接口,功能更强大,增加了对国际化、事件发布、AOP 等企业级特性的支持,是首选。通过调用 setXxx() 方法注入依赖。
<bean id="userDaoBean" class="com.example.spring6.bean.UserDao"/>
<bean id="userServiceBean" class="com.example.spring6.bean.UserService">
<!-- `name` 对应属性名 `userDao` -->
<!-- `ref` 引用另一个 bean 的 id -->
<property name="userDao" ref="userDaoBean"/>
</bean>
<bean id="userBean" class="com.example.spring6.bean.User">
<property name="name" value="Prorise"/>
<property name="age" value="25"/>
</bean>
null 和特殊字符<property name="name"><null/></property>
<property name="expression">
<value><![CDATA[ a < b && b > c ]]></value>
</property>
通过构造方法在实例化时注入依赖。
<bean id="userDaoBean" class="com.example.spring6.bean.UserDao"/>
<bean id="userServiceBean" class="com.example.spring6.bean.UserService">
<constructor-arg name="userDao" ref="userDaoBean"/>
</bean>
<property name="interests">
<list>
<value>编程</value>
<value>游戏</value>
</list>
</property>
<property name="phones">
<set>
<value>13888888888</value>
</set>
</property>
<property name="family">
<map>
<entry key="father" value="老王"/>
<entry key="mother" value="老李"/>
</map>
</property>
<property name="dbConfig">
<props>
<prop key="driver">com.mysql.cj.jdbc.Driver</prop>
</props>
</property>
将易变配置(如数据库连接)移至 .properties 文件。
jdbc.properties
db.driver=com.mysql.cj.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/testdb
db.username=root
db.password=123456
<!-- 引入 context 命名空间 -->
<beans xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="...
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 1. 加载属性文件 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 2. 使用 ${key} 占位符引用值 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${db.driver}"/>
<property name="url" value="${db.url}"/>
<property name="username" value="${db.username}"/>
<property name="password" value="${db.password}"/>
</bean>
</beans>
用于简化 XML 配置,现代开发多用注解代替。
<!-- 引入 p 和 c 命名空间 -->
<beans xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c" ...>
<!-- p 命名空间简化 setter 注入 -->
<bean id="user" class="...User" p:name="Prorise" p:age="25"/>
<!-- c 命名空间简化构造器注入 (按名称) -->
<bean id="service" class="...UserService" c:userDao-ref="userDaoBean"/>
</beans>
scope 属性决定了 Spring 如何创建 Bean 的实例。
| 作用域 | 描述 | 创建时机 |
|---|---|---|
singleton (默认) | 在整个 IoC 容器中,只有一个共享实例。 | 容器启动时创建。 |
prototype | 每次请求(getBean)都会创建一个新实例。 | 请求时创建(懒加载)。 |
XML 配置:
<bean id="sb" class="...SpringBean" scope="prototype"/>
注解配置 (推荐):
@Component
@Scope("prototype")
public class SpringBean { ... }
| 方式 | 描述 | XML 配置 |
|---|---|---|
| 构造方法 (默认) | 通过调用类的无参构造器创建。 | <bean class="...User"/> |
| 静态工厂方法 | 调用一个类的静态方法创建。 | <bean class="...Factory" factory-method="getInstance"/> |
| 实例工厂方法 | 调用一个已存在 Bean 实例的方法创建。 | <bean factory-bean="factoryId" factory-method="create"/> |
FactoryBean 接口 | 实现 FactoryBean 接口,封装复杂创建逻辑。 | <bean id="product" class="...ProductFactoryBean"/> |
FactoryBean 示例:
FactoryBean 是一个特殊的 Bean,它的作用是生产另一个 Bean。当从容器获取它时,得到的是其 getObject() 方法的返回值。
public class MyFactoryBean implements FactoryBean<Product> {
@Override
public Product getObject() throws Exception {
// ... 复杂的创建逻辑
return new Product();
}
// ...
}
<!-- 获取 "myProduct" 时,实际调用的是 MyFactoryBean 的 getObject() 方法 -->
<bean id="myProduct" class="...MyFactoryBean"/>
一个 Bean 从创建到销毁会经历一系列预定义的阶段。
BeanPostProcessor 的 postProcessBeforeInitialization 方法。init-method 或 @PostConstruct)。BeanPostProcessor 的 postProcessAfterInitialization 方法。destroy-method 或 @PreDestroy)。| 方式 | 描述 | 示例 |
|---|---|---|
XML init/destroy-method | 在 <bean> 中指定初始化和销毁方法名。 | <bean ... init-method="init" destroy-method="destroy"/> |
@PostConstruct / @PreDestroy (推荐) | JSR-250 标准注解,无代码侵入。 | @PostConstruct public void init() {} |
BeanPostProcessor | 对容器中所有 Bean 的初始化前后进行统一处理。 | class MyBPP implements BeanPostProcessor { ... } |
指两个或多个 Bean 相互持有对方的引用,形成闭环 (A -> B -> A)。
| 注入方式 | 作用域 | 是否能解决 |
|---|---|---|
| Setter 注入 | singleton | 可以 |
| Setter 注入 | prototype | 不可以 |
| 构造器注入 | singleton | 不可以 |
Spring 仅能解决单例 Bean 的 Setter 注入循环依赖,其核心是三级缓存机制:
singletonObjects: 存放完全初始化好的 Bean 成品。earlySingletonObjects: 存放已实例化但未填充属性的 Bean 半成品。singletonFactories: 存放能生产半成品 Bean 的工厂 (ObjectFactory)。解决流程:
BeanFactory vs FactoryBean这是一个经典面试题,两者名称相似但维度完全不同。
BeanFactory (是工厂):
ApplicationContext 是它的一个功能更强大的子接口。FactoryBean (是 Bean):
BeanFactory 管理。id="myBean" 的 FactoryBean 时,得到的是其 getObject() 的返回值。FactoryBean 本身,需使用 getBean("&myBean")。现代 Spring/Spring Boot 开发全面拥抱基于注解的配置,替代了繁琐的 XML。
| 注解 | 作用 |
|---|---|
@Component | 通用的 Bean 声明注解。 |
@Service | 用于标注业务逻辑层的组件。 |
@Repository | 用于标注数据访问层的组件。 |
@Controller | 用于标注 Web 控制器层的组件。 |
@Configuration | 声明一个类为配置类,替代 XML 文件。 |
@Bean | 在 @Configuration 类的方法上使用,将方法返回值注册为一个 Bean。 |
@Autowired | 按类型自动注入依赖。 |
@Qualifier("beanId") | 与 @Autowired 配合,按名称指定要注入的 Bean。 |
@Value("${key}") | 注入外部配置文件中的值。 |
@Scope("prototype") | 指定 Bean 的作用域。 |
@Lazy | 对 singleton Bean 进行懒加载。 |
@PostConstruct | 声明初始化回调方法。 |
@PreDestroy | 声明销毁回调方法。 |
使用 @Configuration 和 @Bean 完全替代 XML,实现类型安全、易于重构的配置。
@Configuration // 声明这是一个配置类
public class AppConfig {
@Bean // 方法名 "userDao" 就是 bean 的 id
public UserDao userDao() {
return new UserDaoImpl();
}
@Bean("userService") // 也可以自定义 bean 的 id
public UserService userService(UserDao userDao) { // Spring 会自动注入上面定义的 userDao
UserServiceImpl service = new UserServiceImpl();
service.setUserDao(userDao); // 编程方式进行依赖注入
return service;
}
}