Spring依赖注入源码解析(下)
创始人
2024-03-06 23:36:12
0

文章目录

  • 前言
  • 本章目标
  • resolveDependency—解决依赖查找
    • 1、doResolveDependency
    • 2、@Autowreid寻找依赖流程图
  • 依赖注入完整流程图


前言

在上一篇文章Spring依赖注入源码解析(上)中,主要介绍了寻找注入点、以及注入源码分析


本章目标

这一篇主要源码解析在注入过程中,如何找到属性需要注入的依赖对象


resolveDependency—解决依赖查找

上篇文章有看到inject注入方法这里,调用到了resolveDependency方法,这个方法也在属性填充时,非常重要的核心源码之一,用于解决属性的解决依赖查找;

@Overrideprotected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {Field field = (Field) this.member;Object value;if (this.cached) {value = resolvedCachedArgument(beanName, this.cachedFieldValue);}else {DependencyDescriptor desc = new DependencyDescriptor(field, this.required);desc.setContainingClass(bean.getClass());Set autowiredBeanNames = new LinkedHashSet<>(1);Assert.state(beanFactory != null, "No BeanFactory available");TypeConverter typeConverter = beanFactory.getTypeConverter();try {// 依赖查找,参数说明// desc:当前字段的 依赖描述对象// beanName:当前填充类的名称// typeConverter: spring内部常用的类型转换器value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);}catch (BeansException ex) {throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);}// ....这里主要解析resolveDependency ,所以其他源码略过

调用DefaultListableBeanFactory#resolveDependency

@Override@Nullablepublic Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,@Nullable Set autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());// 看类型是不是Optionalif (Optional.class == descriptor.getDependencyType()) {// 是的话则包装成Optional返回return createOptionalDependency(descriptor, requestingBeanName);}// 是ObjectFactory或者ObjectProvider类else if (ObjectFactory.class == descriptor.getDependencyType() ||ObjectProvider.class == descriptor.getDependencyType()) {// 则直接创建一个ObjectFactory对象return new DependencyObjectProvider(descriptor, requestingBeanName);}// 判断是否为javax.inject.Providerelse if (javaxInjectProviderClass == descriptor.getDependencyType()) {// 是的话则创建return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);}// 日常开发基本都是走else这个逻辑else {// 判断有没有lazy注解Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(descriptor, requestingBeanName);if (result == null) {// 没有@Lazy注解,则调用doResolveDependency,真正处理依赖的方法result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);}return result;}}

不含Lazy的时候为null,会直接会去执行doResolveDependency
在这里插入图片描述

属性orderService头上添加@Lazy注解后,不会进if,会直接返回代理对象
在这里插入图片描述


1、doResolveDependency

@Nullablepublic Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,@Nullable Set autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {// 获取当前线程的缓存值,并且把当前依赖描述对象缓存起来InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);try {// 默认实现返回NullObject shortcut = descriptor.resolveShortcut(this);if (shortcut != null) {return shortcut;}// 获取描述对象的类型Class type = descriptor.getDependencyType();// 调用QualifierAnnotationAutowireCandidateResolver#getSuggestedValue方法,查看是否存在@Value注解Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);if (value != null) {// 如果是String类型if (value instanceof String) {// 获取value内部内容值String strVal = resolveEmbeddedValue((String) value);// 获取beanName的Bean定义BeanDefinition bd = (beanName != null && containsBean(beanName) ?getMergedBeanDefinition(beanName) : null);// 获取value的内容,如解析表达式#{“xxx”} 、${"xxx"}等value = evaluateBeanDefinitionString(strVal, bd);}// 获取类型转换器TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());try {// 根据属性的值转换为指定的类型return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());}catch (UnsupportedOperationException ex) {return (descriptor.getField() != null ?converter.convertIfNecessary(value, type, descriptor.getField()) :converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));}}// 判断类型是不是数组、集合、map等(如Map,List等写法),有的话就直接返回Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);if (multipleBeans != null) {return multipleBeans;}// 从beanDefinitionNames找到匹配的类型Map matchingBeans = findAutowireCandidates(beanName, type, descriptor);if (matchingBeans.isEmpty()) {// 如果是Required,并且没有找到就报错if (isRequired(descriptor)) {raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);}// 不是Required,则返回nullreturn null;}String autowiredBeanName;Object instanceCandidate;// 如果有多个匹配属性if (matchingBeans.size() > 1) {// 这里会查看他是不是有@Primary 、@Priority,这里主要是处理优先级 autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);if (autowiredBeanName == null) {如果是Required,并且没有找到就报错if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);}else {// 不是Required,则返回nulreturn null;}}instanceCandidate = matchingBeans.get(autowiredBeanName);}else {Map.Entry entry = matchingBeans.entrySet().iterator().next();autowiredBeanName = entry.getKey();instanceCandidate = entry.getValue();}if (autowiredBeanNames != null) {// 添加到需要注入的集合里autowiredBeanNames.add(autowiredBeanName);}if (instanceCandidate instanceof Class) {// 如果是一个class,则调佣getBean,生成beaninstanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);}Object result = instanceCandidate;if (result instanceof NullBean) {if (isRequired(descriptor)) {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);}}

2、@Autowreid寻找依赖流程图

在这里插入图片描述


依赖注入完整流程图

在这里插入图片描述

相关内容

热门资讯

前端-session、jwt 目录:   (1)session (2&#x...
linux入门---制作进度条 了解缓冲区 我们首先来看看下面的操作: 我们首先创建了一个文件并在这个文件里面添加了...
关于测试,我发现了哪些新大陆 关于测试 平常也只是听说过一些关于测试的术语,但并没有使用过测试工具。偶然看到编程老师...
前缀和与对数器与二分法 1. 前缀和 假设有一个数组,我们想大量频繁的去访问L到R这个区间的和,...
nodejs:本地安装nvm实... 一、背景-使用不同版本node的原因 vue3+ts、nuxt3版本,node...
JAVA集合知识整理 Java集合知识整理 HashMap相关 HashMap的底层数据结构:jdk1.8之...
无刷直流电机介绍及单片机控制实... 无刷直流电机介绍及单片机控制实例前言基本概念优势与劣势使用寿命基本结构使用单片机控制实例电子调速器&...
fwdiary(2) dp2 1.传纸条  AcWing 275. 传纸条 - AcWing 走两条路,走一条最大的...
常用的DOS命令 常用的DOS命令 DOS(Disk Operating System,磁...
<C++> 类和对象(下) 1.const成员函数将const修饰的“成员函数”称之为const成员函数,cons...