正确使用@Autowired

目录

  • 一、前言
  • 二、跟着官方文档,学习正确使用@Autowired
    • 0、实验环境
    • 1、通过构造方法进行注入
      • 1.1 问题1:那万一没有这个CustomerPreferenceDao对象,会报错吗?
    • 2、通过setter方法注入
    • 3、通过方法注入(这个方法可以是任意名称,有任意参数)
    • 4、通过字段注入 【非常常见的做法,简洁】
    • 5、字段注入和构造方法注入可以混用。
    • 6、解释
    • 7、注入一组依赖(通过:字段 或 方法)
      • 7.1 通过字段
      • 7.2 通过方法
    • 8、按顺序注入一组依赖【以字段注入为例】
    • 9、还能注入Map<String, xxx>

一、前言

  • Spring框架两大核心特性:IoC容器(对开发者来说,就是希望Spring帮助注入依赖) + AOP
  • 因此,熟练使用Spring框架之一便是熟练使用依赖注入。
  • 之前介绍了“正确使用@Resource”,本文重点介绍“正确使用@Autowired”

二、跟着官方文档,学习正确使用@Autowired

0、实验环境

@ComponentScan
public class Application {public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Application.class);Arrays.stream(applicationContext.getBeanDefinitionNames()).forEach(System.out::println);System.out.println("---------------------------------------------------------------");MovieRecommender movieRecommender = applicationContext.getBean(MovieRecommender.class);movieRecommender.sayHello();}
}
public class CustomerPreferenceDao {public void sayHello() {System.out.println("Hello, I am " + this.getClass().getSimpleName());}
}@Configuration
public class LearnAutowiredConfig {@Beanpublic CustomerPreferenceDao customerPreferenceDao() {return new CustomerPreferenceDao();}
}

1、通过构造方法进行注入

@Component
public class MovieRecommender {private final CustomerPreferenceDao customerPreferenceDao;@Autowiredpublic MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {this.customerPreferenceDao = customerPreferenceDao;}public void sayHello() {customerPreferenceDao.sayHello();System.out.println("Hello, I am " + this.getClass().getSimpleName());}
}
  • 从Spring 4.3开始,如果组件只有一个构造方法,那么没必要给这个构造方法带上@Autowired。
    • 道理也很简单,Spring为MovieRecommender类创建对象时,少不了调用构造方法。它发现需要一个CustomerPreferenceDao对象,然后在IoC容器里面确实有这个对象,那就自动帮咱注入了。

1.1 问题1:那万一没有这个CustomerPreferenceDao对象,会报错吗?

  • 会报错!

个人觉得,注解是一个非常好的标识,即使能省略,也别省略。

  • 为啥会报错呢?
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {/*** Declares whether the annotated dependency is required.* <p>Defaults to {@code true}.*/boolean required() default true;}
  • 表面上省略了@Autowired,但实际上仍然和带上@Autowired的效果一致。默认要求必须注入依赖,如果待注入的依赖不存在,则报错。
  • 那我改成@Autowired(required = false)可以吗?–> 依然报错
Inconsistent constructor declaration on bean with name 'movieRecommender': single autowire-marked constructor flagged as optional - this constructor is effectively required since there is no default constructor to fall back to: public com.forrest.learnspring.autowired.example1.bean.MovieRecommender(com.forrest.learnspring.autowired.example1.dao.CustomerPreferenceDao)
  • 大意:Spring认为提供的构造方法不符合需求(因为找不到可用的CustomerPreferenceDao的bean),然后发现这个构造方法是可选的,那我就选其他的吧。结果没其他可选了,那只能报错了。
  • 补一个空参构造方法就行:
public MovieRecommender() {this.customerPreferenceDao = null;
}@Autowired(required = false)
public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {this.customerPreferenceDao = customerPreferenceDao;
}
  • 如果bean具有多个构造方法,那么不能省略@Autowired,否则Spring在创建bean的时候,不知道用哪个构造方法。

2、通过setter方法注入

@Component
public class MovieRecommender {private CustomerPreferenceDao customerPreferenceDao;@Autowiredpublic void setCustomerPreferenceDao(CustomerPreferenceDao customerPreferenceDao) {this.customerPreferenceDao = customerPreferenceDao;}...
}

3、通过方法注入(这个方法可以是任意名称,有任意参数)

@Component
public class MovieRecommender {private CustomerPreferenceDao customerPreferenceDao;@Autowiredpublic void prepare(CustomerPreferenceDao customerPreferenceDao) {this.customerPreferenceDao = customerPreferenceDao;}public void sayHello() {customerPreferenceDao.sayHello();System.out.println("Hello, I am " + this.getClass().getSimpleName());}
}
  • 这个prepare方法会被Spring调用,咱不用管。咱需要注意的是:
    • 入参必须是能够在IoC容器中找得到的bean。(String s, CustomerPreferenceDao customerPreferenceDao)这是不可以的。因此,IoC容器中,没有s这个bean。
    • 对访问修饰符没有要求。
      • 我猜测是,Spring创建好MovieRecommender的bean后,由这个bean去调用自己的方法。因此,哪怕方法是private的都没问题。

4、通过字段注入 【非常常见的做法,简洁】

@Component
public class MovieRecommender {@Autowiredprivate CustomerPreferenceDao customerPreferenceDao;...
}
  • 但IDEA不建议字段注入。【但写的代码少了,一般都采用这种,哈哈】

5、字段注入和构造方法注入可以混用。

@Component
public class MovieRecommender {@Autowiredprivate CustomerPreferenceDao customerPreferenceDao;private final UserProcessor userProcessor;@Autowiredpublic MovieRecommender(UserProcessor userProcessor) {this.userProcessor = userProcessor;}...
}

6、解释

官方文档:
Make sure that your target components (for example, MovieCatalog or CustomerPreferenceDao) are consistently declared by the type that you use for your @Autowired-annotated injection points. Otherwise, injection may fail due to a “no type match found” error at runtime.
For XML-defined beans or component classes found via classpath scanning, the container usually knows the concrete type up front. However, for @Bean factory methods, you need to make sure that the declared return type is sufficiently expressive. For components that implement several interfaces or for components potentially referred to by their implementation type, consider declaring the most specific return type on your factory method (at least as specific as required by the injection points referring to your bean).

咋一看,这都是啥啊… 但还是要理解下啊

  • 解释:
    • 从上面的例子可知,不管@Autowired用在构造方法、setter方法、还是字段上,我们都能知道需要的依赖是什么类型的。
    • Spring就会根据这个类型,去IoC容器中找:
      • 因此,我们要保证类型别写错了,否则Spring会找不到。Make sure that your target components are consistently declared by the type (类型兼容)
  • 正例(可以向上转型):
@Controller
public class UserController {@Autowiredprivate UserService userService;...
}
@Configuration
public class LearnAutowiredConfig {// 很显然,这么写相当于:UserService userServie = new UserServiceImpl();// UserController的userService = userServie = new UserServiceImpl(); 也是成立的。@Beanpublic UserService userService() {return new UserServiceImpl();}
}// 同理这么写也行
@Configuration
public class LearnAutowiredConfig {@Beanpublic UserServiceImpl userService() {return new UserServiceImpl();}
}
  • 反例(不能向下转型):
@Controller
public class UserController {@Autowiredprivate UserServiceImpl userService;...
}@Configuration
public class LearnAutowiredConfig {// UserService userService = new UserServiceImpl();// UserController的userService = userService; 这是不行的。属于向下转型。@Beanpublic UserService userService() {return new UserServiceImpl();}
}
  • 报错:No qualifying bean of type ‘com.forrest.learnspring.autowired.example2.service.impl.UserServiceImpl’ available
  • 向下转型需要强转,否则会报错,等同于:
    在这里插入图片描述
  • 推荐】注入依赖,依赖的类型尽可能抽象(有接口用接口!)。

7、注入一组依赖(通过:字段 或 方法)

7.1 通过字段

@Controller
public class UserController {@Autowiredprivate List<UserService> userServices;...
}@Configuration
public class LearnAutowiredConfig {@Beanpublic UserService userService() {return new UserServiceImpl();}@Beanpublic UserService userProxyService() {return new UserProxyServiceImpl();}
}

7.2 通过方法

@Controller
public class UserController {private List<UserService> userServices;@Autowiredpublic void prepare(List<UserService> userServices) {this.userServices = userServices;}...
}

8、按顺序注入一组依赖【以字段注入为例】

  • 办法:
  • (1) implement the org.springframework.core.Ordered interface
  • (2) @Order
  • (3) @Priority
  • 以@Order为例子
@Configuration
public class LearnAutowiredConfig {@Bean@Order(2)public UserService userService() {return new UserServiceImpl();}@Bean@Order(1)public UserService userProxyService() {return new UserProxyServiceImpl();}
}/*
1 : UserProxyServiceImpl
2 : UserServiceImpl
*/
@Order(1)
@Service
public class UserProxyServiceImpl implements UserService {...
}@Order(2)
@Service
public class UserServiceImpl implements UserService {...
}

9、还能注入Map<String, xxx>

  • 以字段注入为例:
@Controller
public class UserController {@Autowiredprivate Map<String, UserService> userServiceMap;...
}/*
userProxyServiceImpl: UserProxyServiceImpl
userServiceImpl: UserServiceImpl
*/

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

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

相关文章

为什么苹果 Mac 电脑需要使用清理软件?

尽管 Apple Mac 电脑因其卓越的性能、简洁高效的 macOS 操作系统及独特的美学设计备受全球用户青睐&#xff0c;但任何电子设备在长期使用后都难以避免面临系统资源日渐累积的问题。其中一个重要维护需求在于&#xff0c;随着使用时间的增长&#xff0c;Mac电脑可能会由于系统垃…

go库x/text缺陷报告CVE-2022-32149的处理方案

#问题描述 go库 golang.org/x/text &#xff0c;注意这里不是go的源码&#xff0c; 在0.3.8版本之前存在一个缺陷(Vulnerability) 缺陷ID CVE-2022-32149 具体描述 攻击者可以通过制作一个Accept-Language报头来导致拒绝服务。 具体的原因是&#xff0c;在解析这个Accept-L…

数据结构__顺序表和单链表

顺序表的改进 问题&#xff1a; 1. 中间/头部的插入删除&#xff0c;时间复杂度为O(N) 2. 增容需要申请新空间&#xff0c;拷贝数据&#xff0c;释放旧空间。会有不小的消耗。 3. 增容一般是呈2倍的增长&#xff0c;势必会有一定的空间浪费。例如当前容量为100&#xff0c;满了…

C++——位图和布隆过滤器

在C中&#xff0c;哈希这种思想的应用场景有很多&#xff0c;位图就是其中的一种。 位图 位图&#xff1a;位图是一种哈希思想的产物&#xff0c;可以通过它来对数据进行快速的查找的方法&#xff0c;在位图中&#xff0c;有2种状态来表示在或者不在&#xff0c;即1/0。 位图…

大数据系列 | Kafka架构分析及应用

大数据系列 | Kafka架构分析及应用 1. Kafka原理分析2. Kafka架构分析3. Kafka的应用3.1. 安装Zookeeper集群3.2. 安装Kafka集群3.3. 生产者和消费者使用3.3.1. 生产者使用3.3.1. 消费者使用 4. Kafka Controller控制器 1. Kafka原理分析 Kafka是一个高吞吐量、 持久性的分布式…

宏的使用(C语言详解)

在写一个代码生成可执行文件的过程需要经过编译和链接&#xff0c;编译又要经过三部&#xff1a;预处理&#xff0c;编译&#xff0c;汇编。 #define定义的变量和宏就是在预处理阶段会处理的。 一个简单的宏定义&#xff1a; #include<stdio.h>; #define Max(a,b) a>…

CTF之GET和POST

学过php都知道就一个简单传参&#xff0c;构造payload:?whatflag得到 flag{3121064b1e9e27280f9f709144222429} 下面是POST那题 使用firefox浏览器的插件Hackbar勾选POST传入whatflag flag{828a91acc006990d74b0cb0c2f62b8d8}

Web APIs简介 Dom

JS的组成 API API 是一些预先定义的函数&#xff0c;目的是提供应用程序与开发人员基于软件或硬件得以访问一组例程的能力&#xff0c;而又无需访问源码&#xff0c;或理解内部工作机制的细节 简单理解&#xff1a;API是给程序员提供的一种工具&#xff0c;以便能更轻松的实现…

【白菜基础】初识蛋白质组学

这篇文章写得很详细&#xff0c;可以仔细阅读&#xff1a;干货&#xff01;5000字基于质谱的蛋白质组详细总结|蛋白质组 1. 蛋白质组学的概念 蛋白质组&#xff08;Proteome&#xff09;&#xff1a;一个细胞或组织由整个基因组表达的全部蛋白质。 蛋白质组学&#xff08;Pr…

Longan Pi 3H简约外壳分享

Longan Pi 3H简约外壳分享 因为购买了Longan Pi 3H&#xff0c;它用的是H618&#xff0c;我记得香橙派zero2w 也是这个芯片&#xff0c;不过我很喜欢sipeed的这个风格&#xff0c;特别好看&#xff0c;而且该有的都有&#xff0c;不说废话了&#xff0c;直接上图片和文件 链接…

redis群集有三种模式

目录 redis群集有三种模式 redis群集有三种模式 分别是主从同步/复制、哨兵模式、Cluster ●主从复制&#xff1a;主从复制是高可用Redis的基础&#xff0c;哨兵和集群都是在主从复制基础上实现高可用的。主从复制主要实现了数据的多机备份&#xff0c;以及对于读操作的负载均…

微信小程序使用icon图标

原因&#xff1a; 微信小程序使用fontawesome库使用icon图标&#xff0c;网上有很多教程&#xff0c;按照网上说法制作&#xff0c;引入到微信小程序中&#xff0c;但是验证成功&#xff0c;只能使用部分图标&#xff0c;结果不尽如人意。后面使用阿里巴巴开源iconfont来使用ic…

Git入门实战教程之创建版本库

一、Git简介 Git是一个分布式版本控制系&#xff0c;分层结构如下&#xff1a; Git分为四层&#xff1a; 1、工作目录 当前正在工作的项目的实际文件目录&#xff0c;我们执行命令git init时所在的地方&#xff0c;也就是我们执行一切文件操作的地方。 2、暂存区 暂存区是…

拾光坞N3 ARM 虚拟主机 i茅台项目

拾光坞N3 在Dcoker部署i茅台案例 OS&#xff1a;Ubuntu 22.04.1 LTS aarch64 cpu&#xff1a;RK3566 ram&#xff1a;2G 部署流程——》mysql——》java8——》redis——》nginx mysql # 依赖 apt update apt install -y net-tools apt install -y libaio* # 下载mysql wg…

分享10个免费高可用的GPT3.5和4.0网站并做功能测试【第一个】

1.介绍 网址&#xff1a;直接点&#xff1a;aicnn 或者 www.aicnn.cn 基于ChatGPT可以实现智能聊天、绘画生成、高清文本转语音、论文润色等多种功能&#xff0c;基于sd和mj实现的绘画功能&#xff0c;下面是功能测试&#xff1a; 博主从 1.GPT3.5是否完全免费/是否限制频率、…

【前沿模型解析】潜在扩散模 1 | LDM第一阶段-感知图像压缩总览

文章目录 0 开始~1 感知压缩的目的2 自回归编码器-解码器生成模型一览2.1 AE 自编码器2.2 VAE 变分自编码器2.3 VQ-VAE2.4 VQ-GAN 3 代码部分讲解总览 0 开始~ 从今天起呢&#xff0c;我们会剖析LDM&#xff08;潜在扩散模型&#xff09; 从去年开始&#xff0c;大量的生成模…

国内ChatGPT大数据模型

在中国&#xff0c;随着人工智能技术的迅猛发展&#xff0c;多个科技公司和研究机构已经开发出了与OpenAI的ChatGPT类似的大型语言模型。这些模型通常基于深度学习技术&#xff0c;尤其是Transformer架构&#xff0c;它们在大量的文本数据上进行训练&#xff0c;以理解和生成自…

Thinkphp5萤火商城B2C小程序源码

源码介绍 Thinkphp5萤火商城B2C小程序源码&#xff0c;是一款开源的电商系统&#xff0c;为中小企业提供最佳的新零售解决方案。采用稳定的MVC框架开发&#xff0c;执行效率、扩展性、稳定性值得信赖。 环境要求 Nginx/Apache/IIS PHP5.4 MySQL5.1 建议使用环境&#xff…

APP渗透总结

APP渗透测试和Web渗透测试本质上没有区别。目前APP应用主要分为Android和IOS&#xff0c;但是由于苹果的IOS操作系统不开源&#xff0c;所以一般对IOS系统进行渗透和反编译会比较困难&#xff0c;所以一般对APP系统进行渗透测试都是对Android进行测试。 目录 安装安卓模拟器抓…

C语言解决汉诺塔问题

背景 首先带大家了解一下汉诺塔问题 汉诺塔是一个典型的函数递归问题&#xff0c;汉诺塔描述了这样的场景&#xff0c;有三个柱子&#xff0c;A,B,C&#xff0c;A柱为起始柱&#xff0c;在A柱上面有若干大小不同的盘子&#xff0c;最下面的最大&#xff0c;最上面的最小&#x…