拉钩笔记_模块二

2020-11-18  本文已影响0人  豪哥不许笑

spring架构

Spring是⼀个分层⾮常清晰并且依赖关系、职责定位⾮常明确的轻量级框架,主要包括⼏个⼤模块:数据处理模块、Web模块、AOP(Aspect Oriented Programming)/Aspects模块、Core Container模块和 Test 模块,如下图所示,Spring依靠这些基本模块,实现了⼀个令⼈愉悦的融合了现有解决⽅案的零侵⼊的轻量级框架。


spring架构

IOC

1.什么是IOC

IoC Inversion of Control (控制反转/反转控制),注意它是⼀个技术思想,不是⼀个技术实现描述的事情:Java开发领域对象的创建,管理的问题

我们丧失了⼀个权利(创建、管理对象的权利),得到了⼀个福利(不⽤考虑对象的创建、管理等⼀系列事情)

为什么叫做控制反转?

2.IOC解决了什么问题

IoC解决对象之间的耦合问题


对象耦合关系

AOP

1.什么是AOP

2.AOP在解决什么问题,如何解决

1.Spring的生命周期

我们在使用Spring的时候,会创建一个main方法,然后在class上添加@SpringBootApplication注解。在main方法中调用SpringApplication的run方法,之后容器便会启动。这时我们需要将注意关注到SpringApplication这个类方法上。

SpringApplication

初始化SpringApplication

SpringApplication在初始化时会在构造函数中调用initialize方法,此方法中主要做了两件事。

注:初始化器与监听器的加载方式都是采用的Spring SPI扩展,通过读取META-INF下的spring.factories文件中的值进行初始化。

image.jpeg

这里初始化的监听器与初始化器如下:

image.jpeg

创建生命周期监听器

SpringApplication初始化完毕后,接下来会调用对应的run方法启动SpringBoot。首先,我们先看到run方法中的这么一句调用:

image.jpeg

此方法中,同样做了如下两件事:

image.jpeg

这里初始化的SpringApplicationRunListener对象如下:

image.jpeg

EventPublishingRunListener对象在初始化的时候,会将SpringApplication作为对象传递进来。然后创建SimpleApplicationEventMulticaster对象并且将SpringApplication中的监听器传递进去。

image.jpeg

生命周期Starting

掉用starting后,会遍历SpringApplicationRunListener中所有的listeners,并调用对应的starting方法。如下所示:

image.jpeg

其中根据之前的逻辑,我们可知这个listeners中只有一个EventPublishingRunListener实例对象。EventPublishingRunListener中的starting方法如下所示:

image.jpeg

这里我们可以看到首先,封装了一个ApplicationStartedEvent事件,然后作为参数执行multicastEvent方法。如下所示:

image.jpeg image.jpeg

进入到multicastEvent方法后,主要做了如下几点操作

其他生命周期

其他生命周期的调用,与starting一样,通过构建一个Event事件,然后调用EventPublishingRunListener中的对应方法,在此方法中或找到Application中的listener执行对应的逻辑操作。如图所示:

image.jpeg

所以SpringApplicarion的生命周期有如下几步:

image.jpeg

2.BeanFactory

基础概念

BeanFactory是IOC容器对象的顶级接口,提供了IOC容器最基本的形态,给具体的IOC实现提供了规范。但是因为BeanFactory这个接口比较原始,无法支持Spring的很多其他插件,所以由这个接口派生出了ApplicationContext接口,通常建议比BeanFactory优先。
类图如下所示


image.jpeg

Spring代码中创建

Spring在SpringApplication.run方法中调用createApplicationContext()获取ApplicationContext实例对象。默认实例对象为AnnotationConfigEmbeddedWebApplicationContext。如下所示:

image.jpeg image.jpeg

在AnnotationConfigEmbeddedWebApplicationContext的父类GenericApplicationContext中,当进行初始化逻辑时,会默认创建一个BeanFactory实例,这个BeanFactory用来初始化IOC容器中的bean对象。

image.jpeg

在Spring中ApplicationContext主要子类的装饰

AnnotationConfigEmbeddedWebApplicationContext

用来读取注解类,主要是@Configuration、@Component、injext相关注解。允许逐个注册类(将类名指定为配置位置)以及类路径扫描(将基本包指定为配置位置)

EmbeddedWebApplicationContext

WebApplicationContext实例,主要用于Servlet相关bean的创建。能够通过EmbeddedServletContainerFactory工厂类引导创建相关属性。在这个实例中,会根据EmbeddedServletContainerFactory创建一个EmbeddedServletContainer实例作为容器的上下文,

另外,上下文中定义的任何bean都将自动注册到嵌入式Servlet容器中。对于单个Servlet bean,将使用“/”映射。如果找到多个Servlet bean,那么小写的bean名称将用作映射前缀。任何名为“dispatcherServlet”的Servlet将始终映射到“/”。Filter bean将映射到所有url('/*')。

GenericApplicationContext

包含DefaultListableBeanFactory实例且不采用特定bean定义格式实现的ApplicationContext实例。实现BeanDefinitionRegistry接口,以便允读取任何的bean定义。

AbstractApplicationContext

实现ApplicationContext的抽象类,主要使用模板模式,提供大量的模板方法供子类实现,其中的refresh()方法最为重要,会初始化所有的bean对象也是初始化bean的调用入口,会直接在SpringApplication中调用。

3.BeanDefinition

基础概念
BeanDefinition接口定义了一套规范,这套规范用来描述一个bean的实例,Spring通过扫描@Configuration、@Component等注解生成BeanDefinition实例保存在beanFactory中的beanDefinitionMap中,通过bean name进行索引。
当容器需要初始化某一个bean时,会优先通过bean name去beanDefinitionMap中读取对应的BeanDefinition实例,然后根据属性信息进行bean的创建。
具体类图如下所示:


image.jpeg

Spring扫描创建BeanDefinition过程

在Spring中,我们可以使用XML、注解、SPI的方式去向容器中注入一个bean实例对象。其中XML与SPI都是采用配置文件的方式直接指定bean的class进行加载,这里我们只说明注解模式下的扫描加载方式。

在上一节中,我们了解到了BeanFactory的作用是用来创建bean实例的工厂方法,自然BeanDefinition的创建也离不开BeanFactory的影子。首先我们还是先找到创建ApplicationContext的位置(BeanFactory的派生类)。如下图所示:

image.jpeg

我们之前了解到,在①处我们创建了ApplicationContext。但是此时的ApplicationContext中并没有各个类的BeanDefinition信息,而具体生成是在②处完成。我们进入refreshContext方法后,发现这个方法执行了((AbstractApplicationContext) applicationContext).refresh();进行刷新,而在这个刷新逻辑中会对所有的bean进行IOC注入。如下图所示:

image.jpeg image.jpeg

而SpringBoot对BeanDefinition的扫描在上图的invokeBeanFactoryPostProcessors方法中执行。我们暂时先直接跳到具体的加载逻辑。如下所示:

image.jpeg

这里,分三步加载了所有BeanDefinition实例

1.扫描加载所有实现了PriorityOrdered接口的class,目标类为ConfigurationClassPostProcessor其中我们通常使用的@Configuration、@Component等注解都是在此扫描生成BeanDefinition。

2.扫描加载所有实现了Ordered接口的class,主要是三方接入的扫描,比如baidu的disconf

3.扫描加载所有其他的class,如SpringSecuret相关

4.BeanFactoryPostProcessor

基本概念

BeanFactoryPostProcessor为一个接口类,里面仅提供了一个postProcessBeanFactory的方法,入参为BeanFactory的派生类ConfigurableListableBeanFactory。

具体如下所示:

image.jpeg

根据里面的入参,我们可知此接口提供了对BeanFactory的自定义操作方式,我们可以通过操作BeanFactory自定义注入相关的BeanDefinition实例,自定义进行bean的注入操作。一般可以作为接入其他组件使用。

SpringBoot调用位置

BeanFactoryPostProcessor在SpringBoot生命周期的refresh中调用如下图所示:

image.jpeg image.jpeg image.jpeg

SpringBoot中大多数BeanFactoryPostProcessor实例会从BeanFactory中获取通过getBean方法获取,所以我们在定义BeanFactoryPostProcessor对象进行注入时,只需要将此class声明为Bean进行注入即可,SpringBoot会在执行Bean初始化前调用BeanFactoryPostProcessor对象。

5.BeanPostProcessor

基本概念

BeanPostProcessor同样也是一个接口,但是与BeanFactoryPostProcessor不同的是,他们在Bean生命周期中执行的位置,接口执行的意义都是不一样的。BeanPostProcessor接口有两个方法,分别是postProcessBeforeInitialization与postProcessAfterInitialization,入参同样都是Object bean与String beanName。

具体如下:

image.jpeg

此接口为一个钩子接口,在IOC容器初始化Bean的时候调用,两个方法分别在Bean初始化时与Bean初始化完成进行调用。用来在Bean的生命周期中进行自定义处理。

有一点需要注意的是BeanPostProcessor是注册在BeanFactory上的,并不会与某一个class进行绑定,所以在入参中会传递进来每一个正在进行初始化或者已经初始化完毕的Bean对象与beanName,我们需要通过此信息与我们想要进行操作的Bean进行匹配,然后执行。

SpringBoot调用位置

同样BeanPostProcessor任然是在refresh方法中进行调用,具体调用路径如下:

image.jpeg image.jpeg image.jpeg

与BeanFactoryPostProcessor不同的是,在refresh中只对BeanPostProcessor进行了注册,并没有调用调用逻辑,而且这里同样也是通过BeanFactory的getBean方法获取具体的实例,所以我们同样在实现此实例时只用将其声明为Bean即可。

具体的执行位置如下:

image.jpeg image.jpeg image.jpeg image.jpeg image.jpeg image.jpeg image.jpeg
上一篇下一篇

猜你喜欢

热点阅读