spring依赖注入详解(下)

news2024/11/17 10:01:47

@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> {

 @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使用的是哪个泛型,就能知道具体类型了

三、@Primary、@Priority

1、@Primary示例

定义一个主类依赖三个bean

@Component
public class UserService {

	@Autowired
	private OrderInterface orderInterface;

	public void test() {
		System.out.println(orderInterface.getClass().getSimpleName());
	}

}

public interface OrderInterface {
}

@Component
public class OrderService implements OrderInterface {

	@Bean
	@Primary
	public 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 {

	@Autowired
	private 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 {

 @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);
 }

}

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

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

相关文章

【多天线传输技术】BPSK调制信号在复高斯瑞利信道下Alamouti的误码率分析

%% [预处理] clc; clear; close all;%% [配置参数] N3000000; %数据点数&#xff08;个&#xff09; SNR_dB0:1:45; %信噪比&#xff08;dB形式&#xff09; SNR10.^(SNR_dB/10); %信噪比&#xff08;一般形式&#xff0c;Eb/N0&#xff09; Ps1; …

Linux Day10 ---Mybash

目录 一、Mybash介绍 1.1.mybash.c 打印函数 分割函数 命令函数 二、Mybash实现 2.1.打印函数 2.1.1需要使用到的功能函数 1.获取与当前用户关联的UID 2.获取与当前用户的相关信息---一个结构体&#xff08;passwd&#xff09; 3.获取主机信息 4.获取当前所处位置 5.给…

论文阅读 FOCUS-AND-DETECT: A SMALL OBJECT DETECTION FRAMEWORK FOR AERIAL IMAGES

文章目录 FOCUS-AND-DETECT: A SMALL OBJECT DETECTION FRAMEWORK FOR AERIAL IMAGESABSTRACT1 Introduction2 Related Work3 Focus-and-Detect3.1 Overview3.2 Focus Stage3.2.1 Generating Ground-Truth Boxes of Focal Regions Using Gaussian Mixture Model 3.3 Detection …

物种气候生态位动态量化与分布特征模拟

在全球气候快速变化的背景下&#xff0c;理解并预测生物种群如何应对气候变化&#xff0c;特别是它们的地理分布如何变化&#xff0c;已经变得至关重要。利用R语言进行物种气候生态位动态量化与分布特征模拟&#xff0c;不仅可以量化描述物种对环境的需求和适应性&#xff0c;预…

StableVideo:使用Stable Diffusion生成连续无闪烁的视频

使用Stable Diffusion生成视频一直是人们的研究目标&#xff0c;但是我们遇到的最大问题是视频帧和帧之间的闪烁&#xff0c;但是最新的论文则着力解决这个问题。 本文总结了Chai等人的论文《StableVideo: Text-driven consistency -aware Diffusion Video Editing》&#xff…

高性能网络模式-Reactor

事实上&#xff0c;Reactor 模式也叫Dispatcher模式&#xff0c;即I/O 多路复⽤监听事件&#xff0c;收到事件后&#xff0c;根据事件类型分配&#xff08;Dispatch&#xff09;给某个进程/线程。Reactor 模式也是一种非阻塞同步网络模式。 Reactor 模式主要由 Reactor部分和处…

Django基础3——视图函数

文章目录 一、基本了解1.1 Django内置函数1.2 http请求流程 二、HttpRequest对象&#xff08;接受客户端请求&#xff09;2.1 常用属性2.2 常用方法2.3 服务端接收URL参数2.4 QueryDict对象2.5 案例2.5.1 表单GET提交2.5.2 表单POST提交2.5.3 上传文件 三、HttpResponse对象&am…

NV PTX ISA 文档的增量说明

无它&#xff0c;维截图尔&#xff0c;汇总一下&#xff0c;找找规律&#xff1b; cuda 12.0 PTX 8.0 关键字&#xff1a; 从cuda 8.0开始&#xff1a; 显然&#xff0c;每次增量的主要因素是对应着对新的硬件功能的提炼&#xff1b;

构建 NodeJS cinema API 网关并部署到 Docker(04/4)

一、说明 构建一个微服务的电影网站&#xff0c;需要Docker、NodeJS、MongoDB&#xff0c;这样的案例您见过吗&#xff1f;如果对此有兴趣&#xff0c;您就继续往下看吧。 我们前几章的快速回顾 第一篇文章介绍了微服务架构模式&#xff0c;并讨论了使用微服务的优缺点。第二篇…

Unity报错DllNotFoundException:sqlite3

Unity项目中要使用轻型数据库sqlite&#xff0c;除了导入sqlite3.dll外&#xff0c;还需要导入Mono.Data.Sqlite.dll和System.Data.dll&#xff08;工程里或者编辑器里面有System.Data.dll时就不需要&#xff09;两个文件。 如果在编辑器中运行出现 “DllNotFoundException:sql…

pyside6最小化的核心调用代码

pyside6最小化的核心调用代码&#xff1a; 一、格式代码 你认为是 制式代码&#xff0c;下面图中的就是核心代码&#xff0c;以后就是这样记住以及使用即可 二、图形代码【生成代码】 2.1designer设计界面 2.2设计的界面转换为代码 注意图纸划线的地方&#xff0c;后续导入…

卓码软件测评简析:软件压力测试工具和流程有哪些?

在软件开发过程中&#xff0c;压力测试是非常重要的一项工作&#xff0c;它可以帮助客户评估软件系统在正常或异常负载下的性能表现。在这个领域&#xff0c;有很多不同的工具可供选择&#xff0c;每个工具具有其独特的特点和优势。那么常见的压力测试工具有哪些以及进行压力测…

外网访问家里虚拟机的两种方法

从外网访问家里虚拟机的两种方法 起因 在公司&#xff0c;当我不想干的时候就想着跑路&#xff0c;但是自己又太菜了&#xff08;饭碗要紧&#xff09;&#xff0c;所以想通过ssh登录到自己的家里一台linux上&#xff0c;去敲一敲 linux命令&#xff0c;sql命令&#xff0c;do…

Mobx在非react组件中修改数据,在ts/js中修改数据实现响应式更新

我们都之前在封装mobx作为数据存储的时候&#xff0c;使用到了useContext作为包裹&#xff0c;将store变成了一个hooks使用&#xff0c;封装代码: import React from react import UserInfo from ./user import Setting from ./seting import NoteStore from ./noteclass Stor…

WSL(centos7.0.1907.3)安装lxc

安装 1.centos的epel源提供了lxc的安装包&#xff0c;在使用epel源时首先安装epel-release包&#xff1a; yum -y install epel-release2.安装lxc软件包和依赖包 yum -y install lxc lxc-templates bridge-utils lxc-libs libcgroup libvirt 安装完成后&#xff0c;通过 lx…

centos安装redis教程

1.下载安装包 redis官网 下载最新版本redis安装包 2.上传到服务器 然后解压 解压命令 tar xzvf redis-7.2.0.tar.gz 进入文件夹 cd redis-7.2.0 执行安装编译命令 make 如果要安装到别的目录则执行 make install PREFIX/目录地址 看到如下内容则说明安装成功 如有遇到报错…

骨传导蓝牙耳机能打电话吗,骨传导蓝牙耳机别人听得到吗

时光荏苒&#xff0c;社会不断发展&#xff0c;年轻人的生活离不开一样必备神器——耳机。而在众多耳机中&#xff0c;骨传导耳机备受青睐。这种耳机的佩戴方式不仅方便&#xff0c;还更安全&#xff0c;能有效降低中耳炎的风险。此外&#xff0c;经过精心设计的耳机还能有效减…

再升级!PP-OCRv4多场景平均精度提升5%!

OCR方向的工程师&#xff0c;一定有在关注PaddleOCR这个项目&#xff0c;其主要推荐的PP-OCR算法更是被国内外企业开发者广泛应用。短短几年时间&#xff0c;PP-OCR累计Star数量已超过32.2k&#xff0c;频频登上GitHub Trending和Paperswithcode日榜月榜第一&#xff0c;称它为…

Navicat for Mysql 显示 emoji 表情符号乱码问题 — 其它乱码情况都可参考

系统环境&#xff1a; 操作系统&#xff1a;MAC OS 10.11.6 MySQL&#xff1a;Server version: 5.6.21 MySQL Community Server (GPL) Navicat for MySQL: version 9.3.1 - standard 1、问题发现 在客户端执行用户注册&#xff0c;用户名包括 emoji 表情符号&#xff0c;注册完…

SpringBoot基于AOP注解方式实现Redis缓存

一、前言 Spring中的AOP&#xff08;Aspect Oriented Programming&#xff09;是基于代理的AOP实现&#xff0c;通过使用基于代理的技术&#xff0c;可以在不修改原有代码的情况下&#xff0c;对原有代码进行增强和改进。Spring AOP实现了面向切面编程的功能&#xff0c;将横切…