当前位置: 首页 > news >正文

spring依赖注入详解(下)

@Autowired注解依赖注入过程

一、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> {@Autowiredprotected O o;@Autowiredprotected 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使用的是哪个泛型,就能知道具体类型了

三、@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的名字&#xff0c;注意是名字&#xff0c;而不是Bean对象&#xff0c;因为我们可以根据BeanDefinition就能判断和当前type是不是匹配&#xff0c;不用生成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 自身原理之高可用

说到高可用&#xff0c;咱们在使用主机环境的时候&#xff08;非 k8s&#xff09;&#xff0c;咱做高可用有使用过这样的方式&#xff1a; 服务器做主备部署&#xff0c;当主节点和备节点同时存活的时候&#xff0c;只有主节点对外提供服务&#xff0c;备节点就等着主节点挂了…...

游乐场vr设备虚拟游乐园vr项目沉浸体验馆

在景区建设一个VR游乐场项目可以为游客提供一种新颖、刺激和沉浸式的游乐体验。提高游客的体验类型&#xff0c;以及景区的类目&#xff0c;从而可以吸引更多的人来体验。 1、市场调研&#xff1a;在决定建设VR游乐场项目之前&#xff0c;需要进行市场调研&#xff0c;了解当地…...

window10安装并使用oracle

1、现在oracle19c或者21c&#xff0c;下载链接如下 Database Software Downloads | Oracle 中国 2、安装好之后&#xff0c; 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

下载地址&#xff1a;前往黑果魏叔官网 AutoCAD是一款计算机辅助设计&#xff08;CAD&#xff09;软件&#xff0c;目前已经成为全球最受欢迎的CAD软件之一。它可以在二维和三维空间中创建精确的技术绘图&#xff0c;并且可以应用于各种行业&#xff0c;如建筑、土木工程、机械…...

Oracle 主从库目录不一致(异路径)的n种处理方案及效果

最近遇到了复制数据&#xff08;DUPLICATE TARGET DATABASE TO xxx&#xff09;的时候 Oracle 源和目标库目录不一致的问题&#xff0c;比较初级但也踩到一些坑&#xff0c;整理记录一下。主从库搭建的时候注意事项其实也类似&#xff0c;而且更通用&#xff0c;所以标题写的是…...

创建型(一) - 简单工厂模式、工厂方法模式和抽象工厂模式

本文使用了王争老师设计模式课程中的例子&#xff0c;写的很清晰&#xff0c;而且中间穿插了代码优化。 由于设计模式就是解决问题的一种思路&#xff0c;所以每个设计模式会从问题出发&#xff0c;这样比较好理解设计模式出现的意义。 一、简单工厂模式 解决问题&#xff1a…...

LeetCode3.无重复字符的最长子串

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

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

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

如何发布自己的小程序

小程序的基础内容组件 text&#xff1a; 文本支持长按选中的效果 <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领域的公司&#xff0c;他们通过构建一套完整的内容生产系统&#xff0c;革新内容创作过程&#xff0c;让用户以更低成本完成内容创作。 客户网络需求汇总 RoCE的计算网络RoCE存储网络1.不少于600端口200G以太网接入端口&#xff0c;未来可扩容至至少1280端口1.…...

Flutter性能揭秘之RepaintBoundary

作者&#xff1a;xuyisheng Flutter会在屏幕上绘制Widget。如果一个Widget的内容需要更新&#xff0c;那就只能重绘了。尽管如此&#xff0c;Flutter同样会重新绘制一些Widget&#xff0c;而这些Widget的内容仍有部分未被改变。这可能会影响应用程序的执行性能&#xff0c;有时…...

29.Netty源码之服务端启动:创建EventLoopSelector流程

highlight: arduino-light 源码篇&#xff1a;从 Linux 出发深入剖析服务端启动流程 通过前几章课程的学习&#xff0c;我们已经对 Netty 的技术思想和基本原理有了初步的认识&#xff0c;从今天这节课开始我们将正式进入 Netty 核心源码学习的课程。希望能够通过源码解析的方式…...

Kotllin实现ArrayList的基本功能

前言 上次面试时&#xff0c;手写ArrayList竟然翻车&#xff0c;忘了里面的扩容与缩容的条件&#xff0c;再次实现一次&#xff0c;加深印象 源码讲了什么 实现了List列表和RandomAccess随机访问接口List具有增删改查功能&#xff0c;RandomAccess支持下标访问内部是一个扩容…...

C++的初步介绍,以及C++与C的区别

C和C的区别 C又称C plus plus&#xff0c;且C语言是对C语言的扩充&#xff0c;几乎支持所有的C语言语法&#xff1b;C语言&#xff1a;面向过程的语言&#xff08;注重问题的解决方法和算法&#xff09;C&#xff1a;面向对象的语言 &#xff08;求解的方法&#xff09;面向对…...

JDK 核心jar之 rt.jar

一、JDK目录展示 二、rt.jar 简介 2.1.JAR释义 在软件领域&#xff0c;JAR文件&#xff08;Java归档&#xff0c;英语&#xff1a;Java Archive&#xff09;是一种软件包文件格式&#xff0c;通常用于聚合大量的Java类文件、相关的元数据和资源&#xff08;文本、图片等&…...

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语言中标识符由字母数字和_(下划线&#xff09;组成&#xff0c;并且只能以字母和_开头。 举几个例子&#xff1a;abc, _, _123, a123。 关键字 关键字和保留字都不建议用作变量名&#xff1a; Go语言中有25个关键字。 此…...

HTML 语义化

目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案&#xff1a; 语义化标签&#xff1a; <header>&#xff1a;页头<nav>&#xff1a;导航<main>&#xff1a;主要内容<article>&#x…...

OpenLayers 可视化之热力图

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 热力图&#xff08;Heatmap&#xff09;又叫热点图&#xff0c;是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...

linux之kylin系统nginx的安装

一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源&#xff08;HTML/CSS/图片等&#xff09;&#xff0c;响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址&#xff0c;提高安全性 3.负载均衡服务器 支持多种策略分发流量…...

解锁数据库简洁之道:FastAPI与SQLModel实战指南

在构建现代Web应用程序时&#xff0c;与数据库的交互无疑是核心环节。虽然传统的数据库操作方式&#xff08;如直接编写SQL语句与psycopg2交互&#xff09;赋予了我们精细的控制权&#xff0c;但在面对日益复杂的业务逻辑和快速迭代的需求时&#xff0c;这种方式的开发效率和可…...

关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案

问题描述&#xff1a;iview使用table 中type: "index",分页之后 &#xff0c;索引还是从1开始&#xff0c;试过绑定后台返回数据的id, 这种方法可行&#xff0c;就是后台返回数据的每个页面id都不完全是按照从1开始的升序&#xff0c;因此百度了下&#xff0c;找到了…...

MMaDA: Multimodal Large Diffusion Language Models

CODE &#xff1a; https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA&#xff0c;它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构&#xf…...

视频字幕质量评估的大规模细粒度基准

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用&#xff0c;因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型&#xff08;VLMs&#xff09;在字幕生成方面…...

安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)

船舶制造装配管理现状&#xff1a;装配工作依赖人工经验&#xff0c;装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书&#xff0c;但在实际执行中&#xff0c;工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...

排序算法总结(C++)

目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指&#xff1a;同样大小的样本 **&#xff08;同样大小的数据&#xff09;**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...

LangChain知识库管理后端接口:数据库操作详解—— 构建本地知识库系统的基础《二》

这段 Python 代码是一个完整的 知识库数据库操作模块&#xff0c;用于对本地知识库系统中的知识库进行增删改查&#xff08;CRUD&#xff09;操作。它基于 SQLAlchemy ORM 框架 和一个自定义的装饰器 with_session 实现数据库会话管理。 &#x1f4d8; 一、整体功能概述 该模块…...