当前位置: 首页 > article >正文

@Autowired 注解在构造器上的使用规则(字段注入也挺好的)

背景

  • 在看Spring Framework官方文档时,看到这样一段描述:

As of Spring Framework 4.3, an @Autowired​ annotation on such a constructor is no longer necessary if the target bean defines only one constructor to begin with. However, if several constructors are available and there is no primary/default constructor, at least one of the constructors must be annotated with @Autowired​ in order to instruct the container which one to use. See the discussion on constructor resolution for details.

  • 为了更好地理解这段话,做了一些实践,写成文章分享给大家。

实践

第一句

“As of Spring Framework 4.3, an @Autowired annotation on such a constructor is no longer necessary if the target bean defines only one constructor to begin with.”

  • 含义:从 Spring Framework 4.3 版本开始,如果一个目标 Bean 只定义了一个构造器,那么在该构造器上标注 @Autowired​ 注解就不再是必须的。
@RestController
public class HelloController {private HelloService helloService;// 只有一个构造器,可以不写@Autowiredpublic HelloController(HelloService helloService) {this.helloService = helloService;}@GetMapping("/hello")public String hello() {return helloService.sayHello();}
}

第二句

“However, if several constructors are available and there is no primary/default constructor, at least one of the constructors must be annotated with @Autowired in order to instruct the container which one to use.”

  • 含义:然而,如果一个类有多个构造器,并且没有一个被标记为“主要构造器”或默认构造器,那么至少需要在一个构造器上标注 @Autowired​,以便告诉 Spring 容器应该使用哪一个构造器。
@RestController
public class HelloController {private HelloService helloService;//    @Autowired 不写@Autowired,helloSService会为nullpublic HelloController(HelloService helloService) {this.helloService = helloService;}public HelloController() {}@GetMapping("/hello")public String hello() {return helloService.sayHello();}
}Cannot invoke "com.forrest.learn.spring.autowired.example1.HelloService.sayHello()" because "this.helloService" is null
@RestController
public class HelloController {private HelloService helloService;@Autowiredpublic HelloController(HelloService helloService) {this.helloService = helloService;}public HelloController() {}@GetMapping("/hello")public String hello() {return helloService.sayHello();}
}

想法

  • 在实际开发中,很少会采用构造器注入,因为写起来太麻烦了…

    image

    image

那我们需要搞清楚,为什么不推荐使用注入?

  • Why field injection is not recommended?

    • (1)不方便写单测(不赞同,挺方便的)
    • (2)不能被final修饰(确实有风险,但完全属于人为造成的风险…)
    • (3)字段注入隐藏了类的依赖项(不赞同,根据字段注入,也可以知道当前类依赖了哪些类)
    • (4)字段注入依赖于 Spring 框架在构建对象后填充依赖项。(下文解释)
    • (5)字段注入使类依赖于用于注入依赖项的框架。(不赞同,@Autowired是Spring的注解,确实依赖了框架,但我们可以用Java的@Resource进行依赖注入)

不能被final修饰(确实有风险,但helloService被恶意修改了,在运行时可以被测出来,因为运行结果不符合预期了)

@RestController
public class HelloController {@Autowiredprivate HelloService helloService;@GetMapping("/hello")public String hello() {return helloService.sayHello();}
}
  • 由于helloService不是final的,因此有被修改的风险:
@RestController
public class HelloController {@Autowiredprivate HelloService helloService;@Autowiredprivate ApplicationContext applicationContext;@GetMapping("/hello")public String hello() {HelloController helloController = applicationContext.getBean(HelloController.class);Field field = null;try {field = HelloController.class.getDeclaredField("helloService");} catch (NoSuchFieldException e) {throw new RuntimeException(e);}field.setAccessible(true);try {field.set(helloController, null);} catch (IllegalAccessException e) {throw new RuntimeException(e);}return helloService.sayHello();}
}

image

helloService注入时不为null,但被修改成了null,导致了npe…

不方便写单测(挺方便的)

public class HelloControllerTest {private MockMvc mockMvc;@Mockprivate HelloService helloService;@InjectMocksprivate HelloController helloController;@BeforeEachpublic void setup() {MockitoAnnotations.initMocks(this);mockMvc = MockMvcBuilders.standaloneSetup(helloController).build();}@Testpublic void hello_WhenCalled_ReturnsHelloMessage() throws Exception {String expectedMessage = "Hello, World!";when(helloService.sayHello()).thenReturn(expectedMessage);mockMvc.perform(get("/hello")).andExpect(status().isOk()).andExpect(content().string(expectedMessage));}
}

字段注入依赖于 Spring 框架在构建对象后填充依赖项。

image

@Service
public class HelloServiceImpl implements HelloService {private final HelloRepository helloRepository;
//
//    public HelloServiceImpl() {
//
//    }@Autowiredpublic HelloServiceImpl(HelloRepository helloRepository) {this.helloRepository = helloRepository;helloRepository.initialize();}@Overridepublic String sayHello() {return "Hello World";}
}
  • 但完全可以先字段注入,然后通过@PostContruct再调用依赖的方法:

    image

总结

  • 通过@Autowired字段注入,并未有不可接受的副作用,而且代码简洁。

  • IDEA的警告挺烦的,怎么关了?

    image

  • 或者采用@Resouce

相关文章:

@Autowired 注解在构造器上的使用规则(字段注入也挺好的)

背景 在看Spring Framework官方文档时,看到这样一段描述: As of Spring Framework 4.3, an Autowired​ annotation on such a constructor is no longer necessary if the target bean defines only one constructor to begin with. However, if seve…...

深度学习视觉2D检测算法综述

目录 一、两阶段目标检测算法 1.1 R-CNN(Region-based CNN,2014) 1.2 Fast R-CNN(Fast Region-based CNN,2015) 1.3 Faster R-CNN(Faster Region-based CNN,2016) 1…...

复试不难,西电马克思主义学院—考研录取情况

01、马克思主义学院各个方向 02、24马克思主义学院近三年复试分数线对比 PS:马院24年院线相对于23年院线增加15分,反映了大家对于马克思主义理论学习与研究的热情高涨,也彰显了学院在人才培养、学科建设及学术研究等方面的不断进步与成就。 6…...

Axios 请求取消:从原理到实践

Axios 请求取消:从原理到实践 在现代前端开发中,网络请求是不可或缺的一部分。Axios 是一个基于 Promise 的 HTTP 客户端,广泛应用于浏览器和 Node.js 环境中。然而,在某些场景下,我们可能需要取消正在进行的请求&…...

【Leetcode 每日一题】3306. 元音辅音字符串计数 I

问题背景 给你一个字符串 w o r d word word 和一个 非负 整数 k k k。 返回 w o r d word word 的 子字符串 中,每个元音字母(‘a’、‘e’、‘i’、‘o’、‘u’)至少 出现一次,并且 恰好 包含 k k k 个辅音字母的子字符串…...

【A2DP】深入解读A2DP中通用访问配置文件(GAP)的互操作性要求

目录 一、模式支持要求 1.1 发现模式 1.2 连接模式 1.3 绑定模式 1.4 模式间依赖关系总结 1.5 注意事项 1.6 协议设计深层逻辑 二、安全机制(Security Aspects) 三、空闲模式操作(Idle Mode Procedures) 3.1 支持要求 …...

分享一个免费的CKA认证学习资料

关于CKA考试 CKA(Certified Kubernetes Administrator)是CNCF基金会(Cloud Native Computing Foundation)官方推出的Kubernetes管理员认证计划,用于证明持有人有履行Kubernetes管理的知识,技能等相关的能力…...

观成科技:​加密C2框架Platypus流量分析

一、工具介绍 Platypus 是一款支持多会话的交互式反向 Shell 管理器。在实际的渗透测试中,为了解决 Netcat/Socat 等工具在文件传输、多会话管理方面的不足,该工具在多会话管理的基础上增加了在渗透测试中能更好发挥作用的功能(如:交互式 Sh…...

Jetson Nano NX 重装系统

本篇记录了自己刚拿到Jetson板子后,刻意去学习给板子重刷系统的过程,学会重装系统是玩嵌入式开发板的基操。 注意:我使用的是 Nvidia 官方 SDK Manager 给 Jetson 刷系统的,需要额外准备一台 linux 电脑(双系统或者虚拟…...

注解+AOP实现权限控制

注解与AOP实战:实现权限控制 在现代Java开发中,注解(Annotation)和面向切面编程(AOP)是两种强大的技术,它们能够帮助我们实现代码的解耦,提高代码的可读性和可维护性。本文将通过一…...

Java数据结构第二十三期:Map与Set的高效应用之道(二)

专栏:Java数据结构秘籍 个人主页:手握风云 目录 一、哈希表 1.1. 概念 1.2. 冲突 1.3. 避免冲突 1.4. 解决冲突 1.5. 实现 二、OJ练习 2.1. 只出现一次的数字 2.2. 随机链表的复制 2.3. 宝石与石头 一、哈希表 1.1. 概念 顺序结构以及平衡树中…...

linux系统命令——权限

一、有哪些权限 读(r)——对应数字4 写(w)——对应数字2 执行(x)——对应数字1 二、权限及数字的对应 4对应r-- 2对应-w- 1对应--x 5对应r-x 6对应rw- 7对应rwx 三、文件的基本属性 如图&#…...

设计模式-工厂模式、策略模式、代理模式、责任链模式

目录 1 工厂模式 1.1 简单工厂模式 1.2 工厂方法模式 1.3 抽象工厂模式 1.4 工厂模式适用的场合 1.5 三种工厂模式的使用选择 2 策略模式 2.1 定义 2.2 结构 3 代理模式 3.1 啥是代理模式 3.2 为啥要用代理模式 3.3 代理模式分类 3.3.1 静态代理 3.3.2 动态代理…...

nginx中间件部署

普通权限账户安装NGINX中间件 1、拥有高级权限的账户安装必要的插件 sudo yum install -y gcc-c make pcre pcre-devel zlib zlib-devel openssl openssl-devel 2、普通账户进行NGINX的脚本式安装 vi nginx_intall.sh #!/bin/bash TAR_NAME"$1" TAR_NAME_DIRba…...

PentestGPT 下载

PentestGPT 下载 PentestGPT 介绍 PentestGPT(Penetration Testing GPT)是一个基于大语言模型(LLM)的智能渗透测试助手。它结合了 ChatGPT(或其他 GPT 模型)与渗透测试工具,帮助安全研究人员自…...

JVM 2015/3/15

定义:Java Virtual Machine -java程序的运行环境(java二进制字节码的运行环境) 好处: 一次编写,到处运行 自动内存管理,垃圾回收 数组下标越界检测 多态 比较:jvm/jre/jdk 常见的JVM&…...

Java中接口隔离原则简介和代码举例

简介: 接口隔离原则(Interface Segregation Principle,ISP)是面向对象设计SOLID原则中的“I”,其核心思想是: 定义 客户端不应被迫依赖它不使用的方法。即,一个类对另一个类的依赖应建立在最…...

基于自定义线程池手写一个异步任务管理器

我们在后端执行某些耗时逻辑操作时往往会导致长时间的线程阻塞,在这种情况之下,我们往往会引一条异步线程去处理这些异步任务,如果每次都创建新的线程来处理这些任务,不仅会增加代码冗余,还可能造成线程管理混乱&#…...

sql靶场-时间盲注(第九、十关)保姆级教程

目录 时间盲注(第九、十关) 1.判断 2.确认时间盲注 2.手工尝试时间盲注 数据库名长度 数据库名字符 表数 表名长度 表名字符 字段数 字段名长度 字段名字符 4.脚本时间盲注注入 5.第十关 时间盲注(第九、十关) 1.判…...

Vuex 高级技巧与最佳实践

使用 map 辅助函数简化代码: javascript import { mapState, mapGetters } from vuexexport default {computed: {...mapState([num]),...mapGetters([doubleNum])} }模块化开发: javascript // modules/student.js export default {namespaced: true,st…...

51c自动驾驶~合集54

我自己的原文哦~ https://blog.51cto.com/whaosoft/13517811 #Chameleon 快慢双系统!清华&博世最新:无需训练即可解决复杂道路拓扑 在自动驾驶技术中,车道拓扑提取是实现无地图导航的核心任务之一。它要求系统不仅能检测出车道和交…...

大模型推理:LM Studio在Mac上部署Deepseek-R1模型

LM Studio LM Studio是一款支持离线大模型部署的推理服务框架,提供了易用的大模型部署web框架,支持Linux、Mac、Windows等平台,并提供了OpenAI兼容的SDK接口,主要使用LLama.cpp和MLX推理后端,在Mac上部署时选择MLX推理…...

扩散模型:AIGC领域的核心引擎,解锁图像生成新维度

一、扩散模型技术原理 扩散模型是一类生成模型,它运用了物理热力学中的扩散思想, 主要包括前向扩散和反向扩散两个过程。 1.1、生成模型 在深度学习中,生成模型的目标是根据给定的样本(训练数据) 生成新样本。首先给…...

Java多线程与高并发专题——原子类和 volatile、synchronized 有什么异同?

原子类和 volatile异同 首先,通过我们对原子类和的了解,原子类和volatile 都能保证多线程环境下的数据可见性。在多线程程序中,每个线程都有自己的工作内存,当多个线程访问共享变量时,可能会出现一个线程修改了共享变…...

//要求:将输入的字符串中的数字转换为罗马数字,长度小于9(运用方法:Switch方法)

import java.util.Scanner;public class Num2 {public static void main(String[] args){ // I II III IV V VI VII VIII IX//要求:将输入的字符串中的数字转换为罗马数字,长度小于9(运用方法:查表法)//1输入数字//2有效字符判断/…...

【数据结构】数据结构,算法 概念

0.本篇问题: 数据、数据元素、数据对象、数据项之间的基本关系?ADT是什么?数据结构的三要素?数据的逻辑结构有哪些?数据的存储结构有哪些?算法的五个特征?O(1) O(logn) O(n^n) O(n) O(n^2…...

pytest 框架学习总结

视频:pytest01-快速上手_哔哩哔哩_bilibili 资料:pytest 框架 - 白月黑羽 基于 Python 语言的自动化测试框架 最知名的 有如下 3 款unittest、pytest、robotframework 前两款框架主要(或者说很大程度上)是 聚焦 在 白盒单元测试…...

总结 HTTP 协议的基本格式, 相关知识以及抓包工具fiddler的使用

目录 1 HTTP是什么 2 HTTP协议格式 3 HTTP请求(Request) 3.1 认识URL 3.2 方法 3.3 认识请求"报头"(header) 4 HTTP响应详解 4.1 认识"状态码"(statuscode) 4.2 认识响应"报头"(header) 4.3 认识响应"正⽂"(body) 5 通过f…...

python中的max(),需要注意的点

words ["apple", "banana", "grape", "cherry"] 对每个单词,keylambda x: len(x) 会计算它的长度: "apple" 长度是 5"banana" 长度是 6"grape" 长度是 5"cherry" 长度…...

DeepSeek-R1大模型微调技术深度解析:架构、方法与应用全解析

1. DeepSeek-R1大模型架构设计与技术特性 1.1 架构设计 DeepSeek-R1作为超大规模语言模型,其核心架构设计包含以下创新: 专家混合架构(MoE) 采用6710亿参数的混合专家架构(MoE),每个推理过程仅激活370亿参数,实现计算效率与资源利用率的突破性提升。 Transformer框架…...