Spring依赖注入逻辑

依赖注入逻辑
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.最终通过反射设置给相应的注入点(反射调用方法 反射设置字段值)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值