Spring两个核心IoCDI(二)

DI(依赖注入)就是从IoC容器中获取对象并赋值给某个属性,这就是依赖注入的过程。

关于依赖注入有3种方式:

1、属性注入

2、构造方法注入

3、setter注入

目录

1、属性注入

2、 构造方法注入

3、Setter方法注入

4、3种注入方式优缺点分析

属性注入

构造方法注入:

Setter注入

5、@Autowired存在的问题以及解决方法

面试题

3种注入方式优缺点

@Autowired与@Resource的区别:

@Autowired的装配顺序


1、属性注入

@Service
public class UserService {public void doService(){System.out.println("UserService.doService");}
}
@ResponseBody
@Controller
public class UserController {@Autowiredprivate UserService userService;public void sayHi() {userService.doService();System.out.println("UserController.sayHi");}@RequestMapping("/hello")public String hello(){return "hello";}
}
@SpringBootApplication
public class SpringIoCDemoApplication {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(SpringIoCDemoApplication.class, args);UserController bean = context.getBean(UserController.class);bean.sayHi();
}
}

通过@Autowired注解,spring就会从容器中取出UserService对象赋值给userService属性,如果不加这个注解,就会在userService.doService()这里报空指针异常。

ApplicationContext的对象也在spring IoC容器中,我们也能通过 @Autowired拿到它的对象,

 @Autowired
    private ApplicationContext context;然后用context再去获取别的Bean对象。

但是我们一般不这样用。

2、 构造方法注入

@Service
public class UserService {public void doService(){System.out.println("UserService.doService");}
}
@Controller
public class UserController2 {private UserService userService;public UserController2(UserService userService){this.userService = userService;}public void sayHi() {userService.doService();System.out.println("UserController.sayHi");}
}
@SpringBootApplication
public class SpringIoCDemoApplication {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(SpringIoCDemoApplication.class, args);UserController2  uc = context.getBean(UserController2.class);uc.sayHi();
}
}

spring在创建UserController2对象的时候,因为这里只提供了一个需要UserService对象参数的构造方法,所以容器就会把UserService对象注入给this.userSercice属性,因此uc.sayHi()能成功运行。

但是为了标准化一般建议把无参的构造方法也写上,

@Controller
public class UserController2 {private UserService userService;public UserController2() {}public UserController2(UserService userService){this.userService = userService;}public void sayHi() {userService.doService();System.out.println("UserController.sayHi");}
}

此时再运行起来就会报错,

因为spring在创建UserController2对象的时候有无参的构造方法就是用了无参的构造方法,所以就没有给userService属性赋值,因此userService.doService()这行会报空指针异常。

为了让spring创建UserController2对象使用有UserService参数的构造方法,我们需要使用@Autowired注解

import com.bit.springiocdemo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;@Controller
public class UserController2 {private UserService userService;public UserController2() {}@Autowiredpublic UserController2(UserService userService){this.userService = userService;}public void sayHi() {userService.doService();System.out.println("UserController.sayHi");}
}

所以只有一个构造方法时,@Autowired可以省略;有多个构造方法时需要通过添加@Autowired来指定spring用哪一个来创建对象。

3、Setter方法注入

import com.bit.springiocdemo.config.UserConfig;
import com.bit.springiocdemo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;@Controller
public class UserController3 {private UserService userService;private UserConfig userConfig;@Autowiredpublic void setUserService(UserService userService) {this.userService = userService;}@Autowiredpublic void setUserConfig(UserConfig userConfig) {this.userConfig = userConfig;}public void sayHi() {userService.doService();userConfig.doConfig();System.out.println("UserController.sayHi");}
}
@SpringBootApplication
public class SpringIoCDemoApplication {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(SpringIoCDemoApplication.class, args);UserController3 uc3 = context.getBean(UserController3.class);uc3.sayHi();
}
}

通过setter方法来为属性赋值,需要给setter方法添加@Autowired属性,否则在sayHi()方法中就会报快指针异常。

4、3种注入方式优缺点分析

属性注入

简洁方便,但是只能用于IoC容器,并且不能注入一个Final修饰的属性。

fianl修饰的属性要么要初始化,要么通过构造方法进行赋值。

构造方法注入:

优点:

  • 可以注入final修饰的属性,就是在构造方法中进行赋值
  • 注入的对象不会被修改
  • 依赖对象在使用前一定会被完全初始化的,因为依赖是在类的构造方法中注入的,而构造方法是在类加载时就会执行的
  • 通用性好,构造方法是jdk支持的,换任何框架都是适用的

缺点:注入多个对象比较麻烦

Setter注入

优点:方便在类实例话之后,还能对该对象进行配置或者注入

@Controller
public class UserController3 {private UserService userService;private UserConfig userConfig;@Autowiredpublic void setUserService(UserService userService) {this.userService = userService;}@Autowiredpublic void setUserConfig(UserConfig userConfig) {this.userConfig = userConfig;}public void sayHi() {userService.doService();userConfig.doConfig();System.out.println("UserController.sayHi");}
}

就这个代码来说,就是在UserController3实例化好之后,还能通过主动调用setter方法来给属性赋值,更换注入的对象,所以这也是一个缺点

缺点:

  • 注入对象可能会被改变,因为setter可能多次调用,就有被修改的风险
  • 不能注入一个final修饰的属性

当前Spring官方更推荐构造方法注入方式,程序员更推荐属性注入方式。

5、@Autowired存在的问题以及解决方法

当一个类型有多个Bean时,使用@Autowired就会报错

@AllArgsConstructor
@Data
public class UserInfo {private Integer id;private String name;private Integer age;
}
@Configuration
public class UserInfoConfig {@Bean(name = {"user1","lisi"})public UserInfo user1() {UserInfo userInfo = new UserInfo(1,"lisi",15);return userInfo;}@Beanpublic UserInfo user2() {UserInfo userInfo = new UserInfo(2,"kiku",31);return userInfo;}
}

从这里可以看到UserInfo类型在IoC容器中存了两个对象,一个是通过user1()创建的,一个是user2()创建的

@Controller
public class UserController {@Autowiredprivate  UserService userService;@Autowiredprivate UserInfo userInfo;public void sayHi() {userService.doService();System.out.println(userInfo);System.out.println("UserController.sayHi");}
}

所以这里通过添加@Autowired给userInfo属性注入对象时,不知道该使用容器中的哪一个来进行注入

@SpringBootApplication
public class SpringIoCDemoApplication {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(SpringIoCDemoApplication.class, args);UserController bean = context.getBean(UserController.class);bean.sayHi();
}
}

报错信息以及建议:

建议中有两种解决方式,

一种是通过添加@Primary来选择一个Bean对象作为主要选择的、默认的,比如:

@Primary
@Bean(name = {"user1","lisi"})
public UserInfo user1() {UserInfo userInfo = new UserInfo(1,"lisi",15);return userInfo;
}

这样就会选择user1()创建的对象来注入。

另一种是通过@Qualifier来指定要注入的对象是谁。

@Controller
public class UserController {@Autowiredprivate  UserService userService;@Autowired@Qualifier("user2")private UserInfo userInfo;public void sayHi() {userService.doService();System.out.println(userInfo);System.out.println("UserController.sayHi");}
}

当两个同时@Primary和@Qualifier都存在时,会使用@Qualifier()指定的,而不是默认的。

另外@Qualifier除了可以加在属性上,还可以加在参数上:

  @Autowiredpublic UserController2(UserService userService, UserConfig userConfig,@Qualifier("user1") UserInfo userInfo) {this.userService = userService;this.userConfig = userConfig;this.userInfo = userInfo;}

除了spring建议的这两种,我们还可以通过@Resource来解决:

//    @Autowired
//    @Qualifier("user2")@Resource(name = "user2")private UserInfo userInfo;

@Resource作用上就等于@Autowired+@Qualifier,

这个注解是jakarta提供的。

面试题

3种注入方式优缺点

@Autowired与@Resource的区别:

1、来源不同,@Autowired是spring框架提供的注解,@Resource是jdk提供的注解。

2、@Autowired是按照类型注入的(如果该类型只有一个Bean,直接注入;如果该类型有多个bean,就按属性名称注入,但是@Autowired不能指定bean的名称来注入),

@Resource是按照名称注入的

@Autowired的装配顺序

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/96344.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/96344.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

广东省省考备考(第八十三天8.21)——言语、判断推理(强化训练)

言语理解与表达 错题解析 文段开篇介绍足够的执法权限对于基层治理高效运行的重要性,接着从两方面进行论证,介绍权限不足和权限过度下放对基层治理的负面影响,最后通过“因此”进行总结,强调一方面要完善执法目录动态调整机制和制…

字符串与算法题详解:最长回文子串、IP 地址转换、字符串排序、蛇形矩阵与字符串加密

字符串与算法题详解:最长回文子串、IP 地址转换、字符串排序、蛇形矩阵与字符串加密 前言 在编程题训练中,字符串相关的题目非常常见。本文将结合几个典型的例题,详细解析它们的解题思路和实现方式,帮助初学者循序渐进地掌握常用技…

从协同设计到绿色制造:工业云渲染的价值闭环

在智能制造、建筑工程、能源电力、船舶海工等工业场景中,3D可视化已从传统的桌面端逐步向Web端迁移,Web 3D凭借其跨平台、轻量化、实时交互等特性,已成为企业构建数字孪生、实现远程协作、推动云端交付的重要工具。这场技术变革不仅改变了工业…

算法第五十一天:图论part02(第十一章)

1.岛屿数量 99. 岛屿数量 🌟 思路总结 — DFS 版 1️⃣ 问题本质 给定一个二维矩阵 grid,1 表示陆地,0 表示水 统计岛屿数量,每个岛屿由上下左右相邻的陆地组成 本质是 在二维网格中找连通块 的问题。 2️⃣ 核心思路 遍历矩阵…

杰里708n tws api 简介

/** 通过搜索码搜索tws设备*/int tws_api_search_sibling_by_code();/**打开可发现, 可连接,可被手机和tws搜索到*/int tws_api_wait_pair_by_code(u16 code, const char *name, int timeout_ms);int tws_api_wait_pair_by_ble(u16 code, const char *name, int tim…

高调光比 LED 恒流驱动芯片方案详解AP5165B:36V/1A

AP5165B 是深圳市世微半导体有限公司推出的一款高性能、连续电流模式的降压型(Buck)LED 恒流驱动芯片。该芯片适用于输入电压高于 LED 电压的应用场景,可驱动单颗或多颗串联的 LED,输出电流最高可达 1A,广泛用于非隔离…

【从零构建企业级线程池管理系统:Python并发编程实战指南】

从零构建企业级线程池管理系统:Python并发编程实战指南 技术博客 | 深入探索Python并发编程、Web开发与现代软件架构设计的完整实践 🚀 项目背景 在当今高并发的互联网时代,线程池作为并发编程的核心组件,其管理和监控能力直接影…

飞牛系统总是死机,安装个工具查看一下日志

崩溃转储 (kernel crash dump)如果你怀疑是内核 panic,可以开启 kdump 或 kernel crash dump。 安装:sudo apt install kdump-tools # Debian/Ubuntu sudo systemctl enable kdump 下次死机时,系统会把内存 dump 到 /var/crash 里。sudo syst…

2025年AI Agent技术深度解析:原理、应用与未来趋势

一、引言随着人工智能技术的飞速发展,AI Agent(智能体)作为人工智能领域的重要分支,正逐渐成为推动各行业智能化转型的关键力量。AI Agent具备自主感知、决策和执行能力,能够在复杂环境中完成特定任务,为人…

linux内核 - 内存分配机制介绍

在linux内核中,下面这张图说明了系统中存在一个可以满足各种内存请求的分配机制。根据你需要内存的用途,你可以选择最接近你目标的分配方式。最底层、最基础的分配器是 页分配器(page allocator),它以页为单位分配内存…

PyTorch生成式人工智能——ACGAN详解与实现

PyTorch生成式人工智能——ACGAN详解与实现0. 前言1. ACGAN 简介1.1 ACGAN 技术原理1.2 ACGAN 核心思想1.3 损失函数2. 模型训练流程3. 使用 PyTorch 构建 ACGAN3.1 数据处理3.2 模型构建3.3 模型训练3.4 模型测试相关链接0. 前言 在生成对抗网络 (Generative Adversarial Net…

Python + 淘宝 API 开发:自动化采集商品数据的完整流程​

在电商数据分析、竞品监控和市场调研等场景中,高效采集淘宝商品数据是关键环节。本文将详细介绍如何利用 Python 结合 API,构建一套自动化的商品数据采集系统,涵盖从 API 申请到数据存储的完整流程,并提供可直接运行的代码实现。​…

2025.8.21总结

工作一年多了,在这期间,确实也有不少压力,但每当工作有压力的时候,最后面都会解决。好像每次遇到解决不了的事情,都有同事给我兜底。这种压力,确实会加速一个人的成长。这种狼性文化,这种环境&a…

VS2022 - C#程序简单打包操作

文章目录VS2022 - C#程序简单打包操作概述笔记实验过程新建工程让依赖的运行时程序安装包在安装时运行(如果发现运行时不能每次都安装程序,就不要做这步)关于”运行时安装程序无法每次都安装成功“的应对知识点尝试打包旧工程bug修复从需求属性中,可以原…

在JAVA中如何给Main方法传参?

一、在IDEA中进行传参:先创建一个类:MainTestimport java.util.Arrays;public class MainTest {public static void main(String[] args) {System.out.println(args.length);System.out.println(Arrays.toString(args));} }1.IDEA ---> 在运行的按钮上…

ORACLE中如何批量重置序列

背景:数据库所有序列都重置为1了,所以要将所有的序列都更新为对应的表主键(这里是id)的最大值1。我这里序列的规则是SEQ_表名。BEGINENHANCED_SYNC_SEQUENCES(WJ_CPP); -- 替换为你的模式名 END; / CREATE OR REPLACE PROCEDURE E…

公号文章排版教程:图文双排、添加图片超链接、往期推荐、推文采集(2025-08-21)

文章目录 排版的基本原则 I 图片超链接 方式1: 利用公号原生编辑器 方式2:在CSDN平台使用markdown编辑器, 利用标签实现图片链接。 II 排版小技巧 自定义页面模版教程 使用壹伴进行文章素材的采集 美编助手的往期推荐还不错 利用365编辑器创建图文双排效果 排版的基本原则 亲…

计算两幅图像在特定交点位置的置信度评分。置信度评分反映了该位置特征匹配的可靠性,通常用于图像处理任务(如特征匹配、立体视觉等)

这段代码定义了一个名为compute_confidence的函数,用于计算两幅图像在特定交点位置的置信度评分。置信度评分反映了该位置特征匹配的可靠性,通常用于图像处理任务(如特征匹配、立体视觉等)。以下是逐部分解析: 3. 结果…

计算机视觉第一课opencv(三)保姆级教学

简介 计算机视觉第一课opencv(一)保姆级教学 计算机视觉第一课opencv(二)保姆级教学 今天继续学习opencv。 一、 图像形态学 什么是形态学:图像形态学是一种处理图像形状特征的图像处理技术,主要用于描…

24.早期目标检测

早期目标检测 第一步,计算机图形学做初步大量候选框,把物体圈出来 第二步,依次将所有的候选框图片,输入到分类模型进行判断 选择性搜索 选择搜索算法(Selective Search),是一种熟知的计算机图像…