当前位置:网站首页 > R语言数据分析 > 正文

spring教程菜鸟(spring菜鸟教程pdf)



 
  
 
  

1.2.1 prepareRefresh() 方法

 
  

1.2.2 obtainFreshBeanFactory() 方法

 
  

1.2.3 prepareBeanFactory() 方法

 
  

1.2.4 invokeBeanFactoryPostProcessors() 方法

  • 方法虽长大概总结一下就是,判断beanFactory类型,然后将注册的BeanPostFactory放入、排好顺序、执行。
  • 方法的内容其实比较少,大部分过程在注释都已经写清楚,这边在稍微总结一下。
  • 整个 方法围绕两个接口, 和 ,其中 继承了 。
  • 主要用来在常规 检测开始之前注册其他 Bean 定义,说的简单点,就是 具有更高的优先级,执行顺序在 之前
 
  

1.2.5 registerListeners() 方法

引用自:https://blog.csdn.net/weixin_/article/details/?spm=1001.2014.3001.5502

 
  

这个方法要做的很简单,就是两个循环遍历,把Spring通过硬编码定义的监听器注册到容器中,然后把我们自定义的监听器注册到容器中,通过这些直接叙述有一些苍白无力,我们写一个简单的发布-订阅的例子方便理解。
在发布订阅模式用需要四个角色:
ApplicationEvent:事件,每个实现类表示一类事件,可携带数据。抽象类。
ApplicationListener:事件监听器,用于接收事件处理时间。接口。
ApplicationEventMulticaster:事件管理者,可以注册(添加)/移除/发布事件。用于事件监听器的注册和事件的广播。接口。
ApplicationEventPublisher:事件发布者,委托事件管理者ApplicationEventMulticaster完成事件发布。
在这里插入图片描述





事件:

 
  

事件监听器:

 
  

事件发布者:

 
  

那么事件的管理器跑哪去了呢?
我们在 registerListeners()方法上面打一个断点,看看我们自定义的事件是如何在Spring中起作用的。
在这里插入图片描述

第一个循环是Spring默认的监听器默认情况下是空。

我们自定义的事件监听器在第二个循环里面被加载到了ApplicationEventMulticaster中,已经很明显了,ApplicationEventMulticaster就是我们的事件管理者。

我们在把他们之间的关系详细串一下
在这里插入图片描述

注:广播器和上面的管理者是一个意思
到这个阶段,事件管理者和监听器都在Spring容器里初始化和注册了,之后就可以实现监听者模式了,对事件的发布进行监听然后处理。
在就是ac.publishEvent(myEvent);方法发布事件后进行的业务处理。

 
  

事件监听机制实际就是主题-订阅模式(观察者模式)的实现,能够降低代码耦合。
本文顺便把观察者模式简要的叙述一下,方便读者可以更好的理解。
观察者(Observer)模式的定义:指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

 
  

汇率变化就是一个事件,当该事件发生时,它的观察者出口公司和进口公司就要做相应的变化。

书归正传重新回到registerListeners()方法中,这时所有的监听器都注册到了容器中,只等publishEvent()发布事件以后,就会执行我们监听器中的业务逻辑。

据说在Springboot中应用了大量的发布订阅模式,抱着求知若渴的态度我们去Springboot中搂一眼,在registerListeners()上面打一个断点,看看和Spring上面的断点有什么区别。
在这里插入图片描述

在Spirng中监听器默认是空,当时在Springboot中有15个之多,不愧是加强版的Spring。具体这些监听器是干嘛的我们就不深究了,在Springboot中会对其逐步拆解的。

引用自:https://blog.csdn.net/weixin_/article/details/?spm=1001.2014.3001.5502

  • 今天解读Spring核心方法refresh()中最最重要的一个方法 方法,该方法负责初始化所有的单例bean
  • 到目前为止,应该说 BeanFactory 已经创建完成,并且所有的实现了 接口的 都已经初始化并且其中的 方法已经得到回调执行了。而且 Spring 已经“手动”注册了一些特殊的 Bean,如 、 等
  • 剩下的就是初始化 了,大都数我们的业务中都是单例bean,就像我们写的、的类(没有设置的)都是在这个地方初始化,以供我们使用,如果没有设置懒加载,那么 Spring 会在接下来初始化所有的 singleton beans
  • 我们深入finishBeanFactoryInitialization(beanFactory)中,里面的调用线路错综复杂,还望读者可以做好心理准备。
 
  

该方法是判断bean的一系列是不是属于某个类型的bean,如果是就调用 方法,如果不是,就调用beanFactory.preInstantiateSingletons()进行初始化,我们先把 放一放,重点看一看 方法。

 
  
  • 方法的主要任务是进行初始化的,在初始化前同样是一系列判断,如,是否是懒加载的,是否是一个factorybean(一个特别的bean,负责工厂创建的bean),最后调用 方法。
    其中有个插曲是否实现了SmartInitializingSingleton接口,将接口让你可以在bean初始化后做一些事,我们写一个简单的实例测试一下
    在这里插入图片描述

  • 其他地方读者看注释了解一下即可,我们开始继续深入getBean()方法
  • getBean()方法内部调用了doGetBean()我们直接看doGetBean方法
 
  

具体的实例化过程在createBean()方法中,我们继续深入createBean()方法。

 
  

我们继续往里看 doCreateBean 这个方法,这个调用过程是真的深

 
  

到这里,我们已经分析完了 doCreateBean 方法,总的来说,我们已经说完了整个初始化流程。
在实例化bean后有一个特别重要的知识点,也是面试中最常问的,Spring怎么解决循环依赖问题?核心代码就在这个方法里面。
循环依赖其实就是循环引用,也就是两个或则两个以上的bean互相持有对方,最终形成闭环。比如A依赖于B,B依赖于C,C又依赖于A。
如下图
在这里插入图片描述



doCreateBean 方法有三个核心流程。
在这里插入图片描述

(1)createBeanInstance:实例化,其实也就是调用对象的构造方法实例化对象
(2)populateBean:填充属性,这一步主要是多bean的依赖属性进行填充
(3)initializeBean:调用spring xml中的init 方法。
从上面讲述的单例bean初始化步骤我们可以知道,循环依赖主要发生在第一、第二步。也就是构造器循环依赖和field循环依赖。
那么我们要解决循环引用也应该从初始化过程着手,对于单例来说,在Spring容器整个生命周期内,有且只有一个对象,所以很容易想到这个对象应该存在Cache中,Spring为了解决单例的循环依赖问题,使用了三级缓存。
我们看一下getSingleton方法。
该方法还依赖于三个map,这三个map就是三级缓存





 
  
 
  
 
  
  • 从singletonFactories中移除,并放入earlySingletonObjects中。其实也就是从三级缓存移动到了二级缓存()(在二级缓存中若保存的是AOP后的的代理对象,则会被原始bean周期中的AOP操作与放入单例池的操作时进行判断)
  • 从上面三级缓存的分析,我们可以知道,Spring解决循环依赖的诀窍就在于singletonFactories这个三级cache。这就是解决循环依赖的关键,这段代码发生在createBeanInstance之后,也就是说单例对象此时已经被创建出来(调用了构造器)。这个对象已经被生产出来了,虽然还不完美(还没有进行初始化的第二步和第三步),但是已经能被人认出来了(根据对象引用能定位到堆中的对象),所以Spring此时将这个对象提前曝光出来让大家认识,让大家使用。
  • A首先完成了初始化的第一步,并且将自己提前曝光到singletonFactories中,此时进行初始化的第二步,发现自己依赖对象B,此时就尝试去get(B),发现B还没有被create,所以走create流程,B在初始化第一步的时候发现自己依赖了对象A,于是尝试get(A),尝试一级缓存singletonObjects(肯定没有,因为A还没初始化完全),尝试二级缓存earlySingletonObjects(也没有),尝试三级缓存singletonFactories,由于A通过ObjectFactory将自己提前曝光了,所以B能够通过ObjectFactory.getObject拿到A对象(虽然A还没有初始化完全,但是总比没有好呀),B拿到A对象后顺利完成了初始化阶段1、2、3,完全初始化之后将自己放入到一级缓存singletonObjects中
  • 此时返回A中,A此时能拿到B的对象顺利完成自己的初始化阶段2、3,最终A也完成了初始化,进去了一级缓存singletonObjects中,而且更加幸运的是,由于B拿到了A的对象引用,所以B现在hold住的A对象完成了初始化。
  • 知道了这个原理时候,肯定就知道为啥Spring不能解决“A的构造方法中依赖了B的实例对象,同时B的构造方法中依赖了A的实例对象”这类问题了!因为加入singletonFactories三级缓存的前提是执行了构造器,所以构造器的循环依赖没法解决。
  • 接下来我们挑 doCreateBean 中的三个细节出来说说。一个是创建 Bean 实例的 createBeanInstance 方法,一个是依赖注入的 populateBean 方法,还有就是回调方法 initializeBean。
    这三个方法也是极其复杂的,读者有兴趣可以继续的深入进去。
    1、 createBeanInstance 方法

 
  

看一下instantiateBean方法是怎么做的。

 
  

我们可以看到,关键的地方在于:beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent); 里面是具体是实例化过程,我们进去看看。

 
  
 
  
 
  

自此,Spring实例化单例非懒加载bean的过程也就完成了,这也是Spirng最最重要的方法了。在我们的日常使用Spring中,定义好各个类,然后在上面加上,@Controller,@Service,Autowired等注解,这些注解是怎么起作用的呢?

引用自:https://blog.csdn.net/weixin_/article/details/?spm=1001.2014.3001.5502
Spring IoC 的核心内容要收尾了,本文将对最后一个方法 finishRefresh 进行介绍,位于refresh 方法中的第九个位置。
本章实际是对发布订阅模式的一种补充,这是Spring在刷新事件完成后发布事件。
由于存在上下文关系,本文也会对 initApplicationEventMulticaster 方法、registerListeners 方法进行回顾。 我们回到refresh 方法中


 
  
 
  

最终只做了一件事,初始化应用的事件广播器。(具体什么是事件广播器及其作用可见上上篇文章,具体就不在吃赘述了)
registerListeners():注册监听器。见上上篇文章
finishRefresh():完成上下文的刷新工作,本文重点。 首先概览finishRefresh方法

 
  
 
  

2.首先将刷新完毕事件传播到生命周期处理器

 
  

3.推送上下文刷新完毕事件到相应的监听器

 
  

这里面调用的publishEvent方法,和我们自定义的监听器调用的publishEvent是同一个方法,ContextRefreshedEvent是Spirng的一个事件称为上下文刷新完毕事件,如果我们在上下文刷新完成后要写一个发布事件,实现ApplicationListener接口即可。
我们在此举一个简单的例子。
在这里插入图片描述

在这里插入图片描述

这样,当 Spring 执行到 finishRefresh 方法时,就会将 ContextRefreshedEvent 事件推送到 MyRefreshedListener 中。
读者可以结合自定义事件对比一个和Spring提供的刷新上下文事件的区别,以便于更好的理解Spring的事件监听机制。
跟 ContextRefreshedEvent 相似的还有:ContextStartedEvent、ContextClosedEvent、ContextStoppedEvent。
好啦,Spirng的refresh方法到这里就结束啦,一共是九篇博客,实际上这也是Spirng的IOC的全部内容了,如果读者能把九篇的完全消化,那么spring的IOC也就理解的七七八八了。


到此这篇spring教程菜鸟(spring菜鸟教程pdf)的文章就介绍到这了,更多相关内容请继续浏览下面的相关推荐文章,希望大家都能在编程的领域有一番成就!

版权声明


相关文章:

  • QPainterPath(qpainterpath求并集)2025-07-02 16:09:07
  • redis没有用户名吗(redis没设置密码)2025-07-02 16:09:07
  • redis连接需要关闭吗(redis连接失败什么意思)2025-07-02 16:09:07
  • list<string>转换成list<int>(list转换成string字符串)2025-07-02 16:09:07
  • 数组方法fill(数组方法filter)2025-07-02 16:09:07
  • chrony服务器配置为源(服务器怎么配置yum源)2025-07-02 16:09:07
  • github的镜像网站(github release 镜像)2025-07-02 16:09:07
  • ifstream获取文件长度(ifstream 读取文件)2025-07-02 16:09:07
  • 如何打开目录对话框(在word2007中,如何打开目录对话框)2025-07-02 16:09:07
  • hprof怎么读(/hp怎么读)2025-07-02 16:09:07
  • 全屏图片