硬钢Spring源码——五万字梳理完Spring核心原理

前言

学习技术,不仅要搞懂原理,还要善于总结,更要学会应用,只有这样,你才能成为真正的高手。

话不多说,直接上干货!

Spring核心接口和类

spring框架解决了一个非常关键的问题,它可以让你将对象之间的关系转而用配置文件来进行管理

  • 这便是它赖以生存的依赖注入机制,让对象之间的依赖关系在Spring的IoC容器中管理。
  • 通过把对象包装在Bean中以达到管理对象和额外操作的目的。

Bean与BeanDefinition

Spring的一等公民——Bean

  • Bean的本质就是Java对象,只是这个对象的生命周期由容器来管理。
    用户可以根据自己的业务需求去定义一个java类,通过配置文件/配置类或者配置相关的注解等Spring框架能理解的方式告知Spring将该java类给管理起来,他就成为了Spring容器中的一个bean

  • 不需要为了创建Bean而在原来的java类上添加任何额外的限制

  • 对Java对象的控制方式体现在配置上

BeanDefinition ——Bean的定义

根据配置,生成用来描述Bean的BeanDefinition

常用属性:

  • 作用范围scope(@Scope)
    • singleton
    • prototype
    • request
    • session
    • globalsession
  • 懒加载lazy-init(@Lazy):决定Bean实例是否延迟加载
  • 首选primary(@Primary):设置true的bean会是优先的实现类
  • factory-bean和factory-method(@Configuration和@Bean)

容器初始化主要做的事情
在这里插入图片描述
首先将xml或者注解等配置信息加载到内存中,在内存中这些文件会被当做成一个个Resource对象,之后会被解析成BeanDefinition实例,最后注册到Spring容器中。

在容器初始化或者bean实例首次使用的时候,容器会按照这些BeanIDifinition实例属性的指示将BeanDifinition对应的Bean实例创建出来,这主要取决于Bean的创建策略,是立即加载还是延迟加载。

BeanDefinition源码探究

下面我们看看BeanDefinition以及它的架构成员:
在这里插入图片描述
BeanDefinition是一个接口,我们点到源码里看看:
在这里插入图片描述
该接口实在spring-beans这个模块中,这个模块中存放的是spring简单容器相关的接口和类。

BeanDefinition继承了AttributeAccessor和BeanMetadataElement这两个接口,Spring中提供了大量的各种接口,每种接口都有不同的能力,某个类实现了某个接口也就相应的承诺拥有了某种能力。

AttributeAccessor
在这里插入图片描述
这个接口定义了最基本的对任意对象元数据的修改或者获取方式,用在BeanDefinition里主要就是用来获取BeanDefinition的属性,并对这些属性进行操作。

BeanMetadataElement
在这里插入图片描述
这个接口提供了一个getSource方法,用来传输一个可配置的元对象,于BeanDefinition里来讲就是通过getSource方法返回BeanDefinition这个Class对象本身。

针对BeanDefinition来讲,主要向Spring容器描述了某个Bean的配置信息。
像是否延迟加载isLazyInit()、获取作用范围getScope()等等,在BeanDefinition都有相应的定义。

AbstractBeanDefinition
在BeanDefinition家族成员中有很多,我这里只列举一些比较常见的类。
AbstractBeanDefinition是BeanDefinition实现类的基类

在AbstractBeanDefinition的基础上,Spring衍生出了一系列具有特殊用途的BeanDefinition

  • RootBeanDefinition
  • GenericBeanDefinition
  • ChildBeanDefinition

RootBeanDefinition可以单独作为一个BeanDefinition,也可以作为其他BeanDefinition的父类,但是不可以作为其他BeanDefinition的子类。
我们可以看看它的源码:
在这里插入图片描述
可以看到在setParentName方法里一旦设置parentName就会抛出异常。

这里需要补充一下:Spring中所定义的继承关系不是通过extends或者implements之类的来继承的,而是通过在BeanDefinition里设置parent属性来决定的。

在这里插入图片描述
从RootBeanDefinition源码的注释里可以看到:RootBeanDefinition通常用于在运行时接收多个BeanDefinition合并起来的信息。
在BeanDefinition里面有个parent的属性,以此属性来表示继承,而RootBeanDefinition便能接受具有继承关系的两个BeanDefinition,承接两者合并在一起的除了parent属性以外的属性。

一般情况下配置文件里的bean标签会被解析成RootBeanDefinition。

在Spring2.5之后,Spring引入了一个GenericBeanDefinition,将RootBeanDefinition和ChildBeanDefinition取代了。但是在合并属性的时候,还是会使用RootBeanDefinition来接收。

而ChildBeanDefinition必须要依赖一个父的BeanDefinition不可以单独存在,不过已经被GenericBeanDefinition完全取代,不需要去学习。

GenericBeanDefinition

GenericBeanDefinition是Spring2.5以后新增加的Bean文件定义配置类,是RootBeanDefinition和ChildBeanDefinition更好的替代方案。

除了具有其他BeanDefinition的特征外,还具备了parentName属性,方便程序在运行时设定parentBeanDefinition。

SpringIoc容器

SpringIoc容器是一个管理Bean的容器,在Spring的定义中要求所有的IOC容器都要实现接口BeanFactory

BeanFactory

BeanFactory位于org.springframework.beans.factory包下,是一个顶级的容器接口

在这个接口下,定义了一个FACTORY_BEAN_PREFIX的变量,该变量主要用于获取FactoryBean的实例。
在这里插入图片描述
大家注意了,FactoryBean和BeanFactory是完全不一样的两个东西。

BeanFactory和FactoryBean 的区别

BeanFactory
BeanFactory是Spring容器的根接口定义了Bean工厂的最基础的功能特性。比如:Object getBean(String name)根据bean名字从容器中获取bean实例等等。

BeanFactory是一个管理Bean的容器,Spring生成的bean都是由BeanFactory的实现类来管理的。

FactoryBean
FactoryBean也是接口,根据T getObject()用户可以使用一套比较复杂的逻辑来生成Bean。

FactoryBean本质也是一个Bean,但是这个bean不是用来注入到其他地方来使用的,而他的作用是用来生成一些普通的bean的,实现了这个接口之后,spring容器在初始化时,会把实现这个接口的Bean取出来,然后使用Bean里面的getObject方法来生成我们想要的Bean,当然那些生成Bean的业务逻辑也要写在getObject方法中。

BeanFactory架构体系

接下来我们看看BeanFactory的架构体系:

在这里插入图片描述
BeanFactory有着庞大的继承和实现体系,有着众多子接口和实现类,每个接口和实现类都有它使用的场合,接口主要用来描述容器具备某些特定的功能,而实现类则是实现这些功能的。

Spring的Ioc主要分为两个路线,一个是以BeanFactory为主的简单容器,一个是以ApplicationContext为主的高级容器。

ApplicationContext应用上下文高级容器也是我们广泛使用的类型,相对于BeanFactory而言高级容器新增了很多面向实际应用的功能,让原本在BeanFactory中通过编码实现的功能简化到用配置即可完成。

根据程序设计的单一原则,其实每一个较顶层接口都是单一职责的,只提供某一方面的功能。

ListableBeanFactory

该接口的方法可以以列表的形式提供Bean的相关信息,这个接口最大的特点就是可以批量列出工厂生产的实例信息

我们大致看一下这个接口的方法:
在这里插入图片描述

int getBeanDefinitionCount(); //获取BeanDefinition总数
String[] getBeanDefinitionNames(); //获取BeanDefinition名字的数组列表
String[] getBeanNamesForType(ResolvableType type);//通过指定类型获取所有Bean名字
//....
AutowireCapableBeanFactory

我们先来补充一下两个术语:

  • 组件扫描:自动发现应用容器中需要创建的Bean
  • 自动装配:自动满足Bean之间的依赖

在spring中的@Autowired 自动装配的逻辑就是通过该接口的Object resolveDependency()方法来实现的依赖注入

在该接口中定义了五种装配策略
在这里插入图片描述
其中AUTOWIRE_AUTODETECT已经在Spring3.0中被废弃掉了。

int AUTOWIRE_NO = 0; //没有自动装配
int AUTOWIRE_BY_NAME = 1; //根据名称自动装配
int AUTOWIRE_BY_TYPE = 2; //根据类型自动装配
int AUTOWIRE_CONSTRUCTOR = 3; //根据构造函数自动装配

对于@Autowired标签来讲,其自动装配策略用的是AUTOWIRE_BY_TYPE根据类型自动装配

DefaultListableBeanFactory

DefaultListableBeanFactory是真正一个可以独立运行的IOC容器,继承了AbstractAutowireCapableBeanFactory这个抽象类,最重要的是它同时把BeanDefinitionRegistry实现了。
BeanDefinitionRegistry是BeanDefinition的注册接口。

DefaultListableBeanFactory有一个最重要的成员变量:

private final Map<String, BeanDefinition> beanDefinitonMap = new ConcurrentHashMap<>(256);

这个成员变量便是用来存储容器里所有已经注册了的BeanDefinition实例的载体。
除此之外,该成员变量还在SimpleBeanDefinitionRegistry中有所定义,但是它在这里它仅仅提供注册表功能,并无工厂功能。

因此在DefaultListableBeanFactory中的beanDefinitonMap才是比较重要的。

由于它是一个私有的成员变量,因此需要调用DefaultListableBeanFactory提供的方法才能对BeanDefinition的载体进行操作。

ApplicationContext

接下来,我们了解一下较为复杂的容器家族,里面最为典型的就是ApplicationContext这个接口了。

Spring高级容器均实现了ApplicationContext这个接口
为了区别于简单容器,高级容器通常被称之为Context,即上下文。

所以大家听到上下文,通常也是容器的意思,只不过是多了许多除创建Bean以外的额外功能,方便用户结合自己的需求开箱即用。这一点有别于我们之前的BeanFactory工厂。

在我们使用SpringIoc容器的时候,与我们接触的绝大多数都是ApplicationContext接口的实现类。

BeanFactory是Spring的基础设施,面向Spring框架自身,而ApplicationContext面向的是使用Spring框架的开发者。
在这里插入图片描述
我们可以看到ApplicationContext之所以被称为高级容器,是因为它比BeanFactory多了更多的功能,因为它继承了多个接口。

首先我们看到它继承了EnvironmentCapable这个接口

public interface EnvironmentCapable {
    
    

	/**
	 * Return the {@link Environment} associated with this component.
	 */
	Environment getEnvironment();

}

在这个接口里面我们看到只有一个getEnvironment()方法,该方法主要用来获取Environment。

说白了其实就是获取一些启动参数。

他还继承了ListableBeanFactory接口,即可以通过列表的方式来管理Bean

同时,还实现了HierarchicalBeanFactory接口,即可以支持多层级的容器,来实现对每一层Bean的管理

除此之外,还继承了MessageSource, ApplicationEventPublisher, ResourcePatternResolver诸多接口

分别可以实现用来管理一些Message,实现国际化的功能、具备事件发布的能力、可以用来加载资源文件。

ApplicationContext容器通过ApplicationEvent类和ApplicationListener接口进行事件处理,如果将实现ApplicationListener接口的Bean注册到容器中时,每次我们通过ApplicationContext发布的ApplicationEvent都会通知到注册的Listener中

这就是标准的观察者设计者模式

ApplicationContext常用容器

传统的基于XML配置的经典容器:

  • FileSystemXmlApplicationContext:从文件系统加载配置
  • ClassPathXmlApplicationContext:从classpath加载配置
  • XmlWebApplicationContext:用于Web应用程序的容器

目前比较流行的容器:

  • AnnotationConfigServletWebServerApplicationContext
  • AnnotationConfigReactiveWebServerApplicationContext
  • AnnotationConfigApplicationContext

他们都具备了refresh()的大致功能

  • 容器初始化、配置解析
  • BeanFactoryPostProcessor和BeanPostProcessor的注册和激活
  • 国际化配置
  • ……

回到ApplicationContext中,我们可以看到它里面的方法时只读的,也就是都是以get来打头的,即只提供get操作:
在这里插入图片描述
因此我们需要子接口来给Application提供可配置的能力,该接口便是
ConfigrableApplicationContext:
在这里插入图片描述
它继承了Lifecycle接口,进入到这个接口中:
在这里插入图片描述

这个接口中提供了stop、start等方法,用于对生命周期的管理。

ConfigrableApplicationContext 主要提供了refresh和close方法,具备启动刷新以及关闭应用上下文的能力,而这里的refresh方法,就是前面所提到的ApplicationContext主流实现容器都需要做的事情。

在ApplicationContext关闭的情况下,refresh可以重新启动容器
而在启动的情况下,调用refresh还可以清除缓存,并重新装载配置信息
具体的方法实现是在实现了该接口的AbstractApplicationContext抽象类中。

AbstractApplicationContext

AbstractApplicationContext通过组合将众多容易变动的功能逻辑,代理给他的一些成员变量来实现,最后再使用模板方法模式,让子类为父类提供一些函数的支持或者设置替换上述的父类成员变量,从而实现了对扩展开放,对修改封闭的设计原则,也就是开闭原则。为SpringFramework提供了灵活性大,并且可扩展性强的架构支撑。

其中的refresh方法便是模板方法模式最好的实现。

Resource

在java中,资源可以被抽象成URL,我们可以解析Url中的协议来处理不同资源的操作逻辑。

而Spring将对物理资源的访问方式,抽象成Resource

在这里插入图片描述
在该接口中定义了对资源的基本操作。Resource接口继承了InputStreamSource接口

InputStreamSource只提供了getInputStream()方法,该方法返回一个InputStream实例,即资源流。

Spring提供了一个强大的资源加载方式:

  • 自动识别“classpath”、“file:”等资源地址前缀
  • 支持自动解析Ant风格带通配符的资源地址
ResourceLoader

ResourceLoader用于实现不同的Resource加载策略,按需返回特定类型的Resource。

refresh方法

我们接下来了解一下AbstractApplicationContext#refresh方法。
在进攻这个方法之前,我们先来了解一些核心知识

后置处理器PostProcessor

Spring框架里提供了各种PostProcessor,作为容器或者Bean的后置处理器

其实这些PostProcessor本身也是一种需要注册到容器里的Bean

  • 其里面的方法会在特定的时机被容器调用。
  • 实现不改变容器或者Bean核心逻辑的情况下对Bean进行扩展
  • 对Bean进行包装,影响其行为,修改Bean的内容
PostProcessor的种类

大致分为容器级别的后置处理器以及Bean级别的后置处理器

  • BeanDefinitionRegistryPostProcessor
  • BeanFactoryPostProcessor
  • BeanPostProcessor

前两个是容器级别的后置处理器,最后一个是Bean级别的后置处理器。

BeanDefinitionRegistryPostProcessor

在这里插入图片描述
根据注释文档,我们可以了解到BeanDefinitionRegistryPostProcessor可以允许在正常的BeanFactoryPostProcessor检测开始之前注册更多的自定义BeanDefinition。

通过源码观察,我们可以看出这个接口继承自BeanFactoryPostProcessor。

里面仅提供了一个方法:
在这里插入图片描述
该方法接收registry参数,光看方法声明信息就可以知道,我们需要在方法体里面创建出BeanDefinition实例,通过传入的registry,将我们的BeanDefinition注册到registry里面

咱们可以来看一下BeanFactoryPostProcessor的源码:在这里插入图片描述
它通过postProcessBeanFactory来影响容器。

BeanPostProcessor

在这里插入图片描述
对于由容器创建的每个Bean实例,后置处理器都会在调用容器初始化之前,以及任何Bean初始化回调之后都从容器获得回调执行。

我们来看下面一个例子:

/**
 * Created By 小飞龙
 */
@Configuration
public class MyBeanPostProcessor implements BeanPostProcessor {
    
    

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    
    
        System.out.println(beanName+"调用了postProcessBeforeInitialization方法");
        return bean;
    }

	@Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    
    
        System.out.println(beanName+"调用了postProcessAfterInitialization方法");
        return bean;
    }
}

我们通过自己实现BeanPostProcessor,然后实现它的postProcessBeforeInitializationpostProcessAfterInitialization方法。
然后启动项目:
在这里插入图片描述
执行完后,我们可以看到,对于每个Bean都会执行这两个方法,并且是先执行postProcessBeforeInitialization再执行postProcessAfterInitialization

看到这里,大家能否灵光一闪,我们是不是可以使用BeanPostProcessor的能力对Bean进行包装,即在Bean创建出来后,在postProcessAfterInitialization里面对Bean包装上一层通用的逻辑,比如说统一去做一些耗时统计方面的日志记录,增强行为后并对Bean进行返回,这又涉及到AOP的范畴了。

关于PostProcessor咱们就先了解这么多,主要涉及容器的后置处理器以及Bean的后置处理器,框架本身也提供了很多针对PostProcessor的实现类,每个PostProcessors实现类分别对于不同的场景需求,Spring应用这些不同的实现类,完成了框架自身的任务,主要在容器启动和Bean获取阶段。此外我们也可以自己实现Processor来扩展它的能力。

Aware

为了方便后续知识顺利拿下,我们再来学习一个重要的接口Aware

前面我们了解到,容器对Bean本身的逻辑基本是无侵入的,因此Bean一般不需要了解容器的状态和直接使用容器,但是在某些情况下是需要在Bean中直接对容器进行操作的,这时候就需要在Bean中设置对容器的感知了,这便是Aware的作用。
在这里插入图片描述
在Aware中我们可以看到是没有任何方法的,只能当作标签来使用,所以Aware在Spring中能直接发挥作用的是其自带的继承了Aware接口的子接口。

常见的Aware子接口如下:

  • ApplicationContextAware
  • MessageSourceAware
  • ApplicationEventPublisherAware
  • BeanFactoryAware
  • ResourceLoaderAware
  • BeanNameAware
ApplicationContextAware

在这里插入图片描述
着这个接口里面我们可以看到它定义了一个setApplicationContext的方法。
这个方法是让实现了该接口的Bean在容器创建这个Bean实例的时候,将容器本身的实例作为参数传进来,给这个Bean使用。

BeanNameAware

我们再来看下一个子接口BeanNameAware:
在这里插入图片描述
在这个接口里我们也可以看到也只定义了一个方法setBeanName
该方法的作用就是用来将Bean的名字传入进来供该接口的实现类使用

BeanFactoryAware

主要用于获取当前的BeanFactory,这样就可以调用容器的服务

MessageSourceAware

主要用来获取MessageSource相关的文本信息

ApplicationEventPublisherAware

主要用来获取发布器实例来发布事件的

ResourceLoadAware

主要用来获取资源加载器,通过资源加载器我们可以获取外部资源文件

我们来通过代码演示一下:

/**
 * Created By 小飞龙
 */
@RestController
public class TestController implements ApplicationContextAware, BeanNameAware {
    
    
    private String myName;
    @Autowired
    private ApplicationContext myContainer;
    
    @GetMapping("/getMyName")
    public String  handleRequest(){
    
    
        System.out.println("我是:"+myName);

        String[] names = myContainer.getBeanDefinitionNames();
        for (String name : names) {
    
    
            System.out.println("获取注册到容器的BeanDefinition名称:"+name);
        }
        return "OK";
    }

    @Override
    public void setBeanName(String name) {
    
    
        this.myName = name;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    
    

    }
}

编写完成后,启动项目,然后打开Postman测试一下:
在这里插入图片描述
经过测试我们发现,确实是可以获取到我们想要的资源,这里值得注意的是,我们要想获取容器资源除了要实现Aware接口外,必须还要注册成容器管理的Bean。

Spring事件通知机制

事件监听器模式

监听器将监听感兴趣的事件,一旦事件发生,便做出响应,事件监听器涉及三个组件:

  • 事件源(Event Source)
  • 事件监听器(Event Listener)
  • 事件对象(Event Object)

我们通过代码演示一下:

1.创建事件

@Data
public class Event {
    
    
    private String type;
}

2.创建事件监听器接口

public interface EventListener {
    
    
    void processEvent(Event event);
}

3.创建具体事件监听器实现EventListener

public class SingleClickEventListener implements EventListener{
    
    
    @Override
    public void processEvent(Event event) {
    
    
        if ("single".equals(event.getType())){
    
    
            System.out.println("单机事件被触发...");
        }
    }
}
public class DoubleClickEventListener implements EventListener{
    
    
    @Override
    public void processEvent(Event event) {
    
    
        if ("double".equals(event.getType())){
    
    
            System.out.println("双击事件被触发...");
        }
    }
}

4.创建事件源

public class EventSource {
    
    
    private List<EventListener> listenerList = Lists.newArrayList();


    public void register(EventListener listener){
    
    
        listenerList.add(listener);
    }

    public void publishEvent(Event event) {
    
    
        for (EventListener listener : listenerList) {
    
    
            listener.processEvent(event);
        }
    }
}

5.创建main函数,进行测试

public static void main(String[] args) {
    
    
        EventSource eventSource = new EventSource();
        SingleClickEventListener singleClickEventListener = new SingleClickEventListener();
        DoubleClickEventListener doubleClickEventListener = new DoubleClickEventListener();
        Event event = new Event();
        event.setType("double");

        //注册时间监听器
        eventSource.register(singleClickEventListener);
        eventSource.register(doubleClickEventListener);

        //发布事件
        eventSource.publishEvent(event);
    }

在这里插入图片描述
经过测试我们发现,事件源向所有注册的监听器广播了双击事件,但是只对该事件感兴趣的监听器响应了事件。
以上便是事件监听者模式的大致实现,事件监听器其实就是经典设计模式观察者模式的一种实现。

Spring事件驱动模型

在这里插入图片描述

事件驱动模型三大组成部分:

  • 事件:ApplicationEvent抽象类

    • ContextStoppedEvent:容器停止后触发的事件
    • ContextRefreshedEvent:容器初始化或刷新完成后触发的事件
    • ContextCloseEvent:容器关闭后触发的事件
    • ContextStartedEvent:容器启动后触发的事件
  • 事件监听器:ApplicationListener

  • 事件发布器

    • ApplicationEventPublisher
    • ApplicationEventMulticaster
事件

我们先来看一下ApplicationEvent源码:
在这里插入图片描述
我们发现,在这个抽象类的构造函数里面,会接受一个Object类型的参数,source就指的就是事件源了。

在Spring4.2之前事件必须继承ApplicationEvent,而从4.2之后框架提供了一个PayloadApplicationEvent:
在这里插入图片描述
它是一个ApplicationEvent的子类,因为它是一个泛型类,因此可以包装任意的类型,之后就不再强制事件继承ApplicationEvent了,在容器内部我们发送一个任意类型的事件后,框架内部自动包装为PayloadApplicationEvent这个事件对象。

事件监听器

在这里插入图片描述
Spring中的监听器继承了EventListener,我们来看看ApplicationListener的源码:
在这里插入图片描述
可以看到,在ApplicationListener里面只有onApplicationEvent这一个方法,它接受的参数是ApplicationEvent,该方法是用于处理事件的。

Spring还定义了两个ApplicationListener的子接口,提供了事件筛选的能力。
SmartApplicationListener和GenericApplicationListener均继承了Ordered接口,具备了排序的能力,按照从小到大的顺序给监听器一个优先级,从而保证执行的顺序。

在这里插入图片描述
我们从源码里看到,GenericApplicationListener筛选的事件相比于SmartApplicationListener它用的是ResolvableType,而ResolvableType是Spring4.0后添加进来的获取泛型信息的工具,通过它可以获取到传入的泛型的各种信息,和反射机制差不多。

事件发布器

事件发布器主要设计的接口有

  • ApplicationEventPublisher
  • ApplicationEventMulticaster

使用了这两个接口,我们的服务便具备了事件发布的能力。

ApplicationEventPublisher

看到这个接口,是不是感觉有点眼熟。
在这里插入图片描述
我们发现ApplicationContext实现了ApplicationEventPublisher,这也说明了ApplicationContext是具备事件发布能力的。

既然我们有一个ApplicationEventPublisher,为什么还要一个ApplicationEventMulticaster呢?
我们先来看一下ApplicationEventPublisher的源码:
在这里插入图片描述
可以看到,它里面只有两个方法,都是发布事件相关的,也就是说,我们这个接口只能用来发布事件。

ApplicationEventMulticaster

而根据我们前面了解到,事件源应该要有注册Linstener的地方才对,抱着这个问题,我们去看一下ApplicationEventMulticaster的源码:
在这里插入图片描述
从源码里我们可以看到,这两个接口并没有任何继承的关系,但是ApplicationEventMulticaster具有添加和删除ApplicationListener的方法,同时还提供了发布事件的方法。

我们来看一下ApplicationEventMulticaster的主要成员:
在这里插入图片描述
可以看到,Spring中设置了一个AbstractApplicationEventMulticaster的抽象类来作为ApplicationEventMulticaster的默认实现。
进到源码里我们看一下:
在这里插入图片描述
在源码里我们可以看到它有一个私有成员变量,从名字就可以看出,它是用来保存注册进来的Listener的,点进去看一下:在这里插入图片描述
可以看到果然是有一个Set类型的applicationListeners,就是用来接收ApplicationListener,因为我们的ApplicationListener也是一些Bean,因此下面另外一个集合是专门保存这些Listener的Bean名字。

因为AbstractApplicationEventMulticaster仅是抽象类如果本地没有AbstractApplicationEventMulticaster的实现就会使用默认的SimpleApplicationEventMulticaster这个实现。
在这里插入图片描述
进到源码里,我们发现它有一个taskExecutor的成员变量,它是一个执行器,也就意味着它支持多线程处理监听器的方法。
我们来看一下这个方法:
在这里插入图片描述

	@Override
	public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
    
    
		ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
		for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
    
    
			Executor executor = getTaskExecutor();
			if (executor != null) {
    
    
				executor.execute(() -> invokeListener(listener, event));
			}
			else {
    
    
				invokeListener(listener, event);
			}
		}
	}

从这个方法里面,我们可以看出,它支持两种模式,如果executor不为空的话,他就会使用多线程的方式异步处理事件,如果没有设置executor的话就会以同步的方式去挨个执行listener。

为什么不直接使用ApplicationEventMulticaster替代ApplicationEventPublisher

站在设计者的角度来说,是一个很容易理解的事情,比如像Bean和容器本身就只想发布一个事件,而不想维护事件监听器,因此Spring将事件源做了进一步分割,抽象出事件发布器接口,然后将ApplicationEventMulticaster作为代理,让ApplicationEventPublisher的实现类来实现publishEvent里面的逻辑。

publishEvent里面就主要用于调用ApplicationEventMulticaster实现类的multicastEvent方法发布事件就可以了。

进攻refresh方法,手撕容器刷新逻辑

既然容器外围的防线已先后被攻克,咱们开始强攻容器的初始化这块逻辑。主要进攻各类高级容器中通用的部分,即AbstractApplicationContext的refresh方法。

其主要作用是刷新Spring容器,刷新的意思就是把BeanFactory清空初始状态,然后再按照下图,填满各种bean实例。

refresh也是面试Spring框架的一个常考点,因此我们一定要下功夫认真学学。

在这里插入图片描述
了解完以后,我们直接在refresh的第一行打个断点,然后启动容器:
在这里插入图片描述
synchronized这一步主要是给容器加上同步锁,避免容器处在refresh阶段的时候别的线程还在对容器进行初始化或者销毁的操作

紧接着就会进入prepareRefresh()这个方法,该方法主要是用于给刷新容器做准备。
在这个方法里主要做了以下事情

	protected void prepareRefresh() {
    
    
        // Switch to active.
        //设置当前时间,也就是容器启动时间,方便后续日志记录,还有容器执行的一些统计工作
        this.startupDate = System.currentTimeMillis();
        //设置非关闭状态
        this.closed.set(false);
        //设置为激活状态
        this.active.set(true);
        //配置日志等级
        if (logger.isDebugEnabled()) {
    
    
            if (logger.isTraceEnabled()) {
    
    
                logger.trace("Refreshing " + this);
            } else {
    
    
                logger.debug("Refreshing " + getDisplayName());
            }
        }
        //初始化环境(Evironment)的propertySource属性
        //样例: <context:property-placeholder location="classpath*:/config/load.properties"/>
        initPropertySources();

        //校验Environment的requiredProperties是否都存在
        getEnvironment().validateRequiredProperties();

        //看看容器启动的时候是否有加载一些监听器,默认情况下earlyApplicationListeners为null
        if (this.earlyApplicationListeners == null) {
    
    
            this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
        } else {
    
    
            this.applicationListeners.clear();
            this.applicationListeners.addAll(this.earlyApplicationListeners);
        }
        //创建事件集合
        this.earlyApplicationEvents = new LinkedHashSet<>();
    }

紧接着就会进入obtainFreshBeanFactory方法:
在这里插入图片描述
这一步主要涉及到BeanDefinition的注册
这一步对于xml配置而言是非常重要的,但是对于注解而言,仅仅是调用了子类的refreshBeanFactory
我们进到这个方法里:
在这里插入图片描述
再进到refreshBeanFactory里:
在这里插入图片描述
对于注解来讲,它实际是调用的GenericApplicationContext里面的refreshBeanFactory方法
而在xml配置中调用refreshBeanFactory主要用于生成DefaultListableBeanFactory内部容器实例,然后将BeanDefinition给注册到DefaultListableBeanFactory内部容器实例上。而针对于我们这里用的注解来讲,就没那么复杂了,DefaultListableBeanFactory在调用容器的构造函数时就创建出来了。

因此这里主要就是用于更新AnnotationApplicationContext实例的刷新状态,同时给它内部的DefaultListableBeanFactory设置上serializationId方便外部通过网络来你序列化来获取此处专属的DefaultListableBeanFactory实例

我们再来看一下prepareBeanFactory这个方法
在这里插入图片描述
此时我们就已经接受到了DefaultListableBeanFactory实例。
进入到prepareBeanFactory方法里面:

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    
    
		// Tell the internal bean factory to use the context's class loader etc.
		//告诉内部Bean工厂使用容器的类加载器
		beanFactory.setBeanClassLoader(getClassLoader());
		//设置BeanFactory的表达式语言处理器,Spring3开始增加了对语言表达式的支持,默认可以使用#{bean.xxx}获取bean里面的实例值
		beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
		//为beanFactory增加一个默认的PropertyEditor
		beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

		//添加后置处理器,作用是:当应用程序定义的Bean实现ApplicationContextAware接口时注入ApplicationContext对象
		beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

		//如果某个Bean依赖于一下某个接口的实现类,在自动装配的时候会忽略他们
		//Spring会通知其他方式处理这些依赖
		beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
		beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
		beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
		beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

		//修正依赖,这里是注册一些自动装配的特殊规则,比如是BeanFactory class接口的实现类则在运行时指定为当前BeanFactory
		beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
		beanFactory.registerResolvableDependency(ResourceLoader.class, this);
		beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
		beanFactory.registerResolvableDependency(ApplicationContext.class, this);

		//注册早期后置处理器,用于检测内部bean作为应用程序的监听器
		//ApplicationListenerDetector的作用就是判断某个Bean是否是ApplicationListener
		//如果是,加入到事件监听者队列
		beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

		// 如果找到一个LoadTimeWeaver,那么就将准备后置处理器“织入”bean工厂
		if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
    
    
			beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
			// 为类型匹配设置临时类加载器
			beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
		}

		// 注册默认environment环境bean
		if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
    
    
			beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
		}
		if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
    
    
			beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
		}
		if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
    
    
			beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
		}
	}

这里看完后,我们再回到refresh方法里面进入到postProcessBeanFactory方法中。
在这里插入图片描述
该方法用于允许容器注册必要的postProcess,是一个钩子方法。
钩子方法就是子类可以实现也可以不实现
跟进去:
在这里插入图片描述
我们会发现针对于本容器而言是不需要注册子类的PostProcessor的

继续往下执行,就来到了invokeBeanFactoryPostProcessors这个方法中
在这里插入图片描述
这个方法的主要作用是注册容器级别的PostProcessor

我们继续往下执行,就会来到registerBeanPostProcessors这个方法中
在这里插入图片描述
完成容器级别的后置处理器之后就是Bean级别的后置处理器了。

registerBeanPostProcessors这一步就是将先前定义的bean级别的后置处理器注册到容器里,方便后续再调用getBean方法创建Bean实例的时候,在特定的各个环节去触发这些后置处理器,执行一些特定的逻辑。

有了这种Bean级别的后置处理器,就方便于我们对于Bean进行精细化以及自定义管理。

再往下就进入到了initMessageSource方法
在这里插入图片描述
这里主要进行一些国际化的配置,主要的目的是针对于不同的地区去展示不同的语言内容。

继续往下执行就进入到了initApplicationEventMulticaster()
通过这个方法来初始化事件发布器,用来接收实现ApplicationEventPublisher接口的类发送过来的不同的事件并派发给不同的事件监听者进行处理。
在这里插入图片描述
进入到这个方法里首先我们看到,它首先判断容器先前有没有注册过自定义的事件发布器,如果有直接用。
否则就会使用就会使用默认的SimpleApplicationEventMulticaster作为事件发布器。
在这里插入图片描述
我们可以看到果然创建了SimpleApplicationEventMulticaster去支持事件发布。
执行完这里我们就创建完成了SimpleApplicationEventMulticaster。

接下来执行到了onRefresh()方法
在这里插入图片描述
这个方法也是一个钩子方法,主要用来预留给其子类,用于初始化其它特殊的Bean,该方法会发生在refresh方法中的finishBeanFactoryInitialization方法之前,即发生在单例的Bean的实例化之前执行。
onRefresh方法一般用于一些Web容器上

继续往下执行

在这里插入图片描述
这个方法就是向我们之前的ApplicationEventMulticaster去注册监听器,用来监听不同的事件,毕竟光有事件和事件发布器还不能构成完整的事件监听机制,有了监听器就完整了。

继续往下执行便来到了finishBeanFactoryInitialization方法
在这里插入图片描述
进入这个方法里:
在这里插入图片描述
我们就会发现该方法首先会判断容器里有没有自动的类型转换器ConversionService,如果有则通过getBean从容器获取提供类型转换的Bean实例,所谓的类型转换器,就是从容器中给Bean实例赋值的时候,将属性值转换为对应的类型。

只有Spring容器本身不支持的一些类型转换是需要这些转换器来处理的。

再往下走:
在这里插入图片描述

这一步的目的就是网容器里注册默认的解析器,这些解析器能解析配置文件中的值,并将他们注入到被@Value注解标记或者Xml里面的配置的${}表达式里

继续往下执行:

// 停止使用临时类加载器进行类型匹配
beanFactory.setTempClassLoader(null);

然后就是停止使用临时类加载器,因为aop的操作已经完成了,不需要使用临时类加载器加载jvm生成的代理类了
再往下执行:

// 允许缓存所有bean定义元数据,不希望有进一步的更改
beanFactory.freezeConfiguration();

这一步主要用于冻结容器相关的配置这一步使得保存在内存里的先前刷新好的内容变得可靠稳定了

再看下一步

// 实例化所有剩余的(non-lazy-init非延时加载的)单例
   beanFactory.preInstantiateSingletons();

这一步就是先实例化剩余所有的默认不是延迟加载的scope为singleton的bean实例

对于Spring高级容器而言,默认的bean都是singleton并且也不是延迟加载的,所以对应的bean实例就会在此处创建并管理起来
在这里插入图片描述
跟进去,我们就会发现它进入到的是DefaultListableBeanFactory这个类里
在这里插入图片描述
跳过日志,我们来看下面的逻辑:

首先是遍历注册好的BeanDefinition的名字,然后根据名字去过去相应的BeanDefinition实例

RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);

这里通过RootBeanDefinition接受合并过后的BeanDefinition,getMergedLocalBeanDefinition这个方法调用层级比较深,分析起来比较晕,所以我们只需要记住他的作用就可以了。

MergedLocalBeanDefinition的作用就是兼容各种BeanDefinition。

不同的Bean在加载SpringBean定义的时候实例化出来的是GenericBeanDefinition,GenericBeanDefinition可以直接转换成RootBeanDefinition,所以对于普通的BeanDefinition这是没有问题的

而对于另外一种情况,他也是支持的,就是具有继承关系的ChildBeanDefinition,他的parent会指定另外一个BeanDefinition,它就会将ChildBeanDefinition和parent BeanDefinition的属性给合并到一起,也可以转成RootBeanDefinition并返回。所以为了兼容原先的ChildBeanDefinition,这里用RootBeanDifition是合理的。

if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
    
    
       if (isFactoryBean(beanName)) {
    
    
				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());
					}

然后在这里判断,首先这个BeanDefinition实例不是抽象的,并且是单例且非延迟加载的。

如果都满足的化,就开始进行实例化了

然后先判断这个bean是否是FactoryBean,如果是,就会去容器里获取FactoryBean实例。

如果获取到了之后,再判断FactoryBean里面的Bean是否是延迟加载的,如果不是延迟加载的话isEagerInit,并且相关的创建方法具有权限访问的话getAccessControlContext(),那么就将FactoryBean里面的Bean通过getBean给创建出来。

在这里插入图片描述
这里涉及到了一个SmartFactoryBean,我们看一下这个接口。

在这里插入图片描述
它可以设置实例是延迟加载还是非延迟加载。

Spring依赖注入

Spring为了实现Bean的生命周期控制,同时也会考虑到自己或者用户在实例化Bean的过程中在每一个阶段都有可能对里面的行为定制化改变,因此,整个输出的过程特别复杂。
光核心代码就有好几千行,如果一个个深入细节去学习,绝对会晕。
但是只要抓住了骨架去了解核心部分的话,效果会好很多,因此我们先把脉络摸清,然后去学习细节,就会发现越来越清晰了。

在AbstractApplicationContext中的refresh方法里:

//实例化所有剩余的(non-lazy-init非延迟加载的)单例
beanFactory.preInstantiateSingletons();

在这个方法里面会初始化那些非延迟加载的bean实例,在我们ApplicationContext容器默认管理的bean都是singleton并且是非延迟加载的。
所以如果没有特别的设置bean都会在这一步调用getBean方法去进行实例化。
因此这里的getBean方法就是我们接下来研究的重点,依赖注入也是在这里面完成的。

依赖注入的方式有很多种,我们重点研究根据@Autowired方式进行注入。

这里小编还是要再给大家提个醒,依赖注入嵌套的层级特别深,并且在多个类里进行跳跃,如果硬钢去了解里面的细节的话,不要说大家了,小编都已经晕菜了。

所以我们必须换一个思路,既然难度太大,咱们唯有抓住重点,不恋战,了解全貌,才能逐个击破。
因此我们还要打开全民地图来作战:
在这里插入图片描述
该路线就是依据@Autowired的注入和解析来进行的。

我们可以从上到下逐个攻克每个模块,所谓攻克并不是所有细节、每行代码都要去了解,主要了解其大致作用即可。

我们的目标很明确,主要是搞懂依赖注入的实现思路,以这种方式将学习成本降到最低,学习效果达到最大化。

脑图里经过刚刚对源码的强攻,咱们可以看到从上到下就是一个不断深入的过程。
接下来,咱们大致了解一下每个模块大致要做的事情。

首先是AbstractBeanFactory 它一个抽象类,提供了一个获取bean实例的方法,该方法里面会涉及到一个根据不同的scope去进行不同的处理。

本文主要研究singleton的情况,因此我们主要来看DefaultSingletonRegistry这个类。看名字我们就能知道,他是单例bean注册的默认实现类,这个类里提供了getSingleton这个方法,用来获取单例实例。

````getSingleton```这个方法会尝试从三层的缓存里去获取Bean实例,之所以要分化出三级缓存,主要是用于解决循环依赖的问题。

如果缓存里没有找到Bean实例,容器就会创建出来,因此就会来到AbstractAutowireCapableBeanFactory里面,这里面会调用createBean方法去做一些创建前的准备工作,之后再调用doCreateBean去创建Bean实例。

在doCreateBean里面光创建出Bean实例是不行的,还要看看bean实例里面的属性有没有被@Autowired或者@Value之类的依赖注入标签给标记上,如果有则进行相关的标记。而我们的applyMergedBeanDefinitionPostProcessors主要用来对合并后的BeanDefinition做后置处理,此时也涉及到对相关逻辑的处理。

在进行标记处理之后,则会考虑对Bean的成员变量进行赋值,所以依赖注入也就是在populateBean里面去做实现的。

咱们的突击部队也就只突击到这一层。

后面他会经过AutowiredAnnotationBeanPostProcessor的postProcessProperties方法做属性的后置处理,实现@Autowired的注入逻辑,逐层深入就会来到DefaultListableBeanFactory去解析依赖关系,这主要因为BeanDefinition都保存在这里,而通过查看BeanDefinition就可以让我们找到Bean之间的依赖关系。

找到依赖关系之后就会调用DependencyDescriptor这个类里提供的服务去进行注入。

以上就是整个依赖注入的流程。这里只是说了个大概,实际上远没有这么简单。

doGetBean

在这里插入图片描述
这里我们主要研究getBean 方法,而在getBean方法里真正起作用的是doGetBean方法,我们来看该方法主要做了什么事情:

  1. 首先,他会尝试从容器的缓存里去获取单例Bean实例,这个单例Bean它有可能是Bean或者FactoryBean实例本身,如果是Bean就会直接返回了,如果是FactoryBean那么就会通过getObject方法去返回bean实例。如果在这一步获取不到的话,就需要让容器去创建Bean了。
  2. 接下来是循环依赖的判断逻辑,正是因为有循环依赖才会使用到三级缓存。
  3. 如果当前容器中没有注册该bean的BeanDefinition实例则会递归去父类容器查找
  4. 如果当前容器里面有该bean的BeanDefinition则从容器里获取其实例。
  5. 递归实例化显式依赖的bean 所谓显式就是给bean设置了一个deoends-on
  6. 根据不同的scope采用不同的策略创建Bean实例
  7. 对Bean进行类型检查

有了这些宏观的了解之后,攻克这部分代码并非难事,我们直接开城门迎战!

直接打开AbstractBeanFactory的doGetBean方法的代码
先看第一行:
在这里插入图片描述
第一行就是将getBean传入的这个Bean的名字转换成容器里的真实的beanName,因为传入的名字可能是bean本身也可能是带了&符号的FactoryBean的名字,或者也有可能是传入别名,所以我们要将其统一转换成beanName。

获取到beanName之后就会进入下一行代码。

//尝试从一级缓存里面获取完备的Bean
Object sharedInstance = getSingleton(beanName);

进入到这个方法:
在这里插入图片描述
我们就可以看到它调用了一个重载的方法,第二个参数allowEarlyReference为true,允许非延迟加载,也就是立即加载。我们进入到方法里面。

	@Nullable
	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    
    
		//尝试从一级缓存里面获取完备的Bean
		Object singletonObject = this.singletonObjects.get(beanName);
		//如果完备的Bean还没有创建出来,创建中的Bean的名字会被保存在singletonsCurrentlyInCreation中
		//因此看看是否正在创建
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
    
    
			//尝试给一级对象加锁,因为接下来就要对缓存对象操作
			synchronized (this.singletonObjects) {
    
    
				//尝试从二级缓存earlySingletonObject这个存储还没有进行属性添加操作的Bean实例缓存中获取
				singletonObject = this.earlySingletonObjects.get(beanName);
				//如果二级缓存还没有获取到并且第二个参数为true,为true则表示bean允许被循环引用
				if (singletonObject == null && allowEarlyReference) {
    
    
					//从三级缓存singletonFactories这个ObjectFactory实例的缓存里尝试获取创建此Bean的单例工厂实例
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					//如果获取到工厂实例
					if (singletonFactory != null) {
    
    
						//调用工厂的getObejct方法返回对象实例
						singletonObject = singletonFactory.getObject();
						//将实例放入二级缓存
						this.earlySingletonObjects.put(beanName, singletonObject);
						//从三级缓存里移除
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

他首先会尝试从一个singletonObjects的一个ConcurrentHashMap里去获取对应于beanName的单例实例,这里的singletonObjects是单例缓存的一级缓存。主要是用来保存最终形态的单例bean实例。

那么由于我们是第一次调用容器的getBean去提前创建非延迟加载的单例的,所以在以及缓存里是找不到的。于是就会进入下面的if语句,if语句主要是确保从一级缓存里获取不到bean实例并且该实例是正在创建的实例。
我们进入到if里这个isSinglesonCurrentlyInCreation方法看看:
在这里插入图片描述

在这里插入图片描述这一步主要是用于去查找正在创建的单例bean名单里是否有beanName,用来解决循环依赖的问题。

然后在下面if逻辑里,首先给一级缓存对象加一个同步锁,去操作后面的缓存,以防止线程对缓存的同时操作。
在这里插入图片描述

上锁后就来到earlySingletonObjects由于已经给singletonObjects这个支持多线程操作的一级缓存上锁了,所以对其他缓存的操作都是线程安全的并且同步的,为了提升性能,其他两个缓存都是用的HashMap

earlySingletonObjects是还没有去给属性调用populateBean方法去赋值的Bean

如果在这一步获取到了,就会直接返回,如果没有获取到,同时allowEarlyReference为true的话,则会进入到if里面尝试从另外一个缓存singletonFactories里去获取,此处为第三层缓存,此处存储的是Bean对应的ObjectFactory实例。看名字我们就能知道这是个对象工厂。

到最后:
在这里插入图片描述
如果此处没有获取到工厂实例,则直接返回空对象,如果获取到,那么就会调用getObject方法去获取singleton实例了,此时由于实例的属性可能还没有注入,所以这时将实例放入earlySingletonObjects二级缓存里,为了保证这三级缓存里只有一个是有某个bean的实例的,所以下一步会将其从三级缓存给清除掉。

分析完createBean方法后,我们继续分析后面的逻辑:

		Object sharedInstance = getSingleton(beanName);
		//如果先前已经创建过单例Bean实例,并且调用的getBean方法传入的参数为空,则执行if里面的逻辑
		//args之所以要求为空是因为如果有args,则需要做进一步赋值,因此无法直接返回
		if (sharedInstance != null && args == null) {
    
    
			if (logger.isTraceEnabled()) {
    
    
				//如果Bean还在创建中,则说明是循环引用
				if (isSingletonCurrentlyInCreation(beanName)) {
    
    
					logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
							"' that is not fully initialized yet - a consequence of a circular reference");
				}
				else {
    
    
					logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
				}
			}
			//如果是普通的bean,直接返回,如果是FactoryBean,则返回它的getObject
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}

我们再来看一下下面else的逻辑:

		//若scope为prototype或者单例模式但是缓存中还不存在bean
		else {
    
    
			//如果scope为prototype并且显示还在创建,则基本是循环依赖的情况。
			//针对prototype的循环依赖,spring无解,直接抛出异常
			if (isPrototypeCurrentlyInCreation(beanName)) {
    
    
				throw new BeanCurrentlyInCreationException(beanName);
			}

			//获取当前容器的父容器
			BeanFactory parentBeanFactory = getParentBeanFactory();
			//如果从当前容器找不到指定名称的bean,并且父容器不为空
			if (parentBeanFactory != null && 
		!containsBeanDefinition(beanName)) {
    
    
				//此时递归去parentFactory查找
				//主要针对FactoryBean,将Bean的&重新加上
				String nameToLookup = originalBeanName(name);
				//如果parent容器依旧是AbstractBeanFactory的实例
				//instance通过返回一个布尔值来指出,这个对象是否是特定类或者是它的子类的一个实例
				if (parentBeanFactory instanceof AbstractBeanFactory) {
    
    
					//直接递归调用方法来查找
					return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
							nameToLookup, requiredType, args, typeCheckOnly);
				}
				else if (args != null) {
    
    
					//如果有参数,则委派父级容器根据指定名称和显式的参数查找
					return (T) parentBeanFactory.getBean(nameToLookup, args);
				}
				else if (requiredType != null) {
    
    
					//委派给父级容器根据指定名称和类型查找
					return parentBeanFactory.getBean(nameToLookup, requiredType);
				}
				else {
    
    
					//委派父级容器根据指定名称查找
					return (T) parentBeanFactory.getBean(nameToLookup);
				}
			}
			//typeCheckOnly是用来判断调用getBean()是否仅仅是为了类型检查获取bean,而不是为了创建Bean
			if (!typeCheckOnly) {
    
    
				//如果不是仅仅做类型检查则是创建bean
				markBeanAsCreated(beanName);
			}
			try {
    
    
				//将父类的BeanDefinition与子类的BeanDefinition进行合并覆盖
				final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				//对合并的BeanDefinition做验证,主要看属性是否为abstract的
				checkMergedBeanDefinition(mbd, beanName, args);

				// 获取当前Bean所有依赖Bean的名称
				String[] dependsOn = mbd.getDependsOn();
				//如果当前Bean设置了dependsOn的属性
				//depends-on用来指定Bean初始化及销毁时的顺序
				if (dependsOn != null) {
    
    
					for (String dep : dependsOn) {
    
    
						//校验该依赖是否已经注册给当前bean,注意这里传入的key是当前的bean名称
						//这里主要是判断是否有以下类型的依赖
						//<bean id="beanA" class="BeanA" depends-on="beanB">
						//<bean id="beanB" class="BeanB" depends-on="beanA">
						//如果有,则直接抛出异常
						//由此可以看出,spring是不支持显式的循环依赖
						if (isDependent(beanName, dep)) {
    
    
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
						}
						//缓存依赖调用,注意这里传入的key是被依赖的bean名称
						registerDependentBean(dep, beanName);
						try {
    
    
							//递归调用getBean方法,注册Bean之间的依赖(如C需要晚于B初始化,而B需要晚于A初始化)
							//初始化依赖的bean
							getBean(dep);
						}
						catch (NoSuchBeanDefinitionException ex) {
    
    
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
						}
					}
				}

				// 如果BeanDefinition是单例
				if (mbd.isSingleton()) {
    
    
					//这里使用一个匿名内部类,创建Bean实例对象,并且注册给所依赖的对象
					sharedInstance = getSingleton(beanName, () -> {
    
    
						try {
    
    
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
    
    
							//显示从单例缓存中删除bean实例
							//因为单例模式下为了解决循环依赖,可能它已经存在了,所以将其销毁
							destroySingleton(beanName);
							throw ex;
						}
					});
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}

				else if (mbd.isPrototype()) {
    
    
					// prototype每次都会创建一个新对象
					Object prototypeInstance = null;
					try {
    
    
						//默认的功能是注册当前创建的prototype对象正在创建中
						beforePrototypeCreation(beanName);
						//创建原型对象实例
						prototypeInstance = createBean(beanName, mbd, args);
					}
					finally {
    
    
						//默认的功能是将先前注册的正在创建中的Bean信息给抹除掉
						afterPrototypeCreation(beanName);
					}
					bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
				}
				//要创建的Bean既不是单例模式,也不是原型模式
				//则根据Bean定义资源中配置的生命周期范围
				//选择实例化Bean的合适方法,这种在Web应用程序中比较常用
				//如:request、session、application等生命周期
				else {
    
    
					String scopeName = mbd.getScope();
					final Scope scope = this.scopes.get(scopeName);
					//Bean定义资源中没有配置生命周期的范围,则Bean定义不合法
					if (scope == null) {
    
    
						throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
					}
					try {
    
    
						Object scopedInstance = scope.get(beanName, () -> {
    
    
							beforePrototypeCreation(beanName);
							try {
    
    
								return createBean(beanName, mbd, args);
							}
							finally {
    
    
								afterPrototypeCreation(beanName);
							}
						});
						bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
					}
					catch (IllegalStateException ex) {
    
    
						throw new BeanCreationException(beanName,
								"Scope '" + scopeName + "' is not active for the current thread; consider " +
								"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
								ex);
					}
				}
			}
			catch (BeansException ex) {
    
    
				cleanupAfterBeanCreationFailure(beanName);
				throw ex;
			}
		}

强攻Bean的创建——createBean

createBean方法大致做了以下事情:

  • Bean类型解析
  • 处理方法覆盖
  • Bean实例化前的后置处理
  • doCreateBean

首先,我们进入到AbstractAutowireCapableBeanFactory#createBean方法里
在这里插入图片描述
在这里插入图片描述
这里用RootBeanDefiniton来接收从容器里获取到的BeanDefinition实例,原因是BeanDefinition是有parent属性的,它就会将parent的BeanDefinition属性也取出来,给合并到当前的ChildBeanDefinition里面,而对于普通的BeanDefinition来讲,RootBeanDefinition也是能接收的。

继续往下走:
在这里插入图片描述
先前我们使用BeanDefinitionReader加载配置的时候,将xml解析成BeanDefinition实例,BeanDefinition实例里面存储的是class的名字。在解析成BeanDefinition这一步的时候是已经创建好了Class对象了
既然要创建Bean实例,获取Class对象是不可或缺的,因此这里主要是根据class的名字,尝试使用类加载器加载出class对象。

再往下走:
在这里插入图片描述
这里进入到一个if的判断,首先判断解析出来的class对象不为空,并且当前BeanDefinition在解析之前是没有class对象的,但是有className的时候,即xml解析BeanDefinition的情况:

	if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
    
    
			//拷贝一份BeanDefinition,用来设置加载出来的class对象
			//之所以后续用该副本进行操作,是因为不希望解析的class绑定到缓存里的BeanDefinition
			//因为class有可能是每次都需要动态解析出来的
			mbdToUse = new RootBeanDefinition(mbd);
			mbdToUse.setBeanClass(resolvedClass);
		}

由于我这里用的是注解的方式,所以不会走到这一步,紧接着往下走:
在这里插入图片描述
这里检查BeanDefinition是否有定义方法的覆盖。

继续往下走:
在这里插入图片描述
这里我们就来到了resolveBeforeInstantiation这个方法里:
该方法主要执行了某些类型的后置处理器的操作。
我们进到这个方法里面看一下:

	protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
    
    
		Object bean = null;
		//如果beforeInstantiationResolved还没有设置或者为false(说明还没有需要在实例化前执行的操作)
		if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
    
    
			//mbd.isSynthetic()默认是false
			// 如果注册了InstantiationAwareBeanPostProcessors类型的BeanPostProcessor
			if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
    
    
				//确定Bean的类型
				Class<?> targetType = determineTargetType(beanName, mbd);
				if (targetType != null) {
    
    
					bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
					if (bean != null) {
    
    
						bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
					}
				}
			}
			mbd.beforeInstantiationResolved = (bean != null);
		}
		return bean;
	}

最后我们回到createBean方法里:

在这里插入图片描述

此时便来到了doCreateBean里面,接下来我们重点探讨一下doCreateBean的逻辑。

doCreateBean

上面,我们已经研究完了createBean的逻辑,主要就是通过BeanDefinition实例加载class对象,在获取到class对象后,检查都是有相关的覆盖方法,随后就会判断是否要对Bean进行自定义的封装处理,如果没有就会调用doCreateBean方法进行对Bean实例的创建。

我们大致看一下doCreateBean要做什么事情:

  • 首先会通过配置好的工厂方法或者含参构造注入或者无参构造注入去创建出一个没有属性值的Bean实例
  • 之后会执行BeanDefinition的后置处理,来处理BeanDefinition的属性,其中包含了@Autowired或者@Value标记的属性,然后记录下来便于后续的依赖注入处理
  • 然后判断是否允许提前暴露
  • 填充Bean属性,@Autowired就是在这里进行的
  • 调用initializeBean对Bean尽心初始化操作。
  • 注册相关销毁逻辑
  • 返回创建好的实例

我们进到源码里,来分析一下这个流程:
在这里插入图片描述
首先,它定义了一个BeanWrapper我们进到这个BeanWrapper的源码里面:
在这里插入图片描述
可以看到,它是一个接口,该接口是Spring提供的一个操作Bean里面属性的工具,使用它可以直接修改Bean里面的属性。

接下来继续往下走:

	//如果是单例
	if (mbd.isSingleton()) {
    
    
			//从未完成创建的包装Bean缓存中清理并获取相关中的包装Bean实例,毕竟是单例的,只能存一份
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		//如果是null
		if (instanceWrapper == null) {
    
    
			//创建bean的时候,这里创建bean的实例有三种方法
			//1.工厂方法创建
			//2.构造方法创建
			//3.无参构造方法注入
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		//获取被包装的Bean,后续对Bean的改动相当于对Wrapper的改动,反之亦然。
		final Object bean = instanceWrapper.getWrappedInstance();
		//获取实例化对象的类型
		Class<?> beanType = instanceWrapper.getWrappedClass();
		if (beanType != NullBean.class) {
    
    
			mbd.resolvedTargetType = beanType;
		}
		//调用BeanDefinition属性合并完成后的BeanPostProcessor后置处理
		// Allow post-processors to modify the merged bean definition.
		synchronized (mbd.postProcessingLock) {
    
    
			if (!mbd.postProcessed) {
    
    
				try {
    
    
					//被@Autowired、@Value标记的属性在这里获取
					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				}
				catch (Throwable ex) {
    
    
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"Post-processing of merged bean definition failed", ex);
				}
				mbd.postProcessed = true;
			}
		}

我们再进入到applyMergedBeanDefinitionPostProcessors这个方法里看看:

	protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
    
    
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
    
    
			if (bp instanceof MergedBeanDefinitionPostProcessor) {
    
    
				MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
				//重点关注AutowiredAnnotationBeanPostProcessor
				//该类会把@Autowired等标记的需要依赖注入的成员变量或者方法实例给记录下来,方便后续populateBean使用
				bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
			}
		}
	}

我们看一下postProcessMergedBeanDefinition这个方法:

在这里插入图片描述

这个AutowiredAnnotationBeanPostProcessor使我们要分析的重点
我们看一下它的构造方法:
在这里插入图片描述
里面便是将Autowired以及Value加入到autowiredAnnotationTypes
在注解模式下,当某个Bean在实例化的时候,就会调用AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition主要就是用来处理Autowired还有Value以及Inject的标签。

单例循环依赖解决

所谓循环依赖就是A依赖于B,然后B又依赖于A,这种情况我们来看一下Spring是如何解决的。
我们先照着代码大致说一下
我们假设A先被创建出来,由于是第一次创建,它先进入doCreateBean方法里经过各种包装,来到createBeanInstance方法里:
在这里插入图片描述
这时会生成一个没有任何属性的A的实例,之后就会在调用addSingletonFactory之前,将相关的ObjectFactory实例放到三级缓存中,此时只有三级缓存保存了A对应的ObjectFactory实例。
在这里插入图片描述
随后就会调用populateBean方法给这个实例赋值。
在这里插入图片描述
此时由于A是依赖于B的,那么就会在populateBean方法里面,再次调用getBean方法在容器里尝试获取实例B,那由于B还没有创建出来过,因此又会递归的调用到了doCreateBean方法。

doCreateBean里面再通过createBeanInstance创建出实例B,将其对应的工厂也就是说ObjectFactoryB放到三级缓存中,此时三级缓存就保存了实例A和实例B各自的ObjectFactory实例。

随后又会在B里调用populateBean方法,那此时我们的B又依赖于A,所以在populateBean又会调用getBean方法尝试获取A实例。
此时由于是调用的AbstractBeanFactory的doGetBean,这个方法会尝试调用getSingleton方法从三级缓存里获取A的实例
在这里插入图片描述
在这里插入图片描述
此时是可以获取到的,那么就会将ObjectFactory实例取出来调用里面的getObject方法区获取A的实例。
这里getObject其实上就是调用doCreateBean里面的getEarlyBeanReference方法获取被后置处理器处理之后的A实例。
在这里插入图片描述
那么获取到之后:
在这里插入图片描述
就会把A实例放入到二级缓存里面,同时清空三级缓存里面的A实例,随后就会将A实例返回。
此时是执行到了这里:
在这里插入图片描述
那么由于A实例是在B实例执行populateBean的时候获取到的,也就是此时将A实例注入到了B里面,当B执行完了populateBean之后,就已经获取到了A,B就会执行完剩余的逻辑,然后获得到了一个完备的Bean实例。

而由于doCreateBean方法是由doGetBean方法调用的,所以它会将完备的B的Bean实例逐层返回到doGetBean方法里。
我们到doGetBean里:
在这里插入图片描述
由于doGetBean是调用了createBean,进而再调用的doCreateBean
我们的doCreateBean是在getSingleton方法里面调用singletonFactory.getObject()的时候才被执行的。
在这里插入图片描述
值得注意的是,这里的getSingleton和上面说的尝试从三级缓存中获取Bean实例的getSingleton方法不是同一个。

在这个方法里面,会最终调用addSingleton方法:
在这里插入图片描述
在addSingleton方法里:
在这里插入图片描述
会最终将实例B添加到一级缓存。
并将B实例从二级以及三级缓存里移除,表明已经彻底完成了B的Bean实例创建。

并随后将B的完备的Bean实例返回。

而又由于B的创建是因为A实例调用populateBean触发的,此时又会回到A的populateBean方法。
在这里插入图片描述
之前是B赋值上了完备的A,这里A有赋值上了完备的B,那么A和B就都完备了。
这时又会返回给doGetBean方法,之后又会调用addSingleton将A实例给放入到一级缓存里。
在这里插入图片描述
在这里插入图片描述
这时就会把A实例放入一级缓存里,同时清除掉A实例的二级缓存和三级缓存。
这样就完成了对循环依赖的支持。

这样说起来可能有点晕,我们通过下面一张图来总结一下:
在这里插入图片描述
当初次创建实例A的时候,会调用addSingletonFactory将A实例对于的ObjectFactory实例给放入到三级缓存中,随后会调用populateBean给我们的A实例赋值属性B,那么赋值的时候会发现B不存在,因此就会调用getBean方法去获取B对应的Bean实例。

此时B实例也是一样的,先将B实例所在的ObjectFactory实例注入到三级缓存,然后再调用populateBean方法给B里面的A属性赋值,此时就会再次调用getBean方法,去获取A实例,因为此时先前已经把A对应的ObjectFactory放入到了三级缓存里了,所以此时可以从三级缓存里获取到A对应的ObjectFactory实例,然后调用ObjectFactory的getObject方法获取到A的实例。

获取到A的实例后就能将A实例注入到B里面,进而完成了B的创建,随后就会将B实例放入一级缓存,并清空其他级缓存,然后将其实例返回给A,此后A也就完成了创建,A也放入到了一级缓存里,清空了其他级缓存的实例,进而就完成了两个相互依赖的单例的创建。

Spring对循环依赖的支持情况

总的来说,Spring会有以下两种循环依赖的情况:

  • 构造器循环依赖(singleton、prototype)
  • Setter注入循环依赖(singleton、prototype)

对于prototype的来讲,Spring默认不支持相关的循环依赖。
因为解决循环依赖的关键取决于单例的三级缓存,而三级缓存除了解决循环依赖之外,还解决了保持单例唯一性的问题。
因为从缓存里取出来的Bean实例,是要保证是唯一的,所以三级缓存支持不了prototype,毕竟prototype它的Bean实例是不唯一的,这也是prototype没有使用三级缓存,只是把名字放入缓存里的原因。

而正因为没有三级缓存的支持,才导致prototype不支持依赖循环。

因此prototype只能通过将Bean名字放入缓存里阻断无限循环。

Spring只支持Setter的singleton的循环依赖。

猜你喜欢

转载自blog.csdn.net/qq_45455361/article/details/121434977
今日推荐