从依赖倒置原则看Spring(三)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 从依赖倒置原则看Spring

Spring的设计

在上一步,我们实现了自己的方案,并基于一些设想进行了扩展性优化,现在,我们就来认识一下实际上Spring的设计

那么,在Spring中又是由哪些"角色"构成的呢?

1、Bean: Spring作为一个IoC容器,最重要的当然是Bean咯

2、BeanFactory: 生产与管理Bean的工厂

3、BeanDefinition: Bean的定义,也就是我们方案中的Class,Spring对它进行了封装

4、BeanDefinitionRegistry: 类似于Bean与BeanFactory的关系,BeanDefinitionRegistry用于管理BeanDefinition

5、BeanDefinitionRegistryPostProcessor: 用于在解析配置类时的处理器,类似于我们方案中的ClassProcessor

6、BeanFactoryPostProcessor: BeanDefinitionRegistryPostProcessor父类,让我们可以再解析配置类之后进行后置处理

7、BeanPostProcessor: Bean的后置处理器,用于在生产Bean的过程中进行一些处理,比如依赖注入,类似我们的AutowiredAnnotationBeanProcessor

8、ApplicationContext: 如果说以上的角色都是在工厂中生产Bean的工人,那么ApplicationContext就是我们Spring的门面,ApplicationContext与BeanFactory是一种组合的关系,所以它完全扩展了BeanFactory的功能,并在其基础上添加了更多特定于企业的功能,比如我们熟知的ApplicationListener(事件监听器)

以上说的类似其实有一些本末倒置了,因为实际上应该是我们方案中的实现类似于Spring中的实现,这样说只是为了让大家更好的理解

我们在经历了自己方案的设计与优化后,对这些角色其实是非常容易理解的

接下来,我们就一个一个的详细了解一下

BeanFactory

BeanFactory是Spring中的一个顶级接口,它定义了获取Bean的方式,Spring中还有另一个接口叫SingletonBeanRegistry,它定义的是操作单例Bean的方式,这里我将这两个放在一起进行介绍,因为它们大体相同,SingletonBeanRegistry的注释上也写了可以与BeanFactory接口一起实现,方便统一管理。

BeanFactory

1、ListableBeanFactory:接口,定义了获取Bean/BeanDefinition列表相关的方法,如getBeansOfType(Class type)

2、AutowireCapableBeanFactory:接口,定义了Bean生命周期相关的方法,如创建bean, 依赖注入,初始化

3、AbstractBeanFactory:抽象类,基本上实现了所有有关Bean操作的方法,定义了Bean生命周期相关的抽象方法

4、AbstractAutowireCapableBeanFactory:抽象类,继承了AbstractBeanFactory,实现了Bean生命周期相关的内容,虽然是个抽象类,但它没有抽象方法

5、DefaultListableBeanFactory:继承与实现以上所有类和接口,是为Spring中最底层的BeanFactory, 自身实现了ListableBeanFactory接口

6、ApplicationContext:也是一个接口,我们会在下面有专门对它的介绍

SingletonBeanRegistry

1、DefaultSingletonBeanRegistry: 定义了Bean的缓存池,类似于我们的BeanMap,实现了有关单例的操作,比如getSingleton(面试常问的三级缓存就在这里)

2、FactoryBeanRegistrySupport:提供了对FactoryBean的支持,比如从FactoryBean中获取Bean

BeanDefinition

BeanDefinition其实也是个接口(想不到吧),这里定义了许多和类信息相关的操作方法,方便在生产Bean的时候直接使用,比如getBeanClassName

它的大概结构如下(这里举例RootBeanDefinition子类):

里面的各种属性想必大家也绝不陌生

同样的,它也有许多实现类:

1、AnnotatedGenericBeanDefinition:解析配置类与解析Import注解带入的类时,就会使用它进行封装

2、ScannedGenericBeanDefinition:封装通过@ComponentScan扫描包所得到的类信息

3、ConfigurationClassBeanDefinition:封装通过@Bean注解所得到的类信息

4、RootBeanDefinition:ConfigurationClassBeanDefinition父类,一般在Spring内部使用,将其他的BeanDefition转化成该类

BeanDefinitionRegistry

定义了与BeanDefiniton相关的操作,如registerBeanDefinitiongetBeanDefinition,在BeanFactory中,实现类就是DefaultListableBeanFactory

BeanDefinitionRegistryPostProcessor

插话:讲到这里,有没有发现Spring的命名极其规范,Spring团队曾言Spring中的类名都是反复推敲才确认的,真是名副其实呀,所以看Spring源码真的是一件很舒服的事情,看看类名方法名就能猜出它们的功能了。

该接口只定义了一个功能:处理BeanDefinitonRegistry,也就是解析配置类中的ImportComponentComponentScan等注解进行相应的处理,处理完毕后将这些类注册成对应的BeanDefinition

在Spring内部中,只有一个实现:ConfigurationClassPostProcessor

BeanFactoryPostProcessor

所谓BeanFactory的后置处理器,它定义了在解析完配置类后可以调用的处理逻辑,类似于一个插槽,如果我们想在配置类解析完后做点什么,就可以实现该接口。

在Spring内部中,同样只有ConfigurationClassPostProcessor实现了它:用于专门处理加了Configuration注解的类

这里串场一个小问题,如知以下代码:

@Configuraiton
public class MyConfiguration{
  @Bean
  public Car car(){
      return new Car(wheel());
  }
  @Bean
  public Wheel wheel(){
      return new Wheel();
  }
}

问:Wheel对象在Spring启动时,被new了几次?为什么?

BeanPostProcessor

江湖翻译:Bean的后置处理器

该后置处理器贯穿了Bean的生命周期整个过程,在Bean的创建过程中,一共被调用了9次,至于哪9次我们下次再来探究,以下介绍它的实现类以及作用

1、AutowiredAnnotationBeanPostProcessor:用于推断构造器进行实例化,以及处理Autowired和Value注解

2、CommonAnnotationBeanPostProcessor:处理Java规范中的注解,如Resource、PostConstruct

3、ApplicationListenerDetector: 在Bean的初始化后使用,将实现了ApplicationListener接口的bean添加到事件监听器列表中

4、ApplicationContextAwareProcessor:用于回调实现了Aware接口的Bean

5、ImportAwareBeanPostProcessor: 用于回调实现了ImportAware接口的Bean

ApplicationContext

ApplicationContext作为Spring的核心,以门面模式隔离了BeanFactory,以模板方法模式定义了Spring启动流程的骨架,又以策略模式调用了各式各样的Processor…实在是错综复杂又精妙绝伦!

它的实现类如下:

1、ConfigurableApplicationContext:接口,定义了配置与生命周期相关操作,如refresh

2、AbstractApplicationContext: 抽象类,实现了refresh方法,refresh方法作为Spring核心中的核心,可以说整个Spring皆在refresh之中,所有子类都通过refresh方法启动,在调用该方法之后,将实例化所有单例

3、AnnotationConfigApplicationContext: 在启动时使用相关的注解读取器与扫描器,往Spring容器中注册需要用的处理器,而后在refresh方法在被主流程调用即可

4、AnnotationConfigWebApplicationContext:实现loadBeanDefinitions方法,以期在refresh流程中被调用,从而加载BeanDefintion

5、ClassPathXmlApplicationContext: 同上

从子类的情况可以看出,子类的不同之处在于如何加载BeanDefiniton, AnnotationConfigApplicationContext是通过配置类处理器(ConfigurationClassPostProcessor)加载的,而AnnotationConfigWebApplicationContext与ClassPathXmlApplicationContext则是通过自己实现loadBeanDefinitions方法,其他流程则完全一致

Spring的流程

以上,我们已经清楚了Spring中的主要角色以及作用,现在我们尝试把它们组合起来,构建一个Spring的启动流程

同样以我们常用的AnnotationConfigApplicationContext为例

图中只画出了Spring中的部分大概流程,详细内容我们会在后面的章节展开

gittee: https://gitee.com/lzj960515/my-spring

目录
相关文章
|
设计模式 Java Spring
【设计模式】依赖倒置原则与工厂方法模式与spring
【设计模式】依赖倒置原则与工厂方法模式与spring
131 0
|
XML 前端开发 Java
从依赖倒置原则看Spring(二)
从依赖倒置原则看Spring
161 0
|
JSON Java 数据格式
从依赖倒置原则看Spring(一)
从依赖倒置原则看Spring
49290 0
|
3月前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
277 2
|
6天前
|
Java 测试技术 应用服务中间件
Spring Boot 如何测试打包部署
本文介绍了 Spring Boot 项目的开发、调试、打包及投产上线的全流程。主要内容包括: 1. **单元测试**:通过添加 `spring-boot-starter-test` 包,使用 `@RunWith(SpringRunner.class)` 和 `@SpringBootTest` 注解进行测试类开发。 2. **集成测试**:支持热部署,通过添加 `spring-boot-devtools` 实现代码修改后自动重启。 3. **投产上线**:提供两种部署方案,一是打包成 jar 包直接运行,二是打包成 war 包部署到 Tomcat 服务器。
28 10
|
20天前
|
Java 数据库连接 Maven
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
自动装配是现在面试中常考的一道面试题。本文基于最新的 SpringBoot 3.3.3 版本的源码来分析自动装配的原理,并在文未说明了SpringBoot2和SpringBoot3的自动装配源码中区别,以及面试回答的拿分核心话术。
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
|
6天前
|
存储 安全 Java
Spring Boot 3 集成Spring AOP实现系统日志记录
本文介绍了如何在Spring Boot 3中集成Spring AOP实现系统日志记录功能。通过定义`SysLog`注解和配置相应的AOP切面,可以在方法执行前后自动记录日志信息,包括操作的开始时间、结束时间、请求参数、返回结果、异常信息等,并将这些信息保存到数据库中。此外,还使用了`ThreadLocal`变量来存储每个线程独立的日志数据,确保线程安全。文中还展示了项目实战中的部分代码片段,以及基于Spring Boot 3 + Vue 3构建的快速开发框架的简介与内置功能列表。此框架结合了当前主流技术栈,提供了用户管理、权限控制、接口文档自动生成等多项实用特性。
36 8
|
27天前
|
NoSQL Java Redis
Spring Boot 自动配置机制:从原理到自定义
Spring Boot 的自动配置机制通过 `spring.factories` 文件和 `@EnableAutoConfiguration` 注解,根据类路径中的依赖和条件注解自动配置所需的 Bean,大大简化了开发过程。本文深入探讨了自动配置的原理、条件化配置、自定义自动配置以及实际应用案例,帮助开发者更好地理解和利用这一强大特性。
85 14
|
2月前
|
缓存 IDE Java
SpringBoot入门(7)- 配置热部署devtools工具
SpringBoot入门(7)- 配置热部署devtools工具
71 1
SpringBoot入门(7)- 配置热部署devtools工具
|
2月前
|
缓存 IDE Java
SpringBoot入门(7)- 配置热部署devtools工具
SpringBoot入门(7)- 配置热部署devtools工具
58 2
 SpringBoot入门(7)- 配置热部署devtools工具