SpringBoot 底层原理完整教程(中篇・Bean 管理全解)

承接上篇 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 特性

  1. 创建时机:项目容器启动时,默认直接实例化所有单例 Bean;
  2. 延迟加载:添加@Lazy注解后,Bean 会延迟到第一次使用时才创建;
  3. 优势:只创建一次,节约内存、提升项目启动与运行性能;
  4. 代码示例
@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 有无状态判断

  1. 无状态 Bean(无成员变量,仅提供方法,数据均为方法局部变量):线程安全示例:Controller、Service、Mapper,所有数据都在方法内定义,多线程调用互不干扰;
  2. 有状态 Bean(定义全局成员变量存储数据):线程不安全多请求同时操作同一个对象的成员变量,会发生数据覆盖、错乱,解决方案:加@Scope("prototype")改为多例。

问题 2:单例 Bean 默认什么时候实例化?如何延迟创建?

  1. 默认:Spring 容器启动阶段全部实例化;
  2. 延迟初始化:在类上添加@Lazy注解,第一次使用才创建对象。
@Component
@Lazy // 延迟创建
public class CommonUtil {}

三、自定义 Bean 四种注解区分

四类组件注解(用于项目自定义类)

@Component@Controller@Service@Repository,底层功能完全一致,仅用于分层标识,方便阅读:

  1. @Controller:控制层 Controller 类;
  2. @Service:业务层 Service 实现类;
  3. @Repository:持久层 Mapper/DAO;
  4. @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 关键知识点

  1. Bean 名称:默认以方法名作为 BeanName;可通过@Bean(name="ossUtil")手动指定;
  2. 依赖自动注入:方法形参直接声明其他 Bean,Spring 自动按类型装配;
  3. 使用方式:业务类直接@Autowired private AliyunOSSOperator ossUtil;注入使用。

五、中篇全文总结

  1. Bean 五大作用:singleton 默认单例、prototype 多例,request/session/application 仅 Web 可用;
  2. 单例 Bean 启动默认创建,@Lazy 实现延迟实例化;
  3. Bean 线程安全:无状态线程安全,有状态必须改为 prototype 多例;
  4. 自定义类用 @Service/@Controller 等,第三方类统一用 @Bean;
  5. @Bean 建议放在独立 @Configuration 配置类,不要写在启动类。

中篇拓展实操练习

  1. 编写带成员变量的有状态工具类,不加 prototype 测试并发数据错乱;添加 @Scope 后对比效果;
  2. 创建 OSS 配置类,使用 @Bean 声明阿里云工具类,在 Controller 注入调用;
  3. 测试 @Lazy 延迟加载,打印日志观察 Bean 创建时机。

中篇面试高频考点

1 Spring Bean 默认作用域,单例 Bean 创建时机?2 单例 Bean 是否线程安全,区分有 / 无状态?3 @Component 和 @Bean 分别适用什么场景?4 为什么有状态类需要使用 prototype?5 @Bean 方法如何自动注入其他依赖 Bean?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值