依赖注入逻辑
1.将injectElements(MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition收集得到)所包含的injectElement(也就是注入元素 实际对应到依赖描述器也就是注入点,字段注入对应AutowiredFieldElement/方法注入对应AutowiredMethodElement)逐一调用inject方法
2.字段注入调用resolveFieldValue 方法注入调用resolveMethodArguments(不同点在于方法注入可能存在多个参数) 但都会将需要注入的字段封装成一个DependencyDescriptor(依赖描述器) 方法注入会构建一个DependencyDescriptor[]数组用于存储每个需要注入的参数 但不管是字段注入还是方法注入每个DependencyDescriptor都会被用作调用resolveDependency方法的参数进行解析依赖(方法注入会每个参数逐一调用resolveDependency方法)
3.解析依赖过程resolveDependency
3.1.先判断注入点也就是当前DependencyDescriptor所指向的方法参数或者字段是否贴有@Lazy注解,如果有说明当前不需要被注入Spring会给它创建一个代理对象 而真正需要注入时则会调用其代理对象的getTarget方法 从而间接调用3.2步的doResolveDependency方法 如果没有@Lazy注解则直接调用3.2步
3.2.没有@Lazy调用doResolveDependency方法
3.2.1 做解析依赖过程doResolveDependency
3.2.1.1 先解析@Value(“${xxxx}”)中的xxxx 在Enviroment对象中的所有PropertyValues中查找是否有指定的key 找到则返回对应value值(Enviroment包括系统环境变量中的key value JVM启动参数-D的key value 以及配置类上的@PropertySource(“xxx.properties”)中引入的属性配置文件的keyvalue)
3.2.1.2 再将3.2.1.1解析出的value值匹配SPEL表达式 如果是普通字符串不是SPEL则会直接返回字符串 如果是SPEL会将表达式结果返回
3.2.1.2.1 如果有类型转换器(PropertyEditor/ConversionService)再尝试进行类型转换 转换完成则返回
3.2.1.3 如果上述@Value没有结果返回那么就开始判断@Autowired/@Inject注入点的注入逻辑 判断注入的对象是否为多个Bean(resolveMultipleBeans方法) 也就是注入的属性或者参数是一个 集合/Map/数组/StreamDependencyDescriptor(流式依赖描述器) 会获取泛型的具体类型然后调用findAutowireCandidates获取候选的Bean(可能是多个 存入集合/Map/数组中) 并尝试使用类型转换器进行转化(如果有,如果需要注入类型和查找出来的类型不同就需要类型转化) 如果找到了对应的multipleBeans则直接返回 否则执行3.2.1.4查找单个Bean
3.2.1.4 上述没有直接返回结果说明需要找一个类型的Bean(上述如果找到一个类型直接用集合装下 而单个Bean如果找到多个就进行过滤) 那么我们直接调用findAutowireCandidates(可能是多个 所以用Map接收 并且需要注意的是这里找出的Map中的value会有两种情况一种是单例Bean也就是在单例池中已经创建好的Bean 还一种可能性是Class对象 譬如FactoryBean中的getObjectType返回的就是一个Class对象或者还未创建在Bean定义中有beanClass属性的Bean此时还不需要先创建好Bean返回因为接下来还需要进行筛选 筛选完成后再创建Bean 避免一开始创建过多的Bean对象 如果是多个Bean后续要进行筛选其中一个进行注入)查找候选的注入Bean 如果一个候选的注入Bean都没有找到 且Bean配置了required=false则直接返回null 如果为true(默认是true)则抛出NoSuchBeanDefinitionException异常
3.2.1.4.1 根据类型查找候选的注入Bean findAutowireCandidates
3.2.1.4.1.1 先根据类型找到所有符合该类型的bean(包括单例和多例) 找到一个String[] candidateNames候选bean的名称数组 BeanFactoryUtils.beanNamesForTypeIncludingAncestors此方法极为复杂没有完全看懂
3.2.1.4.1.2 创建一个和上一步搜索出来的符合类型的Bean的个数一样长的Map(避免Map自动扩容)再判断我们注入的是否是Spring内置的几种类型(BeanFactory/ResourceLoader/ApplicationEventPublisher/ApplicationContext) 如果是则将AbstractApplicationContext.prepareBeanFactory方法中预设的几个key value存入map中
3.2.1.4.1.3 将3.2.1.4.1.1步骤的candidateNames数组迭代 判断当前符合的bean是不是自己,如果是自己则跳过(目的是如果自己注入自己,会优先选择别的同类型Bean,如果没有别的同类型Bean才会选择自己) 如果不是自己再调用isAutowireCandidate判断当前的这个候选bean是不是允许注入 如果允许则调用addCandidateEntry方法添加到上一步的map中 需要注意的是只有集合/Map/数组/StreamDependencyDescriptor(流式依赖描述器)的注入点 此处会直接调用getBean方法创建对象添加到上一步map 而普通类型对象只会将其类型Class对象添加到上一步的map中
3.2.1.4.1.3.1 是否是注入的候选项Bean流程isAutowireCandidate
3.2.1.4.1.3.1.1 先判断beanName是否在bean定义Map中 如果在则调用解析器resolver.isAutowireCandidate(holder, descriptor); 解析器为AnnotationBeanDefinitionReader构造器中设置的ContextAnnotationAutowireCandidateResolver但该类没有重写isAutowireCandidate方法所以调用其父类QualifierAnnotationAutowireCandidateResolver的isAutowireCandidate方法
3.2.1.4.1.3.1.2 QualifierAnnotationAutowireCandidateResolver.isAutowireCandidate(处理@Qualifier注解)先向上调用GenericTypeAwareAutowireCandidateResolver.isAutowireCandidate
3.2.1.4.1.3.1.3 GenericTypeAwareAutowireCandidateResolver.isAutowireCandidate(处理泛型注入)先向上调用SimpleAutowireCandidateResolver.isAutowireCandidate(处理@Bean或者xml中bean的autowireCandidate属性值判断) 作用是判断Bean的配置上是否配置有autowireCandidate 该属性的作用是如果该值设置为true(默认为true)那么该Bean允许被注入到注入点 如果该值设置为false 那么该Bean不允许被注入到注入点中
3.2.1.4.1.3.1.4 当3.2.1.4.1.3.1.3允许作为注入那么继续调用GenericTypeAwareAutowireCandidateResolver.isAutowireCandidate 该方法继续调用checkGenericTypeMatch方法去匹配泛型 如果是普通类型则直接继续往下执行 如果是泛型根据容器中是否有指定泛型类型的Bean判断匹配是否成功
3.2.1.4.1.3.1.5 如果泛型处理完成匹配到了则继续匹配是否有贴有@Qualifier注解的value值所对应的bean 如果没有则继续下一轮循环判断Bean定义Map中的下一个是否是候选Bean
3.2.1.4.1.4 如果上述步骤都没有找到非自己的候选注入Bean那么将会使用自己去匹配 如果匹配成功则认为该项(先匹配别人 匹配不到了最后匹配自己) 调用addCandidateEntry方法添加到上一步的map中 最终返回整个map map中包含了所有符合候选项的bean/beanClass
3.2.1.5 找到了Bean分两种情况
3.2.1.5.1 如果3.2.1.4找到了大于1个Bean那么再次进行筛选 调用determineAutowireCandidate方法在多个Bean中选出一个进行注入
3.2.1.5.1.1 决定注入的候选Bean过程 determineAutowireCandidate
3.2.1.5.1.1.1 先判断找到的多个候选Bean中是否有贴有@Primary注解的Bean 并且不能同时存在两个同时贴有@Primary注解的候选Bean否则抛出NoUniqueBeanDefinitionException异常 如果只找到一个则返回找到的贴有@Primary注解的Bean
3.2.1.5.1.1.2 再判断找到的多个候选Bean中是否有贴有@Priority注解的Bean 可以存在多个多个候选Bean同时贴有@Priority注解 但该注解的value属性值不能相同 否则抛出NoUniqueBeanDefinitionException异常 并且@Priority(value) value的值越小优先级越高 所以如果同时贴有@Priority(0) @Priority(1)的两个同类型Bean那么会使用@Priority(0)的Bean作为筛选后的注入Bean
3.2.1.4.1.1.3 如果上述两个注解都未找到那么则迭代所有的候选Bean的名称和注入点的属性名称进行匹配如果匹配到则使用该Bean作为注入Bean 如果一个都没找到则返回null
3.2.1.5.2 如果3.2.1.4只找到了一个Bean 那么直接用找到的这个Bean的名称作为候选Bean
3.2.1.6 如果找到是一个Class类型对象 那么直接调用getBean方法获取Bean对象并判断和我们需要注入点需要的类型是否一致 如果一致则返回该Bean对象 如果不一致则抛出BeanNotOfRequiredTypeException异常 如果找到的是一个Bean对象那么直接返回
4.最终通过反射设置给相应的注入点(反射调用方法 反射设置字段值)
相关推荐
【38】OpenCV C++实战篇——基于多项式插值的亚像素边缘定位算法
亚像素边缘定位算法实现 本文介绍了一种基于多项式插值的亚像素边缘定位算法,用于提高图像边缘检测的精度。文章首先分析了传统像素级边缘检测方法(如Canny、Sobel)的局限性,指出其在测量应用中的精度不足问题。 算法核心 梯度计算:使用8个方向模板进行卷积运算生成梯度图像 亚像素定位:采用多项式插值方法改进边缘定位精度 实现步骤: 生成8个方向的卷积模板(0°、45°、90°等) 利用filter2D函数计算各方向梯度 通过归一化处理显示梯度图像 代码特点 提供完整的C++实现代码 包含模板生成、梯度计算和
访问Controller方法前拦截添加业务处理逻辑及Spring拦截器的使用于配置
要借助Spring实现拦截器功能,可以实现HandlerInterceptor接口或者实现WebRequestInterceptor接口或者继承HandlerInterceptorAdapter适配器【建议使用】 如果实现HandlerInterceptor或者WebRequestInterceptor接口的话,三个方法必须实现,就算是空实现,也必须要放着 不管你需不需要,所以继承Handle...
商城销售运营数据集(20列,9950条记录)XLS
详情介绍:该数据集是聚焦商城精细化销售的 Excel 数据集,含 9,959 条 “订单 - 产品” 级记录、20 列核心字段,覆盖订单物流(订单 ID、日期、邮寄方式)、客户信息(ID、名称、区域、细分)、产品属性(ID、类别、子类别、名称)、销售业绩(销售额、数量、折扣、利润)四大维度,涵盖国内外多区域、多品类产品。更多说明:https://i4hhqpggqt.feishu.cn/wiki/UIF4wtD3ciJnJrkszokc1bjSnRh
Spring源码 - 深度解析@Resource依赖注入的执行逻辑
若未指定 name属性,默认使用字段名或方法名作为 Bean 名称。名称匹配失败后,尝试按类型匹配,结果必须唯一。详细流程如下:1、处理器执行入口@Resource 注入,是在 populationBean 的时候,遍历处理 InstantiationAwareBeanPostProcessor(实例化感知Bean后置处理器)去执行 postProcessProperties,其中就有。
Spring源码-依赖注入
核心方法是:populateBean整体流程:首先进行Spring自带的依赖注入,包括byName和byType,然后进行注解Autowired的注入。
spring框架底层逻辑(依赖注入和控制反转)
spring框架底层逻辑(依赖注入和控制反转)
Spring中Map类型依赖注入的使用
为了详细解释这段代码的装配过程,并编写一份详细的开发文档,我们需要从几个方面进行阐述:Spring框架的依赖注入机制、@Resource注解的作用、类型作为依赖的特别性,以及这段代码在实际开发中的应用和注意事项。
Java 依赖注入(Dependency Injection, DI)底层逻辑详解
依赖注入是一种设计模式,旨在实现控制反转(Inversion of Control,IoC)。其核心思想在于将对象的依赖关系交由外部容器(例如Spring框架)来管理,而非在对象内部直接创建这些依赖。这种做法的主要目的是降低代码间的耦合度,提升代码的可测试性和可维护性。依赖注入是Spring框架的核心特性之一,通过将对象的依赖关系交给容器管理,实现了代码的解耦和可维护性。理解依赖注入的底层逻辑,有助于更好地使用Spring框架,并解决实际开发中的复杂问题。
spring依赖注入源码分析和mongodb自带连接本地mongodb服务逻辑分析
spring依赖注入本质是一个Map结构,key是beanId,value是bean对应的Object。 autowired是怎么将定义的接口与对应的bean类建立联系? <bean name="fongo" class="com.github.fakemongo.Fongo"> <constructor-arg value="InMemoryMongo" /&...
注解和依赖注入的关系
依赖注入是一种设计模式,让你不用手动创建依赖对象,而是由框架(比如 Spring)来自动帮你注入需要的对象。比如你想用,你不用,Spring 帮你准备好了。注解是实现依赖注入的“方式”和“标记”,真正干活的是 Spring 容器;注解让 DI 更简单、更自动化。
Spring的依赖注入
依赖注入是指所依赖的对象不是由自己new出来的,而是用别的方式注入的.Spring的依赖注入是在BeanFactory创建bean的时候完成的.通常是在"bean"类中定义了"依赖"(成员变量,type为别的类,最好是interface或者abstract class),BeanFactory通过配置注入这些"依赖"(BeanFactory创建bean的时候赋值给这些成员变量).当这些"依赖"的实...
手写Spring简要逻辑02 --依赖注入,Aware回调,初始化,BeanPostProcessor,AOP模拟实现
1 DI 新建OrderService package com.tes.service; import com.spring.Component; @Component("orderService") public class OrderService { } 新建Autowired注解 package com.spring; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import j
Spring 源码系列(23): SpringApplication.run() 启动全流程
本文深入解析了SpringApplication.run()的核心流程,通过源码拆解揭示了从启动到容器就绪的完整生命周期。文章重点分析了三个关键阶段:prepareEnvironment的配置加载逻辑(系统属性>环境变量>配置文件)、createApplicationContext的容器类型推断机制(基于classpath判断Web/Reactive/普通应用),以及callRunners的启动后回调特性(按@Order执行初始化任务)。同时澄清了常见误区,如内嵌Tomcat实际在refresh阶段的onR
简单讲解Java--queue--三组成对出现的方法的区别
操作类型异常派(失败抛异常)特殊值派(失败返null/false)核心选型原则插入add(e)offer(e)生产者:优先用offer做流控;初始化填充用add做断言取出remove()poll()消费者:永远用pollnull判断;原子操作且确定非空时才用remove查看element()peek()只读场景:99%情况用peek;需要强制非空前置条件时用element终极避坑指南不要用remove()element()做轮询——异常栈生成代价极高(填充StackTrace),比if。
Java大厂面试实录:Spring Boot与微服务、Redis缓存、JWT安全、Prometheus监控全解析——记谢飞机的一次硬核面试
周六下午,互联网大厂“星河科技”的会议室里,阳光透过落地窗洒在长桌上。面试官李总眉头微蹙,翻看着眼前这位候选人的简历——谢飞机,三年Java开发经验,自我评价“精通全家桶”。对面,谢飞机正襟危坐,嘴角带着一丝自信到发光的微笑。李总推了推眼镜,语气平淡:“谢飞机先生,我们开始吧。今天聊电商后端场景,你平时写代码用什么Java版本?
Micrometer 系列【66】上下文传播工具库 | 案例演示
context-propagation 是 Micrometer 生态的跨线程上下文搬运协议层,本身零运行时依赖、不依赖 Spring、Micrometer 其他组件。
Java 并发灵魂拷问:notify/signal 唤醒顺序是规范还是实现?
本文探讨了Java中Object.notify()和Condition.signal()唤醒线程的顺序问题。关键结论如下: Object.notify(): JVM规范未规定唤醒顺序,HotSpot实现虽采用FIFO(从WaitSet头部取线程),但这属于实现细节而非规范要求 由于synchronized是非公平锁,被唤醒线程需重新竞争锁,最终执行顺序无法保证 严禁业务代码依赖该顺序 Condition.signal(): 严格按FIFO顺序唤醒(AQS等待队列头部线程) 是设计约定,业务可合理依赖该特性
【Spring Cloud Alibaba】Sentinel(三)
这里有个关键点:不是 “前 10 秒”,是。
[Java]-微服务面试题
服务降级是服务自我保护的一种方式,或者保护下游服务的一种方式,用于确保服务不会受请求突增影响变得不可用,确保服务不会崩溃。微服务的负载均衡主要使用了一个组件Ribbon,比如,我们在使用feign远程调用的过程中,底层的负载均衡就是。2,我们还在skywalking设置了告警规则,特别是在项目上线以后,如果报错,我们分别设置了可以给相关负责人。简历上写的微服务,只要是发生了多个服务之间的写操作,都需要进行分布式事务控制。2,在客户端的配置文件中,可以配置某一个服务调用的负载均衡策略(局部)
49. 【Java】JDK 21的虚拟线程(上):革命性的并发模型
本文深入解析JDK 21引入的虚拟线程(Virtual Threads)技术,从传统平台线程的资源瓶颈出发,阐述虚拟线程的轻量级特性、M:N调度模型及其工作原理。详细介绍了两种创建虚拟线程的方法,并通过性能对比实验展示其在I/O密集型场景下的显著优势。总结了虚拟线程的适用场景、使用注意事项以及与平台线程的核心差异,帮助开发者掌握这一革命性的并发编程工具。
Java Spring 批量修改,实体、接口、方法的定义
本文描述了一个批量更新车辆类型的接口实现。该功能通过Controller层接收包含出库单ID列表和车辆类型的请求参数,调用Service层进行处理。实现层采用事务管理,首先验证参数有效性,然后查询对应出库单数据并批量更新车辆类型字段,最后返回操作结果(成功更新记录数或错误信息)。该接口主要用于快递业务中其他出库单的车辆类型批量修改操作,包含完整的参数校验、异常处理和事务管理机制。

1054




被折叠的 条评论
为什么被折叠?



