news 2026/5/9 12:07:02

【SpringBoot】Spring IOC DI 五大注解 Bean 扫描路径 依赖注入

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【SpringBoot】Spring IOC DI 五大注解 Bean 扫描路径 依赖注入

文章目录

  • Ⅰ. 什么是 `IOC` 和 `DI`❓❓❓
  • Ⅱ. 五大注解
  • Ⅲ. 注解 `@Bean`
  • Ⅳ. 扫描路径 `@ComponentScan`
  • Ⅴ. 依赖注入
    • 一、三种注入方式 `@Autowired`
      • ① 属性注入
      • ② 构造方法注入
      • ③ `Setter`方法注入
      • 三种注入方式的区别
    • 二、`@Autowired` 存在的问题
      • ① `@Primary`
      • ② `@Qualifier`
      • ③ `@Resource`⭐⭐⭐

Ⅰ. 什么是IOCDI❓❓❓

IOC全称是Inversion of Control,中文叫 “控制反转”。

简单的说,就是把对象的创建和依赖关系的维护交给框架管理,而不是自己在代码中new出来

IOC是一种设计思想而注解DI是实现IOC的方式之一

IOC的好处如下所示:

优点说明
解耦组件之间不直接 new,依赖由框架注入
易测试方便用 mock 对象进行单元测试
灵活替换想换实现类,只改配置或注解,不改业务代码
更清晰的架构各层职责分明,依赖关系可视化

此外,Spring容器管理的对象,称为Bean对象。

@Component@AutowiredSpring框架中非常核心的两个注解,是实现IOC(控制反转)DI(依赖注入)的关键工具。

  • @Component:一个类级注解,用于将普通的Java类声明为Spring管理的Bean
  • @Autowired:一个非类级注解,用于自动注入依赖对象,而无需手动new

如何从Spring容器中获取对象❓❓❓

可以从ApplicationContext中的getBean()方法获取,如下所示:

publicstaticvoidmain(String[]args){// 在启动类中拿到ApplicationContext对象ApplicationContextcontext=SpringApplication.run(Application.class,args);// 第一种传参方式UserComponentbean1=context.getBean(UserComponent.class);bean1.func();// 第二种传参方式(需要强转)UserConfigbean2=(UserConfig)context.getBean("userConfig");bean2.func();}

getBean()方法,实际上是ApplicationContext实现了BeanFactory接口得到的,并且在其基础上添加了对国际化支持、资源访问支持、以及事件传播等方面的支持! 此外,getBean()对于Bean的名称约定如下所示:

  • 以小写字母开头,然后使用小驼峰的格式。如类名为:UserController,则Bean名为:userController
  • 特殊情况:当第一个和第二个字母为大写时,则保留原始的大小写。如类名为:UController,则Bean名为UController

Ⅱ. 五大注解

注解作用常见使用位置
@Component通用组件,标识该类为Bean工具类、业务组件
@Controller控制层,接收前端请求MVC控制器类
@Service业务逻辑层Service
@Repository数据持久层DAO类,MyBatis Mapper
@Configuration配置类用于代替XML配置

常见的目录结构规范如下所示:

src └── main └── java └── com.example.project ├── controller # 控制器层(@Controller/@RestController) ├── service # 业务逻辑层(@Service) ├── dao/mapper # 数据访问层(@Repository/@Mapper) ├── model/entity # 实体类(POJO/DTO/DO/VO) └── config # 配置类(@Configuration)

注意:五大注解均可以起别名!

Ⅲ. 注解@Bean

@Bean告诉spring这个方法返回的对象要放进IoC容器(ApplicationContext)里,成为可被任何其他Bean注入的组件

💥注意事项:

  1. @Bean要配合五大注解使用,不能单独使用

  2. Spring中,默认情况下Bean的作用域是singleton(单例)的,即整个Spring容器中只存在一个该Bean实例

  3. 对于同一个类,要定义多个Bean对象的话,需要对不同的方法进行注解,然后使用ApplicationContext对象的getBean()方法中传入Bean名称的方式进行获取,对应的Bean名称是对应方法的名称,当然也可以进行重命名,默认重命名的属性是name,如下所示

    @ComponentpublicclassUserComponent{@Bean("{u3}")publicUseru1(){returnnewUser();}@BeanpublicUseru2(){returnnewUser();}}publicstaticvoidmain(String[]args){ApplicationContextcontext=SpringApplication.run(Application.class,args);// 通过 Bean 名获取,不然 Spring 会报错,识别不出要哪个对象// 并且可以对 Bean 对象进行重命名!Useru1=(User)context.getBean("u3");Useru2=(User)context.getBean("u2");System.out.println(u1);System.out.println(u2);}// 运行结果:com.liren.ioc.model.User@abbe000com.liren.ioc.model.User@3f81621c

Ⅳ. 扫描路径@ComponentScan

Spring默认扫描的范围是SpringBoot启动类所在包及其子包,如下图所示,一般也推荐直接把启动类放到项目目录中!

但是如果需要放在特定包内,还需要访问其它非子包的包内,则需要使用@ComponentScan来添加要扫描的包,如下所示,当然也可以{}配置多个包路径

@ComponentScan("com.liren.ioc.service")// 指定扫描com.liren.ioc.service包中的内容@SpringBootApplicationpublicclassApplication{publicstaticvoidmain(String[]args){SpringApplication.run(Application.class,args);}}

Ⅴ. 依赖注入

一、三种注入方式@Autowired

① 属性注入

这种方式虽然不是官方最推荐的,但却是日常开发最常用的。

@ControllerpublicclassUserController{@AutowiredprivateUserServiceuserService;publicvoidfunc(){System.out.println("UserController");userService.func();}}

② 构造方法注入

💥注意:如果类只有一个构造方法,那么@Autowired注解可以省略;如果类中有多个构造方法,那么需要添加上@Autowired来明确指定到底使用哪个构造方法。

@ControllerpublicclassUserController{privateUserServiceuserService;// 默认构造方法publicUserController(){}// 如果有默认构造方法,那么不显式写上@Autowired的话,会去调用默认构造方法@AutowiredpublicUserController(UserServiceuserService){this.userService=userService;}publicvoidfunc(){System.out.println("UserController");userService.func();}}

Setter方法注入

@ControllerpublicclassUserController{privateUserServiceuserService;@AutowiredpublicvoidsetUserService(UserServiceuserService){this.userService=userService;}publicvoidfunc(){System.out.println("UserController");userService.func();}}

三种注入方式的区别

  1. 属性注入
    1. 优点:简洁,使用方便
    2. 缺点:
      1. 只能用于IOC容器,如果是非IOC容器不可用,并且只有在使用的时候才会出现空指针异常
      2. 不能注入一个Final修饰的属性
  2. 构造函数注入(Spring 4.X 推荐)
    1. 优点:
      • 可以注入final修饰的属性
      • 注入的对象不会被修改
      • 依赖对象在使用前一定会被完全初始化,因为依赖是在类的构造方法中执行的,而构造方法是在类加载阶段就会执行的方法。
      • 通用性好,构造方法是JDK支持的,所以更换任何框架,它都是适用的
    2. 缺点:
      • 注入多个对象时,代码会比较繁琐
  3. Setter 注入(Spring 3.X 推荐)
    1. 优点:方便在类实例之后,重新对该对象进行配置或者注入
    2. 缺点:
      • 不能注入一个final修饰的属性
      • 注入对象可能会被改变,因为setter方法可能会被多次调用,就有被修改的风险

二、@Autowired存在的问题

当同一个类存在多个Bean时,使用@Autowired会存在问题,如下所示:

如何解决上述问题呢❓❓❓Spring提供了以下几种解决方案:

  • @Primary
  • @Qualifier
  • @Resource

@Primary

当存在多个相同类型的Bean注入时,加上@Primary注解,来确定默认的实现!

这个注解加在要被指定注入的Bean对象上,如下所示:

@ComponentpublicclassUserComponent{@Primary@BeanpublicUseru3(){returnnewUser();}@BeanpublicUseru4(){returnnewUser();}}

@Qualifier

注意该注解不能单独使用,需要配合@Autowired才行

@ControllerpublicclassUserController2{@Qualifier("u3")// 指定对应Bean的名称@AutowiredprivateUseruser;publicvoidfunc(){System.out.println("UserController2");}}

@Resource⭐⭐⭐

该注解可以单独使用,不过需要显式用属性name来指定对应的Bean对象!

@ControllerpublicclassUserController2{@Resource(name="u3")// 需要显式写一下name来指定privateUseruser;publicvoidfunc(){System.out.println("UserController2");}}

需要注意的是,@ResourceJDK自带的,支持更多的参数设置,而@AutowiredSpring框架提供的,没有前者功能那么多!

@Autowired的装配顺序如下图所示:

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/9 10:04:34

一句话生成专业问卷?百考通AI平台让调研“零门槛、高效率”!

你是否曾因为不会设计问卷而放弃一个好选题?是否在写论文或做项目时,明明有清晰的研究问题,却卡在“怎么把它变成一道道科学的问题”?又或者,花了一整天做的问卷被导师或同事指出“逻辑混乱”“选项不全”“问题有引导…

作者头像 李华
网站建设 2026/5/3 1:44:18

3步征服iOS WebApp状态栏:打造完美沉浸式全屏体验

3步征服iOS WebApp状态栏:打造完美沉浸式全屏体验 【免费下载链接】Mars 腾讯移动 Web 前端知识库 项目地址: https://gitcode.com/gh_mirrors/mar/Mars 还在为iOS WebApp状态栏遮挡内容而苦恼吗?想要让你的Web应用拥有原生App一样的全屏视觉效果…

作者头像 李华
网站建设 2026/5/8 3:00:17

基于springboot +web旅游网站系统

旅游网站 目录 基于springboot web旅游网站系统 一、前言 二、系统功能演示 三、技术选型 四、其他项目参考 五、代码参考 六、测试参考 七、最新计算机毕设选题推荐 八、源码获取: 基于springboot web旅游网站系统 一、前言 博主介绍:✌️大…

作者头像 李华
网站建设 2026/5/3 16:20:00

基于springboot + vue学生成绩管理系统

学生成绩管理 目录 基于springboot vue学生成绩管理系统 一、前言 二、系统功能演示 三、技术选型 四、其他项目参考 五、代码参考 六、测试参考 七、最新计算机毕设选题推荐 八、源码获取: 基于springboot vue学生成绩管理系统 一、前言 博主介绍&…

作者头像 李华
网站建设 2026/5/7 20:09:49

60、SQL与对象技术的融合发展

SQL与对象技术的融合发展 一、对象技术对SQL和关系数据库的挑战 在过去十年左右,SQL和关系数据库管理的主导地位面临着来自面向对象技术崛起的严峻挑战。面向对象编程语言(如C++和Java)、面向对象开发工具以及面向对象网络(包括对象请求代理和最近的Web服务)已成为现代软…

作者头像 李华
网站建设 2026/5/3 13:42:29

python的print(f ‘ {xxx}‘ )

在 Python 中,print(f{xxx}) 是使用f-string(格式化字符串字面值,Formatted String Literals) 进行字符串格式化并输出的方式,它从 Python 3.6 版本开始引入,是目前最简洁、高效且易读的字符串格式化方法。…

作者头像 李华