[Spring 原理] 依赖查找

2023-12-22 08:36:58

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

文章来源:https://blog.csdn.net/qq_45704048/article/details/135142875
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。