Spring原理篇(7)--Spring最经常使用的一个功能 依赖注入, 该功能源码是一定需要知道的;这是我们日常开发中的核心; 了解其源码(1)

“’ to allow for resolving potential circular references”);

}

该方法 是解决循环依赖; 循环依赖将放在下个篇章去讲;

addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));

}

这时候 开始了Bean的属性注入;

Object exposedObject = bean;

try {

这个方法 是主要方法;

populateBean(beanName, mbd, instanceWrapper);

exposedObject = initializeBean(beanName, exposedObject, mbd);

}

以下源码全部省去; 进入populateBean里面去看看;

}

进入 populateBean

===========================================================================

@SuppressWarnings(“deprecation”)

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {

按照惯例 先隐藏前面代码; 方便阅读;

前面有说道 会先去拿它的PropertyDescriptor 这个东西是什么作用的 自己去看上面的我写的案例;

PropertyDescriptor[] filteredPds = null;

if (hasInstAwareBpps) {

if (pvs == null) {

pvs = mbd.getPropertyValues();

}

循环当前Bean的 BeanPostProcessor BP

在5.3.5 版本有6个 其他版本可能个数会不一样

主要的一个BP 是 : AutowiredAnnotationBeanPostProcessor

for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {

PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);

if (pvsToUse == null) {

if (filteredPds == null) {

filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);

}

pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);

if (pvsToUse == null) {

return;

}

}

pvs = pvsToUse;

}

}

隐藏后面代码

这个for循环这个List给你们打印出来

在通过了这个bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);

会往BeanWrapper.getWrappedInstance() 这里 保存的值 的内存引用 就是单例池里面的相对应需要注入的哪个Bean. 所以 这里将他注入; 那么外面哪个Bean里面就有值了;

在这里插入图片描述

AutowiredAnnotationBeanPostProcessor

================================================================================================

postProcessProperties

@Override

public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {

顾名思义; 应该可以知道这个方法里面是在做些什么事情;

InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);

try {

依赖注入核心方法;

metadata.inject(bean, beanName, pvs);

}

catch (BeanCreationException ex) {

throw ex;

}

catch (Throwable ex) {

throw new BeanCreationException(beanName, “Injection of autowired dependencies failed”, ex);

}

return pvs;

}

inject

==================================================================

public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {

这个源码熟吧? 里面的InjectedElement 放着就是 你依赖注入的每一个属性;

Collection checkedElements = this.checkedElements;

Collection elementsToIterate =

(checkedElements != null ? checkedElements : this.injectedElements);

if (!elementsToIterate.isEmpty()) {

for (InjectedElement element : elementsToIterate) {

element.inject(target, beanName, pvs);

}

}

}

inject2 进入这个inject的时候要注意; 是这个;

==========================================================================================

在这里插入图片描述

@Override

protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {

filed就是我们要注入的属性;

Field field = (Field) this.member;

Object value;

检查缓存

if (this.cached) {

try {

value = resolvedCachedArgument(beanName, this.cachedFieldValue);

}

catch (NoSuchBeanDefinitionException ex) {

value = resolveFieldValue(field, bean, beanName);

}

}

else {

如果没有缓存的情况下 走resolveFieldValue

value = resolveFieldValue(field, bean, beanName);

}

if (value != null) {

ReflectionUtils.makeAccessible(field);

field.set(bean, value);

}

}

resolveFieldValue

=============================================================================

最后在上面那个方法中的最后 注入这个属性;

=================================================================================

@Nullable

private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {

传入之后 先看你的required 是否为false;

在Autowired 里面的那个required 表示是否一定要注入;默认为true

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();

Object value;

try {

通过这个步骤找到了 value

value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);

}

------省掉部分代码

返回这个value;

return value;

}

}

总结

==============================================================

寻找注入点:

==================================================================

在创建一个Bean的过程中,Spring会利用AutowiredAnnotationBeanPostProcessor的 **postProcessMergedBeanDefinition()**找出注入点并缓存,找注入点的流程为:

  1. 遍历当前类的所有的属性字段Field

  2. 查看字段上是否存在@Autowired、@Value、@Inject中的其中任意一个,存在则认为该字段 是一个注入点

  3. 如果字段是static的,则不进行注入

  4. 获取@Autowired中的required属性的值

  5. 将字段信息构造成一个AutowiredFieldElement对象,作为一个注入点对象添加到 currElements集合中。

  6. 遍历当前类的所有方法Method

  7. 判断当前Method是否是桥接方法,如果是找到原方法

  8. 查看方法上是否存在@Autowired、@Value、@Inject中的其中任意一个,存在则认为该方法 是一个注入点

  9. 如果方法是static的,则不进行注入

  10. 获取@Autowired中的required属性的值

  11. 将方法信息构造成一个AutowiredMethodElement对象,作为一个注入点对象添加到 currElements集合中。

  12. 遍历完当前类的字段和方法后,将遍历父类的,直到没有父类

  13. 最后将currElements集合封装成一个InjectionMetadata对象,作为当前Bean对于的注入点集合 对象,并缓存。

static的字段或方法为什么不支持

==============================================================================

我们假设:

在属性中 我们的Bean是原型Bean 也就是多例的 那么 他属性如果用了static会怎么样? 这个问题如果想明白了 就知道为什么不支持了.

在static修饰的方法中 其字节码文件会生成两个同样的方法 其中一个方法带有 synthetic bridge 并且都是存在@Autowired注解的 所以在Spring中需要处理这种情况,当遍历到桥接方法时,得找到原方法

注入点进行注入

===================================================================

Spring在AutowiredAnnotationBeanPostProcessor的**postProcessProperties()**方法中,会遍 历所找到的注入点依次进行注入。

字段注入


自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
img

总结

大型分布式系统犹如一个生命,系统中各个服务犹如骨骼,其中的数据犹如血液,而Kafka犹如经络,串联整个系统。这份Kafka源码笔记通过大量的设计图展示、代码分析、示例分享,把Kafka的实现脉络展示在读者面前,帮助读者更好地研读Kafka代码。

麻烦帮忙转发一下这篇文章+关注我

就这一次!拼多多内部架构师培训Kafka源码笔记(现已绝版)

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img

对你有帮助,可以添加V获取:vip1024b (备注Java)**
[外链图片转存中…(img-oUMOfq9k-1712674986386)]

总结

大型分布式系统犹如一个生命,系统中各个服务犹如骨骼,其中的数据犹如血液,而Kafka犹如经络,串联整个系统。这份Kafka源码笔记通过大量的设计图展示、代码分析、示例分享,把Kafka的实现脉络展示在读者面前,帮助读者更好地研读Kafka代码。

麻烦帮忙转发一下这篇文章+关注我

[外链图片转存中…(img-hzbbvXtn-1712674986386)]

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-VzFECazB-1712674986387)]

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值