Spring Bean的生命周期以及IOC源码解析

IOC源码这一块太多只能讲个大概吧,建议还是去买本Spring IOC源码解析的书来看比较好,我也是自己看源代码以及视频整理的笔记

Bean的生命周期大概可以分为四个阶段,具体的等会再说,先看看IOC的源码吧

1、bean的创建

2、bean的属性赋值

3、bean的初始化

4、bean的销毁

IOC容器源码解析

我们创建容器以new AnnotationConfigApplicationContext(Config.class)为示例,我们点开源代码,看一下

其实做了挺多事的,在父类的的无参构造函数当中,就创建了一个BeanFactory的实例,其实可以去看一下这个类的无参构造函数,其实加载了很多必备的Bean到容器当中,例如之前提到过的一些常用的BeanPostProcessor,这里就不多说了,不然博客会太长了

接下来就是第一个方法register(componentClasses)解析配置类的注解,并且创建了BeanFactory的实例(org.springframework.beans.factory.support.DefaultListableBeanFactory的实例)并且将配置类注入到容器中

方法点进去之后能看到

 我们进到注册Bean的方法(BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);)里面

我们看一下是怎么注入的

其实就是将对象包装成BeanDefinition对象,然后添加到ConcurrentHashMap当中。

第二部,进入到refresh()方法,但是该方法位于父类的org.springframework.context.support.AbstractApplicationContext.class的515行,这个是一个刷新方法,将我们的业务Bean注入进去

无论是通过哪种创建Spring 的ioc容器都会执行这个refresh方法。大致的主要方法如下,不过有些方法的细节就不讲了,IOC过于庞大,懂个大概就差不多了,但是方法具体是干嘛的会一个一个讲

prepareRefresh()

1)、initPropertySources()初始化一些属性设置;子类自定义个性化的属性设置方法;

2)、getEnvironment().validateRequiredProperties();检验属性的合法等

3)、earlyApplicationEvents= new LinkedHashSet<ApplicationEvent>();保存容器中的一些早期的事件;

obtainFreshBeanFactory()

获取到BeanFactory对象

prepareBeanFactory(beanFactory)

设置一下BeanFactory对象一些属性

         1)、设置BeanFactory的类加载器、支持表达式解析器...

         2)、添加部分BeanPostProcessor【ApplicationContextAwareProcessor】

         3)、设置忽略的自动装配的接口EnvironmentAware、EmbeddedValueResolverAware、xxx;

         4)、注册可以解析的自动装配;我们能直接在任何组件中自动注入:BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext

         5)、添加BeanPostProcessor【ApplicationListenerDetector】

         6)、添加一些loadTimeWeaver;

         7)、给BeanFactory中注册一些能用的组件;

                   environment【ConfigurableEnvironment】、

                   systemProperties【Map<String, Object>】、

                   systemEnvironment【Map<String, Object>】

postProcessBeanFactory(beanFactory)

BeanFactory完成的后置工作,当前为空,但是可以继承当前类,在子类中可以实现这个方法

invokeBeanFactoryPostProcessors(beanFactory)

加载并执行BeanFactoryPostProcessor以及BeanDefinitionRegistryPostProcessor这两个接口的两个实现方法

1、postProcessBeanFactory()

2、postProcessBeanDefinitionRegistry():

这个方法里面做了很多加载,这里就不展示,自行去看源码吧

initMessageSource()

注册一个MessageSource的对象,但是这个Bean并没有加载到之前的那个Map当中,而是加载到一个缓存的Map当中,用于解决循环依赖

initApplicationEventMulticaster()

初始化一个派发器,跟上面那个差不多,只是对象不一样

onRefresh()

跟之前的那个postProcessorBeanFactory方法差不多,留给子类实现

registerListeners()

注册监听器,实现ApplicationListener<?>接口,并指定时在什么时候加载即指定ContextEvent

finishBeanFactoryInitialization(beanFactory)

这个就是加载所有业务单实例Bean的方法,并且生命周期都会在这里执行,首先会配置一些BeanFactory的一些属性,然后在加载业务Bean

第一部分优先获取Bean名称的一些定义信息getMergedLocalBeanDefinition(beanName),然后先处理实现FactoryBean的Bean

点进去getBean(beanName)之后,调用方法 doGetBean(name, null, null, false),这个方法就不贴截图了,代码太多不好截图,可以自己去对照这源码看,就讲调用了哪个方法就好了。

Object sharedInstance = getSingleton(beanName) 从缓存的Bean中去获取看看在不在,如果存在的话就直接获取(会去校验FactoryBean缓存中是否存在),不存在就执行else方法

如果缓存中不存在的话,就是一个新的Bean等待创建

运行到了markBeanAsCreated(String beanName),这个是用来标记当前beanName已经存在了,将beanName添加到alreadyCreated集合当中,然后运行到了下面

然后继续执行

进入到createBean()方法后,有个获取代理的方法,这个方法就得讲一下,跟Spring的AOP以及事务有关

Object bean = resolveBeforeInstantiation(beanName, mbdToUse)讲解:

我们点开查看一下这个方法,有个createProxy()创建代理方法

进入到创建代理的方法里面,我们看一下

我们点开getProxy方法,会返回一个createAopProxy().getProxy(classLoader);对象,我们依次点开后,在使用AOP到底是JDK动态代理还是CGLIB代理的关键所在

好了,代理的那个方法差不多了,我们改回到正题了

我们进入到Object beanInstance = doCreateBean(beanName, mbdToUse, args);

有个BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args);这个是创建BeanWrapper的包装类,在createBeanInstance方法中最后会执行instantiateBean()

我们进入到这个instantiate(),最后有个BeanUtils.instantiateClass(constructorToUse)方法用来创建对象,这就不深入的讨论了,大家可以自己去看

然后包装一个BeanWrapperImpl对象,最后返回出去;创建好后,进行属性赋值以及Bean的初始化,在属性赋值的方法里面有个InstantiationAwareBeanPostProcessors方法执行

我们看下初始化方法

Bean的初始化,会先加载Aware,然后调用BeanPostProcessor的前置方法,然后加载初始化方法,再加载BeanPostProcessor的后置方法

这个方法基本就加载完了

finishRefresh()

加载完业务Bean的一些工作

resetCommonCaches()

这个是处于finally代码块的方法用来清除创建时临时缓存数据

Bean生命周期

在上面IOC分析里面已经提到了Bean的创建以及属性赋值了

接下来就是初始化以及销毁

初始化

初始化使用的方法有三种

1@Bean(initMethod = "")调用指定初始化方法

2、在类中设置@PostConstruct注解

3、实现InitializingBean接口,实现afterPropertiesSet()方法

销毁

对应的销毁也有三种

1、@Bean(destroyMethod= "")调用指定销毁方法

2、在类中设置@PreDestroy注解

3、实现DisposableBean接口,实现destroy()方法

销毁在容器关闭是时候执行

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

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

相关文章

python3绘图_python3绘图示例2(基于matplotlib:柱状图、分布图、三角图等)

#!/usr/bin/env python# -*- coding:utf-8 -*-from matplotlib import pyplot as pltimport numpy as npimport pylabimport os,sys,time,math,random# 图1-给已有的图加上刻度filer‘D:\jmeter\jmeter3.2\data\Oracle数据库基础.png‘arrnp.array(file.getdata()).reshape(fil…

bzoj4152-[AMPPZ2014]The_Captain

Description 给定平面上的n个点&#xff0c;定义(x1,y1)到(x2,y2)的费用为min(|x1-x2|,|y1-y2|)&#xff0c;求从1号点走到n号点的最小费用。 Input 第一行包含一个正整数n(2<n<200000)&#xff0c;表示点数。 接下来n行&#xff0c;每行包含两个整数x[i],yi&#xff0c;…

python日志统计_python试用-日志统计

最近两天尝试用python代替bash写Linux Shell脚本来统计日志。发现python写起来比bash更简单和容易阅读&#xff0c;发现不少惊喜。所以写了一个粗糙的脚本来统计日志。目标1、通过简单命令和脚本统计事件发生数2、日志限定文本类型假定环境日志文件&#xff1a;1.logtest:aaa,1…

Spring AOP两种使用方式以及如何使用解析

AOP是一种面向切面编程思想&#xff0c;也是面向对象设计&#xff08;OOP&#xff09;的一种延伸。 在Spring实现AOP有两种实现方式&#xff0c;一种是采用JDK动态代理实现&#xff0c;另外一种就是采用CGLIB代理实现&#xff0c;Spring是如何实现的在上篇已经讲到了Spring Be…

如何用python生成可执行程序必须经过_python怎么生成可执行文件

.py文件&#xff1a;对于开源项目或62616964757a686964616fe58685e5aeb931333363393664者源码没那么重要的&#xff0c;直接提供源码&#xff0c;需要使用者自行安装Python并且安装依赖的各种库。(Python官方的各种安装包就是这样做的).pyc文件&#xff1a;有些公司或个人因为机…

Jmeter 老司机带你一小时学会Jmeter

Jmeter的安装 官网下载地址&#xff1a;http://jmeter.apache.org/download_jmeter.cgi 作为Java应用&#xff0c;是需要JDK环境的&#xff0c;因此需要下载安装JAVA&#xff0c;并且作必要的的环境变量配置。 一、bin目录 examples:    目录中有CSV样例 jmeter.bat/jmeter…

MongoDB位运算基本使用以及位运算应用场景

最近在公司业务上用到了二进制匹配数据&#xff0c;但是MongoDB进行二进制运算&#xff08;Bitwise&#xff09;没用过&#xff0c;网上博客文章少&#xff0c;所以就上官网看API&#xff0c;因此记录一下&#xff0c;顺便在普及一下使用二进制位运算的一些应用。 在MongoDB的…

好用的下拉第三方——nicespinner

1.简介 GitHub地址&#xff1a;https://github.com/arcadefire/nice-spinner Gradle中添加&#xff1a; allprojects {repositories {...maven { url "https://jitpack.io" }} }dependencies {implementation com.github.arcadefire:nice-spinner:1.3.7 }2.使用 xml文…

Mybatis配置文件参数定义

官网有时候进不去&#xff0c;所以就记录一下Mybatis的配置文件的各项参数定义&#xff0c;大家也可以上官网查询&#xff0c;官方文档&#xff0c;进不进的去看各自的缘分了 properties 定义配置&#xff0c;在这里配置的属性可以在整个配置文件使用&#xff1b;可以加载指定…

python和java后期发展_Python与java的发展前景谁最大

Python和Java是目前IT行业内两大编程语言&#xff0c;很多人都喜欢拿来比较&#xff0c;一个是后起之秀&#xff0c;潜力无限&#xff1b;一个是行业经典&#xff0c;成熟稳定。对于许多想从事IT行业的同学来说&#xff0c;这两门语言真的很难抉择。那么&#xff0c;Python和Ja…

JDK源码学习笔记——Enum枚举使用及原理

一、为什么使用枚举 什么时候应该使用枚举呢&#xff1f;每当需要一组固定的常量的时候&#xff0c;如一周的天数、一年四季等。或者是在我们编译前就知道其包含的所有值的集合。 利用 public final static 完全可以实现的功能&#xff0c;为什么要使用枚举&#xff1f; public…

Mybatis源码日志模块分析

看源码需要先下载源码&#xff0c;可以去Mybatis的github上的仓库进行下载&#xff0c;Mybatis 这次就先整理一下日志这一块的源码分析&#xff0c;这块相对来说比较简单而且这个模块是Mybatis的基础模块。 之前的文章有谈到过Java的日志实现&#xff0c;大家也可以参考一下&…

python手机端给电脑端发送数据_期货交易软件有哪些比较好用?分手机端和电脑端...

一、电脑端交易软件期货电脑端交易软件目前市场上用的最多的是文华财经和博易大师&#xff0c;这两个软件都是免费交易使用的。从投资者使用角度来看&#xff0c;目前电脑端文华财经的评价比博易大师高一些。当然每个投资者有自己的使用习惯&#xff0c;博易大师也有自己优点&a…

Find the Difference(leetcode389)

2019独角兽企业重金招聘Python工程师标准>>> Given two strings s and t which consist of only lowercase letters. String t is generated by random shuffling string s and then add one more letter at a random position. Find the letter that was added in …

Mybatis源码之数据源模块分析

先来看看java纯jdbc查询数据的示例&#xff1a; try {//加载对应的驱动类Class.forName("com.mysql.cj.jdbc.Driver");//创建连接Connection connection DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test?serverTimezoneUTC", "roo…

reactnative 获取定位_[RN] React Native 获取地理位置

import React, {Component} from react;import {StyleSheet, Text, View}from react-native;exportdefault classTestGeo extends Component {state{longitude:,//经度latitude: ,//纬度city: ,district:,street:,position:,//位置名称};componentWillMount () >{this.getPo…

第二冲刺阶段第三天

查阅资料&#xff0c;修改控件界面转载于:https://www.cnblogs.com/gyy0/p/10066452.html

Mybatis源码之缓存模块分析

缓存这个东西在很多应用中都能看到它们的身影&#xff0c;这次就讲讲在Mybatis中的缓存是怎么应用的&#xff0c;虽然说吧Mybatis中的缓存基本不怎么用&#xff0c;用的更多是第三方组件redis、MongoDB、MemCache等等。 Mybatis的缓存是基于Map实现的&#xff0c;从缓存中读写…

Mybatis源码之核心流程分析

终于谈到了Mybatis最核心的东西了&#xff0c;最核心的就是通过配置XML文件或注解中的SQL&#xff0c;直接调用接口就能执行配置好的SQL语句并封装成对应的返回类型的数据。 先看一下Mybatis使用示例&#xff1a; //创建Builder对象 SqlSessionFactoryBuilder builder new S…

mimakatz用法_两步完成利用procdump64+mimikatz获取win用户密码

使用procdump64mimikatz可实现从内存中获取明文密码工具链接&#xff1a;https://pan.baidu.com/s/1gNc9qLcNSNBohIVrAiqShw 密码&#xff1a;fc38首先得先获取到内存文件lsass.exe进程, 它用于本地安全和登陆策略,一般在进程管理器中能看到, 比如这样1.导出lsass.exeprocdump6…