Spring依赖注入 - Resource注解详解及与Autowired注解区别

news2024/9/21 1:39:01

上篇博客我们讲了Spring中的自动注入(byName,byType)和@Autowired注解的工作原理以及源码分析,那么这次,我们来分析还没讲完的,剩下的核心的方法:

@Nullable
Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
		@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException;

该方法表示,传入一个依赖描述(DependencyDescriptor),该方法会根据该依赖描述从BeanFactory中找出对应的唯一的一个Bean对象。

findAutowireCandidates()实现

  1. 找出BeanFactory中类型为type的所有的Bean的名字,注意是名字,而不是Bean对象,因为我们可以根据BeanDefinition就能判断和当前type是不是匹配,不用生成Bean对象
  2. 把resolvableDependencies中key为type的对象找出来并添加到result中
  3. 遍历根据type找出的beanName,判断当前beanName对应的Bean是不是能够被自动注入
  4. 先判断beanName对应的BeanDefinition中的autowireCandidate属性,如果为false,表示不能用来进行自动注入,如果为true则继续进行判断
  5. 判断当前type是不是泛型,如果是泛型是会把容器中所有的beanName找出来的,如果是这种情况,那么在这一步中就要获取到泛型的真正类型,然后进行匹配,如果当前beanName和当前泛型对应的真实类型匹配,那么则继续判断
  6. 如果当前DependencyDescriptor上存在@Qualifier注解,那么则要判断当前beanName上是否定义了Qualifier,并且是否和当前DependencyDescriptor上的Qualifier相等,相等则匹配
  7. 经过上述验证之后,当前beanName才能成为一个可注入的,添加到result中

关于依赖注入中泛型注入的实现

首先在Java反射中,有一个Type接口,表示类型,具体分类为:

  1. raw types:也就是普通Class
  2. parameterized types:对应ParameterizedType接口,泛型类型
  3. array types:对应GenericArrayType,泛型数组
  4. type variables:对应TypeVariable接口,表示类型变量,也就是所定义的泛型,比如T、K
  5. primitive types:基本类型,int、boolean

大家可以好好看看下面代码所打印的结果:

public class TypeTest<T> {

	private int i;
	private Integer it;
	private int[] iarray;
	private List list;
	private List<String> slist;
	private List<T> tlist;
	private T t;
	private T[] tarray;

	public static void main(String[] args) throws NoSuchFieldException {

		test(TypeTest.class.getDeclaredField("i"));
		System.out.println("=======");
		test(TypeTest.class.getDeclaredField("it"));
		System.out.println("=======");
		test(TypeTest.class.getDeclaredField("iarray"));
		System.out.println("=======");
		test(TypeTest.class.getDeclaredField("list"));
		System.out.println("=======");
		test(TypeTest.class.getDeclaredField("slist"));
		System.out.println("=======");
		test(TypeTest.class.getDeclaredField("tlist"));
		System.out.println("=======");
		test(TypeTest.class.getDeclaredField("t"));
		System.out.println("=======");
		test(TypeTest.class.getDeclaredField("tarray"));

	}

	public static void test(Field field) {

		if (field.getType().isPrimitive()) {
			System.out.println(field.getName() + "是基本数据类型");
		} else {
			System.out.println(field.getName() + "不是基本数据类型");
		}

		if (field.getGenericType() instanceof ParameterizedType) {
			System.out.println(field.getName() + "是泛型类型");
		} else {
			System.out.println(field.getName() + "不是泛型类型");
		}

		if (field.getType().isArray()) {
			System.out.println(field.getName() + "是普通数组");
		} else {
			System.out.println(field.getName() + "不是普通数组");
		}

		if (field.getGenericType() instanceof GenericArrayType) {
			System.out.println(field.getName() + "是泛型数组");
		} else {
			System.out.println(field.getName() + "不是泛型数组");
		}

		if (field.getGenericType() instanceof TypeVariable) {
			System.out.println(field.getName() + "是泛型变量");
		} else {
			System.out.println(field.getName() + "不是泛型变量");
		}

	}

}

Spring中,但注入点是一个泛型时,也是会进行处理的,比如:

@Component
public class UserService extends BaseService<OrderService, StockService> {

	public void test() {
		System.out.println(o);
	}

}

public class BaseService<O, S> {

	@Autowired
	protected O o;

	@Autowired
	protected S s;
}

  1. Spring扫描时发现UserService是一个Bean
  2. 那就取出注入点,也就是BaseService中的两个属性o、s
  3. 接下来需要按注入点类型进行注入,但是o和s都是泛型,所以Spring需要确定o和s的具体类型。
  4. 因为当前正在创建的是UserService的Bean,所以可以通过userService.getClass().getGenericSuperclass().getTypeName()获取到具体的泛型信息,比如com.zhouyu.service.BaseService<com.zhouyu.service.OrderService, com.zhouyu.service.StockService>
  5. 然后再拿到UserService的父类BaseService的泛型变量: for (TypeVariable<? extends Class<?>> typeParameter : userService.getClass().getSuperclass().getTypeParameters()) { System._out_.println(typeParameter.getName()); }
  6. 通过上面两段代码,就能知道,o对应的具体就是OrderService,s对应的具体类型就是StockService
  7. 然后再调用oField.getGenericType()就知道当前field使用的是哪个泛型,就能知道具体类型了

@Qualifier的使用

定义两个注解:

@Target({ElementType.TYPE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier("random")
public @interface Random {
}
@Target({ElementType.TYPE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier("roundRobin")
public @interface RoundRobin {
}

定义一个接口和两个实现类,表示负载均衡:

public interface LoadBalance {
	String select();
}

@Component
@Random
public class RandomStrategy implements LoadBalance {

	@Override
	public String select() {
		return null;
	}
}
@Component
@RoundRobin
public class RoundRobinStrategy implements LoadBalance {

	@Override
	public String select() {
		return null;
	}
}

使用:

@Component
public class UserService  {

	@Autowired
	@RoundRobin
	private LoadBalance loadBalance;

	public void test() {
		System.out.println(loadBalance);
	}

}

@Resource

@Resource注解底层工作流程图:
在这里插入图片描述

两者区别

● autoworied是springframework提供的,resoure是JSR-250提供的,它是java标准,巨大部分框架都支持
● auto默认byType先通过类型查询,在匹配名字,resource默认byname先通过名字查询
● auto能用在构造器、方法、参数、成员变量和注解上,resouce只能用在类、成员变量和方法上

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

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

相关文章

0.96寸OLED液晶显示器

在日常的小项目制作中我们经常会接触到OLED液晶显示器&#xff0c;本文介绍0.96寸液晶显示器的基本原理&#xff0c;辅助我们后续的小项目开发 OLED被称为有机激光二极管&#xff0c;也被称为有机激光显示&#xff0c;OLED采用有机材料涂层和玻璃基板&#xff0c;当有电流通过…

#Chrome扩展程序开发教程--02:Hello Extensions

#Chrome扩展程序开发教程--02&#xff1a;Hello Extensions 引言1、Hello Extensions2、固定扩展程序3、重新加载扩展程序4、查看扩展程序的输出 引言 本系列博客旨在带来最新的Chrome扩展程序开发入门教程。 1、Hello Extensions 本节博客中&#xff0c;笔者将带领读者创建一个…

C++附加篇: 空间适配器

"我有时难过&#xff0c;却还有些抚慰和感动。" 一、我们来谈谈空间适配器 (1) 什么是空间配置器? STL的六大组件&#xff0c;容器、算法、迭代器、适配器、仿函数&#xff0c;最后一个也就是"空间适配器"。 所谓"空间适配器"&#x…

轻松掌握K8S使用kubectl操作配置文件挂载ConfigMap和密钥Secret知识点05

1、挂载应用配置文件配置集ConfigMap 当有许多应用如redis、mysql&#xff0c;希望将它的配置文件挂载出去&#xff0c;以便随时修改&#xff0c;可以用ConfigMap配置集 具体用法查看使用命令行操作里的 3、ConfigMap配置集实战 2、挂载应用配置文件的敏感信息Secret Secre…

JAVA开发运维(云基础设备监控)

在大型的商用系统中&#xff0c;经常需要监控云设备的健康状态&#xff0c;性能情况&#xff0c;流量数据等。及时发现系统问题&#xff0c;及时修复&#xff0c;以确保系统的高可用。检查云资源的工作内容主要包括基础监控、主动拨测、用户体验、APM监控、指标体系、业务分析、…

Java运行时内存管理

一、前言 希望能在我们平时开发写代码的时候&#xff0c;能够知道当前写的这段代码&#xff0c;内存方面是如何分配的。 我们深知&#xff0c;一个Java程序员在很多时候根本不用操心内存的释放&#xff0c;而是依靠JVM去管理&#xff0c;以前写C代码的时候&#xff0c;却要时刻…

SAP 自定义生产订单状态

1、生产订单通常系统有一整套订单状态&#xff0c;做PP的各位同学都应该知道。 CRTD状态 REL已下达 CNF已报工 DLV已入库 TECO技术性完成 等等状态这里就不在罗列了&#xff0c;可以自行在生产订单中看到 2、这篇文章主要是在生产订单系统外&#xff0c;在自定义一套状态。这个…

Spring更简单的读取和存储Bean(基于注解)

目录 ①从Maven中央仓库获取spring-context和spring-beans的依赖&#xff0c;将依赖引入到pom.xml中 ②配置扫描路径 ③添加注解存储Bean对象&#xff08;可以使用5大类注解和方法注解&#xff09; 类注解&#xff08;写在类上&#xff0c;作用于类上&#xff09; Contro…

【致敬未来的攻城狮计划】— 连续打卡第十一天:FSP固件库开发点亮第一个灯。

系列文章目录 1.连续打卡第一天&#xff1a;提前对CPK_RA2E1是瑞萨RA系列开发板的初体验&#xff0c;了解一下 2.开发环境的选择和调试&#xff08;从零开始&#xff0c;加油&#xff09; 3.欲速则不达&#xff0c;今天是对RA2E1 基础知识的补充学习。 4.e2 studio 使用教程 5.…

leetcode刷题--辅助工具

idea插件 插件商店搜索leetcode&#xff0c;可以让你利用idea调试leetcode的题目 插件首先需要填写用户名密码登录&#xff0c;登录上就可以在idea搜题、做题、提交等 注意&#xff1a; 一些版本登录可能登录失败&#xff0c;解决方法是换leetcode地址为leetcode.cn。 有些可…

通过用户名密码认证保障 MQTT 接入安全

认证是一种安全措施&#xff0c;用于识别用户并验证他们是否有权访问系统或服务器。它能够保护系统免受未经授权的访问&#xff0c;确保只有经过验证的用户才能使用系统。 物联网连接万物&#xff0c;对试图访问基础设施的用户进行认证至关重要。未经授权的访问存在重大的安全…

数据保管库的数据质量错误

数据保管库的数据质量错误 在过去的几年里&#xff0c;数据仓库发生了巨大的变化&#xff0c;但这并不意味着支撑健全数据架构的基本原理需要被抛在窗外。事实上&#xff0c;随着GDPR等数据法规的日益严格以及对优化技术成本的重新重视&#xff0c;我们现在看到了“Data Vault…

设计模式之备忘录模式(C++)

作者&#xff1a;翟天保Steven 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 一、备忘录模式是什么&#xff1f; 备忘录模式是一种行为型的软件设计模式&#xff0c;在不破坏封装的前提下&#xff0c;获取一个…

OpenCV实例(八)行人跟踪

OpenCV实例&#xff08;八&#xff09;行人跟踪 1.目标跟踪概述2.基于背景差分检测运动物体2.1 实现基本背景差分器2.2 使用MOG背景差分器2.3 使用卡尔曼滤波器寻找运动趋势 3.跟踪行人 作者&#xff1a;Xiou 1.目标跟踪概述 目标跟踪是对摄像头视频中的移动目标进行定位的过…

数据结构与算法基础-学习-20-查找之散列表(HASH TABLE)

目录 目录 一、基本思想 二、术语 1、散列方法 2、散列函数 3、散列表 4、冲突 5、同义词 三、如何减少哈希冲突 四、构造散列函数需考虑的情况 五、散列函数的构造方法 1、直接定址法 2、除留余数法 六、如何处理哈希冲突 1、开地址法 2、拉链法 七、散列表查…

【微服务笔记16】微服务组件之Gateway服务网关基础环境搭建、高可用网关环境搭建

这篇文章&#xff0c;主要介绍微服务组件之Gateway服务网关基础环境搭建、高可用网关环境搭建。 目录 一、Gateway服务网关 1.1、什么是Gateway 1.2、Gateway基础环境搭建 &#xff08;1&#xff09;基础环境介绍 &#xff08;2&#xff09;引入依赖 &#xff08;3&#…

快速上手Navicat~

众所周知&#xff0c; Navicat是一款轻量级的用于MySQL连接和管理的工具&#xff0c;非常好用&#xff0c;使用起来方便快捷&#xff0c;简洁。下面我会简单的讲一下其安装以及使用的方法。并且会附带相关的永久安装教程。 简介 一般我们在开发过程中是离不开数据库的&#xf…

【Unity VR开发】结合VRTK4.0:添加对象追随器

语录&#xff1a; 我已经准备好了足够挡雨的伞&#xff0c;可是却迟迟没有等到雨的到来&#xff0c;这样的尴尬只是我漫长人生中的小插曲罢了。 前言&#xff1a; 对象追随器的目的是让一个或多个游戏对象跟随场景中的另一个对象&#xff0c;而无需将游戏对象嵌套在彼此之下。 …

『pyqt5 从0基础开始项目实战』13. 打包生成exe(保姆级图文)

目录 项目源码打包exe打开闪退需要db文件夹总结 欢迎关注 『pyqt5 从0基础开始项目实战』 专栏&#xff0c;持续更新中 欢迎关注 『pyqt5 从0基础开始项目实战』 专栏&#xff0c;持续更新中 项目源码 请查阅专栏上文获取源码 ## 安装库包 python pip install pyinstaller ![…

Stable Diffusion的原理

CSDN-markdown语法之怎样使用LaTeX语法编写数学公式 参考视频&#xff1a;【diffusion】扩散模型详解&#xff01;原理代码&#xff01; 用一颗桃树为你讲清楚 知识点&#xff1a;AI绘图原理 Diffusion扩散模型 Windows深度学习环境搭建&#xff1a;Windows深度学习环境搭建 …