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个关键字。 此…...
jenkins使用
安装插件 maven publish over ssh publish over ssh 会将打包后的jar包,通过ssh推送到指定的服务器上,,在jenkins中设置,推送后脚本,实现自动部署jar包,, 装了这个插件之后,可以在项…...
多线程基础篇(包教包会)
文章目录 一、第一个多线程程序1.Jconsole观察线程2.线程休眠-sleep 二、创建线程三、Thread类及常见方法1. Thread 的常见构造方法2. Thread 的几个常见属性3. 启动线程 - start4. 中断线程5. 等待一个线程 四、线程状态五、线程安全问题(synchronized)(重点&#…...
Android/Java中,各种数据类型之间的互相转换,给出各种实例,附上中文注释
目录 1.字符串(String)转整数(int): 2.整数(int)转字符串(String): 3.字符串(String)转浮点数(float)&…...
机器学习知识点总结:什么是EM(最大期望值算法)
什么是EM(最大期望值算法) 在现实生活中,苹果百分百是苹果,梨百分白是梨。 生活中还有很多事物是概率分布,比如有多少人结了婚,又有多少人有工作, 如果我们想要调查人群中吸大麻者的比例呢?敏感问题很难得…...
漏洞挖掘和安全审计的技巧与策略
文章目录 漏洞挖掘:发现隐藏的弱点1. 源代码审计:2. 黑盒测试:3. 静态分析工具: 安全审计:系统的全面评估1. 渗透测试:2. 代码审计:3. 安全策略审查: 代码示例:SQL注入漏…...
[SpringBoot3]Web服务
五、Web服务 基于浏览器的B/S结构应用十分流行。SpringBoot非常适合Web应用开发,可以使用嵌入式Tomcat、Jetty、Undertow或Netty创建一个自包含的HTTP服务器。一个SpringBoot的Web应用能够自己独立运行,不依赖需要安装的Tomcat、Jetty等。SpringBoot可以…...
构建系统自动化-autoreconf
autoreconf简介 autoreconf是一个GNU Autotools工具集中的一个命令,用于自动重新生成构建系统的配置脚本和相关文件。 Autotools是一组用于自动化构建系统的工具,包括Autoconf、Automake和Libtool。它们通常用于跨平台的软件项目,以便在不同…...
Mysql之InnoDB和MyISAM的区别
InnoDB和MyISAM是MySQL数据库中两种常见的存储引擎,它们在功能和性能方面有一些明显的区别。下面是它们之间的详细解释和说明: 底层数据 存数据的时候,MyISAM是数据和索引分开存储,分为MYD和MYI 而InnoDB是数据即索引࿰…...
Unity 之 Transform.Translate 实现局部坐标系中进行平移操作的方法
文章目录 Translate 默认使用局部坐标也可以转换成世界坐标 Translate 默认使用局部坐标 在Unity中,Transform.Translate是用于在游戏对象的局部坐标系中进行平移操作的方法。这意味着它将游戏对象沿着其自身的轴进行移动,而不是世界坐标轴。这在实现物…...
PostgreSQL Error: sorry, too many clients already
Error PG的默认最大连接数是100. 如果超过100就会报错sorry, too many clients already Find show max_connections; SELECT COUNT(*) from pg_stat_activity; SELECT * FROM pg_stat_activity;Solution 提高最大连接数 ALTER SYSTEM SET max_connections 然后重启pg查看…...
网站建设中的思想和算法/济南seo网站优化
File(文件、路径)public static void main(String[] args) throws IOException {//构造方法 无法判断 路径是否存在win下文件夹名称不区分大小写 文件与文件夹不能重名File f new File("D:\a"); //(文件/文件夹)对象//File f new File("D:" File.sepa…...
海口网站建设哪家专业/百度百家号登录入口
有时需要在代码中对文件或者文件夹 进行删除,或者添加 导入的包:import os,shutil 主要涉及到三个函数 1、os.path.exists(path) 判断一个目录是否存在 2、os.makedirs(path) 多层创建目录 3、os.mkdir(path) 创建目录 1 新建文件夹2 import os,shutil3 …...
店铺出租转让信息网站建设多少钱/百度sem竞价推广pdf
前言 介于上一篇 「今日头条」前端面试题和思路解析 中提到的 async/await,让我想起了之前写过的一篇文章,在此做个分享。它细说了什么是async函数,以及其相较于 Promise 的优势。 温故而知新,正文开始。 async 函数是什么&#x…...
政府门户网站建设管理/下载百度软件
1、吞吐率 简单的说吞吐率就是指在一指定时间内由一处传输到另一处或被处理的数据量。以太网吞吐率的单位为"兆比特每秒"或"Mb/s"。...
家居网站开发项目计划书/网络推广怎么做效果好
IBM SPSS Statistics为用户提供了三种相关性分析的方法,分别是双变量分析、偏相关分析和距离分析,三种相关分析方法各针对不同的数据情况,接下来我们将为大家介绍如何使用SPSS相关性分析中的距离分析。 一、数据简述 距离分析和其他两类相关…...
日本网站欣赏/宁海关键词优化怎么优化
一、需求:有这么一张表前四个属性当作联合主键需要把该表所有的行在前端以表格形式显示出来,要求activityId相同时合并成一行,activityCode相同时,合并一行,activityVersion相同时也合并一行。类似这种:二、…...