Spring之实例化Bean _ @Resource和@Autowired实现原理(3)

news2024/11/18 9:34:03

目录

1. 搜集注解信息 applyMergedBeanDefinitionPostProcessor(*)                                                            

2. 将实例化的Bean放入3级缓存中  addSingletonFactory(***)为循环依赖做准备                               

3. 根据搜集的注解进行依赖注入  populateBean(***)                                                                                

至此,@Autowired 和 @Resource实现DI功能全部说完了。可以说,他们两个对于变量的依赖注入,逻辑几乎一模一样。

4. 最后是对Bean进行初始化操作。initializeBean(****)                                                                            


在上一篇Spring之实例化Bean(2)_chen_yao_kerr的博客-CSDN博客中,我已经基本上梳理出了Spring实例化Bean的全部流程。但是那一篇是以最简单的对象作为解释的,目的就是通俗易懂。而这一篇是基于上一篇继续做一些更为深入的分析的。

本章节主要是针对@Resource和@Autowired这两个注解的实现展开,因为这两个注解就是Spring IOC中依赖注入的核心。上一篇中实例化Bean完成以后,后面有几个方法我只是简单的带了过去。而这一次,我会聚焦它们。

在IOC中,我们主要就是交给Spring去实例化Bean,然后将Bean进行依赖注入。上一篇Spring之实例化Bean(2)_chen_yao_kerr的博客-CSDN博客我们主要就是围绕实例化Bean讲解的。本篇就是实例化Bean以后,我们还需要进行依赖注入操作,其实依赖注入大体上可以分为4个部分,分别是:

1. 搜集注解信息 applyMergedBeanDefinitionPostProcessors(***)

2. 将实例化的Bean放入3级缓存中  addSingletonFactory(***)为循环依赖做准备

3. 根据搜集的注解进行依赖注入  populateBean(***)

4. 最后是对Bean进行初始化操作。initializeBean(****)

上一篇我们是最简单的Dao对象实例化,而今天的主角是MyTestBean2。它将使用@Resource和@Autowired分别注入Dao和Dao2.  并且依旧使用@PostConstruct完成初始化变量的作用,顺便看看是先进行依赖注入,还是先初始化Bean。

Dao类:

package com.xiangxue.jack.bean;

import org.springframework.stereotype.Repository;

import javax.annotation.PostConstruct;

@Repository
public class Dao {

    private String name;

    private String id;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    @PostConstruct  //相当于init-method
    void init () {
        id = "001";
        name = "yy";
    }
    @Override
    public String toString() {
        return "name :" + name + " id :" + id;
    }
}

Dao2类:这个类是我强行实例化BeanDefinition的,因此它没有注解,不用在spring.xml中配置<bean>,依旧可以被Spring实例化,不懂可以看Spring_让Spring 依赖注入彻底废掉_chen_yao_kerr的博客-CSDN博客

public class Dao2 {

    private String name;

    private String id;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "name :" + name + " id :" + id;
    }
}

主角MyTestBean2类:

package com.xiangxue.jack.bean;

import com.xiangxue.jack.postProcessor.Dao2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

@Service
public class MyTestBean2 {

    @Autowired
    private Dao dao;

    @Resource
    private Dao2 dao2;

    private String name;

    public void system () {
        System.out.println("测试@PostConstruct初始化name-----> :" + name);
        System.out.println("测试@Autowired注入Dao-----> :" + dao.toString());
        System.out.println("测试@Resource注入Dao2-----> :" + dao2.toString());
    }


    @PostConstruct
    public void writeName () {
        name = "test init-method is after populateBean";
    }
}

1. 搜集注解信息 applyMergedBeanDefinitionPostProcessor(*)                                                            

在Spring之基于注解方式实例化BeanDefinition(1)_chen_yao_kerr的博客-CSDN博客一文中,我们提到过registerComponents是注册一些BeanPostProcessor接口的。而这些接口就是今天的主角。注解信息的搜集,DI注入,对Bean进行初始化都依靠这些接口。接下来我将会直接提到对象的PostProcessor接口,不会再累赘说明这些接口是哪里来的。

首先,我们还是进入AbstractAutowireCapableBeanFactory类的doCreateBean方法中。此时,我们已经实例化完了Bean操作。聚焦于applyMergedBeanDefinitionPostProcessor方法:

而这个方法内部,其实就是调用我们之前注册的BeanPostProcessor的postProcessMergedBeanDefinition方法而已:

我们再次列举一下不同的接口所支持的注解信息:

AutowiredAnnotationBeanPostProcessor  支持@Autowired  @Value

CommonAnnotationBeanPostProcessor  支持 @PostConstruct  @PreDestroy @Resource

首先,我们关注一下CommonAnnotationBeanPostProcessor ,看看它是如何搜集@PostConstruct  @PreDestroy @Resource信息的。

既然是分开搜集的,那我们就先看@PostConstruct  @PreDestroy的搜集过程

我们遇到了熟悉的代码结构了:之前是lamadba表达式 getSingleton(beanName, () ->{****** createBean() *******}),而这次是换成匿名类,原理是一样的。

1,首先调用doWithLocalMethods方法,内部肯定是回调进入method匿名类方法中

2. 在这个方法中,我们会把搜集到的有@PostConstruct  @PreDestroy 的方法分别放入currInitMethods 和 curDestoryMethods 集合中

3. 最后再把他们放入 initMethods 和 destoryMethods 集合中。请记住这两个集合的名字

 而在doWithLocalMethods方法内部,就是一个反射调用:

 4. 最终返回的是一个Metadata, 把init-method方法和destroy-method方法分别放入各自的集合中。这样就搜集完成了。

接下来再看它是如何搜集@Resource注解的:请重点记住injectionMetadataCache这个集合名称。

 关注一下具体的搜集过程: 还是熟悉的代码结构。

因为@Resource可以在变量上使用,也可以在方法上使用。所以,我们需要分别搜集

 到此为止,我们的CommonAnnotationBeanPostProcessor 搜集注解信息工作就完成了。重要的信息就是3个集合。 initMethods 、destoryMethods和injectionMetadataCache

接下来,我们再看看AutowiredAnnotationBeanPostProcessor是如何搜集信息的,我不用看代码,猜测大体流程应该基本相同。接下来重点关注一下@Autowired 在变量上使用的情况。因为,这样的使用情况比较多

 

 最终我们发现,@Autowired注解的搜集过程和@Resource的搜集过程,基本上是完全一样的代码逻辑。

2. 将实例化的Bean放入3级缓存中  addSingletonFactory(***)为循环依赖做准备                               

 

 缓存会在讲循环依赖的时候具体分析,此处只要知道有3级缓存,而且实例化Bean以后首先放入3级缓存即可。

3. 根据搜集的注解进行依赖注入  populateBean(***)                                                                                

 

debug进入populateBean方法,看看它是如何进行依赖注入的。以下这段代码,我们在Spring_让Spring 依赖注入彻底废掉_chen_yao_kerr的博客-CSDN博客一文中作为甜点分享过了,我们是可以通过这段代码逻辑,自己实现一个InstantiationAwareBeanPostProcessor让Spring的依赖注入功能彻底报废的。

 

在 populateBean方法内部,继续debug往下:我们发现代码再次调用了PostProcessor接口

因为我们只关注@Resource和@Autowired这两个注解,所以我们继续去看看AutowiredAnnotationBeanPostProcessor 和

CommonAnnotationBeanPostProcessor,看看她们是怎么实现的。

首先,我们看看CommonAnnotationBeanPostProcessor是如何实现@Resource注解

果真是直接从缓存中拿到的metadata数据,那么我们继续看看它是如何设置值的。

看看具体是如何设置值的:

很简单,就是通过反射的形式,将变量dao2,类实例MyTestBean2,通过反射的形式给dao2注入值。但是,这个dao2的值是如何来的呢? 这个地方就和循环依赖扯上关系了。不过,我们这一次不说循环依赖,只看它是如何获取到dao2这个对象的。进入方法内部:

模板设计模板,再次进入CommonAnnotationBeanPostProcessor的内部类ResourceElement中

 继续跟进:

 

最后,还是返回到反射调用处,直接给变量dao2赋值,至此@Resource注解全部流程结束。

 接下来该轮到AutowiredAnnotationBeanPostProcessor 实现@Autowired注解的流程了。在阅读源码之前,大胆猜测一下,整体流程基本相同。

接下来看看具体拿metadata过程是否相同:

 再来看看注入dao的过程是否相同

进入这个方法以后,我们发现拿值的逻辑是不同的

 

 进入doResolveDependency方法内部:

 

上面几个方法,做了一些列的逻辑判断,这个是比@Resource注解复杂一些。但是,最后,我们发现,它还是调用了getBean() 方法,也就是说还是要进行实例化的操作。搞了半天,最终才发现,@Autowired 和 @Resource实现逻辑几乎一模样,唯一的不同就是拿变量的对象过程中,逻辑判断稍微有些区别。

至此,@Autowired 和 @Resource实现DI功能全部说完了。可以说,他们两个对于变量的依赖注入,逻辑几乎一模一样。

4. 最后是对Bean进行初始化操作。initializeBean(****)                                                                            

实例化+ioc依赖注入完以后的调用,简单概括就是对象实例化完成以后,里面的变量,无论是通过注解注入的,还是调用什么方法初始化的,此时都没有值。看下图:

 而在调用完initializeBean方法以后,我们可以确认,它已经初始化完成。

其实,它的实现原理,我在 Spring之实例化Bean(2)_chen_yao_kerr的博客-CSDN博客一文中已经解释过了,就是根据之前搜集到的注解信息,找到对应的方法名称,然后通过反射,调用初始化方法,完成变量的初始化操作。具体debug过程可以直接在Spring之实例化Bean(2)_chen_yao_kerr的博客-CSDN博客中搜索 “  initializeBean   ”

最终测试结果可以在控制台打印,测试通过:

本文的重点就是populatedBean方法,而循环依赖其实就是基于这个方法完成的。理解这篇文章,那循环依赖就是非常简单的事情了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/398387.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

RS232/RS485信号接口转12路模拟信号 隔离D/A转换器LED智能调光控制

特点&#xff1a;● RS-485/232接口&#xff0c;隔离转换成12路标准模拟信号输出● 可选型输出4-20mA或0-10V控制其他设备● 模拟信号输出精度优于 0.2%● 可以程控校准模块输出精度● 信号输出 / 通讯接口之间隔离耐压3000VDC ● 宽电源供电范围&#xff1a;10 ~ 30VDC● 可靠…

搭建SpringBoot多模块微服务项目脚手架(一)

搭建SpringBoot多模块微服务项目脚手架(一) 文章目录搭建SpringBoot多模块微服务项目脚手架(一)1.概述2.微服务环境搭建介绍1.微服务环境描述2.搭建环境组件和版本清单3.搭建父模块环境3.1.创建springboot父工程1.创建springboot2.配置maven和java3.精简父模块4.pom文件配置5.父…

记录--服务端推送到Web前端有哪几种方式?

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 这个问题&#xff1f; 这个问题一般会出现在面试题里面&#xff0c;然后回答一些诸如轮询、WebSocket之类的答案。当然&#xff0c;实际开发中&#xff0c;也会遇到类似别人给你赞了&#xff0c;要通知…

华为OD机试题,用 Java 解【一种字符串压缩表示的解压】问题

华为Od必看系列 华为OD机试 全流程解析+经验分享,题型分享,防作弊指南)华为od机试,独家整理 已参加机试人员的实战技巧华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典使用说明 参加华为od机试,一定要注意不…

20230309英语学习

What Is Sleep Talking? We Look at the Science 为什么人睡觉会说梦话&#xff1f;来看看科学咋说 Nearly everyone has a story about people talking in their sleep.Though it tends to be more common in children, it can happen at any age:A 2010 study in the jour…

如何恢复已清空的 Windows 回收站?

Windows 95 中引入的回收站文件夹&#xff08;也称为垃圾桶&#xff09;是有史以来最有用的功能之一&#xff0c;可以保护您免受自己的错误和粗心大意的影响。 通常&#xff0c;从文件夹中恢复丢失的文件就像单击桌面上的回收站图标并执行简单的拖放操作一样简单。 但是&…

Java实例实验项目大全源码企业通讯打印系统计划酒店图书学生管理进销存商城门户网站五子棋

wx供重浩&#xff1a;创享日记 对话框发送&#xff1a;java实例 获取完整源码源文件视频讲解文档资料等 文章目录1、企业通讯2、快递打印系统3、开发计划管理系统4、酒店管理系统5、图书馆管理系统6、学生成绩管理系统7、进销存管理系统8、神奇Book——图书商城9、企业门户网站…

数据库管理-第六十期 监听(20230309)

数据库管理 2023-03-09第六十期期 监听1 无法访问2 监听配置3 问题复现与解决4 静态监听5 记不住配置咋整总结第六十期期 监听 不知不觉又来到了一个整10期数&#xff0c;我承认上一期有很大的划水的。。。嫌疑吧&#xff0c;本期内容是从帮群友解决ADG前置配置时候的一个问题…

C51---定时器中断相关寄存器

1.中断系统&#xff0c;是为使CPU具有对外界紧急事件的实时处理能力而设置的。 当中央处理器CPU正在处理某件事情的时候&#xff0c;要求CPU暂停当前任务或工作&#xff0c;转而去处理这这个紧急事件。处理完以后&#xff0c;再回到原来的被中断的地方&#xff0c;继续原来的工…

华为OD机试题,用 Java 解【寻找相同子串】问题

华为Od必看系列 华为OD机试 全流程解析+经验分享,题型分享,防作弊指南)华为od机试,独家整理 已参加机试人员的实战技巧华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典使用说明 参加华为od机试,一定要注意不…

RoCEv2网络部署实践

延续上篇RoCE网络的介绍&#xff0c;我们知道承载ROCEv2流量必须有一张无损网络。 本章主要介绍在以太网环境部署无损网络的关键点。 首先是QoS&#xff0c;包含流分类和队列调度两部分。 流分类&#xff1a;在网络接入设备&#xff08;TOR&#xff09;配置if-match类的语句&am…

一本通 2.8.1 广度优先搜索算法

1329&#xff1a;【例8.2】细胞 【题目描述】 一矩形阵列由数字0到9组成,数字1到9代表细胞,细胞的定义为沿细胞数字上下左右还是细胞数字则为同一细胞,求给定矩形阵列的细胞个数。如:阵列 有4个细胞。 【题目分析】 遍历所有节点&#xff0c;当无标识且不为零&#xff0c;…

「Vue面试题」动态给vue的data添加一个新的属性时会发生什么?怎样去解决的?

一、直接添加属性的问题 我们从一个例子开始 定义一个p标签&#xff0c;通过v-for指令进行遍历 然后给botton标签绑定点击事件&#xff0c;我们预期点击按钮时&#xff0c;数据新增一个属性&#xff0c;界面也 新增一行 <p v-for"(value,key) in item" :key&q…

Esp8266学习4. 基于Arduino的PWM与红外信号处理

Esp8266学习4. 基于Arduino的PWM与红外信号处理一、基本概念1. PWM2. ESP8266 的 PWM功能3. node-mcu 引脚图4. 模拟写入&#xff08;1&#xff09;analogWrite&#xff08;2&#xff09;修改频率 analogWriteFreq&#xff08;3&#xff09;调节分辨率二、使用 analogWrite实现…

思腾合力深思系列 | 四款高性能 AI 服务器

深思系列 AI 服务器涵盖多种 CPU 平台&#xff0c;支持按客户需求预装 OS、驱动、DL 框架、常用 DL 库&#xff0c;节省您大量的前期调试时间&#xff0c;开机即用。 一个简单的任务&#xff0c;若想要在 AI 的脑中形成清晰的思路&#xff0c;需要大量的实验和练习。从 AI 训练…

05-CSS

今日目标能够说出 为什么要用定位能够说出 定位的 4 种分类能够说出 4 种定位各自的特点能够说出 为什么常用子绝父相布局能够写出 淘宝轮播图布局能够说出 显示隐藏的 3 种方式以及区别1. 定位(position) 介绍1.1 为什么使用定位我们先来看一个效果&#xff0c;同时思考一下用…

ctfshow_crypto_妈呀完了writeup

目录一、题目原题二、解题步骤1.去掉01串中的空格2.把01二进制串转换成十进制数3.将十进制整数转换成bytes三、后记一、题目原题 题目给了一串01和一个png图片&#xff0c;打开看了提示说“图文无关”&#xff1a; 图片附件如下&#xff1a; 二、解题步骤 1.去掉01串中的空…

3·8 妇女节特别策划 | 对话开源社里的“半边天”:多彩的她们,有别样的力量~...

三八妇女节Womens Day< 2023/03/08 >01职场女性 陈阳开源社理事长、微软云计算机与人工智能事业部首席产品经理一句话介绍自己&#xff1a;开源社区中的二进制女性向上滑动阅览采访Q1&#xff1a;能介绍一下自己目前正在做的职业或者项目嘛&#xff1f;白天在微软云计算和…

Oracle调优日记

Oracle调优日记前言前置知识联表查询Inner Joinleft joinright join环境背景描述问题展示最初代码问题解决过程优化一优化二优化三接口测试检查数据库连接总结前言 很难想想会在600条数据和4万条数据的两张表联表查询的的情况下&#xff0c;查询花了10多s。这里记录一下排查过…

PMP考试是什么?介绍+资料分享

我来介绍一下PMP&#xff1a; PMP考试是由PMI组织和出题&#xff0c;严格评估项目管理人员知识技能是否具有高品质的资格认证考试。 1999年&#xff0c;PMP考试在所有认证考试中第一个获得ISO9001国际质量认证,从而成为全球权威的认证考试之一。下载PMP备考资料可看封面或在文…