spring依赖注入详解(下)
@Autowired注解依赖注入过程
一、findAutowireCandidates()实现
- 找出BeanFactory中类型为type的所有的Bean的名字,注意是名字,而不是Bean对象,因为我们可以根据BeanDefinition就能判断和当前type是不是匹配,不用生成Bean对象
- 把resolvableDependencies中key为type的对象找出来并添加到result中
- 遍历根据type找出的beanName,判断当前beanName对应的Bean是不是能够被自动注入
- 先判断beanName对应的BeanDefinition中的autowireCandidate属性,如果为false,表示不能用来进行自动注入,如果为true则继续进行判断
- 判断当前type是不是泛型,如果是泛型是会把容器中所有的beanName找出来的,如果是这种情况,那么在这一步中就要获取到泛型的真正类型,然后进行匹配,如果当前beanName和当前泛型对应的真实类型匹配,那么则继续判断
- 如果当前DependencyDescriptor上存在@Qualifier注解,那么则要判断当前beanName上是否定义了Qualifier,并且是否和当前DependencyDescriptor上的Qualifier相等,相等则匹配
- 经过上述验证之后,当前beanName才能成为一个可注入的,添加到result中
二、关于依赖注入中泛型注入的实现
首先在Java反射中,有一个Type接口,表示类型,具体分类为:
- raw types:也就是普通Class
- parameterized types:对应ParameterizedType接口,泛型类型
- array types:对应GenericArrayType,泛型数组
- type variables:对应TypeVariable接口,表示类型变量,也就是所定义的泛型,比如T、K
- 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> {@Autowiredprotected O o;@Autowiredprotected S s;
}
- Spring扫描时发现UserService是一个Bean
- 那就取出注入点,也就是BaseService中的两个属性o、s
- 接下来需要按注入点类型进行注入,但是o和s都是泛型,所以Spring需要确定o和s的具体类型。
- 因为当前正在创建的是UserService的Bean,所以可以通过
userService.getClass().getGenericSuperclass().getTypeName()
获取到具体的泛型信息,比如com.zhouyu.service.BaseService<com.zhouyu.service.OrderService, com.zhouyu.service.StockService>
- 然后再拿到UserService的父类BaseService的泛型变量:
for (TypeVariable<? extends Class<?>> typeParameter : userService.getClass().getSuperclass().getTypeParameters()) { System._out_.println(typeParameter.getName()); }
- 通过上面两段代码,就能知道,o对应的具体就是OrderService,s对应的具体类型就是StockService
- 然后再调用
oField.getGenericType()
就知道当前field使用的是哪个泛型,就能知道具体类型了
三、@Primary、@Priority
1、@Primary示例
定义一个主类依赖三个bean
@Component
public class UserService {@Autowiredprivate OrderInterface orderInterface;public void test() {System.out.println(orderInterface.getClass().getSimpleName());}}public interface OrderInterface {
}@Component
public class OrderService implements OrderInterface {@Bean@Primarypublic OrderInterface order() {return new OrderService2();}
}@Component
public class OrderService1 implements OrderInterface {}public class OrderService2 implements OrderInterface {}
打印最后注入到属性的值
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);UserService userService = (UserService) applicationContext.getBean("userService");userService.test();
打印结果:OrderService2
会对使用@Primary注解的bean注入依赖的属性或对应方法中
2、@Priority示例
@Component
public class UserService {@Autowiredprivate OrderInterface orderInterface;public void test() {System.out.println(orderInterface.getClass().getSimpleName());}}public interface OrderInterface {
}@Component
@Priority(3)
public class OrderService implements OrderInterface {}@Component
@Priority(1)
public class OrderService1 implements OrderInterface {}@Component
@Priority(4)
public class OrderService2 implements OrderInterface {}
打印最后注入到属性的值
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);UserService userService = (UserService) applicationContext.getBean("userService");userService.test();
打印结果:OrderService1
会对使用@Priority注解的类设置的值最小注入到对应属性或方法参数中
四、@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 {@Overridepublic String select() {return null;}
}@Component
@RoundRobin
public class RoundRobinStrategy implements LoadBalance {@Overridepublic String select() {return null;}
}
使用:
@Component
public class UserService {@Autowired@RoundRobinprivate LoadBalance loadBalance;public void test() {System.out.println(loadBalance);}}
相关文章:

spring依赖注入详解(下)
Autowired注解依赖注入过程 一、findAutowireCandidates()实现 找出BeanFactory中类型为type的所有的Bean的名字,注意是名字,而不是Bean对象,因为我们可以根据BeanDefinition就能判断和当前type是不是匹配,不用生成Bean对象把re…...
python的dataframe常用处理方法
import pandas as pdclass DataFrameProcessor:staticmethoddef sort_by_column(df, by_column, ascendingTrue):"""根据指定列对DataFrame进行排序。Parameters:df (pd.DataFrame): 要排序的DataFrame。by_column (str): 要排序的列名。ascending (bool): True…...

k8s 自身原理之高可用
说到高可用,咱们在使用主机环境的时候(非 k8s),咱做高可用有使用过这样的方式: 服务器做主备部署,当主节点和备节点同时存活的时候,只有主节点对外提供服务,备节点就等着主节点挂了…...

游乐场vr设备虚拟游乐园vr项目沉浸体验馆
在景区建设一个VR游乐场项目可以为游客提供一种新颖、刺激和沉浸式的游乐体验。提高游客的体验类型,以及景区的类目,从而可以吸引更多的人来体验。 1、市场调研:在决定建设VR游乐场项目之前,需要进行市场调研,了解当地…...
window10安装并使用oracle
1、现在oracle19c或者21c,下载链接如下 Database Software Downloads | Oracle 中国 2、安装好之后, 2.1PL/SQL连接方式 命令窗口输入sqlplus conn as sysdba 2.2DBeaver连接 输入IP、 端口默认1521 数据库默认是ORCL 用户名是system 角色是N…...

[Mac软件]AutoCAD 2024 for Mac(cad2024) v2024.3.61.182中文版支持M1/M2/intel
下载地址:前往黑果魏叔官网 AutoCAD是一款计算机辅助设计(CAD)软件,目前已经成为全球最受欢迎的CAD软件之一。它可以在二维和三维空间中创建精确的技术绘图,并且可以应用于各种行业,如建筑、土木工程、机械…...
Oracle 主从库目录不一致(异路径)的n种处理方案及效果
最近遇到了复制数据(DUPLICATE TARGET DATABASE TO xxx)的时候 Oracle 源和目标库目录不一致的问题,比较初级但也踩到一些坑,整理记录一下。主从库搭建的时候注意事项其实也类似,而且更通用,所以标题写的是…...
创建型(一) - 简单工厂模式、工厂方法模式和抽象工厂模式
本文使用了王争老师设计模式课程中的例子,写的很清晰,而且中间穿插了代码优化。 由于设计模式就是解决问题的一种思路,所以每个设计模式会从问题出发,这样比较好理解设计模式出现的意义。 一、简单工厂模式 解决问题:…...

LeetCode3.无重复字符的最长子串
虽然是一道中等题,但我5分钟就写完了,而且是看完题就知道怎么写,这一看就知道双指针,一个左一个右,右指针往后移如果没有重复的长度1;如果有重复的,左指针往右移,那如何判断重复呢&a…...

鲁图中大许少辉博士八一新书《乡村振兴战略下传统村落文化旅游设计》山东省图书馆典藏
鲁图中大许少辉博士八一新书《乡村振兴战略下传统村落文化旅游设计》山东省图书馆典藏...

如何发布自己的小程序
小程序的基础内容组件 text: 文本支持长按选中的效果 <text selectable>151535313511</text> rich-text: 把HTML字符串渲染为对应的UI <rich-text nodes"<h1 stylecolor:red;>123</h1>"></rich-text> 小程序的…...

【微服务】spring 条件注解从使用到源码分析详解
目录 一、前言 二、spring 条件注解概述 2.1 条件注解Conditional介绍 2.2 Conditional扩展注解 2.2.1 Conditional扩展注解汇总 三、spring 条件注解案例演示 3.1 ConditionalOnBean 3.2 ConditionalOnMissingBean 3.2.1 使用在类上 3.2.2 使用场景补充 3.3 Condit…...

客户案例:高性能、大规模、高可靠的AIGC承载网络
客户是一家AIGC领域的公司,他们通过构建一套完整的内容生产系统,革新内容创作过程,让用户以更低成本完成内容创作。 客户网络需求汇总 RoCE的计算网络RoCE存储网络1.不少于600端口200G以太网接入端口,未来可扩容至至少1280端口1.…...

Flutter性能揭秘之RepaintBoundary
作者:xuyisheng Flutter会在屏幕上绘制Widget。如果一个Widget的内容需要更新,那就只能重绘了。尽管如此,Flutter同样会重新绘制一些Widget,而这些Widget的内容仍有部分未被改变。这可能会影响应用程序的执行性能,有时…...
29.Netty源码之服务端启动:创建EventLoopSelector流程
highlight: arduino-light 源码篇:从 Linux 出发深入剖析服务端启动流程 通过前几章课程的学习,我们已经对 Netty 的技术思想和基本原理有了初步的认识,从今天这节课开始我们将正式进入 Netty 核心源码学习的课程。希望能够通过源码解析的方式…...
Kotllin实现ArrayList的基本功能
前言 上次面试时,手写ArrayList竟然翻车,忘了里面的扩容与缩容的条件,再次实现一次,加深印象 源码讲了什么 实现了List列表和RandomAccess随机访问接口List具有增删改查功能,RandomAccess支持下标访问内部是一个扩容…...
C++的初步介绍,以及C++与C的区别
C和C的区别 C又称C plus plus,且C语言是对C语言的扩充,几乎支持所有的C语言语法;C语言:面向过程的语言(注重问题的解决方法和算法)C:面向对象的语言 (求解的方法)面向对…...

JDK 核心jar之 rt.jar
一、JDK目录展示 二、rt.jar 简介 2.1.JAR释义 在软件领域,JAR文件(Java归档,英语:Java Archive)是一种软件包文件格式,通常用于聚合大量的Java类文件、相关的元数据和资源(文本、图片等&…...
el-form表单验证:只在点击保存时校验(包含select、checkbox、radio)
1、input类型 input类型 在el-input里加入:validate-event"false" <el-form-item label"活动名称" prop"name"><el-input v-model"ruleForm.name" :validate-event"false"></el-input> </el-form-i…...
Golang基本语法(上)
1. 变量与常量 Golang 中的标识符与关键字 标识符 Go语言中标识符由字母数字和_(下划线)组成,并且只能以字母和_开头。 举几个例子:abc, _, _123, a123。 关键字 关键字和保留字都不建议用作变量名: Go语言中有25个关键字。 此…...

【2025年】解决Burpsuite抓不到https包的问题
环境:windows11 burpsuite:2025.5 在抓取https网站时,burpsuite抓取不到https数据包,只显示: 解决该问题只需如下三个步骤: 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...

PL0语法,分析器实现!
简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...
数据库分批入库
今天在工作中,遇到一个问题,就是分批查询的时候,由于批次过大导致出现了一些问题,一下是问题描述和解决方案: 示例: // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...
Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换
目录 关键点 技术实现1 技术实现2 摘要: 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式(自动驾驶、人工驾驶、远程驾驶、主动安全),并通过实时消息推送更新车…...
第7篇:中间件全链路监控与 SQL 性能分析实践
7.1 章节导读 在构建数据库中间件的过程中,可观测性 和 性能分析 是保障系统稳定性与可维护性的核心能力。 特别是在复杂分布式场景中,必须做到: 🔍 追踪每一条 SQL 的生命周期(从入口到数据库执行)&#…...

Proxmox Mail Gateway安装指南:从零开始配置高效邮件过滤系统
💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:「storms…...
十九、【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建
【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建 前言准备工作第一部分:回顾 Django 内置的 `User` 模型第二部分:设计并创建 `Role` 和 `UserProfile` 模型第三部分:创建 Serializers第四部分:创建 ViewSets第五部分:注册 API 路由第六部分:后端初步测…...

MySQL的pymysql操作
本章是MySQL的最后一章,MySQL到此完结,下一站Hadoop!!! 这章很简单,完整代码在最后,详细讲解之前python课程里面也有,感兴趣的可以往前找一下 一、查询操作 我们需要打开pycharm …...
加密通信 + 行为分析:运营商行业安全防御体系重构
在数字经济蓬勃发展的时代,运营商作为信息通信网络的核心枢纽,承载着海量用户数据与关键业务传输,其安全防御体系的可靠性直接关乎国家安全、社会稳定与企业发展。随着网络攻击手段的不断升级,传统安全防护体系逐渐暴露出局限性&a…...