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寻找依赖流程图

在这里插入图片描述


依赖注入完整流程图

在这里插入图片描述

相关内容

热门资讯

AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWR报告解读 WORKLOAD REPOSITORY PDB report (PDB snapshots) AW...
AWS管理控制台菜单和权限 要在AWS管理控制台中创建菜单和权限,您可以使用AWS Identity and Access Ma...
​ToDesk 远程工具安装及... 目录 前言 ToDesk 优势 ToDesk 下载安装 ToDesk 功能展示 文件传输 设备链接 ...
群晖外网访问终极解决方法:IP... 写在前面的话 受够了群晖的quickconnet的小水管了,急需一个新的解决方法&#x...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
Azure构建流程(Power... 这可能是由于配置错误导致的问题。请检查构建流程任务中的“发布构建制品”步骤,确保正确配置了“Arti...