[Spring 原理] 依赖查找

在Spring框架中,依赖注入是一项非常重要的功能,它能够帮助我们解决对象之间的依赖关系。而其中的doResolveDependency方法是Spring框架中执行依赖注入的核心方法之一。本篇博客将对doResolveDependency方法进行详细介绍,帮助读者更好地理解和应用依赖注入。

文章目录

    • 模拟`doResolveDependency`
      • 整体步骤
        • 获取 `DependencyDescriptor`
        • 获取注入的参数类型
        • 获取候选者
        • 获取最终 `bean`
    • 多个 `bean`符合注入条件的处理方式
    • `doResolveDependency`源码
  • 总结

在这里插入图片描述

模拟doResolveDependency

package com.example.autowired;import lombok.SneakyThrows;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ContextAnnotationAutowireCandidateResolver;
import org.springframework.stereotype.Component;import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;@Configuration
public class Autowired2Application {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Autowired2Application.class);DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 1. 数组类型");testArray(beanFactory);System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 2. List 类型");testList(beanFactory);System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 3. applicationContext");testApplicationContext(beanFactory);System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 4. 泛型");testGeneric(beanFactory);System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 5. @Qualifier");testQualifier(beanFactory);}@SneakyThrowsprivate static void testQualifier(DefaultListableBeanFactory beanFactory) {DependencyDescriptor dd5 = new DependencyDescriptor(Target.class.getDeclaredField("service"), true);Class<?> type = dd5.getDependencyType();ContextAnnotationAutowireCandidateResolver resolver = new ContextAnnotationAutowireCandidateResolver();resolver.setBeanFactory(beanFactory);for (String name : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, type)) {BeanDefinition bd = beanFactory.getMergedBeanDefinition(name);// DependencyDescriptor 对象中包含了 @Qualifier 注解信息if (resolver.isAutowireCandidate(new BeanDefinitionHolder(bd, name), dd5)) {System.out.println(name);System.out.println(dd5.resolveCandidate(name, type, beanFactory));}}}@SneakyThrowsprivate static void testGeneric(DefaultListableBeanFactory beanFactory) {DependencyDescriptor dd4 = new DependencyDescriptor(Target.class.getDeclaredField("dao"), true);Class<?> type = dd4.getDependencyType();ContextAnnotationAutowireCandidateResolver resolver = new ContextAnnotationAutowireCandidateResolver();resolver.setBeanFactory(beanFactory);// 循环所有的目标类型 Bean 名称for (String name : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, type)) {BeanDefinition bd = beanFactory.getMergedBeanDefinition(name);// 对比 BeanDefinition 的泛型与 DependencyDescriptor 的泛型是否匹配if (resolver.isAutowireCandidate(new BeanDefinitionHolder(bd, name), dd4)) {System.out.println(name);System.out.println(dd4.resolveCandidate(name, type, beanFactory));}}}@SneakyThrowsprivate static void testApplicationContext(DefaultListableBeanFactory beanFactory) {DependencyDescriptor dd3 = new DependencyDescriptor(Target.class.getDeclaredField("applicationContext"), true);Field resolvableDependencies = DefaultListableBeanFactory.class.getDeclaredField("resolvableDependencies");resolvableDependencies.setAccessible(true);Map<Class<?>, Object> dependencies = (Map<Class<?>, Object>) resolvableDependencies.get(beanFactory);
//        dependencies.forEach((k, v) -> {
//            System.out.println("key:" + k + " value: " + v);
//        });for (Map.Entry<Class<?>, Object> entry : dependencies.entrySet()) {// 左边类型                      右边类型if (entry.getKey().isAssignableFrom(dd3.getDependencyType())) {System.out.println(entry.getValue());break;}}}@SneakyThrowsprivate static void testList(DefaultListableBeanFactory beanFactory) {DependencyDescriptor dd2 = new DependencyDescriptor(Target.class.getDeclaredField("serviceList"), true);if (List.class.equals(dd2.getDependencyType())) {// 获取泛型信息Class<?> resolve = dd2.getResolvableType().getGeneric().resolve();System.out.println(resolve);List<Object> list = new ArrayList<>();String[] names = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, resolve);for (String name : names) {Object bean = dd2.resolveCandidate(name, resolve, beanFactory);list.add(bean);}System.out.println(list);}}@SneakyThrowsprivate static void testArray(DefaultListableBeanFactory beanFactory) {DependencyDescriptor dd1 = new DependencyDescriptor(Target.class.getDeclaredField("serviceArray"), true);if (dd1.getDependencyType().isArray()) {// 获取数组中的元素类型Class<?> componentType = dd1.getDependencyType().getComponentType();System.out.println(componentType);String[] names = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, componentType);List<Object> beans = new ArrayList<>();for (String name : names) {System.out.println(name);Object bean = dd1.resolveCandidate(name, componentType, beanFactory);beans.add(bean);}Object array = beanFactory.getTypeConverter().convertIfNecessary(beans, dd1.getDependencyType());System.out.println(array);}}static class Target {@Autowiredprivate Service[] serviceArray;@Autowiredprivate List<Service> serviceList;@Autowiredprivate ConfigurableApplicationContext applicationContext;@Autowiredprivate Dao<Teacher> dao;@Autowired@Qualifier("service2")private Service service;}interface Dao<T> {}@Component("dao1")static class Dao1 implements Dao<Student> {}@Component("dao2")static class Dao2 implements Dao<Teacher> {}static class Student {}static class Teacher {}interface Service {}@Component("service1")static class Service1 implements Service {}@Component("service2")static class Service2 implements Service {}@Component("service3")static class Service3 implements Service {}
}

输出

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 1. 数组类型
interface com.example.autowired.Autowired2Application$Service
service3
service2
service1
[Lcom.example.autowired.Autowired2Application$Service;@1dac5ef
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 2. List 类型
interface com.example.autowired.Autowired2Application$Service
[com.example.autowired.Autowired2Application$Service3@175b9425, com.example.autowired.Autowired2Application$Service2@3098cf3b, com.example.autowired.Autowired2Application$Service1@610f7aa]
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 3. applicationContext
org.springframework.context.annotation.AnnotationConfigApplicationContext@6e3c1e69, started on Thu Dec 21 23:00:38 CST 2023
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 4. 泛型
dao2
com.example.autowired.Autowired2Application$Dao2@71c3b41
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 5. @Qualifier
service2
com.example.autowired.Autowired2Application$Service2@3098cf3b

整体步骤

获取 DependencyDescriptor
DependencyDescriptor dd3 = new DependencyDescriptor(Target.class.getDeclaredField("applicationContext"), true);
获取注入的参数类型

类型的可能值

  1. 数组
  2. 列表
  3. 特殊 bean, 如 ConfigurableApplicationContext
  4. 范型
  5. 接口类型(多个实现)
Class<?> type = dd3.getDependencyType();
获取候选者
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, type)
获取最终 bean
Object bean = dd3.resolveCandidate(name, resolve, beanFactory);

多个 bean符合注入条件的处理方式

package com.example.autowired;
import lombok.Data;
import lombok.SneakyThrows;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;@Configuration
public class Autowired3Application {public static void main(String[] args) throws NoSuchFieldException {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Autowired3Application.class);DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();context.register(Target1.class);context.register(Target2.class);testPrimary(beanFactory);testDefault(beanFactory);}@SneakyThrowsprivate static void testDefault(DefaultListableBeanFactory beanFactory) {DependencyDescriptor dd = new DependencyDescriptor(Target2.class.getDeclaredField("service3"), false);Class<?> type = dd.getDependencyType();for (String name : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, type)) {if (name.equals(dd.getDependencyName())) {System.out.println("default: " + name);}}Target2 bean = beanFactory.getBean(Target2.class);System.out.println("testDefault >>>>>>" + bean.getService3());}@SneakyThrowsprivate static void testPrimary(DefaultListableBeanFactory beanFactory) {DependencyDescriptor dd = new DependencyDescriptor(Target1.class.getDeclaredField("service"), false);Class<?> type = dd.getDependencyType();for (String name : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, type)) {if (beanFactory.getMergedBeanDefinition(name).isPrimary()) {System.out.println("primary: " + name);}}Target1 bean = beanFactory.getBean(Target1.class);System.out.println("testPrimary >>>>> " + bean.getService());}@Datastatic class Target1 {@Autowiredprivate Service service;}@Datastatic class Target2 {@Autowiredprivate Service service3;}interface Service {}@Component("service1")static class Service1 implements Service {}@Primary@Component("service2")static class Service2 implements Service {}@Component("service3")static class Service3 implements Service {}}

输出

primary: service2
testPrimary >>>>> com.example.autowired.Autowired3Application$Service2@6f45df59
default: service3
testDefault >>>>>>com.example.autowired.Autowired3Application$Service2@6f45df59

优先级: @Qualifier> @Primary > 名称

doResolveDependency源码

	public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);try {// Step 1: pre-resolved shortcut for single bean match, e.g. from @AutowiredObject shortcut = descriptor.resolveShortcut(this);if (shortcut != null) {return shortcut;}Class<?> type = descriptor.getDependencyType();// Step 2: pre-defined value or expression, e.g. from @ValueObject value = getAutowireCandidateResolver().getSuggestedValue(descriptor);if (value != null) {if (value instanceof String strValue) {String resolvedValue = resolveEmbeddedValue(strValue);BeanDefinition bd = (beanName != null && containsBean(beanName) ?getMergedBeanDefinition(beanName) : null);value = evaluateBeanDefinitionString(resolvedValue, bd);}TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());try {return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());}catch (UnsupportedOperationException ex) {// A custom TypeConverter which does not support TypeDescriptor resolution...return (descriptor.getField() != null ?converter.convertIfNecessary(value, type, descriptor.getField()) :converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));}}// Step 3a: multiple beans as stream / array / standard collection / plain mapObject multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);if (multipleBeans != null) {return multipleBeans;}// Step 3b: direct bean matches, possibly direct beans of type Collection / MapMap<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);if (matchingBeans.isEmpty()) {// Step 3c (fallback): custom Collection / Map declarations for collecting multiple beansmultipleBeans = resolveMultipleBeansFallback(descriptor, beanName, autowiredBeanNames, typeConverter);if (multipleBeans != null) {return multipleBeans;}// Raise exception if nothing found for required injection pointif (isRequired(descriptor)) {raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);}return null;}String autowiredBeanName;Object instanceCandidate;// Step 4: determine single candidateif (matchingBeans.size() > 1) {autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);if (autowiredBeanName == null) {if (isRequired(descriptor) || !indicatesArrayCollectionOrMap(type)) {// Raise exception if no clear match found for required injection pointreturn descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);}else {// In case of an optional Collection/Map, silently ignore a non-unique case:// possibly it was meant to be an empty collection of multiple regular beans// (before 4.3 in particular when we didn't even look for collection beans).return null;}}instanceCandidate = matchingBeans.get(autowiredBeanName);}else {// We have exactly one match.Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();autowiredBeanName = entry.getKey();instanceCandidate = entry.getValue();}// Step 5: validate single resultif (autowiredBeanNames != null) {autowiredBeanNames.add(autowiredBeanName);}if (instanceCandidate instanceof Class) {instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);}Object result = instanceCandidate;if (result instanceof NullBean) {if (isRequired(descriptor)) {// Raise exception if null encountered for required injection pointraiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);}result = null;}if (!ClassUtils.isAssignableValue(type, result)) {throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());}return result;}finally {ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);}}

总结

通过本篇博客的介绍,我们了解到doResolveDependency方法是Spring框架中执行依赖注入的关键方法。该方法的主要作用是通过遍历候选的依赖项集合,找到与要注入的类型匹配的依赖项,并完成注入操作。具体而言,该方法会根据依赖项的注解或类型,通过解析BeanDefinition并利用Bean工厂来获取对应的实例对象,并将其注入到目标对象中。

在博客中,我们详细介绍了doResolveDependency方法的执行流程和关键步骤,包括对依赖项的解析、对象实例化、依赖关系的处理和注入操作的实现。同时,我们也提到了该方法在不同情况下的应用场景和一些注意事项。

通过深入了解doResolveDependency方法,读者可以更好地理解Spring框架中依赖注入的实现原理,并在实际开发中更加灵活和准确地使用依赖注入功能。同时,读者也能够更好地理解和调试Spring框架中出现的依赖注入相关的问题。

总之,掌握doResolveDependency方法对于理解和应用依赖注入是非常重要的。通过本篇博客的学习,相信读者对于该方法的作用和实现机制有了更深入的了解,将能够在实际项目中更好地运用依赖注入的功能。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【数据结构】五、数组与广义表

目录 一、定义 二、计算数组元素地址 三、稀疏矩阵快速转置 稀疏矩阵的表示 稀疏矩阵快速转置 四、广义表 一、定义 我们所熟知的一维、二维数组的元素是原子类型。广义表中的元素除了原子类型还可以是另一个线性表。当然所有的数据元素仍然属于同一类型。 这里的数组可…

DMR与DPMR以及DMR的分层

数字移动无线电 (DMR) 和数字专用移动无线电 (dPMR) 是数字对讲机中使用的流行通信技术。 与传统模拟无线电相比&#xff0c;这两种技术都提供了改进的音频质量、增强的安全功能和增加的网络容量。 但是&#xff0c;DMR 和 dPMR 无线电之间使用的技术存在重大差异&#xff…

逻辑回归(LR,Logistic Regression)算法 简介

逻辑回归&#xff08;LR&#xff0c;Logistic Regression&#xff09;算法 当线性回归的预测结果&#xff0c;由于受到个别极端数值的影响而不准的时候, 可以用逻辑回归来解决. 逻辑回归模型的输出只能在 0 到 1 之间&#xff0c;也就是表达一个事件会发生的概率&#xff0c;…

阿里云赵大川:弹性计算推理解决方案拯救 AIGC 算力危机

云布道师 本篇文章围绕弹性计算推理解决方案 DeepGPU 实例如何支持 Stable Diffusion 文生图推理、Stable Diffusion 推理演示示例等相关话题展开。 赵大川 阿里云弹性计算高级技术专家 GPU 云服务器推理解决方案的提出背景 随着 AIGC 时代的到来&#xff0c;两个重要应用应…

使用@jiaminghi/data-view实现一个数据大屏

<template><div class"content bg"><!-- 全局容器 --><!-- <dv-full-screen-container> --><!-- 第二行 --><div class"module-box" style"align-items: start; margin-top: 10px"><!-- 左 -->…

Bash 脚本学习

文章目录 1、脚本编程基础2. 变量2.1 参数变量的引用2.2 环境变量 3 条件判断语句3.1 if 语句3.1.1 语法3.1.2 案例 3.2 case 语句3.2.1 语法3.2.2 案例 3.3 判断参数说明 4 循环语句4.1 for 循环4.1.1 语法4.1.2 案例 4.2 while循环4.2.1 语法4.2.2 案例4. 3 循环总结 5. 函数…

【网络技术设备安全】BGP 基础与概述-2-中转 AS 中的 IBGP 路由传递

0x01 中转 AS 中的 IBGP 路由传递 参考该图&#xff1a; 上图&#xff0c;我们模拟一个 1.0 的路由通过 AS 65101 来传递 1&#xff1a;通过图可知&#xff0c;A 与 B 之间的 Peer 为 EBGP&#xff0c;B 与 E 之间为 Peer IBGP&#xff0c;E 与 F 之间为 Peer EBGP 邻接 2&a…

Mac查询本机ip地址

Mac系统版本和网络配置不同&#xff0c;可能会有一些细微差别。 一、 使用系统偏好设置 1、点击屏幕左上角的Apple图标&#xff0c;选择“系统偏好设置”。 2、点击“网络”。 3、 在左侧选择当前连接的网络&#xff08;如Wi-Fi或以太网&#xff09;&#xff0c;在右侧界面&a…

CMake项目管理

背景 目前看到很过很多框架&#xff0c;很好奇大家如何从头搭建一个C的库&#xff0c;这里简单介绍一个基本模板. 参考&#xff1a;https://zhuanlan.zhihu.com/p/631257434 目录组织 假如项目名称叫project&#xff0c; 一般可以按照下面的方式组织代码&#xff0c;这里可以…

双向A*算法-python

GitHub - LittleFox99/B_A_star: Bidirectional A Star 其中a&#xff0c;b分别为双向A*搜索的权重 #-*- coding:utf-8 -*- # Time : 2020/11/11 1:21 下午 # Author : LittleFox99 # File : a_star.py # 参考&#xff1a; # https://blog.csdn.net/lustyoung/article/d…

2 Pandas之Series

Pandas数据结构简介 Pandas可以处理以下三种数据&#xff1a; SeriesDataFramePanel 这些数据建立在NumPy上&#xff0c;故可以快速运行。 纬度描述 更好的理解这些数据结构的方式是将高维数据看作是低维数据的容器。例如&#xff0c;DataFrame是Series的容器&#xff0c;P…

java并发编程七 无锁解决加锁问题

文章目录 问题提出解决思路-锁解决思路-无锁 CAS 与 volatile慢动作分析volatile为什么无锁效率高CAS 的特点 问题提出 有如下需求&#xff0c;保证 account.withdraw 取款方法的线程安全 package cn.onenewcode; import java.util.ArrayList; import java.util.List; interf…