0


【Spring从成神到升仙系列 二】2023年再不会 IOC 源码,就要被淘汰了

  • 👏作者简介:大家好,我是爱敲代码的小黄,独角兽企业的Java开发工程师,CSDN博客专家,阿里云专家博主
  • 📕系列专栏:Java设计模式、数据结构和算法、Kafka从入门到成神、Kafka从成神到升仙、Spring从成神到升仙系列
  • 🔥如果感觉博主的文章还不错的话,请👍三连支持👍一下博主哦
  • 🍂博主正在努力完成2023计划中:以梦为马,扬帆起航,2023追梦人
  • 📝联系方式:hls1793929520,和大家一起学习,一起进步👀

在这里插入图片描述

文章目录

Spring IOC源码解析

一、引言

对于Java开发者而言,关于

Spring

,我们一般当做黑盒来进行使用,不需要去打开这个黑盒。

但随着目前程序员行业的发展,我们有必要打开这个黑盒,去探索其中的奥妙。

本期

Spring

源码解析系列文章,将带你领略

Spring

源码的奥秘

本期源码文章吸收了之前

Kafka

源码文章的错误,将不再一行一行的带大家分析源码,我们将一些不重要的部分当做黑盒处理,以便我们更快、更有效的阅读源码。

废话不多说,发车!

本文流程图可关注公众号:爱敲代码的小黄,回复:IOC 获取
贴心的小黄为大家准备的文件格式为 POS文件,方便大家直接导入 ProcessOn 修改使用

二、Spring启动配置

首先,我们要引入 Spring 的依赖,这里是用的

4.3.11.RELEASE

版本的,不同的版本源码较有差异,但整体业务逻辑不变

这里讲个小细节,如果你在面试,这里一定要提前给面试官说好你阅读的源码版本,有三方面好处:
第一:避免不同版本的Spring源码不一致导致和面试官的分歧问题
第二:让面试官感觉你小子是真的阅读过源码,就算你说的逻辑和面试官有分歧,面试官第一反应会是源码版本差异导致的
第三:装逼使用…

<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>4.3.11.RELEASE</version></dependency>

创建接口

 MessageService

publicinterfaceMessageService{StringgetMessage();}

实现类

MessageServiceImpl 

publicclassMessageServiceImplimplementsMessageService{publicStringgetMessage(){return"hello world";}}

配置文件

application.xml
<?xml version="1.0" encoding="UTF-8"?><beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><beanid="messageService"class="cn.hls.spring.MessageServiceImpl"/></beans>

启动类

SpringStart

publicclassSpringStart{publicstaticvoidmain(String[] args){ApplicationContext context =newClassPathXmlApplicationContext("application.xml");System.out.println("context 启动成功");MessageService messageService = context.getBean(MessageService.class);// 输出: hello worldSystem.out.println(messageService.getMessage());}}

最终输出结果:

context 启动成功
hello world

通过上述代码,我们可以看到,

Spring

IOC

完全代替了我们之前的

new

的功能,将创建实例交由

Spring

来管理。

三、IOC 源码剖析

Spring

是如何管理的呢?源码背后又有什么小技巧呢?今天我们一起来看一下

IOC

源码的解析

为了阅读性,我们将以

xml

文件的配置来阅读源码

首先,我们从

ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");

这一行入手,看其到底执行了什么

我们

debug

点进去可以看到共分为了三部分:

publicClassPathXmlApplicationContext(String[] configLocations,boolean refresh,ApplicationContext parent){super(parent);setConfigLocations(configLocations);if(refresh){refresh();}}

简单来说,这三部分的作为分别是:

  • super(parent):调用父类的构造方法,创建 PathMathingResourcePatternResolver 解析配置文件
  • setConfigLocations(configLocations):设置 configLocations(配置文件路径) 到当前应用程序中
  • refresh():解析配置文件、完成bean的注册、实例化、初始化、代理等一系列的工作最终创建出一个 Bean 实例

我们一起来看一下

refresh

到底做了什么

1、prepareRefresh

整体简介:做容器刷新前的准备工作

  • 设置容器的启动时间:this.startupDate = System.currentTimeMillis();
  • 设置活跃状态为 trueactive.set(true)
  • 设置关闭状态为 falseclosed.set(false)
  • 获取 Environment 对象,并加载当前系统的属性值到 Environment 对象中
  • 准备监听器和事件的集合对象,默认为空的集合:earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();

这个方法不重要,也不必要去深入了解,知道做了容器刷新的准备工作即可。

2、obtainFreshBeanFactory

整体简介:创建容器,并且完成配置文件的加载

重要的来了,这个方法是比较重要的,一定要记住

首先该方法分为了以下几部分:

  • refreshBeanFactory:解析我们的 application.xml 文件并生成 BeanDefinition 注册至 DefaultListableBeanFactorybeanDefinitionMap
  • getBeanFactory:获取工厂bean

2.1 refreshBeanFactory

protectedfinalvoidrefreshBeanFactory()throwsBeansException{// 创建 BeanFactory,类型为 DefaultListableBeanFactoryDefaultListableBeanFactory beanFactory =createBeanFactory();
    beanFactory.setSerializationId(getId());customizeBeanFactory(beanFactory);loadBeanDefinitions(beanFactory);synchronized(this.beanFactoryMonitor){this.beanFactory = beanFactory;}}

上述我们必须记住这个工厂类:**

DefaultListableBeanFactory

**,甚至要做到背诵+默写的程度

其次,最重要的就属

loadBeanDefinitions(beanFactory)

方法了

protectedvoidloadBeanDefinitions(DefaultListableBeanFactory beanFactory){// 创建XmlBeanDefinitionReader,这个是我们xml文件的解析器XmlBeanDefinitionReader beanDefinitionReader =newXmlBeanDefinitionReader(beanFactory);
   beanDefinitionReader.setEnvironment(this.getEnvironment());
   beanDefinitionReader.setResourceLoader(this);
   beanDefinitionReader.setEntityResolver(newResourceEntityResolver(this));initBeanDefinitionReader(beanDefinitionReader);// 加载BeanDefinitionsloadBeanDefinitions(beanDefinitionReader);}

我们继续深入看其做了什么

protectedvoidloadBeanDefinitions(XmlBeanDefinitionReader reader)throwsBeansException,IOException{// 拿到xml文件的地址Resource[] configResources =getConfigResources();if(configResources !=null){
      reader.loadBeanDefinitions(configResources);}String[] configLocations =getConfigLocations();if(configLocations !=null){
      reader.loadBeanDefinitions(configLocations);}}

继续往下看,一直到

loadBeanDefinitions
publicintloadBeanDefinitions(String location,Set<Resource> actualResources){ResourceLoader resourceLoader =getResourceLoader();if(resourceLoader instanceofResourcePatternResolver){try{Resource[] resources =((ResourcePatternResolver) resourceLoader).getResources(location);// 直接看这行,其余不重要int loadCount =loadBeanDefinitions(resources);if(actualResources !=null){for(Resource resource : resources){
               actualResources.add(resource);}}return loadCount;}}else{Resource resource = resourceLoader.getResource(location);int loadCount =loadBeanDefinitions(resource);if(actualResources !=null){
         actualResources.add(resource);}return loadCount;}}
XmlBeanDefinitionReader

388

// 将路径封装成一个DOC格式Document doc =doLoadDocument(inputSource, resource);// 继续注册returnregisterBeanDefinitions(doc, resource);
XmlBeanDefinitionReader

505

publicintregisterBeanDefinitions(Document doc,Resource resource)throwsBeanDefinitionStoreException{BeanDefinitionDocumentReader documentReader =createBeanDefinitionDocumentReader();int countBefore =getRegistry().getBeanDefinitionCount();// 其余不重要,直接看这行
   documentReader.registerBeanDefinitions(doc,createReaderContext(resource));returngetRegistry().getBeanDefinitionCount()- countBefore;}publicvoidregisterBeanDefinitions(Document doc,XmlReaderContext readerContext){this.readerContext = readerContext;// 获取根节点Element root = doc.getDocumentElement();// 从根节点开始解析遍历doRegisterBeanDefinitions(root);}protectedvoiddoRegisterBeanDefinitions(Element root){BeanDefinitionParserDelegate parent =this.delegate;this.delegate =createDelegate(getReaderContext(), root, parent);if(this.delegate.isDefaultNamespace(root)){String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);if(StringUtils.hasText(profileSpec)){String[] specifiedProfiles =StringUtils.tokenizeToStringArray(
                        profileSpec,BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);}}preProcessXml(root);// 直接看这里,其余不重要parseBeanDefinitions(root,this.delegate);postProcessXml(root);this.delegate = parent;}
protectedvoidparseBeanDefinitions(Element root,BeanDefinitionParserDelegate delegate){if(delegate.isDefaultNamespace(root)){NodeList nl = root.getChildNodes();for(int i =0; i < nl.getLength(); i++){Node node = nl.item(i);if(node instanceofElement){Element ele =(Element) node;if(delegate.isDefaultNamespace(ele)){// 直接看这里parseDefaultElement(ele, delegate);}else{
               delegate.parseCustomElement(ele);}}}}else{
      delegate.parseCustomElement(root);}}// 根据不同的配置走不同的分支,配置:import、alias、bean、beansprivatevoidparseDefaultElement(Element ele,BeanDefinitionParserDelegate delegate){if(delegate.nodeNameEquals(ele, IMPORT_ELEMENT)){importBeanDefinitionResource(ele);}elseif(delegate.nodeNameEquals(ele, ALIAS_ELEMENT)){processAliasRegistration(ele);}elseif(delegate.nodeNameEquals(ele, BEAN_ELEMENT)){processBeanDefinition(ele, delegate);}elseif(delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)){// recursedoRegisterBeanDefinitions(ele);}}

我们这里只看

bean

的配置,其余的读者有兴趣可以自己去

debug

protectedvoidprocessBeanDefinition(Element ele,BeanDefinitionParserDelegate delegate){// 解析各种xml标签去生成对应的BeanDefinition,读者有兴趣可以自己看一下BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);if(bdHolder !=null){
      bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);try{// 重点:正式开始注册BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder,getReaderContext().getRegistry());}getReaderContext().fireComponentRegistered(newBeanComponentDefinition(bdHolder));}}publicstaticvoidregisterBeanDefinition(BeanDefinitionHolder definitionHolder,BeanDefinitionRegistry registry){// 重点,开始注册String beanName = definitionHolder.getBeanName();
        registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());// 注册别名String[] aliases = definitionHolder.getAliases();if(aliases !=null){for(String alias : aliases){
                registry.registerAlias(beanName, alias);}}}publicvoidregisterBeanDefinition(String beanName,BeanDefinition beanDefinition){// 看一下原来的beanDefinitionMap是不是已经有该 beanName 了// 如果已经存在,我们要排抛出异常(Spring不允许覆盖)BeanDefinition oldBeanDefinition =this.beanDefinitionMap
beanDefinitionMap.get(beanName);if(oldBeanDefinition !=null){if(!isAllowBeanDefinitionOverriding()){thrownewBeanDefinitionStoreException()}}if(oldBeanDefinition !=null){this.beanDefinitionMap.put(beanName, beanDefinition);}else{// 重点在这:将我们的beanName与beanDefinition放至beanDefinitionMap中this.beanDefinitionMap.put(beanName, beanDefinition);this.beanDefinitionNames.add(beanName);this.manualSingletonNames.remove(beanName);}}

到这里,基本就结束了,我们来回顾一下

refreshBeanFactory

的业务:

  • 通过我们传递的xml 文件的路径,利用 documentLoader 将其封装成 Document 格式
  • 创建 BeanDefinitionDocumentReader 来正式解析 xml 文件并找到文件的 root
  • 根据 root 扫描遍历,对不同配置的标签(import、alias、bean、beans)走不同的逻辑判断
  • 将当前的标签各属性进行组装成 beanDefinition,调用 DefaultListableBeanFactory 进行注册
  • 根据 BeanName 查询该 beanDefinition 是否被注册过,如果被注册过,则直接抛出异常(Spring不允许覆盖
  • 如果没有注册过,则将 BeanNamebeanDefinition 注册至 DefaultListableBeanFactorybeanDefinitionMap
  • 最后,如果该 beanDefinition 含有别名,也要将别名进行注册,至于为什么注册别名,可见:附录1

这里可能有人会说,小黄小黄,按你之前解析

kafka

的套路,肯定会分析

beanDefinition

的形成的,现在怎么偷懒不分析了,是不是看不懂~

答:之前分享的

kafka

系列的文章,大家都知道分享的很细,但是我们细细品味一下,我们读源码到底为了什么,以及如何去读、如何有效的读、如何快速的读,我相信每一个人心中都有一套读源码的方式。至于哪一种阅读方式更为合理,后面博主准备单独出一篇文章来讲解,或者你可以私信我,告知我你的读源码的方式,一起加油、一起学习。

3、prepareBeanFactory

整体简介:

beanFactory

的准备工作,对各种属性进行填充

这个方法不重要,也不必要去深入了解,知道做了

beanFactory

的填充即可

不过,这里记住,

beanFactory

的类一定要记清楚,是

DefaultListableBeanFactory

,不多说直接 背诵+默写

4、postProcessBeanFactory

整体简介: 默认没有实现,留给子类进行实现操作

5、invokeBeanFactoryPostProcessors

整体简介: 可以自由扩展,通过实现

BeanFactoryPostProcessor

BeanDefinitionRegistryPostProcessor

接口,对

beanFactory

里面的

BeanDefinition

进行修改

protectedvoidinvokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory){// 找到当前 beanDefinitionMap 中`BeanFactoryPostProcessor` 和 `BeanDefinitionRegistryPostProcessor`接口的实现// 若这些实现有对应的order(顺序),则排序之后依次调用PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory,getBeanFactoryPostProcessors());if(beanFactory.getTempClassLoader()==null&& beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)){
      beanFactory.addBeanPostProcessor(newLoadTimeWeaverAwareProcessor(beanFactory));
      beanFactory.setTempClassLoader(newContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));}}

温馨小提示:这里有的小伙伴可能对

BeanFactoryPostProcessor

BeanDefinitionRegistryPostProcessor

接口不熟悉,我们将此处的讲解放至:附录2

6、registerBeanPostProcessors

整体简介: 完成

spring

自带或者用户自定义的

BeanPostProcessor

的解析

protectedvoidregisterBeanPostProcessors(ConfigurableListableBeanFactory beanFactory){// 实例化并且注册所有的beanPostProcessorPostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory,this);}

这里的操作实际上和我们上面

invokeBeanFactoryPostProcessors

里面很像,都是对实现一些特定接口的类做加载,但需要注意的是:对于实现

BeanPostProcessor

接口的来说,我们不会在此立即调用,会在

Bean

初始化方法前后调用。

对了,提前剧透一下,我们响当当的

AOP

也是在这里实现的,后续我们也会讲的。

温馨小提示:这里有的小伙伴可能对

BeanFactoryPostProcessor

BeanDefinitionRegistryPostProcessor

接口不熟悉,我们将此处的讲解放至:附录3

7、initMessageSource

整体简介: Spring 中国际化的功能

8、initApplicationEventMulticaster

整体简介: 初始化事件广播器

9、onRefresh

整体简介:

spring

中默认没有任何实现,模板方法,但是在

springboot

中启动了

web

容器

10、registerListeners

整体简介: 注册监听器,为了方便接受广播的事件

11、finishBeanFactoryInitialization

整体简介:完成所有非懒加载的单例对象的实例化操作,从此方法开始进行对象的创建,包含了实例化,初始化,循环依赖,AOP等核心逻辑的处理过程,此步骤是最最核心且关键的点,要对其中的细节最够清楚

由于篇幅原因,博主会尽量挑选一些重要的地方进行分析。

protectedvoidfinishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory){// 实例化剩下的单例对象
   beanFactory.preInstantiateSingletons();}publicvoidpreInstantiateSingletons(){// 拿到我们之前存储的所有beanDefinition的名字List<String> beanNames =newArrayList<>(this.beanDefinitionNames);// 触发单例bean的初始化,遍历集合的对象for(String beanName : beanNames){// 如果beanName对应的bean不是FactoryBean,只是普通的bean,通过beanName获取bean实例getBean(beanName);}}publicObjectgetBean(String name)throwsBeansException{// 此方法是实际获取bean的方法,也是触发依赖注入的方法returndoGetBean(name,null,null,false);}protected<T>TdoGetBean(String name,@NullableClass<T> requiredType,@NullableObject[] args,boolean typeCheckOnly){// 这里需要一步转换,这里的原因我们附录1提到过,这里不再过多讨论String beanName =transformedBeanName(name);// 提前检查单例缓存中是否有手动注册的单例对象,剧透一下(和循环依赖有关联)Object sharedInstance =getSingleton(beanName);// 当对象都是单例的时候会尝试解决循环依赖的问题,但是原型模式下如果存在循环依赖的情况,那么直接抛出异常if(isPrototypeCurrentlyInCreation(beanName)){thrownewBeanCurrentlyInCreationException(beanName);}if(mbd.isSingleton()){// 返回以beanName的(原始)单例对象,如果尚未注册,则使用singletonFactory创建并注册一个对象:
        sharedInstance =getSingleton(beanName,()->{try{// 为给定的合并后BeanDefinition(和参数)创建一个bean实例// 这也是我们的核心方法returncreateBean(beanName, mbd, args);}});}protectedObjectcreateBean(String beanName,RootBeanDefinition mbd,@NullableObject[] args){// 实际创建bean的调用Object beanInstance =doCreateBean(beanName, mbdToUse, args);}protectedObjectdoCreateBean(String beanName,RootBeanDefinition mbd,@NullableObject[] args){// 根据执行bean使用对应的策略创建新的实例,如,工厂方法,构造函数主动注入、简单初始化BeanWrapper instanceWrapper =createBeanInstance(beanName, mbd, args);// 对bean的属性进行填充,将各个属性值注入,其中,可能存在依赖于其他bean的属性,则会递归初始化依赖的beanpopulateBean(beanName, mbd, instanceWrapper);// 执行初始化逻辑
    exposedObject =initializeBean(beanName, exposedObject, mbd);}

到这里我们先停一停,我们总结一下创建实例的一些步骤:

  • 拿到我们之前注册的 beanDefinitionNames,遍历整个 beanDefinitionNames,每一个 BeanName 生成一个对象
  • 我们需要进行名称转化,防止传入的是一个别名或其他的名称,利用转换后的别名去调用
  • 查询我们的单例缓存中是否已经存在该实例,如果存在直接返回即可
  • 如果不存在,则需要去根据该 beanDefinition 去生成对应的实例
  • 对于生成实例共有三个步骤:- 创建实例- 属性填充- 初始化逻辑 - 实现 BeanPostProcessor 的前置方法- 对象的初始化方法- 实现 BeanPostProcessor 的后置方法

我们对于每个步骤都进行分析:

11.1 创建实例

对于实例创建,

Spring

中创建

bean

的方式大致可分为三种:

  • 类名称 + 自定义 beanName
  • 工厂类名称+ 自定义工厂静态方法 + 自定义 beanName
  • 提前注册工厂bean,使用工厂bean + 工厂方法+自定义 beanName

可能大家有点懵,怎么这么多创建的方法,这里其实我们不需要太过于关注,只需要关注

类名称 + 自定义 beanName

这种方法即可,其余两种基本很少用到

对于

类名称 + 自定义 beanName

我们一般有两种构造方法:

  • 无参构造(常用)
  • 有参构造(不常用)

为了便于理解,我们这里只介绍无参构造

BeanWrapper instanceWrapper =createBeanInstance(beanName, mbd, args);protectedBeanWrappercreateBeanInstance(String beanName,RootBeanDefinition mbd,Object[] args){// 根据当前的beanName拿到其 ClassClass<?> beanClass =resolveBeanClass(mbd, beanName);// 前面的有参都不存在,则进行无参构造returninstantiateBean(beanName, mbd);}protectedBeanWrapperinstantiateBean(String beanName,RootBeanDefinition mbd){// 获取实例化策略并且进行实例化操作
    beanInstance =getInstantiationStrategy().instantiate(mbd, beanName,this);}publicObjectinstantiate(RootBeanDefinition bd,@NullableString beanName,BeanFactory owner){// 锁一下对象,线程安全synchronized(bd.constructorArgumentLock){// 得到当前bean的ClassClass<?> clazz = bd.getBeanClass();// 通过class得到其默认的构造方法
        constructorToUse = clazz.getDeclaredConstructor();// returnBeanUtils.instantiateClass(constructorToUse);}}publicstatic<T>TinstantiateClass(Constructor<T> ctor,Object... args){// 构造方法+入参// 如果当前是无参构造方法的话,则argsWithDefaultValues为空return ctor.newInstance(argsWithDefaultValues);}

总结一下通过无参构造创建实例的步骤:

  • 加锁,保证线程安全
  • 得到当前 beanClass,通过其 Class 得到默认的无参构造方法
  • 通过反射直接创建即可

其实有参的构造方法也类似,只不过相较于无参构造,反射传入的

argsWithDefaultValues

的参数,这里的参数可以为

Bean

也可以为数值,所以这里也会出现循环依赖的问题。

11.2 属性填充

属性填充相对简单,流程我们大致过一下,属性注入类似:

<beanid="messageService"class="com.mashibing.hls.MessageServiceImpl"><propertyname="name"value="hls"/></bean>

其中的

property

标签就是我们的属性值。

protectedvoidpopulateBean(String beanName,RootBeanDefinition mbd,@NullableBeanWrapper bw){// 得到当前 BeanDefinition 的属性值PropertyValues pvs = mbd.getPropertyValues();if(pvs !=null){// 注入属性applyPropertyValues(beanName, mbd, bw, pvs);}}protectedvoidapplyPropertyValues(String beanName,BeanDefinition mbd,BeanWrapper bw,PropertyValues pvs){// 获取pvs的PropertyValue对象数组,并将其转换成列表List<PropertyValue> original =Arrays.asList(pvs.getPropertyValues());for(PropertyValue pv : original){// 获取属性的名字String propertyName = pv.getName();// 获取未经类型转换的值Object originalValue = pv.getValue();// 这里需要进行一系列的转换// 因为我们的属性注入有可能注入的是一个BeanReference,需要重新去 BeanFactory 中获取实例// 转换后的放至 deepCopy// 按原样使用deepCopy构造一个新的MutablePropertyValues对象然后设置到bw中以对bw的属性值更新
        bw.setPropertyValues(newMutablePropertyValues(deepCopy));}}publicvoidsetPropertyValues(PropertyValues pvs){setPropertyValues(pvs,false,false);}publicvoidsetPropertyValues(PropertyValues pvs,boolean ignoreUnknown,boolean ignoreInvalid){// 后续主要通过反射对值进行设置,感兴趣的可以自己去看下源码实现setPropertyValue(pv);}

11.3 初始化逻辑

我们这里先实现一个

BeanPostProcessor

接口,便于我们的观察:

publicclassMyTestimplementsBeanPostProcessor{publicObjectpostProcessBeforeInitialization(Object bean,String beanName){System.out.println("我前置增强");return bean;}publicObjectpostProcessAfterInitialization(Object bean,String beanName){System.out.println("我后置增强");return bean;}}

直接看我们的源码:

// 执行初始化逻辑
exposedObject =initializeBean(beanName, exposedObject, mbd);protectedObjectinitializeBean(String beanName,Object bean,@NullableRootBeanDefinition mbd){// 将BeanPostProcessors应用到给定的现有Bean实例,调用它们的postProcessBeforeInitialization初始化方法。// 返回的Bean实例可能是原始Bean包装器
    wrappedBean =applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);//调用初始化方法,先调用bean的InitializingBean接口方法,后调用bean的自定义初始化方法invokeInitMethods(beanName, wrappedBean, mbd);// 将BeanPostProcessors应用到给定的现有Bean实例,调用它们的postProcessAfterInitialization方法。// 返回的Bean实例可能是原始Bean包装器
    wrappedBean =applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);//返回包装后的Beanreturn wrappedBean;}// 执行所有的BeanPostProcessors接口下的类// 如果我们自己实现的类对 Bean 进行了包装,比如AOP,则使用我们实现类里面返回的publicObjectapplyBeanPostProcessorsBeforeInitialization(Object existingBean,String beanName){Object result = existingBean;//遍历 该工厂创建的bean的BeanPostProcessors列表for(BeanPostProcessor processor :getBeanPostProcessors()){// 默认实现按原样返回给定的 BeanObject current = processor.postProcessBeforeInitialization(result, beanName);// 如果 current为nullif(current ==null){//直接返回result,中断其后续的BeanPostProcessor处理return result;}//让result引用processor的返回结果,使其经过所有BeanPostProcess对象的后置处理的层层包装
            result = current;}//返回经过所有BeanPostProcess对象的后置处理的层层包装后的resultreturn result;}protectedvoidinvokeInitMethods(String beanName,Object bean,@NullableRootBeanDefinition mbd){// 如果mbd不为null&&bean不是NullBean类if(mbd !=null&& bean.getClass()!=NullBean.class){// 获取mbd指定的初始化方法名String initMethodName = mbd.getInitMethodName();// 在bean上调用指定的自定义init方法invokeCustomInitMethod(beanName, bean, mbd);// 具体调用,反射执行// Method methodToInvoke = ClassUtils.getInterfaceMethodIfPossible(initMethod);//  methodToInvoke.invoke(bean);}}// 执行所有的BeanPostProcessors接口下的类// 如果我们自己实现的类对 Bean 进行了包装,比如AOP,则使用我们实现类里面返回的publicObjectapplyBeanPostProcessorsAfterInitialization(Object existingBean,String beanName){//初始化结果对象为result,默认引用existingBeanObject result = existingBean;//遍历该工厂创建的bean的BeanPostProcessors列表for(BeanPostProcessor processor :getBeanPostProcessors()){//回调BeanPostProcessor#postProcessAfterInitialization来对现有的bean实例进行包装Object current = processor.postProcessAfterInitialization(result, beanName);// 如果current为nullif(current ==null){//直接返回result,中断其后续的BeanPostProcessor处理return result;}//让result引用processor的返回结果,使其经过所有BeanPostProcess对象的后置处理的层层包装
            result = current;}//返回经过所有BeanPostProcess对象的后置处理的层层包装后的resultreturn result;}

其实初始化的逻辑也很简单,就是调用我们的

BeanPostProcess

实现扩展点的应用

然后初始化

init

方法即可

12、finishRefresh

整体简介: 完成整个容器的启动,所有的对象都准备完成,可以进行后续业务流程的操作,清除上下文缓存,初始化生命周期处理器,发送刷新完成事件

13、销毁

前面我们已经创建成功了对象,当我们使用完成之后,肯定要进行销毁,那么

Spring

是如何做的销毁对象的管理呢

执行

context.close();

方法:

publicvoidclose(){synchronized(this.startupShutdownMonitor){doClose();}}protectedvoiddoClose(){// 清空 DefaultListableBeanFactory 里面的缓存destroyBeans();// 直接将beanFactory置为nullcloseBeanFactory();}protectedvoiddestroyBeans(){// 清空在包含的Bean名称之间映射:bean名称-Bean包含的Bean名称集this.containedBeanMap.clear();// 清空在相关的Bean名称之间映射:bean名称-一组相关的Bean名称this.dependentBeanMap.clear();// 清空在相关的Bean名称之j键映射:bean名称bean依赖项的Bean名称集this.dependenciesForBeanMap.clear();// 清除此注册表中所有缓存的单例实例clearSingletonCache();}protectedvoidclearSingletonCache(){// 加锁,使用单例对象的高速缓存:beam名称-bean实例作为锁synchronized(this.singletonObjects){// 清空单例对象的高速缓存:beam名称-bean实例this.singletonObjects.clear();// 清空单例工厂的缓存:bean名称-ObjectFactorythis.singletonFactories.clear();// 清空早期单例对象的高速缓存:bean名称-bean实例this.earlySingletonObjects.clear();// 清空已注册的单例集,按照注册顺序包含bean名称this.registeredSingletons.clear();// 设置当前是否在destroySingletons中的标志为falsethis.singletonsCurrentlyInDestruction =false;}}privatevoidclearByTypeCache(){this.allBeanNamesByType.clear();this.singletonBeanNamesByType.clear();}// 直接将beanFactory置空protectedfinalvoidcloseBeanFactory(){DefaultListableBeanFactory beanFactory =this.beanFactory;if(beanFactory !=null){
        beanFactory.setSerializationId(null);this.beanFactory =null;}}

这基本就是销毁的整个流程。

这里还有一个小知识点,就是我们可以自定义我们的销毁方法,比如如下:

<bean id="messageService"class="cn.hls.spring.MessageServiceImpl" init-method="init" destroy-method="destroy"/>publicclassMessageServiceImplimplementsMessageService{publicStringgetMessage(){return"hello world";}publicvoidinit(){System.out.println("我是类的初始化");}publicvoiddestroy(){System.out.println("我是类的销毁");}}

在执行

context.close();

方法时,会调用该

Bean

的销毁方法,至于怎么调用的。

这里交给读者了(真不是我懒

五、流程图

在这里插入图片描述

六、总结

又是一篇大工程的文章结束了

记得校招时候,当时对

Spring

懵懂无知,转眼间也被迫看了源码

有些小伙伴可能疑惑:哎,博主,你这不对呀,你这循环依赖也没讲、三级缓存也没讲,你是不是漏的有点多。

因为咱们这篇文章主要针对的是

Spring IOC

的源码,对于三级缓存、循环依赖来说,主要解决 AOP 代理对象的问题,这个我们后面单独出一篇来描述,不要着急,小黄不会不讲的。

当然,本篇只介绍了

XML

配置,如果你对注解的配置感兴趣的话,也可以去看一下

AnnotationConfigApplicationContext

的流程,区别不大,一个是解析的

xml

,一个是解析的注解

但通过这篇文章,我相信,99% 的人应该都可以理解了

Spring IOC

的来龙去脉

那么如何证明你真的理解了

Spring IOC

呢,我这里出个经典的题目,大家可以想一下:Bean 的生命周期

如果你能看到这,那博主必须要给你一个大大的鼓励,谢谢你的支持!

喜欢的可以点个关注,后续会更新 Spring 源码系列文章

我是爱敲代码的小黄,独角兽企业的Java开发工程师,CSDN博客专家,Java领域新星创作者,喜欢后端架构和中间件源码。

我们下期再见。

七、附录

1、注册别名的原因

当我们使用

GetBean(beanName)

时,

Spring

会默认其是别名,并进行循环获取

protected<T>TdoGetBean(String name){finalString beanName =transformedBeanName(name);}protectedStringtransformedBeanName(String name){returncanonicalName(BeanFactoryUtils.transformedBeanName(name));}publicStringcanonicalName(String name){String canonicalName = name;String resolvedName;do{
        resolvedName =(String)this.aliasMap.get(canonicalName);if(resolvedName !=null){
            canonicalName = resolvedName;}}while(resolvedName !=null);return canonicalName;}

2、BeanFactoryPostProcessor 和 BeanDefinitionRegistryPostProcessor

这两个类的作用主要对我们

BeanFactory

BeanDefinitions

进行修改,举个例子:

publicclassMyTestimplementsBeanFactoryPostProcessor{@OverridepublicvoidpostProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)throwsBeansException{// 拿到我们 id = messageService 的 PropertyValueMutablePropertyValues messageService = beanFactory.getBeanDefinition("messageService").getPropertyValues();List<PropertyValue> propertyValueList = messageService.getPropertyValueList();// 遍历输出,当然也可以进行修改for(PropertyValue propertyValue : propertyValueList){System.out.println("BeanFactoryPostProcessor : name = "+ propertyValue.getName()+" value = "+ propertyValue.getValue());}}}

我们看一下启动的效果:

BeanFactoryPostProcessor: name = name value =TypedStringValue: value [hls], target type [null]

3、BeanFactoryPostProcessor 和 BeanDefinitionRegistryPostProcessor

这两个类主要是扩展进行使用,比如我们的

AOP

或者其他的扩展点,举个例子:

publicclassMyTestimplementsBeanPostProcessor{@OverridepublicObjectpostProcessBeforeInitialization(Object bean,String beanName)throwsBeansException{System.out.println("我会在类初始化前调用");return bean;}@OverridepublicObjectpostProcessAfterInitialization(Object bean,String beanName)throwsBeansException{System.out.println("我会在类初始化后调用");return bean;}}

我们看一下启动的效果:

我会在类初始化前调用
我是类的初始化
我会在类初始化后调用
标签: java spring kafka

本文转载自: https://blog.csdn.net/qq_40915439/article/details/129329048
版权归原作者 爱敲代码的小黄 所有, 如有侵权,请联系我们删除。

“【Spring从成神到升仙系列 二】2023年再不会 IOC 源码,就要被淘汰了”的评论:

还没有评论