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个关键字。 此…...
基于算法竞赛的c++编程(28)结构体的进阶应用
结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...
利用ngx_stream_return_module构建简易 TCP/UDP 响应网关
一、模块概述 ngx_stream_return_module 提供了一个极简的指令: return <value>;在收到客户端连接后,立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量(如 $time_iso8601、$remote_addr 等)&a…...
【入坑系列】TiDB 强制索引在不同库下不生效问题
文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...
sqlserver 根据指定字符 解析拼接字符串
DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...
全志A40i android7.1 调试信息打印串口由uart0改为uart3
一,概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本:2014.07; Kernel版本:Linux-3.10; 二,Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01),并让boo…...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
SAP学习笔记 - 开发26 - 前端Fiori开发 OData V2 和 V4 的差异 (Deepseek整理)
上一章用到了V2 的概念,其实 Fiori当中还有 V4,咱们这一章来总结一下 V2 和 V4。 SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务),代理中间件(ui5-middleware-simpleproxy)-CSDN博客…...
HarmonyOS运动开发:如何用mpchart绘制运动配速图表
##鸿蒙核心技术##运动开发##Sensor Service Kit(传感器服务)# 前言 在运动类应用中,运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据,如配速、距离、卡路里消耗等,用户可以更清晰…...
Webpack性能优化:构建速度与体积优化策略
一、构建速度优化 1、升级Webpack和Node.js 优化效果:Webpack 4比Webpack 3构建时间降低60%-98%。原因: V8引擎优化(for of替代forEach、Map/Set替代Object)。默认使用更快的md4哈希算法。AST直接从Loa…...
Razor编程中@Html的方法使用大全
文章目录 1. 基础HTML辅助方法1.1 Html.ActionLink()1.2 Html.RouteLink()1.3 Html.Display() / Html.DisplayFor()1.4 Html.Editor() / Html.EditorFor()1.5 Html.Label() / Html.LabelFor()1.6 Html.TextBox() / Html.TextBoxFor() 2. 表单相关辅助方法2.1 Html.BeginForm() …...
