Spring IoC 入门详解:Bean 注册、注解使用与 @ComponentScan 配置

目录

一、什么是 Spring IoC?

1. 先搞懂:IoC是什么

IoC 全称 Inversion of Control (控制反转) ,咱先不说Spring IOC概念,我们首先按照字面意思给你举个生活的例子来对比一下

假设你要装一套新房:

方式1在没有IOC下:你就是业主,要亲手搞定所有事情,做的事情包括不限于:自己找工人,自己买材料,自己管流程,自己扛风险

方式2在IOC下:你只需要做 2 件事,告诉装修公司需求:比如说我要简约风格、预算 30 万、3 个月完工。最后验收房子:装修公司把所有细节搞定,你直接拎包入住,剩下的所有事,全由装修公司负责,找工人、买材料等等

这就是控制权反转 ------ 原本由业主掌控的工人招聘、材料采购、流程管理的权力,反转给了装修公司(Spring IoC 容器 )。你不再管细节,只关心最终需求结果验收

所以控制反转就是控制权反转,而 Spring IoC 的核心就是反转控制权 :将对象的创建、依赖(DI)的注入、生命周期 的管理全部交给 Spring 容器负责,开发者不再手动控制

2.Spring IoC 容器:IoC 的 "执行者"

Spring IoC 容器 是实现 IoC 思想的核心载体,如果 Spring IOC 是个思想 ,那Spring IOC容器 就是这个思想的具体实现工具或载体 ,当需要某个对象时,创建对象的任务交给容器, 程序中只需要依赖注⼊(DependencyInjection,DI)就可以了,其实笼统的来说Spring是⼀个IoC容器,所以有时Spring也称为Spring容器

二、Bean 的存储

Bean 的存储核心是 Spring 容器(IoC 容器) 对对象的 "注册 - 实例化 - 管理" 过程 ,本质是将 Bean 的元数据(类信息、依赖、配置)注册到容器,再由容器根据规则创建实例并存储,供后续依赖注入或直接获取,简单的说将对象的控制权交给Spring的IOC容器,由IOC容器创建及管理对象就是Bean的存储

1. 注解驱动

要让 Spring 容器存储 Bean,首先需要通过某种方式定义 Bean(即告诉 Spring "哪个类需要被管理"),这种方式之一就是注解,Spring框架为此提供了更丰富的注解
共有两类注解类型可以实现:

  1. 类注解:@Controller、@Service、@Repository、@Component、@Configuration
  2. 方法注解:@Bean

@Controller(控制器存储)

从Spring容器中获取对象

获得对象后,调用print方法,测试结果为HelloController对象中的print方法的打印结果

那如果把@Controller删掉呢?

结合上述结果可以得知: @Controller 所标识的类会被 Spring 容器注册为 Bean,也就是将控制权反转给了Spring管理 ,从而可以能从Spring中获取到Controller对象来使用

获取bean对象的其他⽅式

主要为三次方式:

  1. 根据类型获得Bean
  2. 根据Bean名称和类型获得Bean
  3. 根据Bean名称获得Bean

什么是bean名?

Spring bean是Spring框架在运⾏时管理的对象,Spring会给管理的对象起⼀个名字.⽐如学校管理学⽣,会给每个学⽣分配⼀个学号,根据学号,就可以找到对应的学⽣.Spring也是如此,给每个对象起⼀个名字,根据Bean的名称(BeanId)就可以获取到对应的对象

怎么知道bean名为什么?

如何知道bean名为什么,这一点在spring 官方文档中有详细说明

程序开发⼈员不需要为bean指定名称(BeanId),如果没有显式的提供名称(BeanId),Spring容器将为该bean⽣成唯⼀的名称.

命名约定使⽤Java标准约定作为实例字段名.bean名称以⼩写字⺟开头(当第⼀个和第⼆个字符都是⼤写时,将保留原始的⼤⼩写),然后使⽤驼峰式大小写,也就是说在此处HelloerController的bean名为helloController,但是注意此处的getBean为object类性,需要强制转换到对应的bean对象类型

2. 类注解总结

其实这些注解本质都是 @Component 的 "派生注解" ,这些类注解的存在是为了明确类的职责分层 ,让代码更具可读性,Spring 扫描时会将它们统一识别为 Bean 并纳入容器管理,只是在 "语义" 和 "附加功能" 上做了区分。

源码:

从源码中可知并无太大区别

"语义" 和 "附加功能"区别

注解 "语义" 和 "附加功能"
@Component 通用组件
@Controller 控制层,接收请求,对请求进⾏处理,并进⾏响应
@Servie 业务逻辑层,处理具体的业务逻辑
@Repository 数据访问层,也称为持久层.负责数据访问操作
@Configuration 配置层.处理项⽬中的⼀些配置信息.

注意:

这5个注解, @Controler不可以和其他注解替换,在控制层中必须要使用@Controller

在不固定场景下,控制层使用@Service也可能能访问成功

3. ⽅法注解@Bean

上述所说的注解是添加到某个类上的类注解,但是存在两个问题:

  1. 外部依赖包中的类,无法手动为其添加类注解
  2. 同一个类需要创建多个实例(比如多个不同配置的数据源)

这种场景, 我们就需要使⽤⽅法注解@Bean

⽅法注解@Bean的使⽤



测试结果:

@Bean 必须搭配五大注解类使用,否则无法被 Spring 扫描识别,提示错误

定义多个对象

一个 @Bean 方法对应一个 Bean 实例,在同一个类中,通过编写多个 @Bean 方法,即可注册多个对象到 Spring 容器

测试结果:

为什么这里我直接使用BeanName而不直接Student类呢,核心原因就是:同一类型有多个 Bean时,按类型获取会报错(Spring 无法确定选定的是s1,还是s2),而容器中 Bean 名称是唯一的

@Bean注解的bean,bean的名称就是它的⽅法名

当@Bean方法中传参

java 复制代码
String name="hr";
    @Bean
    public Student s1(String name){
       return  new Student(name,1);
    }

Spring 会从Spring容器当中, 查找String类型的对象,赋值给name

@Bean的重命名

@Bean 的重命名本质是通过注解的 name 或 value 属性 自定义 Bean 的名称,替代默认的方法名作为 Bean 在 Spring 容器中的标识。

name 和 value 属性完全等价

测试结果:

这里就是通过重命名student1,student2来代替s1方法名

三、扫描路径

在刚刚开始搭建spring boot的时候,我们有学到过默认扫描的范围是SpringBoot启动类所在包及其⼦包的@controller,但是随着我们深入学习,难道这个范围就是固定的吗,显然不是,这就引入了 @ComponentScan注解

@ComponentScan

@ComponentScan就是告诉 Spring:"从这些包路径下,查找并加载所有带候选注解的类,将它们注册为 Bean"

操作@ComponentScan来更改扫描的范围

测试结果:

四、最后再说一下

总结一下,本篇IOC内容就一句话 "注解定标识,扫描定范围,@Bean 补灵活 ",还有本篇文章没有怎么提及依赖(DI)的内容,在Spring IOC中IOC和DI是 "目标 - 手段" 的统一关系,对应DI的理解也同样很重要,下篇文章将重点讲解

相关推荐
Rust研习社4 小时前
组合真的优于继承吗?为什么 Rust 和 Go 都拥抱组合舍弃继承?
后端·rust·编程语言
IT_陈寒5 小时前
JavaScript的闭包把我坑惨了,说好的内存会自动回收呢?
前端·人工智能·后端
CaffeinePro5 小时前
Pydantic深度使用:数据校验、枚举、ORM映射
后端·fastapi
Chenyiax6 小时前
从 Chat 到 Responses:OpenAI API 抽象为什么变了?
后端
MariaH6 小时前
Koa和Express的区别
后端
MariaH6 小时前
Koa框架的使用
后端
luckdewei7 小时前
那个用 passlib 做认证的新同事,上线第一天就把用户密码写进了日志
后端
ping某8 小时前
为什么 Nginx 明明监听了 80,转发后端时却用了 4xxxx 端口?
后端·nginx
JustHappy8 小时前
我汇总了身边朋友的经历才发现,其实第一份实习是最难找的......
前端·后端·面试
uhakadotcom9 小时前
在python 的 工程化架构中 ,什么是 薄包装器层?
后端·面试·github