Spring中Bean的实例化详细流程
还是举个例子,我有一个朋友小汪他远赴南方某城市打工。然后安定下来后他的朋友很想来家里玩,但是呢我这个朋友家里搞的很乱,所以他不好意思请朋友来家里玩。这时我的另一个朋友说那请一个保姆把家里好好整理一下就可以了,然后给他介绍了一个保姆大S(PS:本文无意指向任何人,因为Spring的前缀是S)然后就把家里整理得井井有条,就请朋友来家里玩了。
好了引入正文,很早很早的Java开发者应该熟悉,最早的时候我们前端访问后端都是需要自己写Servlet的,大概是一个接口写一个Servlet。Java开发又是面向对象的编程,我们程序里面写了new 了很多的对象。写了很多个Servlet,对象很难管理造成我们的程序很乱,都看不下去。后面Spring来了对象都交给了Spring管理,Servlet相关的也都交给了SpringMVC,这样我们开发就顺利多了。好了这下懂我上面举的例子了吧,懂得保姆是什么意思了吧【Spring就像一个管家,一个保姆】。所以多了解Spring相关知识我们提高开发效率有很大的帮助。既然我们的对象交给了Spring管理,那我们的对象怎么生成的呢,就让我们一起看下。

我们在使用Spring的时候,容器中的Bean在我们项目启动的时候都已经给我们生成了,直接使用就行了。容器启动的时候会调用这个方法:
AbstractApplicationContext.refresh()
然后就会调用下面这个方法:
// Instantiate all remaining (non-lazy-init) singletons.
// 翻译一下就是 实例化所有非懒加载的Bean
finishBeanFactoryInitialization(beanFactory);
如图refresh中的方法,它再次调用的每个方法都很重要,实例化所有单例Bean的方法在这个方法的最后调用

我们写的对象基本都在这个方法内进行实例化。【PS方法只讲一些很重要的,具体的更详细方法调用我会在文章后面的流程图中展示出来。】
DefaultListableBeanFactory.preInstantiateSingletons()。
@Override
public void preInstantiateSingletons() throws BeansException { // Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
// 获取所有的要实例化的Bean的名称
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
// 开始初始化单例的Bean
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
// Bean 不是抽象的,是单例的,不是懒加载的进入如下分支
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
// 如果是FactoryBean进入此分支。本次只聊自己开发写的非FactoryBean
// 所以聊else下面的分支。
if (isFactoryBean(beanName)) {
// FactoryBean的名称很特别
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
final FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
// 非 FactoryBean进入此分支
getBean(beanName);
}
}
}
}
然后会进入如下方法。
AbstractBeanFactory.doGetBean() 的方法。
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
// 这个方法主要是获取Bean的名称,一些Bean的名称可能命名的比较特别
// 需要进行转换。
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
// 首先先从容器的缓存中获取Bean,如果容器中已经存在,直接返回。
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
// 先检查这个Bean是否在创建中,如果在创建中抛出异常
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// 标记Bean为正在创建中。
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
// Create bean instance.
// 如果Bean是单例开始创建Bean .
// 后面判断还有Prototype(多例)不是要讲的重点,代码删除了。
if (mbd.isSingleton()) {
// 这个方法是Java 8的 lambda 写法,这个方法里面会把创建好的
// Bean放到Spring容器中,后面再获取这个Bean直接从容器中获取了。
sharedInstance = getSingleton(beanName, () -> {
try {
// 正式开始创建Bean 。
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// 创建过程出现异常,销毁Bean
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
return (T) bean;
}
然后是正式真正的创建Bean的方法如下:
AbstractAutowireCapableBeanFactory.createBean() 的方法。
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
RootBeanDefinition mbdToUse = mbd;
try {
// doCreateBean 是Spring正在做事的方法。
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
}
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
// 实例化Bean 先创建一个BeanWrapper .这个方法里面Spring 一般为默认
// 无参的构造方法创建对象,所以大家如果重写对象的构造方法的时候,一定
// 要把无参构造方法也写出来。要不然某些情况下启动Spring容器可能会报错。
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
// 为Bean的属性赋值。
populateBean(beanName, mbd, instanceWrapper);
// 初始化Bean 。
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
return exposedObject;
}
// 初始化Bean。
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
// 如果你的Bean实现了Spring内置的Aware方法,会在这里执行
invokeAwareMethods(beanName, bean);
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 执行Bean的初始化前置处理器,很重要也就是Spring的钩子函数
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// 执行Bean的初始化方法
invokeInitMethods(beanName, wrappedBean, mbd);
}
if (mbd == null || !mbd.isSynthetic()) {
// 执行Bean的后置处理器,也很重要。
// 很多写底层架构的人都会对此钩子方法灵活应用
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
PS:下面是Bean实例化的详细的流程图,由于画好后的整个流程图无法完全保存,只有一张一张的截屏了。图片一张一张往下看就是整个完整的流程,自己可以找着图片一步一步看,就会对Bean的整个流程很清楚了。



读完熟悉了Spring实例化的流程你能做些什么呢?

1:比如实现BeanPostProcessor。A初始化前和后分别会执行下面2个方法。
@Component
public class A implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println(beanName);
return null;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println(beanName);
return null;
}
}
2:实现InitializingBeanA初始化的时候会执行以下方法。
@Component
public class A implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("执行InitializingBean的afterPropertiesSet方法");
}
}
上面实现的方法都会在A实例化的时候执行,如果你写的业务逻辑有需要在A实例化时候执行的就可以使用上面的方法完成。

欢迎跟着图中走一遍源码,相信你会对Spring创建Bean的流程更加了解。看一些源码你的思路会更清晰,写代码也更得心应手,写代码的时候你可能不自己觉的就按照这些大神写代码的思路去完成高质量的代码。
Spring中Bean的实例化详细流程的更多相关文章
- Spring中Bean的实例化
Spring中Bean的实例化 在介绍Bean的三种实例化的方式之前,我们首先需要介绍一下什么是Bean,以及Bean的配置方式. 如果 ...
- Spring中Bean的实例化与DI的过程
引言 前文我们介绍了关于如何学习Spring的源码以及解析了spring中加载配置文件注册Beandefinition的过程.今天我们继续学习DI的过程. 创建实例和DI过程 IOC和DI都是对spr ...
- Spring中bean的实例化过程
1.从缓存中.优先从一级缓存中拿,有则返回. 如果没有,则从二级缓存中获取,有则返回. 如果二级缓存中拿不到,则从三级缓存中拿,能拿到,则从三级缓存中删除,移到二级缓存. 如果三级缓存也没有,则返回n ...
- spring中bean实例化时机以及整个运转方式
接上一篇文章,一般在servlet获取到请求之后 在service方法中就可以完成所有的请求处理以及返回,但是我们会采用更高级的MVC框架来做.也就是说所有的MVC框架入口就是serlvet中的ser ...
- 一次性讲清楚spring中bean的生命周期之三:bean是如何实例化的
在前面的两篇博文<一次性讲清楚spring中bean的生命周期之一:getSingleton方法>和<一次性讲清楚spring中bean的生命周期之二:FactoryBean的前世今 ...
- Spring中Bean的作用域和生命周期
作用域的种类 Spring 容器在初始化一个 Bean 的实例时,同时会指定该实例的作用域.Spring3 为 Bean 定义了五种作用域,具体如下. 1)singleton 单例模式,使用 sing ...
- Spring官网阅读(十)Spring中Bean的生命周期(下)
文章目录 生命周期概念补充 实例化 createBean流程分析 doCreateBean流程分析 第一步:factoryBeanInstanceCache什么时候不为空? 第二步:创建对象(crea ...
- 如果你每次面试前都要去背一篇Spring中Bean的生命周期,请看完这篇文章
前言 当你准备去复习Spring中Bean的生命周期的时候,这个时候你开始上网找资料,很大概率会看到下面这张图: 先不论这张图上是否全面,但是就说这张图吧,你是不是背了又忘,忘了又背? 究其原因在于, ...
- JAVA面试题:Spring中bean的生命周期
Spring 中bean 的生命周期短暂吗? 在spring中,从BeanFactory或ApplicationContext取得的实例为Singleton,也就是预设为每一个Bean的别名只能维持一 ...
- Spring中bean的注入方式
首先,要学习Spring中的Bean的注入方式,就要先了解什么是依赖注入.依赖注入是指:让调用类对某一接口的实现类的实现类的依赖关系由第三方注入,以此来消除调用类对某一接口实现类的依赖. Spring ...
随机推荐
- Day1.无敌难受且成功
Markdown学习 标题 字体 ctrl+b.l.u.k加粗.斜体.下划线.超链接 引用 大于号+空格 分割线 三个*** ###都 图片 !+[]+() 英文输入法的符号 输入的图片路径可本地也要 ...
- Ubuntu实战
Ubuntu是什么 Ubuntu早期是一个由Debian Linux发展起来的以桌面应用为主的操作系统.作为Linux发行版中的后起 之秀,Ubuntu Linux在短短几年时间里便迅速成长为从Lin ...
- Glass Beads
UVA719 将循环串SSS展开成两倍大小:S+SS+SS+S,这样线性处理就可以处理所有循环的情况了.对S+SS+SS+S建立一个后缀自动机,让后从初始状态开始走,每次选择字典序最小的道路,走NNN ...
- ybtoj 12F
求值的话改为求解前缀和的值,通过两个前缀和相减即可得到每个值. 每次询问相当于给一个方程. 一共有 $n$ 个未知数,因此需要 $n$ 个方程,同时每个数都必须至少在方程中出现一次. 最小生成树求解即 ...
- CatDCGAN项目复现与对抗网络初识
CatDCGAN项目复现与对抗网络初识 作者 CarpVexing 日期 100521 禁止转载 目录 CatDCGAN项目复现与对抗网络初识 引言 CatDCGAN项目基本信息 复现项目的准备工作 ...
- idea修改背景颜色|护眼色|项目栏背景修改
https://blog.csdn.net/heytyrell/article/details/89743068
- 前端基础复习之HTML
1.web基础知识 1 1.Web基础知识 2 1.Internet 3 1.简介 4 Internet 实际上就是由计算机所组成的网络结构 5 6 服务: 7 1.Telnet 8 远程登录 9 2 ...
- 基于5G边缘网关的智慧公交站台应用
发展智能物联网,有利于提高城市运行效率,优化居民生活体验,促进城市迸发活力.智能物联网已经融合进生活的方方面面,例如最常见.分布最广泛的公交站台,也能够通过物联网实现升级换代,为居民提供更丰富.更便捷 ...
- webservice学习随笔(一):简单的webservice实例
一.webService概念简单介绍: 简单来说,webservice就是远程调用技术,也叫XML Web Service WebService是一种可以接收从Internet或者Intranet上的 ...
- unidbgrid导出Excel到多个sheet
xls := TXlsFile.Create(true); xls.NewFile; xls.ActiveSheet := 1; xls.SheetName := '未自评人员清单'; xls.Act ...