在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);
获取注入的参数类型
类型的可能值
- 数组
- 列表
- 特殊
bean
, 如ConfigurableApplicationContext
- 范型
- 接口类型(多个实现)
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方法对于理解和应用依赖注入是非常重要的。通过本篇博客的学习,相信读者对于该方法的作用和实现机制有了更深入的了解,将能够在实际项目中更好地运用依赖注入的功能。