当前位置: 首页
编程语言
Spring IoC容器与Bean管理核心原理与实战深入全面解析

Spring IoC容器与Bean管理核心原理与实战深入全面解析

热心网友 时间:2026-07-21
转载

SpringIoC容器通过@Controller、@Service、@Repository、@Component、@Configuration五大类注解以及@Bean方法注解来注册和管理Bean对象,默认采用单例模式。依赖注入支持属性注入、构造方法注入和Setter注入三种方式,其中构造方法注入被推荐。当存在多个同类型Bean时,可通过@Primary、@Q

一、Bean的存储

我们先来深入探讨Bean的存储方式。上一节已经提到,若想将某个对象交由IoC容器管理,只需在类上添加@Component注解即可。不过,Spring为了更好地适配Web开发场景,还提供了更细化的注解,让不同层次的代码各司其职、清晰分工。

类注解:@Controller、@Service、@Repository、@Component、@Configuration

方法注解:@Bean

1.1 @Controller(控制器存储)

使用@Controller注解来存储Bean,操作非常直观且易于理解。

SpringIoC容器与Bean管理全解析

接下来,我们从Spring容器中取出这个对象,验证其存储效果。

SpringIoC容器与Bean管理全解析

上述代码是通过类型来查找Bean对象。但有一个常见问题:如果同一个类型在Spring容器中存在多个Bean,该如何处理?关于Bean的命名规则,上一节已经讨论过,这里不再赘述。

1.根据bean名称获取bean

Object getBean(String var1)throws BeansException;

2.根据bean名称和类型获取bean

T getBean(String var1,Class var2)throws BeansException;

3.根据类型获取bean

T getBean(Class var1)throws BeansException;

4. 按bean名称和构造函数动态创建bean,只适用于具有原型(prototype)作用域的bean

Object getBean(String var1,Class var2)throws BeansException;

5.按bean类型和构造函数动态创建bean,只适用于具有原型(prototype)作用域的bean

T getBean(String var1,Class var2)throws BeansException;

在实际开发中,前三种方法的使用频率最高。后面的几种注解同理,我们重点展示这三种常用方式。

SpringIoC容器与Bean管理全解析

我们来验证一下,通过不同方式获取到的对象是否为同一个实例。

SpringIoC容器与Bean管理全解析

从内存地址来看,它们完全一致,说明获取到的是同一个Bean对象。这体现了Spring容器默认的单例模式,这一特性至关重要。

1.2 @Service(服务存储)

使用@Service注解存储Bean,其用法与@Controller几乎完全相同。

SpringIoC容器与Bean管理全解析

读取Bean的步骤也如出一辙。

SpringIoC容器与Bean管理全解析

1.3 @Repository(仓库存储)

@Repository顾名思义,主要用于数据访问层(持久层)。

SpringIoC容器与Bean管理全解析

读取Bean的方式同样一脉相承。

SpringIoC容器与Bean管理全解析

1.4 @Component(组件存储)

@Component是一个通用组件注解,它相当于一个基础模板,其他注解都是它的衍生品。

SpringIoC容器与Bean管理全解析

读取Bean的步骤保持不变。

SpringIoC容器与Bean管理全解析

1.5 @Configuration(配置存储)

@Configuration注解用于处理项目中的配置信息,例如数据源配置等。

SpringIoC容器与Bean管理全解析

读取Bean当然也没有问题。

SpringIoC容器与Bean管理全解析

1.6 这些注解的用途

  • @Controller:控制层,负责接收请求、处理请求并返回响应。
  • @Service:业务逻辑层,专门处理核心业务逻辑。
  • @Repository:数据访问层,也称持久层,负责与数据库进行交互。
  • @Configuration:配置层,专门处理项目中的各类配置信息。
  • @Component:通用组件注解,对于不属于上述分层的普通业务类、工具类,可通过它标记,然后由Spring自动扫描并存入IoC容器。

@Controller@Service@Repository@Configuration 都是@Component的衍生注解。除了@Controller不完全等同于@ResponseBody外,其余衍生注解主要起到分层语义区分的作用,底层功能其实一致——都是将类交给Spring IoC容器管理。

SpringIoC容器与Bean管理全解析

打个比方:杯子有喝水的杯子,也有刷牙的杯子。虽然都是杯子,但日常使用中我们更倾向于用刷牙的杯子刷牙,用喝水的杯子喝水。这些注解的角色划分,本质上也是为了让代码结构更加清晰有序。

1.7 ApplicationContext VS BeanFactory

  • 从继承关系和功能来看:Spring容器有两个顶级接口:BeanFactory和ApplicationContext。BeanFactory提供最基础的容器访问能力,而ApplicationContext是它的子类,除了继承所有功能,还额外支持国际化、资源访问和事件传播等高级特性。
  • 从性能方面来看:ApplicationContext倾向于一次性加载并初始化所有Bean,而BeanFactory则采用按需加载的方式,谁用谁加载,因此更加轻量。

二、方法注解@Bean

上面介绍了五大类注解,但实际开发中经常会遇到两个棘手的问题:

1. 外部包中的类,无法添加类注解

2. 一个类需要多个实例对象,例如配置多个数据源

这两个场景,就需要借助方法注解@Bean了。请注意,@Bean注解必须搭配五大类注解才能正常使用。

2.1 搭配类注解的使用

SpringIoC容器与Bean管理全解析

SpringIoC容器与Bean管理全解析

在Spring的设计中,@Bean方法注解必须配合类注解,才能将对象正确地存储到容器中。

如果把@Component注释掉,会是什么结果?

SpringIoC容器与Bean管理全解析

2.2 定义多个对象

SpringIoC容器与Bean管理全解析

2.3 重命名Bean

2.3.1 方法一:最完整的写法

SpringIoC容器与Bean管理全解析

2.3.2 方法二:省略“name={ }”

SpringIoC容器与Bean管理全解析

2.3.3 方法三:当只有一个名称时,{} 也可省略

SpringIoC容器与Bean管理全解析

三、扫描路径

问题来了:使用五大注解声明的Bean,一定会生效吗?

答案是不一定。 原因很简单:Bean想要生效,必须被Spring扫描到才行。

下面,我们通过调整项目工程的目录结构,来测试Bean是否生效。

SpringIoC容器与Bean管理全解析

然后运行下面的代码:

@SpringBootApplication
public class SpringIocDemoApplication {
    public static void main(String[] args) {
        // 获取 Spring 上下文对象
        ApplicationContext context = 
            SpringApplication.run(SpringIocDemoApplication.class, args);
        // 从 Spring 上下文中获取对象
        User u1 = (User) context.getBean("u1");
        // 使用对象
        System.out.println(u1);
    }
}

运行结果:

SpringIoC容器与Bean管理全解析

报错了: 找不到名称为“u1”的Bean。

为什么找不到?

使用五大注解声明的Bean,要想生效,还需要配置扫描路径,让Spring能够扫描到这些注解。这个任务由@ComponentScan负责。

@ComponentScan({"com.example.demo"})
@SpringBootApplication
public class SpringIocDemoApplication {
    public static void main(String[] args) {
        // 获取 Spring 上下文对象
        ApplicationContext context = 
            SpringApplication.run(SpringIocDemoApplication.class, args);
        // 从 Spring 上下文中获取对象
        User u1 = (User) context.getBean("u1");
        // 使用对象
        System.out.println(u1);
    }
}

{} 中可配置多个包路径,例如:@ComponentScan({"com.example.demo", "com.example.service"})

注意: 这种做法了解即可,并不推荐在生产环境中使用。

那为什么前面没有显式配置@ComponentScan也能正常运行呢?因为@ComponentScan其实已经包含在启动类上的@SpringBootApplication注解中了。默认情况下,它会扫描启动类所在包及其所有子包。

推荐做法: 将启动类放在我们希望扫描的根包路径下,这样所有定义的Bean都能被自动扫描到。

扫描路径配置总结

  1. 默认扫描:Spring Boot项目默认扫描启动类所在包及其所有子包。
  2. 自定义扫描:使用@ComponentScan注解可以指定要扫描的包路径。
  3. 多包扫描:通过数组形式指定多个包路径。
  4. 最佳实践:合理组织项目结构,将需要被扫描的类放在启动类的子包中。

合理配置扫描路径,是确保Spring能够正确发现和管理所有Bean组件的基础,也是IoC容器正常工作的前提条件。

四、DI详解

以上内容主要围绕控制反转(IoC)展开,接下来我们重点讲解依赖注入(DI)。

依赖注入的过程, 简单来说,就是IoC容器在创建Bean时,自动将运行时所需的资源(即其他依赖对象)注入进来。

Spring提供了三种依赖注入方式:

  1. 属性注入
  2. 构造方法注入
  3. Setter注入

4.1 属性注入 @Autowired

代码实现如下:

SpringIoC容器与Bean管理全解析

运行效果:

SpringIoC容器与Bean管理全解析

4.2 构造方法注入

代码实现:

SpringIoC容器与Bean管理全解析

运行效果:

SpringIoC容器与Bean管理全解析

如果只有一个构造方法,@Autowired可以省略。

如果有多个构造方法,默认采用无参构造方法。

可以通过@Autowired来指定使用哪个构造方法。

4.3 setter注入

代码实现:

SpringIoC容器与Bean管理全解析

运行效果:

SpringIoC容器与Bean管理全解析

Setter注入与属性的Setter方法实现类似,区别在于set方法上需要添加@Autowired注解。

4.4 三种注入的优缺点分析

Spring提供了三种依赖注入方式,每种方式都有其适用的场景。了解它们之间的差异,可以帮助我们在实际开发中做出更合适的选择。

1. 属性注入(Field Injection)

优点:

  • 简洁直观:代码量最少,直接在字段上添加@Autowired即可。
  • 使用方便:无需编写额外的构造方法或Setter方法。
  • 可读性好:依赖关系一目了然,类的依赖项一眼就能看出。

缺点:

  • 仅适用于IoC容器:脱离Spring容器后,这种方式无法正常工作。
  • 空指针风险:运行时才能发现空指针异常,编译期无法检测。
  • 无法注入final字段:不能注入被final修饰的属性。
  • 测试困难:单元测试时需依赖Spring容器,或通过反射设置字段。
  • 违反单一职责原则:容易导致类依赖过多,职责不清晰。

2. 构造方法注入(Constructor Injection)

优点:

  • 可以注入final字段:支持注入被final修饰的属性,保证依赖不可变。
  • 依赖不可变:注入的对象在构造完成后不会被修改,状态一致性有保障。
  • 完全初始化:依赖在使用前一定被完全初始化,因为构造方法在类加载时即执行。
  • 通用性好:构造方法是JDK标准特性,不依赖特定框架,切换框架也能使用。
  • 便于测试:单元测试中可直接通过构造方法传入模拟对象。
  • 强制依赖:明确类的必需依赖,避免依赖缺失。

缺点:

  • 代码略显繁琐:依赖较多时,构造方法的参数列表会变长。
  • 循环依赖问题:存在循环依赖时,构造方法注入会直接报错。

注意事项:如果类只有一个构造方法,@Autowired可以省略;如果有多个构造方法,则需要通过@Autowired指定使用哪一个。

3. Setter 注入(Setter Injection)

优点:

  • 灵活性高:方便在类实例化之后重新配置或注入对象。
  • 可选依赖:适合非必需依赖,可以设置默认值或允许为空。
  • 便于继承:子类可以重写Setter方法来改变注入行为。
  • 解决循环依赖:某些情况下能解决构造方法注入无法处理的循环依赖。

缺点:

  • 无法注入final字段:不能注入被final修饰的属性。
  • 依赖可能被改变:Setter方法可能被多次调用,存在被修改的风险。
  • 对象状态不稳定:在Setter方法被调用前,依赖可能尚未初始化。
  • 时序问题:需要确保在对象使用前,所有必要的Setter方法都已被调用。

三种注入方式对比总结

特性属性注入构造方法注入Setter 注入
代码简洁性★★★★★★★★☆☆★★★★☆
不可变性★☆☆☆☆★★★★★★★☆☆☆
测试友好性★★☆☆☆★★★★★★★★★☆
框架通用性★☆☆☆☆★★★★★★★★★☆
循环依赖处理★★★★☆★☆☆☆☆★★★★☆
Spring 官方推荐Spring 4.x 之前Spring 4.x 之后Spring 3.x 推荐

选择建议

  1. 强制依赖:推荐使用构造方法注入,确保依赖在对象创建时即正确设置。
  2. 可选依赖:推荐使用Setter注入,灵活性更高。
  3. 快速原型:可以使用属性注入快速搭建,但生产环境建议优先选择构造方法注入。
  4. 不可变对象:必须使用构造方法注入。
  5. 测试驱动开发:优先考虑构造方法注入,便于编写单元测试。

在实际开发中,Spring官方从4.x版本开始推荐构造方法注入,因为它能保证依赖的不可变性和完全初始化,同时提高代码的可测试性。当然,具体选择哪种方式,还需要结合项目需求和团队规范来决定。

4.5 @Autowired存在的问题

当同一个类型存在多个Bean时,@Autowired会面临歧义问题。

SpringIoC容器与Bean管理全解析

Spring提供了三种解决方案:

  • @Primary
  • @Qualifier
  • @Resource

4.5.1 @Primary

使用@Primary注解:当存在多个相同类型的Bean时,通过@Primary指定一个默认实现。

SpringIoC容器与Bean管理全解析

4.5.2 @Qualifier

使用@Qualifier注解:通过value属性指定要注入的Bean名称。注意,@Qualifier不能单独使用,必须配合@Autowired。

SpringIoC容器与Bean管理全解析

4.5.3 @Resource

使用@Resource注解:按Bean的名称进行注入,通过name属性指定要注入的Bean名称。

SpringIoC容器与Bean管理全解析

五、小结

这几天的作息有些混乱,感觉身体疲惫乏力,可能跟平时缺乏运动有关。原本想报个游泳班,但价格偏高,最终还是决定先暂缓,等以后有机会再考虑。明天吃完火锅后,就要开始认真减肥控糖,一定要坚持瘦下来。

来源:https://www.jb51.net/program/367791gem.htm

游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。

同类文章
更多
FileZilla断点续传设置与操作指南

FileZilla断点续传设置与操作指南

FileZilla支持断点续传,需客户端与服务器均开启REST命令。设置中确保启用断点续传及继续传输选项。中断后自动或手动从断点恢复。注意服务器支持、传输模式匹配及文件完整性校验。

时间:2026-07-25 22:29
Debian系统C++编译器位置查找方法

Debian系统C++编译器位置查找方法

在Debian系统中,通过apt安装的C++编译器g++默认位于 usr bin g++,可使用which或whereis命令验证路径。g++属于build-essential软件包,若未安装则需执行sudoaptinstallbuild-essential。该包还包含gcc、make等编译工具链,g++是GNUC++编译器,实际是符号链接指向具体版本,验证

时间:2026-07-25 22:29
Debian系统安装C++环境的方法

Debian系统安装C++环境的方法

在Debian系统安装C++开发环境:先sudoaptupdate更新包列表,再sudoaptinstallbuild-essential安装编译工具链,或单独安装g++。用g++--version验证。可选安装VSCode、GDB、CMake等工具并配置默认编译器版本。

时间:2026-07-25 22:29
Debian系统C++开发环境配置指南

Debian系统C++开发环境配置指南

在Debian系统中,先执行aptupdate更新软件包列表,再安装build-essential元包即可获得GCC、G++、Make和GDB。通过运行g++--version命令验证编译器安装成功。可选安装VisualStudioCode、CLion等编辑器及CMake构建工具,并编写一个简单的HelloWorld程序,使用g++编译运行以验证环境配置正确

时间:2026-07-25 22:29
通过cpustat工具查看CPU状态的具体方法与详细步骤

通过cpustat工具查看CPU状态的具体方法与详细步骤

cpustat是sysstat包中的CPU监控工具,可按固定间隔输出带时间戳的CPU使用率统计。安装后运行cpustat即可实时显示各核心信息,常用指标包括%usr、%sys、%iowait、%steal和%idle,用于定位用户态、内核态或I O瓶颈。高级选项-c可显示单核统计,-m可同时查看内存使用,适合脚本采集和性能分析。

时间:2026-07-25 22:18
热门专题
更多
刀塔传奇破解版无限钻石下载大全 刀塔传奇破解版无限钻石下载大全
洛克王国正式正版手游下载安装大全 洛克王国正式正版手游下载安装大全
思美人手游下载专区 思美人手游下载专区
好玩的阿拉德之怒游戏下载合集 好玩的阿拉德之怒游戏下载合集
不思议迷宫手游下载合集 不思议迷宫手游下载合集
百宝袋汉化组游戏最新合集 百宝袋汉化组游戏最新合集
jsk游戏合集30款游戏大全 jsk游戏合集30款游戏大全
宾果消消消原版下载大全 宾果消消消原版下载大全
  • 热门数据榜