关于java:爱上源码重学Spring-IoC深入

请答复:
咱们为什么要学习源码?
1、知其然知其所以然
2、站在伟人的肩膀上,进步本人的编码程度
3、应酬面试

1.1 Spring源码浏览小技巧

1、类档次藏得太深,不要一个类一个类的去看,遇到办法该进就大胆的进

2、更不要一行一行的去看,看外围点,有些办法并不重要,不要跟它纠缠

3、看不懂的先不看,依据语义和返回值能晓得这个办法达到了啥目标即可

4、只看外围接口(上面标注了重点的中央)和外围代码,有些中央兴许你应用spring以来都没触发过

5、debug跟步走,源码中给大家标注好了,见到 ”===>“ 就进去

​ 进去之前,下一行打个断点,不便疾速回到岔路口

​ 进去之前,能够先点办法看源码,再debug跟进

6、广度优先,而非深度优先。先沿着主流程走,理解大略,再细化某些办法

7、认命。spring里多少万行的代码,一部书都写不完。只能学关键点

浏览源码目标

加深了解spring的bean加载过程

面试吹牛x

江湖传说,spring的类关系是这样的……

1.2 IoC初始化流程与继承关系

引言
在看源码之前须要把握Spring的继承关系和初始化
1) IoC容器初始化流程

指标:

1、IoC容器初始化过程中到底都做了哪些事件(宏观指标)

2、IoC容器初始化是如何实例化Bean的(划重点,最终目标)

//没有Spring之前咱们是这样的
User user=new User();
user.xxx();

//有了Spring之后咱们是这样的
<bean id="userService" class="com.spring.test.impl.UserServiceImpl">
User user= context.getBean("xxx");
user.xxx();

IoC流程简化图:

tips:

上面的流转记不住没有关系

在分析源码的整个过程中,咱们始终会拿着这个图和源码对照

初始化:

1、容器环境的初始化

2、Bean工厂的初始化(IoC容器启动首先会销毁旧工厂、旧Bean、创立新的工厂)

读取与定义

读取:通过BeanDefinitonReader读取咱们我的项目中的配置(application.xml)

定义:通过解析xml文件内容,将外面的Bean解析成BeanDefinition(未实例化、未初始化)

实例化与销毁

Bean实例化、初始化(注入)

销毁缓存等

扩大点

事件与多播、后置处理器

简单的流程关键点:

重点总结:

1、工厂初始化过程

2、解析xml到BeanDefinition,放到map

3、调用后置处理器

4、从map取出进行实例化( ctor.newInstance)

5、实例化后放到一级缓存(工厂)

2) 容器与工厂继承关系

tips:

别缓和,上面的继承记不住没有关系

关注色彩标注的几个就能够

指标:简略了解ioC容器继承关系

继承关系了解:

1、ClassPathXmlApplicationContext最终还是到了 ApplicationContext 接口,同样的,咱们也能够应用绿色彩的 FileSystemXmlApplicationContext 和 AnnotationConfigApplicationContext 这两个类实现容器初始化的工作

2、FileSystemXmlApplicationContext 的构造函数须要一个 xml 配置文件在零碎中的门路,其余和 ClassPathXmlApplicationContext 基本上一样

3、AnnotationConfigApplicationContext 的构造函数扫描classpath中相干注解的类,主流程一样

课程中咱们以最经典的 classpathXml 为例。

Bean工厂继承关系

指标:

ApplicationContext 和 BeanFactory 啥关系?

BeanFactory 和 FactoryBean呢?

总结:

别胆怯,下面的继承关系不必刻意去记住它

其实接触到的就最上面这个!

1.3 开始搭建测试项目

四步:

1、新建测试module我的项目

首先咱们在 Spring 源码我的项目中新增一个测试项目,点击 New -> Module… 创立一个 Gradle 的 Java 我的项目

2、详细信息

3、设置gradle

4、欠缺信息

在 build.gradle 中增加对 Spring 源码的依赖:

compile(project(':spring-context'))

spring-context 会主动将 spring-core、spring-beans、spring-aop、spring-expression 这几个根底 jar 包带进来。

接着,咱们须要在我的项目中创立一个 bean 和配置文件(application.xml)及启动文件(Main.java)

接口如下:

package com.spring.test.service;

public interface UserService {
    public String getName();
}

实现类

package com.spring.test.impl;

import com.spring.test.service.UserService;

public class UserServiceImpl implements UserService {
    @Override
    public String getName() {
        return "Hello World";
    }
}

Main代码如下

public class Test {
    public static void main(String[] args) {
        ApplicationContext context =
                new ClassPathXmlApplicationContext("classpath*:application.xml");

        UserService userService = context.getBean(UserService.class);
        System.out.println(userService);
        // 这句将输入: hello world
        System.out.println(userService.getName());

    }
}

配置文件 application.xml(在 resources 中)配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="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">
    <bean id="userService" class="com.spring.test.impl.UserServiceImpl"/>
</beans>

运行

输入如下
[email protected]
Hello World

1.4 工厂的构建

引言:
接下来,咱们就正式解说Spring ioC容器的源码
咱们的目标:看一下ioC如何帮咱们生成对象的

生命周期

1)ApplicationContext入口

参考 IocTest.java

测试代码:spring反对多种bean定义形式,为不便大家了解构造,以xml为案例,前面的解析流程统一

        ApplicationContext context = new ClassPathXmlApplicationContext("classpath*:${xmlName}.xml");
        // (c)从容器中取出Bean的实例,call:AbstractApplicationContext.getBean(java.lang.Class<T>)
        //工厂模式(simple)
        UserService userService = (UserService) context.getBean("userServiceBeanId");
        // 这句将输入: hello world
        System.out.println(userService.getName());

进入到ClassPathXmlApplicationContext的有参结构器

org.springframework.context.support.ClassPathXmlApplicationContext#ClassPathXmlApplicationContext(java.lang.String[], boolean, org.springframework.context.ApplicationContext)

    public ClassPathXmlApplicationContext(
            String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
            throws BeansException {
        //继承结构图
        //1、返回一个classloader
        //2、返回一个解析器
        super(parent);
        // 1、获取环境(零碎环境、jvm环境)
        // 2、设置Placeholder占位符解析器
        // 2、将xml的门路解析完存储到数组
        setConfigLocations(configLocations);
        //默认为true
        if (refresh) {
            //外围办法(模板)
            refresh();
        }
    }

重点步骤解析(断点跟踪解说)

super办法做了哪些事件
1、super办法:通过点查看父容器与子容器概念
2、super办法:调用到顶端,一共5层,每一层都要与讲义中的【ioC与Bean工厂类关系继承】进行对照
3、super办法:在什么中央初始化的类加载器和解析器
setConfigLocations办法做了哪些事件:
1、如何返回的零碎环境和jvm环境
2、门路的解析
3、设置占位符解析器

进入外围办法refresh
2)预刷新

prepareRefresh()【筹备刷新】

        // synchronized块锁(monitorenter --monitorexit),不然 refresh() 还没完结,又来个启动或销毁容器的操作
        synchronized (this.startupShutdownMonitor) {
            //1、【筹备刷新】【Did four things】
            prepareRefresh();
            
            
    ......。略

解说重点(断点跟踪、类继承关系、架构图解说)

prepareRefresh干了哪些事件

    //1、记录启动工夫/设置开始标记
    //2、子类属性扩大(模板办法)
    //3、校验xml配置文件
    //4、初始化晚期公布的应用程序事件对象(不重要,仅仅是创立setg对象)
3)创立bean工厂【重点】

【取得新的bean工厂】obtainFreshBeanFactory()

最终目标就是解析xml,注册bean定义

            关键步骤
            //1、敞开旧的 BeanFactory
            //2、创立新的 BeanFactory(DefaluListbaleBeanFactory)
            //3、解析xml/加载 Bean 定义、注册 Bean定义到beanFactory(未初始化)
            //4、返回全新的工厂
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
4)bean工厂前置操作

【筹备bean工厂】prepareBeanFactory(beanFactory);

    //1、设置 BeanFactory 的类加载器
    //2、设置 BeanFactory 的表达式解析器
    //3、设置 BeanFactory 的属性编辑器
    //4、智能注册

tips

以后代码逻辑简略、且非核心

5)bean工厂后置操作

【后置处理器Bean工厂】postProcessBeanFactory(beanFactory) 空办法

tips:子类实现

空办法,跳过

6)工厂后置处理器【重点】

【调用bean工厂后置处理器】invokeBeanFactoryPostProcessors(beanFactory);

    //调用程序一:bean定义注册后置处理器
    //调用程序二:bean工厂后置处理器

    PostProcessorRegistrationDelegate 类里有具体注解

tips

invoke办法近200行

关注两类后置处理器的办法执行步骤和程序

7)bean后置处理器

【注册bean后置处理器】registerBeanPostProcessors(beanFactory)

//6、【注册bean后置处理器】只是注册,然而不会反射调用
//性能:找出所有实现BeanPostProcessor接口的类,分类、排序、注册
registerBeanPostProcessors(beanFactory);
//    外围:查看重要的3步;最终目标都是实现bean后置处理器的注册
// 第一步: implement PriorityOrdered
// 第二步: implement Ordered.
// 第三步: Register all internal BeanPostProcessors.



8)国际化

【初始化音讯源】国际化问题i18n initMessageSource();

tips:

就加了个bean进去,非核心步骤,跳过

9)初始化事件播送器

【初始化应用程序事件多路播送】initApplicationEventMulticaster();

tips:

须要解说观察者设计模式

重点:就放了个bean进去, 到上面的 listener再联调。

10)刷新

【刷新】 onRefresh();

空的,交给子类实现:默认状况下不执行任何操作

// 具体的子类能够在这里初始化一些非凡的 Bean(在初始化 singleton beans 之前)
onRefresh();

不重要,跳过
11)注册监听器【重点】

【注册所有监听器】registerListeners();

测试代码参考:MulticastTest

    //获取所有实现了ApplicationListener,而后进行注册
    //1、汇合applicationListeners查找
    //2、bean工厂找到实现ApplicationListener接口的bean
    //3、this.earlyApplicationEvents;

tips:

须要解说观察者设计模式

重点:演示多播和容器公布

12)实现bean工厂【重点】

【实现bean工厂初始化操作】finishBeanFactoryInitialization(beanFactory);

//【实现bean工厂初始化操作】负责初始化所有的 singleton beans
//此处开始调用Bean的前置处理器和后置处理器
finishBeanFactoryInitialization(beanFactory);

解说重点(断点跟踪、类继承关系、架构图解说)

  //1、设置辅助器:例如:解析器、转换器、类装载器
    //2、实例化
    //3、填充
    //4、调用前置、后置处理器
//外围代码在  getBean() , 上面独自解说
13)实现刷新

【实现刷新】

    protected void finishRefresh() {
        // 1、革除上下文级资源缓存
        clearResourceCaches();

        // 2、LifecycleProcessor接口初始化
        // ps:当ApplicationContext启动或进行时,它会通过LifecycleProcessor来与所有申明的bean的周期做状态更新
        // 而在LifecycleProcessor的应用前首先须要初始化
        initLifecycleProcessor();

        // 3、启动所有实现了LifecycleProcessor接口的bean
        //DefaultLifecycleProcessor,默认实现
        getLifecycleProcessor().onRefresh();

        // 4、公布上下文刷新结束事件到相应的监听器
        //ps:当实现容器初始化的时候,
        // 要通过Spring中的事件公布机制来收回ContextRefreshedEvent事件,以保障对应的监听器能够做进一步的逻辑解决
        publishEvent(new ContextRefreshedEvent(this));

        // 5、把以后容器注册到到MBeanServer,用于jmx应用
        LiveBeansView.registerApplicationContext(this);
    }

tips:

非核心步骤

2 singleton bean 创立【重点】

上面拎进去,重点讲 getBean办法。

参考代码:

先看没有循环依赖的状况,一般单例bean的初始化 SinigleTest.java

前面再讲循环依赖

1)调用入口

大家都晓得是getBean()办法,然而这个办法要留神,有很多调用机会

如果你把断点打在了这里,再点进去getBean,你将会间接从singleton汇合中拿到一个实例化好的bean

无奈看到它的实例化过程。

能够debug试一下。会发现间接从getSingleTon返回了bean,这不是咱们想要的模样……

思考一下,为什么呢?

回顾 1.4中的第 12 大节,在bean工厂实现后,会对singleton的bean实现初始化,那么真正的初始化应该产生在那里!

那就须要找到:DefaultListableBeanFactory的第 809 行,那里的getBean

也能够从 1.4的第12大节的入口跟进去。断点打在这里试试:

这也是咱们在下面留下的尾巴。

本大节咱们从这里持续……

2)主流程

小tip:先搞革除3级缓存的事

对于bean的三级缓存:DefaultSingletonBeanRegistry代码

    /**
     * 一级缓存:单例(对象)池,这外面的对象都是确保初始化实现,能够被失常应用的
     * 它可能来自3级,或者2级
     */
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

    /**
     * 三级缓存:单例工厂池,这外面不是bean自身,是它的一个工厂,将来调getObject来获取真正的bean
     * 一旦获取,就从这里删掉,进入2级(产生闭环的话)或1级(没有闭环)
     */
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

    /**
     * 二级缓存:晚期(对象)单例池,这外面都是半成品,只是有人用它提前从3级get进去,把援用裸露进来
     * 它外面的属性可能是null,所以叫晚期对象,early!半成品
     * 将来在getBean付完属性后,会调addSingleton清掉2级,正式进入1级
     */
    private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

传统叫三级缓存里拿bean,其实就是仨map

严格意义上,只有single一级缓存,其余俩基本算不上是缓存

他们只是在生成bean的过程中,暂存过bean的半成品。

就那么称说,不用较真

主流程图很重要!前面的debug会带着这张图走

getBean   :
入口

doGetBean   :
调getSingleton查一下缓存看看有没有,有就返回,没有给singleton一个lambda表达式,函数式编程里调上面的createBean拿到新的bean,而后革除3级缓存,放入1级缓存

createBean  :
调这里。一堆查看后,进入上面

doCreateBean  :
真正创立bean的中央: 调构造函数初始化 - 放入3级缓存 - 解析属性赋值 - bean后置处理器
3)getSingleton

在DefaultSingletonBeanRegistry里,有三个,作用齐全不一样

//啥也没干,调上面传了个true
public Object getSingleton(String beanName) 
  
//从1级缓存拿,1级没有再看状况
//前面的参数如果true,就应用3级升2级返回,否则间接返回null 
protected Object getSingleton(String beanName, boolean allowEarlyReference)

//1级没有,通过给的factory创立并放入1级里,革除2、3
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory)
4)bean实例化
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance
5)放入三级缓存

循环依赖和aop

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#addSingletonFactory
4)注入属性
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean
真正给bean设置属性的中央!
7)bean前后置

还记得下面咱们自定义的 Bean后置处理器吗

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean
前、后置的调用,在这里

具体见下图第3步,很多,理解即可,须要时查一下在相干中央扩大

8)小结

伪代码,无循环依赖时,生成bean流程一览

getBean("A"){
    doGetBean("A"){
    a = getSingleton("A"){
      a = singletonObjects(); //查1级缓存,null
      if("创立过3级缓存"){  //不成立
        //疏忽
      }
      return a;
    }; // null
    
    if(a == null){
      a = getSingleton("A" , ObjectFactory of){
        
        
        a = of.getObject() -> { //lambda表达式
          createBean("A"){
            doCreateBean("A"){
              createBeanInstance("A"); // A 实例化
              addSingletonFactory("A"); // A 放入3级缓存
              populateBean("A"); // A 注入属性
              initializeBean("A"); // A 后置处理器
            } //end doCreateBean("A")
          } //end crateBean("A")
          } // end lambda A
        
        addSingleton("A" , a) // 革除2、3级,放入1级
      } // end getSingleton("A",factory)
  
    } // end if(a == null)
    
    return a;
      
  } //end doGetBean("A")
}//end getBean("A")

3 Spring的循环依赖

引言
在下面,咱们分析了bean实例化的整个过程
也就是咱们的Bean他是独自存在的,和其余Bean没有交加和援用
而咱们在业务开发中,必定会有多个Bean互相援用的状况
也就是所谓的循环依赖

3.1 什么是循环依赖

简略回顾下

艰深的讲就是N个Bean相互援用对方,最终造成闭环

我的项目代码介绍如下(测试类入口: CircleTest.java)

配置文件

    <!--循环依赖BeanA依赖BeanB -->
    <bean id="userServiceImplA" class="com.spring.test.impl.UserServiceImplA">
        <property name="userServiceImplB" ref="userServiceImplB"/>
    </bean>

    <!--循环依赖BeanB依赖BeanA -->
    <bean id="userServiceImplB" class="com.spring.test.impl.UserServiceImplB">
        <property name="userServiceImplA" ref="userServiceImplA"/>
    </bean>

userServiceImplA代码如下

public class UserServiceImplA implements UserService {
    private UserServiceImplB userServiceImplB;
    public void setUserServiceImplB(UserServiceImplB userServiceImplB) {
        this.userServiceImplB = userServiceImplB;
    }

    @Override
    public String getName() {

        return "在UserServiceImplA的Bean中" +
                "userServiceImplB注入胜利>>>>>>>>>"+userServiceImplB;

    }

}

userServiceImplB代码如下

//实现类
public class UserServiceImplB implements UserService {
    private UserServiceImplA userServiceImplA;

    public void setUserServiceImplA(UserServiceImplA userServiceImplA) {
        this.userServiceImplA = userServiceImplA;
    }

    @Override
    public String getName() {

        return "在UserServiceImplB的Bean中" +
                "userServiceImplA注入胜利>>>>>>>>>"+userServiceImplA;

    }

入口Main

        ApplicationContext context = new ClassPathXmlApplicationContext("classpath*:application.xml");
        
    UserService userService = context.getBean("userServiceImplA",UserService.class);
    System.out.println(userService.getName());

输入如下

3.2 Spring如何解决循环依赖

如果无奈解决循环依赖

1、Bean无奈胜利注入,导致业务无奈进行

2、产生死循环(一种假如情景)

1)三级缓存变动过程

指标:

只有明确三级缓存变动过程,能力晓得是如何解决循环依赖的

略去其余步骤,只看缓存变动

变动过程3-1:如下图:

步骤:

A :… – 走到doCreateBean: 初始化 – 进3级缓存 – 注入属性,发现须要B

B :… – 走到doCreateBean: 初始化 – 进3级缓存

1、BeanA经验gdcd四个办法,走到doCreatebean里在实例化后、注入前放到三级缓存

2、放到三级缓存后;BeanA在正式的注入的时候,发现有循环依赖,反复上【1】的步骤

3、最终:BeanA和BeanB都放到了三级缓存

变动过程3-2:如下图:

步骤:

1、BeanB放到三级缓存后,这个时候BeanB要开始注入了;

于是,BeanB找到了循环依赖BeanA后,再从头执行A的getBean和doGetBean办法;

此处在getSingleton外面(这货第一次是必经的,但第二次来行为不一样了)将BeanA设置到了二级缓存,并且把BeanA从三级缓存移除走了

2、BeanB如愿以偿的拿到了A,注入,此时,实现了注入过程;始终到DefaultSingletonBeanRegistry#addSingleton办法后;BeanB从三级缓存间接进入一级缓存,实现它的使命

3、目前,一级缓存有BeanB(外面的BeanA属性还是空)、二级缓存有BeanA 三级缓存为空

成果如下

走到这一步,B外面有A,它已实现。

然而很可怜,A外面的B还是null,咱们第三步会持续实现这个设置

思考一下:

如果不必三级,咱们间接用2级也能实现,然而3级咱们说它是一个Factory,外面能够在创立的前后嵌入咱们的代码,和前后置处理器,Aop之类的操作就产生在这里

而2级寄存的是bean实例,没这么多扩大的可能性,如果仅仅用于bean循环创立,倒是能够

总结:

1、如果不调用后置,返回的bean和三级缓存一样

2、如果调用后置,返回的就是代理对象

3、这就是三级缓存设计的奇妙之处!!!!Map<String, ObjectFactory<?>>

变动过程3-3:如下图:

步骤:

此时, BeanB外面曾经注入了BeanA,它本人实现并进入了一级缓存

要留神,它的实现是被动的后果,也就是A须要它,长期先腾出工夫创立了它

接下来,BeanA 还要持续本人的流程,而后populateBean办法将BeanB注入到本人里

最初,BeanA 进一级缓存,删除之前的二级

整个流程实现!

功败垂成:单方互相持有对方成果如下:

2)三级缓存解决方案总结

简化版

序列图

三级缓存解决循环依赖过程(回顾)

1、BeanA通过gdcd办法、放入到3级缓存、如果有循环依赖BeanB,反复执行gdcd办法

2、直到发现了它也须要A,而A后面经验了一次get操作,将3级缓存的BeanA放到2级缓存

3、而后2级缓存的A注入进BeanB, BeanB完事进一级缓存,此时BeanB持有BeanA

3、接下来,持续实现BeanA剩下的操作,取BeanB填充进BeanA,将BeanA放到一级缓存,实现!

伪代码,循环依赖流程一览,都是关键步骤,不能再简化了

倡议粘贴到vscode等编辑器里查看,因为……它层级太tmd深了!

getBean("A"){
    doGetBean("A"){
    a = getSingleton("A"){
      a = singletonObjects(); //查1级缓存,null
      if("创立过3级缓存"){  //不成立
        //疏忽
      }
      return a;
    }; // A第一次,null
    
    if(a == null){
      a = getSingleton("A" , ObjectFactory of){
        
        
        a = of.getObject() -> { //lambda表达式
          createBean("A"){
            doCreateBean("A"){
              createBeanInstance("A"); // A 实例化
              addSingletonFactory("A"); // A 放入3级缓存
              populateBean("A"){
                //A 须要B,进入B的getBean
                b = getBean("B"){
                  doGetBean("B"){
                    b = getSingleton("B"); // B第一次,null

                    if(b == null){
                      b = getSingleton("B", ObjectFactory of){

                        b = of.getObject() -> {
                          createBean("B"){
                            doCreateBean("B"){
                              createBeanInstance("B"); // B 实例化
                              addSingletonFactory("B"); // B 放入3级缓存
                              populateBean("B"){
                                //B 须要A,2次进入A的getBean
                                a = getBean("A"){
                                  doGetBean("A"){
                                    a = getSingleton("A"){
                                      a = singletonObjects(); //查1级缓存,null
                                      if("创立过3级缓存"){  //成立!
                                        a = singletonFactory.getObject("A"); //取3级缓存,生成a
                                        earlySingletonObjects.put("A", a); //放入2级缓存
                                        singletonFactories.remove("A"); //移除3级缓存
                                        return a;
                                      }
                                    }; // A第二次,不是null,然而半成品,还待在2级缓存里
                                  } // end doGetBean("A")
                                } // end getBean("A")
                              }  // end populate B
                              initializeBean("B",b); // B后置处理器
                            } // end doCreateBean B
                          } // end createBean B
                        } // end lambda B

                        // B 创立实现,并且是残缺的,尽管它外面的A还是半成品,但不影响它进入1级               
                        addSingleton("B",b) ; // 革除3级缓存,进入1级
                      ); // end getSingleton("B",factory)                 


                    } // end if(b==null);

                    return b;

                  } // end doGetBean("B")
                } // end getBean("B")
              } // end populateBean("A")

              initializeBean("A"); // A 后置处理器
            } //end doCreateBean("A")
          } //end crateBean("A")
          } // end lambda A
        
        addSingleton("A" , a) // 革除2、3级,放入1级
      } // end getSingleton("A",factory)
  
    } // end if(a == null)
    
    return a;
      
  } //end doGetBean("A")
}//end getBean("A")

总结

能够发现,通过spring的三级缓存完满解决了循环依赖

Spring解决机制很聪慧;它先扫描一遍Bean,先放到一个容器(3级缓存待命)

此时也不晓得是否存在循环依赖,先放到三级缓存再说

等到设置属性的时候,取对应的属性bean去(此时才发现有了循环依赖) ,在放到第二个容器(2级缓存,半成品)

持续,而后从二级缓存拿出进行填充(注入)

填充结束,将本人放到一级缓存(这个bean是被动创立进去的,因为他人须要它,后果它先实现了)

而后一直循环外层,解决最原始要创立的那个bean

为什么设计三级?二级缓存是否解决循环依赖?

能够解决。别说2级,1级都行

尽管二级缓存能解决循环依赖,然而aop时会可能会引发问题,三级是一个factory,在外面装备了对应的后置处理器,其中就有咱们的aop (前面会讲到),如果有人要用它,会在调用factory的getObject时失效,生成代理bean而不是原始bean。

如果不这么做,间接创立原始对象注入,可能引发aop生效。

所以spring的3级各有意义:

1级:最终成品

2级:半成品

3级:工厂,备用

在下面的办法getEarlyBeanReference(提前裸露的援用)

回顾下

AbstractAutowireCapableBeanFactory.getEarlyBeanReference

        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            //循环所有Bean后置处理器
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                    SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
                  //重点:开始创立AOP代理
                    exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
                }
            }
        }

总结下:

1、如果不调用后置处理器,返回的Bean和三级缓存一样,都是实例化、一般的Bean

2、如果调用后置,返回的就是代理对象,不是一般的Bean了

其实;这就是三级缓存设计的奇妙之处

那为什么要2级呢? 不能间接放入1级吗?

不能!

A-B-A中,第二次A的时候,A还是个半成品,不能放入1级

以下面为例,A在进入2级缓存的时候,它外面的B还是个null !

如果放入1级,被其余应用的中央取走,会引发问题,比方空指针

4 IoC用到的那些设计模式

引言:

Spring中应用了大量的设计模式(面试)

4.1 工厂

工厂模式(Factory Pattern)提供了一种创建对象的最佳形式。

工厂模式(Factory Pattern)分为三种

1、简略工厂

2、工厂办法

3、形象工厂

1. 简略工厂模式

ApplicationContext context =
    new ClassPathXmlApplicationContext("classpath*:application.xml");\
UserService userService = context.getBean(UserService.class);

简略工厂模式对对象创立治理形式最为简略,因为其仅仅简略的对不同类对象的创立进行了一层简略的封装

定义接口IPhone

public interface Phone {
    void make();
}

实现类

public class IPhone implements Phone {
    public IPhone() {
        this.make();
    }

    @Override
    public void make() {
        // TODO Auto-generated method stub
        System.out.println("生产苹果手机!");
    }
}

实现类

public class MiPhone implements Phone {
    public MiPhone() {
        this.make();
    }
    @Override
    public void make() {
        // TODO Auto-generated method stub
        System.out.println("生产小米手机!");
    }
}

定义工厂类并且测试

public class PhoneFactory {
    public Phone makePhone(String phoneType) {
        if (phoneType.equalsIgnoreCase("MiPhone")) {
            return new MiPhone();
        } else if (phoneType.equalsIgnoreCase("iPhone")) {
            return new IPhone();
        }
        return null;
    }

    //测试简略工厂
    public static void main(String[] arg) {
        PhoneFactory factory = new PhoneFactory();
        Phone miPhone = factory.makePhone("MiPhone");             
        IPhone iPhone = (IPhone) factory.makePhone("iPhone");     
    }
}

4.2 模板

模板模式(Template Pattern):基于抽象类的,外围是封装算法

Spring外围办法refresh就是典型的模板办法
org.springframework.context.support.AbstractApplicationContext#refresh

模板设计模式—

模板办法定义了一个算法的步骤,并容许子类为一个或多个步骤提供具体实现

//模板模式
public abstract class TemplatePattern {
    protected abstract void step1();

    protected abstract void step2();

    protected abstract void step3();

    protected abstract void step4();

    //模板办法
    public final void refresh() {
    //此处也可退出以后类的一个办法实现,例如init()
        step1();
        step2();
        step3();
        step4();
    }


}

定义子类

//模板模式
public class SubTemplatePattern extends TemplatePattern {
    @Override
    public void step1() {
        System.out.println(">>>>>>>>>>>>>>1");
    }

    @Override
    public void step2() {
        System.out.println(">>>>>>>>>>>>>>2");

    }

    @Override
    public void step3() {
        System.out.println(">>>>>>>>>>>>>>3");

    }

    @Override
    public void step4() {
        System.out.println(">>>>>>>>>>>>>>4");
    }
    
    //测试
    public static void main(String[] args) {
        TemplatePattern tp = new SubTemplatePattern();
        tp.refresh();
    }
}

输入

4.3 观察者

什么是观察者模式

观察者模式(Observer Pattern):当对象间存在一对多关系时,则应用观察者模式(Observer Pattern)。比方,当一个对象被批改时,则会主动告诉依赖它的对象。

Spring 的事件机制就是具体的观察者模式的实现

spring中的多播与事件
AbstractApplicationContext#initApplicationEventMulticaster
    
AbstractApplicationContext#registerListeners

观察者模式有哪些角色?

事件 ApplicationEvent 是所有事件对象的父类,继承JDK的EventObject

事件监听 ApplicationListener,也就是观察者对象,继承自 JDK 的 EventListener,能够监听到事件;该类中只有一个办法 onApplicationEvent。当监听的事件产生后该办法会被执行。

事件公布ApplicationContext, 实现事件的公布。

(公布事件)

========================or=================================

Spring中的多播

事件公布 ApplicationEventMulticaster,用于事件监听器的注册和事件的播送。

自定义一个事件MessageSourceEvent并且实现ApplicationEvent接口

//在Spring 中应用事件监听机制(事件、监听、公布)
//定义事件
//执行程序
//1、进入到事件源的有参数结构器
//2、公布事件
//3、进入到监听器类---one
//4、进入到事件源的办法
//5、进入到监听器类---two
//6、进入到事件源的办法
public class MessageSourceEvent extends ApplicationEvent {
    public MessageSourceEvent(Object source) {
        super(source);
        System.out.println("进入到事件源的有参数结构器");
    }

    public void print() {
        System.out.println("进入到事件源的办法");
    }
}

有了事件之后还须要自定义一个监听用来接管监听到事件,自定义ApplicationContextListener监听 须要交给Spring容器治理, 实现ApplicationListener接口并且重写onApplicationEvent办法,

监听一

//在Spring 中应用事件监听机制(事件、监听、公布)
//监听类,在spring配置文件中,注册事件类和监听类
public class ApplicationContextListener implements ApplicationListener {
    @Override
    public void onApplicationEvent(ApplicationEvent event) {

        if (event instanceof MessageSourceEvent) {
            System.out.println("进入到监听器类---one");
            MessageSourceEvent myEvent = (MessageSourceEvent) event;
            myEvent.print();
        }

    }
}

监听二

//在Spring 中应用事件监听机制(事件、监听、公布)
//监听类,在spring配置文件中,注册事件类和监听类
public class ApplicationContextListenerTwo implements ApplicationListener  {

    @Override
    public void onApplicationEvent(ApplicationEvent event) {

        if(event instanceof MessageSourceEvent){
            System.out.println("进入到监听器类---two");
            MessageSourceEvent myEvent=(MessageSourceEvent)event;
            myEvent.print();
        }


    }
}

公布事件

//在Spring 中应用事件监听机制(事件、监听、公布)
//该类实现ApplicationContextAware接口,失去ApplicationContext对象
// 应用该对象的publishEvent办法公布事件
public class ApplicationContextListenerPubisher implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    public void publishEvent(ApplicationEvent event) {
        System.out.println("公布事件");
        applicationContext.publishEvent(event);
    }

}

配置文件

    <!--  Spirng中的事件>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -->
    <!--<bean id="messageSourceEvent" class="com.spring.test.pattern.observer.MessageSourceEvent"  />-->
    <bean id="applicationContextListener" class="com.spring.test.pattern.observer.ApplicationContextListener"/>
    <bean id="applicationContextListenerTwo" class="com.spring.test.pattern.observer.ApplicationContextListenerTwo"/>

    <bean id="applicationContextListenerPubisher" class="com.spring.test.pattern.observer.ApplicationContextListenerPubisher"/>
    <!--  Spirng中的事件>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -->

测试

//总结 :应用bean工厂公布和应用多播器成果是一样的
public class Test {

    public static void main(String[] args) {
        ApplicationContext context =
                new ClassPathXmlApplicationContext("classpath*:application.xml");
        //***************应用spring的多播器公布**********************
        ApplicationEventMulticaster applicationEventMulticaster = (ApplicationEventMulticaster) context.getBean("applicationEventMulticaster");
        applicationEventMulticaster.multicastEvent(new MessageSourceEvent("测试..."));
//***************应用BeanFactory的publishEvent公布*********************
        //    ApplicationContextListenerPubisher myPubisher = (ApplicationContextListenerPubisher)
        //context.getBean("applicationContextListenerPubisher");
        //myPubisher.publishEvent(new MessageSourceEvent("测试..."));
    }

}

多播公布

工厂公布

总结:

​ 1、spring的事件驱动模型应用的是 观察者模式

  2、通过ApplicationEvent抽象类和ApplicationListener接口,能够实现事件处理

  3、ApplicationEventMulticaster事件播送器实现了监听器的注册,个别不须要咱们实现,只须要显示的调用 applicationcontext.publisherEvent办法即可

​ 4、应用bean工厂公布和应用多播器成果是一样的

如果本文对您有帮忙,欢送关注点赞`,您的反对是我保持创作的能源。

转载请注明出处!

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理