正确使用@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.mzph.cn/news/799209.shtml

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

相关文章

【Android】apk安装报错:包含病毒: a.gray.BulimiaTGen.f

​ 有时候apk安装或者更新时&#xff0c;显示&#xff1a;[高风险]包含病毒: a.gray.BulimiaTGen.f这种bug&#xff1b; 原因&#xff1a;这是手机管家误报病毒。 处理方法&#xff1a;我看网上其他资料可以进行申诉&#xff0c;也可以进行apk加固&#xff0c;我这边尝试用360…

无参数绕过RCE

一.什么是无参数 顾名思义&#xff0c;就是只使用函数&#xff0c;且函数不能带有参数&#xff0c;这里有种种限制&#xff1a;比如我们选择的函数必须能接受其括号内函数的返回值&#xff1b;使用的函数规定必须参数为空或者为一个参数等 无参数题目特征 if(; preg_replace…

基于小程序+ssm实现的悬赏信息发布系统

作者主页&#xff1a;Java码库 主营内容&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app等设计与开发。 收藏点赞不迷路 关注作者有好处 文末获取源码 技术选型 【后端】&#xff1a;Java 【框架】&#xff1a;ssm 【…

2024年妈妈杯数学建模MathorCup数学建模思路B题思路解析+参考成品

1 赛题思路 (赛题出来以后第一时间在群内分享&#xff0c;点击下方群名片即可加群) 2 比赛日期和时间 报名截止时间&#xff1a;2024年4月11日&#xff08;周四&#xff09;12:00 比赛开始时间&#xff1a;2024年4月12日&#xff08;周五&#xff09;8:00 比赛结束时间&…

数字人解决方案——Champ单个视频单张图像生成可控且一致的人体视频生成

概述 Champ是阿里巴巴集团、南京大学和复旦大学的研究团队共同提出了一种创新的人体动画生成技术&#xff0c;Champ能够在仅有一段原始视频和一张静态图片的情况下&#xff0c;激活图片中的人物&#xff0c;使其按照视频中的动作进行动态表现&#xff0c;极大地促进了虚拟主播…

【Emgu CV教程】10.12、Moments()函数计算轮廓矩和质心

文章目录 一、概念介绍1.矩2.矩能干什么3.矩函数 二、演示1.原始素材2.代码3.运行结果 一、概念介绍 1.矩 矩&#xff0c;英文叫moment&#xff0c;是一个数学中的概念&#xff0c;以下的解释来自百度百科&#xff1a; 是不是看不懂&#xff0c;没关系&#xff0c;数学基础不…

mysqldump: Got error: 1049: Unknown database ‘root‘ when selecting the datab

1.问题描述 MySQL版本号&#xff1a;MySQL Server 8.3MySQL持久化到处数据库结构及数据 mysqldump: Got error: 1049: Unknown database root when selecting the datab2.问题解决 cmd 切换本地路径 cd /d D:\Program Files\MySQL\MySQL Server 8.3\bin执行数据库备份命令 …

Java智慧校园系统源码 微信小程序+电子班牌

Java智慧校园系统源码 微信小程序电子班牌 通过设备管理对百纳智慧校园的智慧班牌以及百纳智慧屏&#xff08;校牌&#xff09;进行统一集中式管理&#xff0c;支持浏览所有设备的基本信息以及在离线状态&#xff0c;支持添加设备、设备一键开关机、一键重启、设置节假日开关机…

Java单链表和LinkedList的实现

一、单链表的实现 无头单向非循环链表 定义异常用于判断所给位置是否合法 public class IndexNotLegal extends RuntimeException{public IndexNotLegal(){}public IndexNotLegal(String smg){super(smg);} } class ListNode中包含当前节点的值和下一个节点指向 实现链表的…

nginx支持的多种负载均衡策略

目录 1.轮询&#xff08;默认&#xff09; 2. ip_hash 3. 加权轮询&#xff08;weight&#xff09; 4. fair&#xff08;第三方&#xff09; 5. 最少连接&#xff08;least_conn&#xff09; 1.轮询&#xff08;默认&#xff09; 将请求依次分配给每个服务器&#xff0c;确…

SpringCloud Alibaba Sentinel 实现熔断功能

一、前言 接下来是开展一系列的 SpringCloud 的学习之旅&#xff0c;从传统的模块之间调用&#xff0c;一步步的升级为 SpringCloud 模块之间的调用&#xff0c;此篇文章为第十六篇&#xff0c;即使用 Sentinel 实现熔断功能。 二、 Ribbon 系列 首先我们新建两个服务的提供者…

[StartingPoint][Tier1]Pennyworth

Important Jenkins是一个用于自动化构建、测试和部署软件项目的开源持续集成和持续部署&#xff08;CI/CD&#xff09;工具。它允许开发团队自动执行和监控在软件开发过程中的重复性任务&#xff0c;例如构建代码、运行测试、部署应用程序等。Jenkins提供了一个易于使用的Web界…

基于R语言BIOMOD2模型的物种分布模拟

随着生物多样性全球大会的举办&#xff0c;不论是管理机构及科研单位、高校都在积极准备&#xff0c;根据国家林草局最新工作指示&#xff0c;我国将积极整合、优化自然保护地&#xff0c;加快推进国家公园体制试点&#xff0c;构建以国家公园为主体的自然保护地体系。针对我国…

Spring 如何优雅的灵活的Http重试

1、背景说明 在互联网时代&#xff0c; 不同系统之间大多数是通过http调用&#xff0c;调用过程中会超时、异常等过种问题。为了保证业务稳定&#xff0c;http 重试是常用方案。下面列举几种方案。 2、Http重试方案介绍 2.1 传统方案 1、使用传统的递归调用&#xff0c;实现方…

SQL 注入之 Windows/Docker 环境 SQLi-labs 靶场搭建!

在安全测试领域&#xff0c;SQL注入是一种常见的攻击方式&#xff0c;通过应用程序的输入执行恶意SQL查询&#xff0c;从而绕过认证和授权&#xff0c;可以窃取、篡改或破坏数据库中的数据。作为安全测试学习者&#xff0c;如果你要练习SQL注入&#xff0c;在未授权情况下直接去…

深入浅出 -- 系统架构之负载均衡Nginx实现高可用

一、Nginx的高可用 线上如果采用单个节点的方式部署Nginx&#xff0c;难免会出现天灾人祸&#xff0c;比如系统异常、程序宕机、服务器断电、机房爆炸、地球毁灭....哈哈哈&#xff0c;夸张了。但实际生产环境中确实存在隐患问题&#xff0c;由于Nginx作为整个系统的网关层接入…

anylabeling使用和安装

源码地址&#xff1a; git clone https://github.com/vietanhdev/anylabeling.git Auto Labeling with Segment Anything Youtube Demo: https://www.youtube.com/watch?v5qVJiYNX5KkDocumentation: https://anylabeling.nrl.ai Features: Image annotation for polygon, r…

利用Leaflet + React:构建WEBGIS

React是 Facebook 开发的一个开源库&#xff0c;用于构建用户界面。就其本身而言&#xff0c;Leaflet是一个用于将地图发布到网络的JavaScript 库。这两个工具的组合很简单&#xff0c;允许您创建动态网络地图。在本文中&#xff0c;我们将看到这种组合的一些特征以及一些简单的…

多输入多输出 | Matlab实现OOA-BP鱼鹰算法优化BP神经网络多输入多输出预测

多输入多输出 | Matlab实现OOA-BP鱼鹰算法优化BP神经网络多输入多输出预测 目录 多输入多输出 | Matlab实现OOA-BP鱼鹰算法优化BP神经网络多输入多输出预测预测效果基本介绍程序设计往期精彩参考资料 预测效果 基本介绍 多输入多输出 | Matlab实现OOA-BP鱼鹰算法优化BP神经网络…

java数据结构与算法刷题-----LeetCode367. 有效的完全平方数

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 文章目录 自实现Math.sqrt()函数&#xff1a;牛顿迭代法 自实现Math.sqrt(…