欢迎光临
我们一直在努力

Spring Bean 注入与容器管理:从“怎么交给容器”到“怎么被注入使用”的完整总结

Spring Bean 注入与容器管理:从“怎么交给容器”到“怎么被注入使用”的完整总结

面向学习复习:把 Spring 容器里最核心的三件事讲清楚

  • Bean 如何注册进容器(交给 Spring 管理)
  • Spring 容器如何管理 Bean(创建、增强、生命周期、销毁)
  • 依赖注入如何发生(@Autowired / 构造器注入 / @Resource 等)

  • 1. Spring 容器到底是什么?它管理什么?

    1.1 Spring 容器的本质

    Spring 容器可以理解为一个“对象工厂 + 对象仓库 + 生命周期管理器”。

    它内部维护一个很关键的结构:

    • BeanDefinition(Bean 的定义信息):类名、作用域、依赖关系、初始化/销毁方法等
    • SingletonObjects(单例池):已经创建完成的单例对象缓存(key=beanName,value=bean实例)

    1.2 容器管理的对象是谁?

    容器管理的对象叫 Bean。

    “交给容器管理”意味着:

    • 对象由 Spring 创建(而不是你手动 new)
    • 依赖由 Spring 注入
    • AOP/事务等增强由 Spring 织入
    • 初始化/销毁由 Spring 统一回调

    2. Bean 是怎么“交给 Spring 容器管理”的?

    本质上只有一句话:

    让 Spring 在启动时“知道这个 BeanDefinition”,并在需要时创建出实例。

    常见注册方式分为 5 类:

  • 组件扫描(类上注解)
  • @Bean(方法返回值)
  • MyBatis Mapper(代理对象)
  • 配置属性类(读取 yml)
  • Spring Boot 自动配置(starter)
  • 下面展开。


    3. 组件扫描注册:@Component/@Service/@Controller/@RestController/@Repository/@Aspect

    3.1 怎么注册?

    Spring 启动时会“扫描包路径”,发现被标注的类,生成 BeanDefinition。

    扫描范围通常由主启动类决定:

    • @SpringBootApplication 所在包及子包会被默认扫描
    • 也可通过 @ComponentScan 手动指定

    3.2 关键过程(记流程)

    启动 → 扫描包 → 发现带组件注解的类 → 为类创建 BeanDefinition → 注册到容器

    3.3 常用注解与语义

    注解语义常见层
    @Component 通用组件 工具类/通用类
    @Service 业务组件 Service
    @Repository 持久层组件 DAO
    @Controller / @RestController 控制器 Controller
    @Aspect + @Component 切面组件 AOP

    这些注解本质都属于组件扫描机制,只是语义不同。


    4. @Bean 显式注册:你 new 对象,Spring 管理它

    4.1 为什么要用 @Bean?

    适用场景:

    • 第三方类(不能加 @Component)
    • 构造过程复杂(要传配置、组合对象)
    • 需要创建多个不同实例

    4.2 @Bean 的注册过程

    启动 → 创建@Configuration类 → 执行@Bean方法 → 拿到返回对象 → 注册为 Bean

    4.3 示例(典型:OSS/JWT 工具类)

    @Configuration
    public class OssConfig {
    @Bean
    public AliOssUtil aliOssUtil(OssProperties props) {
    return new AliOssUtil(props.getEndpoint(), props.getAccessKeyId(),
    props.getAccessKeySecret(), props.getBucketName());
    }
    }


    5. MyBatis Mapper 注册:接口也能成为 Bean(代理)

    Mapper 是接口,没有实现类,但能注入的原因是:

    MyBatis 在启动时扫描 Mapper 接口,为每个接口创建一个“代理对象”,并注册为 Bean。

    注册方式:

    • @Mapper 标注接口
    • 或 @MapperScan("com.sky.mapper") 扫描整个包(推荐)

    结果:

    • @Autowired DishMapper dishMapper; 能注入,因为容器里有 Mapper 代理对象。

    6. 配置属性类注册:@ConfigurationProperties

    目的:把 yml 配置变成对象,并放进容器。

    两种方式:

    6.1 @Component + @ConfigurationProperties

    @Component
    @ConfigurationProperties(prefix="aliyun.oss")
    public class OssProperties { ... }

    6.2 @EnableConfigurationProperties

    @EnableConfigurationProperties(OssProperties.class)
    @Configuration
    public class OssConfig { }

    这类 Bean 通常是“配置 Bean”,用于给其他 Bean 提供参数。


    7. Spring Boot 自动配置:你没写 Bean,但容器里有

    很多能力来自 starter:

    • MVC
    • Jackson
    • MultipartFile 上传
    • Tomcat

    本质:Spring Boot 的 AutoConfiguration 根据“条件注解”按需注册 Bean。

    学习阶段只需记结论:

    starter 引入依赖 → 自动注册一批基础设施 Bean。


    8. Spring 容器是怎么“管理 Bean 生命周期”的?

    8.1 单例 Bean(默认)的完整生命周期(重点)

    1) 读取 BeanDefinition
    2) 实例化(new / 反射创建)
    3) 属性填充(依赖注入)
    4) Aware 回调(可选)
    5) BeanPostProcessor 前置处理
    6) 初始化:@PostConstruct / InitializingBean / init-method
    7) Bean 可用(进入单例池)
    8) 容器关闭:@PreDestroy / DisposableBean / destroy-method

    8.2 初始化/销毁常用方式

    • 初始化:@PostConstruct
    • 销毁:@PreDestroy
    • 或在 @Bean(initMethod="…", destroyMethod="…")

    9. “注入”到底是什么?Spring 是怎么把依赖塞进去的?

    依赖注入(DI)的核心:

    当 Spring 创建一个 Bean 时,会查它依赖哪些其他 Bean,并把这些依赖自动填充进去。

    注入发生的时机:生命周期第 3 步:属性填充(依赖注入)


    10. 注入方式详解

    10.1 构造器注入

    @Service
    public class DishServiceImpl implements DishService {
    private final DishMapper dishMapper;

    public DishServiceImpl(DishMapper dishMapper) {
    this.dishMapper = dishMapper;
    }
    }

    特点:

    • 依赖不可变(final)
    • 更易测试
    • 避免空指针

    10.2 字段注入

    @Autowired
    private DishMapper dishMapper;

    特点:

    • 写法简单
    • 但不利于单元测试、依赖不可见

    10.3 Setter 注入

    @Autowired
    public void setDishMapper(DishMapper dishMapper) { ... }

    适合可选依赖。


    11. @Autowired 注入规则

    11.1 默认按类型注入(byType)

    @Autowired DishService dishService;

    • 容器里找类型为 DishService 的 Bean

    11.2 如果同类型有多个 Bean,会报错

    解决方法:

    • @Qualifier("beanName") 指定名称
    • 或 @Primary 指定默认

    示例:

    @Autowired
    @Qualifier("dishServiceImpl")
    private DishService dishService;


    12. Bean 名称(beanName)是怎么来的?

    • @Component:默认是类名首字母小写
      DishServiceImpl → dishServiceImpl

    • @Bean:默认是方法名
      aliOssUtil() → aliOssUtil

    你也可以显式指定:

    @Bean("ossUtil")
    public AliOssUtil aliOssUtil() { ... }


    13. 为什么会出现 “Could not autowire. No beans found …”?

    本质原因:容器里没有对应 Bean。

    常见情况:

  • 只有接口,没有实现类加 @Service
  • 实现类不在扫描包范围
  • 忘记加 @Component/@Service
  • 类不是 Bean,却试图在其中 @Autowired
  • 多模块依赖未引入导致类根本没被加载
  • 排查思路:

    • 看实现类是否被扫描
    • 看注解是否存在
    • 看启动类包结构
    • 看 beanName 是否冲突/重复

    14. 总结:从“注册”到“注入”的一条线串起来

    1) 注册阶段:把 BeanDefinition 放进容器(扫描/@Bean/@MapperScan/自动配置…)
    2) 创建阶段:容器按需创建 Bean(实例化)
    3) 注入阶段:容器解析依赖并注入(byType/byName)
    4) 增强阶段:AOP/事务等通过后置处理器织入代理
    5) 生命周期阶段:初始化回调 → 使用 → 容器关闭销毁

    总结:

    Bean 能被注入的前提是:它先通过某种方式注册进容器;Spring 创建 Bean 时会根据依赖关系完成注入,并在生命周期内统一管理初始化、增强与销毁。

    赞(0)
    未经允许不得转载:171主机测评 » Spring Bean 注入与容器管理:从“怎么交给容器”到“怎么被注入使用”的完整总结
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址