承接上篇 SpringBoot 多配置文件与加载优先级,本篇聚焦 Spring IOC 容器 Bean 完整管理体系,包含五大 Bean 作用域、单例 Bean 创建时机、Bean 线程安全判定、第三方组件 @Bean 注解规范、统一配置类开发标准,配套大量业务代码、面试高频问答,是 Spring 核心必考内容;下篇拆解 SpringBoot 两大核心:起步依赖、自动配置源码、@EnableAutoConfiguration、自定义 Starter 完整落地。
一、Bean 五大作用域详解
Spring 容器中 Bean 的作用域决定容器会创建多少个实例对象,一共 5 种,前两种通用,后三种仅 Web 项目生效。
| 作用域 | 关键字 | 实例创建规则 | 使用场景 |
|---|---|---|---|
| singleton(单例) | @Scope("singleton") | 整个 IOC 容器仅创建 1 个 Bean 实例,Spring 默认 | Controller、Service、Mapper,绝大多数业务类 |
| prototype(多例) | @Scope("prototype") | 每次通过 @Autowired / 上下文获取 Bean,都会新建对象 | 内部存在成员变量、存储临时数据的有状态类 |
| request | @Scope("request") | 一次 HTTP 请求内仅一个实例 | Web 开发请求级临时对象(极少使用) |
| session | @Scope("session") | 同一个浏览器会话共享一个实例 | 登录会话存储类(了解即可) |
| application | @Scope("application") | 整个 Web 应用全局单例 | 全局公共缓存类(了解即可) |
1. 默认 singleton 单例 Bean 特性
- 创建时机:项目容器启动时,默认直接实例化所有单例 Bean;
- 延迟加载:添加
@Lazy注解后,Bean 会延迟到第一次使用时才创建; - 优势:只创建一次,节约内存、提升项目启动与运行性能;
- 代码示例
@Slf4j
@RestController // 默认singleton单例,无需额外写@Scope
public class DeptController {
@Autowired
private DeptService deptService;
@GetMapping("/depts")
public Result<List<Dept>> list(){
log.info("查询全部部门");
return Result.success(deptService.findAll());
}
}
2. prototype 多例 Bean 使用场景
单例 Bean 如果定义了成员变量用于临时存储数据,多线程并发访问会出现数据错乱,这种有状态 Bean必须设置多例。
有状态类示例(存在成员变量存储临时数据)
@Component
@Scope("prototype") // 多例,每次获取新建对象
public class DataProcessor {
// 成员变量存储临时业务数据(有状态)
private List<EmpModel> dataList = new ArrayList<>();
private Integer errorCount = 0;
public void process(List<Emp> empList){
// 处理数据,修改成员变量
dataList = empList.stream().map(...).toList();
}
}
无状态类(无成员变量、仅提供方法)直接使用默认单例即可。
二、高频面试题:Bean 单例与线程安全
问题 1:Spring 容器 Bean 默认单例,是否线程安全?
结论:分 Bean 有无状态判断
- 无状态 Bean(无成员变量,仅提供方法,数据均为方法局部变量):线程安全示例:Controller、Service、Mapper,所有数据都在方法内定义,多线程调用互不干扰;
- 有状态 Bean(定义全局成员变量存储数据):线程不安全多请求同时操作同一个对象的成员变量,会发生数据覆盖、错乱,解决方案:加
@Scope("prototype")改为多例。
问题 2:单例 Bean 默认什么时候实例化?如何延迟创建?
- 默认:Spring 容器启动阶段全部实例化;
- 延迟初始化:在类上添加
@Lazy注解,第一次使用才创建对象。
@Component
@Lazy // 延迟创建
public class CommonUtil {}
三、自定义 Bean 四种注解区分
四类组件注解(用于项目自定义类)
@Component、@Controller、@Service、@Repository,底层功能完全一致,仅用于分层标识,方便阅读:
- @Controller:控制层 Controller 类;
- @Service:业务层 Service 实现类;
- @Repository:持久层 Mapper/DAO;
- @Component:通用工具类,不属于三层时使用。
局限性
仅能管理项目内部自定义类;第三方依赖包中的类(OSS 工具、Gson、Redis 模板等)无法添加这四类注解,必须使用@Bean。
四、第三方 Bean 管理:@Bean 注解 + 配置类规范
核心场景
引入第三方 SDK、工具类,无法在源码添加 @Component,使用 @Bean 交给 IOC 容器管理。
开发规范:统一使用 @Configuration 配置类集中管理第三方 Bean
不推荐写在启动类中,配置类分层,项目结构更清晰。
错误写法(启动类内写 Bean,混乱难维护)
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
// 不推荐:启动类混杂第三方Bean
@Bean
public AliyunOSSOperator ossOperator(AliyunOSSProperties prop){
return new AliyunOSSOperator(prop);
}
}
标准推荐写法:独立配置类
// 配置类,统一存放OSS相关第三方Bean
@Configuration
public class OssConfig {
// @Bean:方法返回对象交给IOC容器
@Bean
public AliyunOSSOperator aliyunOSSOperator(AliyunOSSProperties ossProperties) {
return new AliyunOSSOperator(ossProperties);
}
}
@Bean 关键知识点
- Bean 名称:默认以方法名作为 BeanName;可通过
@Bean(name="ossUtil")手动指定; - 依赖自动注入:方法形参直接声明其他 Bean,Spring 自动按类型装配;
- 使用方式:业务类直接
@Autowired private AliyunOSSOperator ossUtil;注入使用。
五、中篇全文总结
- Bean 五大作用:singleton 默认单例、prototype 多例,request/session/application 仅 Web 可用;
- 单例 Bean 启动默认创建,@Lazy 实现延迟实例化;
- Bean 线程安全:无状态线程安全,有状态必须改为 prototype 多例;
- 自定义类用 @Service/@Controller 等,第三方类统一用 @Bean;
- @Bean 建议放在独立 @Configuration 配置类,不要写在启动类。
中篇拓展实操练习
- 编写带成员变量的有状态工具类,不加 prototype 测试并发数据错乱;添加 @Scope 后对比效果;
- 创建 OSS 配置类,使用 @Bean 声明阿里云工具类,在 Controller 注入调用;
- 测试 @Lazy 延迟加载,打印日志观察 Bean 创建时机。
中篇面试高频考点
1 Spring Bean 默认作用域,单例 Bean 创建时机?2 单例 Bean 是否线程安全,区分有 / 无状态?3 @Component 和 @Bean 分别适用什么场景?4 为什么有状态类需要使用 prototype?5 @Bean 方法如何自动注入其他依赖 Bean?
&spm=1001.2101.3001.5002&articleId=162386450&d=1&t=3&u=ca455f7972154d769cc30daac06cbc92)
1785

被折叠的 条评论
为什么被折叠?



