[Spring 原理] 依赖查找

简介: [Spring 原理] 依赖查找

在Spring框架中,依赖注入是一项非常重要的功能,它能够帮助我们解决对象之间的依赖关系。而其中的doResolveDependency方法是Spring框架中执行依赖注入的核心方法之一。本篇博客将对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);
    }
    @SneakyThrows
    private 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));
            }
        }
    }
    @SneakyThrows
    private 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));
            }
        }
    }
    @SneakyThrows
    private 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;
            }
        }
    }
    @SneakyThrows
    private 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);
        }
    }
    @SneakyThrows
    private 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 {
        @Autowired
        private Service[] serviceArray;
        @Autowired
        private List<Service> serviceList;
        @Autowired
        private ConfigurableApplicationContext applicationContext;
        @Autowired
        private 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);
        }
        @SneakyThrows
        private 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());
        }
        @SneakyThrows
        private 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());
        }
        @Data
        static class Target1 {
            @Autowired
            private Service service;
        }
        @Data
        static class Target2 {
            @Autowired
            private 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 @Autowired
      Object shortcut = descriptor.resolveShortcut(this);
      if (shortcut != null) {
        return shortcut;
      }
      Class<?> type = descriptor.getDependencyType();
      // Step 2: pre-defined value or expression, e.g. from @Value
      Object 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 map
      Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
      if (multipleBeans != null) {
        return multipleBeans;
      }
      // Step 3b: direct bean matches, possibly direct beans of type Collection / Map
      Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
      if (matchingBeans.isEmpty()) {
        // Step 3c (fallback): custom Collection / Map declarations for collecting multiple beans
        multipleBeans = resolveMultipleBeansFallback(descriptor, beanName, autowiredBeanNames, typeConverter);
        if (multipleBeans != null) {
          return multipleBeans;
        }
        // Raise exception if nothing found for required injection point
        if (isRequired(descriptor)) {
          raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
        }
        return null;
      }
      String autowiredBeanName;
      Object instanceCandidate;
      // Step 4: determine single candidate
      if (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 point
            return 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 result
      if (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 point
          raiseNoMatchingBeanFound(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方法对于理解和应用依赖注入是非常重要的。通过本篇博客的学习,相信读者对于该方法的作用和实现机制有了更深入的了解,将能够在实际项目中更好地运用依赖注入的功能。

相关文章
|
1月前
|
XML Java 开发者
Spring Boot开箱即用可插拔实现过程演练与原理剖析
【11月更文挑战第20天】Spring Boot是一个基于Spring框架的项目,其设计目的是简化Spring应用的初始搭建以及开发过程。Spring Boot通过提供约定优于配置的理念,减少了大量的XML配置和手动设置,使得开发者能够更专注于业务逻辑的实现。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,为开发者提供一个全面的理解。
31 0
|
3天前
|
NoSQL Java Redis
Spring Boot 自动配置机制:从原理到自定义
Spring Boot 的自动配置机制通过 `spring.factories` 文件和 `@EnableAutoConfiguration` 注解,根据类路径中的依赖和条件注解自动配置所需的 Bean,大大简化了开发过程。本文深入探讨了自动配置的原理、条件化配置、自定义自动配置以及实际应用案例,帮助开发者更好地理解和利用这一强大特性。
35 14
|
4月前
|
安全 Java 数据库
一天十道Java面试题----第四天(线程池复用的原理------>spring事务的实现方式原理以及隔离级别)
这篇文章是关于Java面试题的笔记,涵盖了线程池复用原理、Spring框架基础、AOP和IOC概念、Bean生命周期和作用域、单例Bean的线程安全性、Spring中使用的设计模式、以及Spring事务的实现方式和隔离级别等知识点。
|
4月前
|
Java
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
这篇文章是Spring5框架的实战教程,深入讲解了AOP的基本概念、如何利用动态代理实现AOP,特别是通过JDK动态代理机制在不修改源代码的情况下为业务逻辑添加新功能,降低代码耦合度,并通过具体代码示例演示了JDK动态代理的实现过程。
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
|
16天前
|
存储 缓存 Java
Spring面试必问:手写Spring IoC 循环依赖底层源码剖析
在Spring框架中,IoC(Inversion of Control,控制反转)是一个核心概念,它允许容器管理对象的生命周期和依赖关系。然而,在实际应用中,我们可能会遇到对象间的循环依赖问题。本文将深入探讨Spring如何解决IoC中的循环依赖问题,并通过手写源码的方式,让你对其底层原理有一个全新的认识。
38 2
|
24天前
|
Java 开发者 Spring
Spring AOP 底层原理技术分享
Spring AOP(面向切面编程)是Spring框架中一个强大的功能,它允许开发者在不修改业务逻辑代码的情况下,增加额外的功能,如日志记录、事务管理等。本文将深入探讨Spring AOP的底层原理,包括其核心概念、实现方式以及如何与Spring框架协同工作。
|
2月前
|
Java Spring 容器
Spring底层原理大致脉络
Spring底层原理大致脉络
|
2月前
|
Java Spring 容器
Spring IOC、AOP与事务管理底层原理及源码解析
【10月更文挑战第1天】Spring框架以其强大的控制反转(IOC)和面向切面编程(AOP)功能,成为Java企业级开发中的首选框架。本文将深入探讨Spring IOC和AOP的底层原理,并通过源码解析来揭示其实现机制。同时,我们还将探讨Spring事务管理的核心原理,并给出相应的源码示例。
144 9
|
3月前
|
缓存 Java Spring
手写Spring Ioc 循环依赖底层源码剖析
在Spring框架中,IoC(控制反转)是一个核心特性,它通过依赖注入(DI)实现了对象间的解耦。然而,在实际开发中,循环依赖是一个常见的问题。
46 4
|
2月前
|
XML 前端开发 Java
拼多多1面:聊聊Spring MVC的工作原理!
本文详细剖析了Spring MVC的工作原理,涵盖其架构、工作流程及核心组件。Spring MVC采用MVC设计模式,通过DispatcherServlet、HandlerMapping、Controller和ViewResolver等组件高效处理Web请求。文章还探讨了DispatcherServlet的初始化和请求处理流程,以及HandlerMapping和Controller的角色。通过理解这些核心概念,开发者能更好地构建可维护、可扩展的Web应用。适合面试准备和技术深挖
48 0