Spring之实例化Bean(2)
创始人
2024-05-29 15:24:43
0

Spring是非常复杂的一个框架,想要一篇博客就说完实例化Bean的全流程,那将注定会是是很长很长的篇博客,说实话,换做我自己是没有耐心看完的。

本章,我将会以一个最简单的例子来阐述Spring实例化Bean的过程,下一章我们将会重点基于本章节的实例化过程,来阐释一些复杂的实例化过程。 比如:@Autowired @Resource如何注册的,以及循环依赖的大流程。

在开始今天的源码分析之前,我们需要强调几个概念,不懂没关系,先记住就好:

首先,getBean(beanName)方法就是实例化bean的方法,而且是核心方法。

其次, spring中会存在1级、2级、3级缓存的概念。1级缓存是存放已经实例化好的bean的,2级缓存和3级缓存都是存放正在实例化过程中的bean的相关信息的。

接着上一篇Spring之基于注解方式实例化BeanDefinition(1)_chen_yao_kerr的博客-CSDN博客,我们知道,在spring开始实例化之前,我们都是需要首先把java类封装成BeanDefinition对象的。

今天,我们看一下本章测试的最简单的Demo

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-methodvoid init () {id = "001";name = "yy";}@Overridepublic String toString() {return "name :" + name + " id :" + id;}
}

今天,我就从这个最简单的类实例化开始将起。

 1. 首先进入AbstractApplicationContext的refresh方法中,我们直接跳转到实例化bean的方法处

 进入这个方法 :

 继续进入:

此时,我们见到了熟悉的面孔了。beanDefitionNames这个集合是放所有的beanDenation的name值的,然后我们根据name获取到BeanDefinition对象。 此时,我们知道,只有是单例、非抽象、非懒加载的BeanDefinition才有资格继续进行实例化操作

2. 此时,代码继续往下走,我们发现它调用了getBean方法,而本章节一开始我就说过,getBean方法就是实例化Bean的。因此,此时应该是进入了实例化bean的主流程了,逐层debug进去:

3. getBean(beanName)方法内部调用了doGetBean方法进行实例化的,继续跟进去,我们发现它是从缓存中拿的。而第一次实例化之前,肯定是拿不到任何bean的对象的。

此处,我们有必要点进去看一下getSingleton方法,看一下3级缓存。其实,就是3个集合而已。此处稍微记一下就好,本章节不会就3级缓存展开解释。

4. 此时,我们接着 doGetBean方法继续主干流程讲解。中间会有父子类合并,@DependOn的判断等等,全部跳过。我们直接来到实例化bean的核心代码处

 此时,我们需要关注2个方法,分别是getSingleton方法和createBean方法。这是一个lambda表达式, 流程就是先调用getSingleton方法,然后回调createBean方法

getSingleton:首先从1级缓存中拿,拿不到就把当前的beanDefinition的名字放入集合  singletonsCurrentlyInCreation中,表示当前beanDefinition正在实话bean;

 然后调用singletonObject = singletonFactory.getObject(); 进入到createBean方法

 

createBean : 在createBea方法中,我们会调用到doCreateBean方法, 然后在doCreateBean内部会调用到createBeanInstance方法

 

此时,我们进入到createBeanInstance方法中:其实,在这个方法中,我们知道实例化的2种方法,一个是有参构造函数,另一个是无参构造函数。而本章节的demo,我们是最简单的实例化步骤,因此是无参构造函数

 

 到此时,我们知道最终返回值是一个经过包装的BeanWrapper对象。但是,我们继续debug进去看实例化的具体步骤:

继续跟进,我们知道就是反射调用生成对象了

反射实例化完成以后,我们将对象包装成BeanWrapper对象进行返回。

5. 此时,我们还是回到了doCreateBean方法体中,继续往下走。

我们会遇到方法applyMergedBeanDefinitionPostProcessors,此处我们稍微介绍一下。这个方法其实就是搜集注解的作用。比如:@Autowired @Resource @PostConstruct等等。

这些收集注解的工作,是我们在实例化BeanDefinition的时候,通过调用registerComponents方法注进去的各种PostProcessor实现的。上一章的补充说明部分。可以直接在Spring之基于注解方式实例化BeanDefinition(1)_chen_yao_kerr的博客-CSDN博客

中搜索 “最后补充一下”。

继续回到applyMergedBeanDefinitionPostProcessors方法:

 此处,我仅仅列出了一个CommonAnnotationBeanPostProcessor作为举例。

6. 言归正传,我们还是继续doCreateBean方法, 往下走:接下来我们会遇到3个比较重要的方法,逐个列举出来解释:

addSingletonFactory : 添加缓存

populateBean: ioc di,依赖注入的核心方法。 本章是最简单的实例化过程,不涉及。下章节会重点分析。

initializeBean:实例化+ioc依赖注入完以后的调用,简单概括就是对象实例化完成以后,里面的变量,无论是通过注解注入的,还是调用什么方法初始化的,此时都没有值。本章中,我们使用到了@PostConstruct注解,那么我们此处简单的分析一下这个方法。下章节再重点分析。

进入这个方法,我们直接来到核心代码处: 

 点进去,我们发现,它又是调用我们在实例化BeanDefinition是注册的那些PostProcessor。我们使用到了@PostConstruct注解,那么我们还是以CommonAnnotationBeanPostProcessor为例进行分析:

 进入CommonAnnotationBeanPostProcessor的postProcessBeforeInitialization方法:

 这里,我们先来解释一下MetaData类。每个java都会生成一个BeanDefinition和一个MetaData对象,而MetaData里面存储了类的基本信息,比如:这个类的父类是谁,使用了哪些注解,有哪些方法,类和方法的作用域等各种各样的信息。MetaData会被大量的使用,以后我们会经常看到。

继续跟进这个方法:

此时,在我们的Dao.java文件的init方法上打上断点,代码会直接进入我们的方法进行初始化操作。因为它使用了@PostConstruct注解:

   @PostConstruct  //相当于init-methodvoid init () {id = "001";name = "yy";}

返回到 applyBeanPostProcessorsBeforeInitialization方法中,我们可以确认dao对象已经被初始化完成:

继续返回上一层方法 initializeBean 中。此时,下面还有2个比较重要的方法,本例暂时没有用到,暂时忽略。

继续返回上一层方法中,此时由来到了doCreateBean方法中了。此时,它会注册bean销毁时的类DisposableBeanAdapter,最后返回bean对象。

继续返回上一层方法中,此时来到了createBean方法中。

等等,前面好像说过createBean方法,从第4步开始介绍createBean,一直到现在才最终回到了createBean方法中,而且这个方法内部又调用了N多实例化的核心方法,值得反复研究。此时,createBean方法来到了结尾处了:

返回createBean方法的上一层:

 我们之前说过,在调用getSingleton方法的时候会回调进入createBean方法,那此时createBean方法结束了,接下来又会进入到getSingleton方法中了

继续debug方法 getSingleton 往下走:此时会完成2件事

第4步一开始的时候,我们说从一级缓存中拿不到beanName的对象,会把beanName放入一个集合中,表示这个bean正在实例化。而此时,我们实例化和初始化都完成了,需要把当前的beanName从表示正在创建的集合中删除掉。

第4步一开始的时候就说从缓存中拿beanName的对象,那时候拿不到。现在已经完成实例化了。需要将当前实例化的bean放入1级缓存,并从2、3级缓存中删除。

 

 哇塞,说了这么多,终于完成了第4步全部流程的梳理。就这么一小段代码,反反复复的调用,干了如此多的事情,真是不容易啊

	if (mbd.isSingleton()) {sharedInstance = getSingleton(beanName, () -> {try {return createBean(beanName, mbd, args);}catch (BeansException ex) {// Explicitly remove instance from singleton cache: It might have been put there// eagerly by the creation process, to allow for circular reference resolution.// Also remove any beans that received a temporary reference to the bean.destroySingleton(beanName);throw ex;}});//改方法是FactoryBean接口的调用入口bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);}

7. 好了,我们又回到了主流程方法 doGetBean 中了。接下来就是一路返回。至此,实例化Bean对象也已经全部完成了。

测试:

下面开始我们的测试

package com.xiangxue.jack;import com.xiangxue.jack.bean.Dao;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.test.context.ContextConfiguration;//@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:spring.xml"})
public class MyTest {@Autowiredprivate ApplicationContext applicationContext;@Testpublic void myBean3() {applicationContext = new ClassPathXmlApplicationContext("spring.xml");Dao dd = (Dao) applicationContext.getBean("dao");System.out.println(dd.toString());}
}

直接debug 进入getBean方法中,只要我们从1级缓存中直接拿到对象就说明整个流程梳理都是对的。

 确实是拿到了实例化并且初始化后的bean对象了,而且控制台也正确的打印了出来。测试成功

相关内容

热门资讯

电视安卓系统哪个品牌好,哪家品... 你有没有想过,家里的电视是不是该升级换代了呢?现在市面上电视品牌琳琅满目,各种操作系统也是让人眼花缭...
安卓会员管理系统怎么用,提升服... 你有没有想过,手机里那些你爱不释手的APP,背后其实有个强大的会员管理系统在默默支持呢?没错,就是那...
安卓系统软件使用技巧,解锁软件... 你有没有发现,用安卓手机的时候,总有一些小技巧能让你玩得更溜?别小看了这些小细节,它们可是能让你的手...
安卓系统提示音替换 你知道吗?手机里那个时不时响起的提示音,有时候真的能让人心情大好,有时候又让人抓狂不已。今天,就让我...
安卓开机不了系统更新 手机突然开不了机,系统更新还卡在那里,这可真是让人头疼的问题啊!你是不是也遇到了这种情况?别急,今天...
安卓系统中微信视频,安卓系统下... 你有没有发现,现在用手机聊天,视频通话简直成了标配!尤其是咱们安卓系统的小伙伴们,微信视频功能更是用...
安卓系统是服务器,服务器端的智... 你知道吗?在科技的世界里,安卓系统可是个超级明星呢!它不仅仅是个手机操作系统,竟然还能成为服务器的得...
pc电脑安卓系统下载软件,轻松... 你有没有想过,你的PC电脑上安装了安卓系统,是不是瞬间觉得世界都大不一样了呢?没错,就是那种“一机在...
电影院购票系统安卓,便捷观影新... 你有没有想过,在繁忙的生活中,一部好电影就像是一剂强心针,能瞬间让你放松心情?而我今天要和你分享的,...
安卓系统可以写程序? 你有没有想过,安卓系统竟然也能写程序呢?没错,你没听错!这个我们日常使用的智能手机操作系统,竟然有着...
安卓系统架构书籍推荐,权威书籍... 你有没有想过,想要深入了解安卓系统架构,却不知道从何下手?别急,今天我就要给你推荐几本超级实用的书籍...
安卓系统看到的炸弹,技术解析与... 安卓系统看到的炸弹——揭秘手机中的隐形威胁在数字化时代,智能手机已经成为我们生活中不可或缺的一部分。...
鸿蒙系统有安卓文件,畅享多平台... 你知道吗?最近在科技圈里,有个大新闻可是闹得沸沸扬扬的,那就是鸿蒙系统竟然有了安卓文件!是不是觉得有...
宝马安卓车机系统切换,驾驭未来... 你有没有发现,现在的汽车越来越智能了?尤其是那些豪华品牌,比如宝马,它们的内饰里那个大屏幕,简直就像...
p30退回安卓系统 你有没有听说最近P30的用户们都在忙活一件大事?没错,就是他们的手机要退回安卓系统啦!这可不是一个简...
oppoa57安卓原生系统,原... 你有没有发现,最近OPPO A57这款手机在安卓原生系统上的表现真是让人眼前一亮呢?今天,就让我带你...
安卓系统输入法联想,安卓系统输... 你有没有发现,手机上的输入法真的是个神奇的小助手呢?尤其是安卓系统的输入法,简直就是智能生活的点睛之...
怎么进入安卓刷机系统,安卓刷机... 亲爱的手机控们,你是否曾对安卓手机的刷机系统充满好奇?想要解锁手机潜能,体验全新的系统魅力?别急,今...
安卓系统程序有病毒 你知道吗?在这个数字化时代,手机已经成了我们生活中不可或缺的好伙伴。但是,你知道吗?即使是安卓系统,...
奥迪中控安卓系统下载,畅享智能... 你有没有发现,现在汽车的中控系统越来越智能了?尤其是奥迪这种豪华品牌,他们的中控系统简直就是科技与艺...