Spring之概念和工作流程

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: Spring之概念和工作流程

一、前言

这是我Spring专栏的第五篇文章: Spring中Bean的工作流程及一些重要类的概念 在之前我为大家讲解了以下内容:

二、Beandefinition

BeanDefinition表示Bean定义,BeanDefinition中存在很多属性用来描述一个Bean的特点。比如:

  • class,表示Bean类型
  • scope,表示Bean作用域,单例或原型等
  • lazyInit:表示Bean是否是懒加载
  • initMethodName:表示Bean初始化时要执行的方法
  • destroyMethodName:表示Bean销毁时要执行的方法
  • 等等

网络异常,图片无法展示
|

在Spring中, 我们经常使用以下三种方式来定义一个bean:

  • @Bean
  • @Component(@Service, @Controller)
  • <bean/>

除了这三种声明式定义Bean之外, 我们还可以编程式定义Bean

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
// 生成一个BeanDefinition对象,并设置beanClass为User.class,并注册到ApplicationContext中
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition.setBeanClass(Juejin.class);
context.registerBeanDefinition("juejin", beanDefinition);
System.out.println(context.getBean("juejin"));
复制代码

我们还可以使用 BeanDefinition对 Bean的其他属性进行设置

beanDefinition.setScope("prototype"); // 设置作用域
beanDefinition.setInitMethodName("init"); // 设置初始化方法
beanDefinition.setLazyInit(true); // 设置懒加载
复制代码

最终, 通过声明式定义的 Bean都会被Spring解析成对应的 BeanDefinition对象, 并放入Spring容器中

三、BeanDefinition读取器

接下来主要讲解的是几种 BeanDefinition读取器(BeanDefinitionReader), 这几种读取器在Spring源码中使用的较多

AnnotatedBeandefinitionReader

可以直接把某个类转换为 BeanDefinition, 并且会解析该类上的注解

具体以懒加载注解 @Lazy为例, 可以跟着下面几张图进入源代码看一遍

网络异常,图片无法展示
|

网络异常,图片无法展示
|

通过下图第一个红框可以看到, 他创建了一个 BeanDefinition, 点进第二个红框的方法, 就可以进入具体的判断注解方法了

网络异常,图片无法展示
|

首先我们看到他做了一个方法重载, 具体是做什么的先忽略掉, 看第二个红框, 这里就是判断我们是否使用了懒加载

网络异常,图片无法展示
|

AnnotatedBeandefinitionReader 可以解析的注解有: @Lazy, @Scope, @Conditional, @Primary, @DependsOn, @Role, @Description

XmlBeanDefinitionReader

可以解析 <bean/> 标签, 通过标签定义一个 bean好像很少去使用了就不进源码看了

ClassPathBeanDefinitionScanner

ClassPathBeanDefinitionScanner 是扫描器, 可以扫描包路径也可以对扫描到的类进行解析

四、BeanFactory

简单的说: BeanFactory表示工厂, 主要负责创建 Bean的同时提供获取Bean的API, 而ApplicationContext是BeanFactory的一种, 在Spring源码中, ApplicationContext的源码如下

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
    MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
            ...
}
复制代码

ApplicationContext具体实现的几个接口功能如图所示

网络异常,图片无法展示
|

强大的 DefaultListableBeanFactory

在 BeanFactory接口存在一个非常重要的实现类: DefaultListableBeanFactory, 也是非常核心的

通过 DefaultListableBeanFactory也可以来实现某个类, 具体代码如下所示

DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition.setBeanClass(Juejin.class);
beanFactory.registerBeanDefinition("juejin", beanDefinition);
System.out.println(beanFactory.getBean("juejin"));
复制代码

下图是关于 DefaultListableBeanFactory具体实现的一些接口功能简介

网络异常,图片无法展示
|

文字版:

  • AliasRegistry:支持别名功能,一个名字可以对应多个别名
  • BeanDefinitionRegistry:可以注册、保存、移除、获取某个BeanDefinition
  • BeanFactory:Bean工厂,可以根据某个bean的名字、或类型、或别名获取某个Bean对象
  • SingletonBeanRegistry:可以直接注册、获取某个单例Bean
  • SimpleAliasRegistry:它是一个类,实现了AliasRegistry接口中所定义的功能,支持别名功能
  • ListableBeanFactory:在BeanFactory的基础上,增加了其他功能,可以获取所有BeanDefinition的beanNames,可以根据某个类型获取对应的beanNames,可以根据某个类型获取{类型:对应的Bean}的映射关系
  • HierarchicalBeanFactory:在BeanFactory的基础上,添加了获取父BeanFactory的功能
  • DefaultSingletonBeanRegistry:它是一个类,实现了SingletonBeanRegistry接口,拥有了直接注册、获取某个单例Bean的功能
  • FactoryBeanRegistrySupport:支持了FactoryBean的功能
  • AutowireCapableBeanFactory:是直接继承了BeanFactory,在BeanFactory的基础上,支持在创建Bean的过程中能对Bean进行自动装配
  • DefaultListableBeanFactory:继承了AbstractAutowireCapableBeanFactory,实现了ConfigurableListableBeanFactory接口和BeanDefinitionRegistry接口,所以DefaultListableBeanFactory的功能很强大
  • AbstractBeanFactory:实现了ConfigurableBeanFactory接口,继承了FactoryBeanRegistrySupport,这个BeanFactory的功能已经很全面了,但是不能自动装配和获取beanNames
  • ConfigurableListableBeanFactory:继承了ListableBeanFactory、AutowireCapableBeanFactory、ConfigurableBeanFactory
  • ConfigurableBeanFactory:在HierarchicalBeanFactory和SingletonBeanRegistry的基础上,添加了设置父BeanFactory、类加载器(表示可以指定某个类加载器进行类的加载)、设置Spring EL表达式解析器(表示该BeanFactory可以解析EL表达式)、设置类型转化服务(表示该BeanFactory可以进行类型转化)、可以添加BeanPostProcessor(表示该BeanFactory支持Bean的后置处理器),可以合并BeanDefinition,可以销毁某个Bean等等功能
  • AbstractAutowireCapableBeanFactory:继承了AbstractBeanFactory,实现了AutowireCapableBeanFactory,拥有了自动装配的功能

五、ApplicationContext

BeanFactory我们一般称其为IOC容器, 而ApplicationContext我们称其为应用上下文

ApplicationContext是BeanFactory的子接口, 最主要的方法就是 getBean(String beanName), ApplicationContext除了提供 BeanFactory所支持的功能之外, ApplicationContext还增加了以下几个额外的功能(主要就是上面ApplicationContext接口展示的图片)

  • 事件机制
  • 国际化
  • 同时加载多个配置文件
  • 以声明式方式启动并创建Spring容器
  • 默认初始化所有的Singleton
  • 获取运行时环境变量

六、类型转换器

PropertyEditor

PropertyEditor 是JDK中提供的类型转化工具类, 下面是实现这个类的代码

public class StringToJuejinPropertyEditor extends PropertyEditorSupport implements PropertyEditor {
  @Override
  public void setAsText(String text) throws IllegalArgumentException {
    Juejin juejin = new Juejin();
    juejin.setName(text);
    this.setValue(user);
  }
}
复制代码

下面是测试代码

// 创建对象
StringToJuejinPropertyEditor propertyEditor = new StringToJuejinPropertyEditor();
// 调用方法
propertyEditor.setAsText("宁轩");
// 取出value
Juejin value = (Juejin) propertyEditor.getValue();
// 打印
    System.out.println(value);// 对象地址
复制代码

ConversionService

Spring中提供的类型转换服务, 实现代码如下:

public class StringToJuejinConverter implements ConditionalGenericConverter {
        // 自定义转化器使用场景
  @Override
  public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
                // String  ==> Juejin.class
    return sourceType.getType().equals(String.class) && targetType.getType().equals(Juejin.class);
  }
  @Override
  public Set<ConvertiblePair> getConvertibleTypes() {
    return Collections.singleton(new ConvertiblePair(String.class, Juejin.class));
  }
  @Override
  public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
    Juejin juejin = new Juejin();
    juejin.setName((String)source);
    return juejin;
  }
}
复制代码

测试代码

DefaultConversionService conversionService = new DefaultConversionService();
conversionService.addConverter(new StringToUserConverter());
Juejin value = conversionService.convert("宁轩", Juejin.class);
System.out.println(value);
复制代码

TypeConverter

Spring内部使用的类型转化类

SimpleTypeConverter typeConverter = new SimpleTypeConverter();
typeConverter.registerCustomEditor(Juejin.class, new StringToUserPropertyEditor());
Juejin value = typeConverter.convertIfNecessary("1", Juejin.class);
System.out.println(value);
复制代码

七、OrderComparator

OrderComparator是Spring所提供的一种比较器, 可以根据 @Order注解来实现排序

八、SimpleMetadataReader

在Spring中需要去解析类的信息, 得到类的元数据, Spring对类的元数据做了抽象, 并提供了一些工具类

MetadataReader表示类的元数据读取器,默认实现类为SimpleMetadataReader

public class Test {
  public static void main(String[] args) throws IOException {
    SimpleMetadataReaderFactory simpleMetadataReaderFactory = new SimpleMetadataReaderFactory();
        // 构造一个MetadataReader
        MetadataReader metadataReader = simpleMetadataReaderFactory.getMetadataReader("com.ningxuan.demo.service.JuejinService");
        // 得到一个ClassMetadata,并获取了类名
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        System.out.println(classMetadata.getClassName());
        // 获取一个AnnotationMetadata,并获取类上的注解信息
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
    for (String annotationType : annotationMetadata.getAnnotationTypes()) {
      System.out.println(annotationType);
    }
  }
}
复制代码

MetadataReader表示类的元数据读取器,主要包含了一个AnnotationMetadata,功能有

  • 获取类的名字、
  • 获取父类的名字
  • 获取所实现的所有接口名
  • 获取所有内部类的名字
  • 判断是不是抽象类
  • 判断是不是接口
  • 判断是不是一个注解
  • 获取拥有某个注解的方法集合
  • 获取类上添加的所有注解信息
  • 获取类上添加的所有注解类型集合

需要注意的是,SimpleMetadataReader去解析类时,使用的ASM技术

为什么要使用ASM技术,Spring启动的时候需要去扫描,如果指定的包路径比较宽泛,那么扫描的类是非常多的,那如果在Spring启动时就把这些类全部加载进JVM了,这样不太好,所以使用了ASM技术。

九、ExcludeFilter和IncludeFilter

这两个Filter是Spring扫描过程中用来过滤的。ExcludeFilter表示排除过滤器,IncludeFilter表示包含过滤器

如下图所示, 在扫描类的时候, 碰到类为 JuejinService.class的时候会排除

网络异常,图片无法展示
|

如下图所示, 在扫描类的时候, 哪怕JuejinService类没有使用@Component也会将其声明为注解

网络异常,图片无法展示
|

includeFilters具体代码实现如下图所示:

  • 进入AnnotationCOnfigApplicationContext无参构造方法之后
  • 在生成scanner的时候默认会执行 registerDefaultFilters() 方法
  • 在这个方法中, 会 new一个Component注解添加进 includeFilters中

网络异常,图片无法展示
|

网络异常,图片无法展示
|

网络异常,图片无法展示
|

网络异常,图片无法展示
|

在Spring内部是怎么支持 @Component注解

具体可以跟着下面图走一遍源代码, 具体步骤:

  • 进入AnnotationConfigApplicationContext构造方法
  • 进入无参构造
  • 无参生成了一个扫描器 ==> this.scanner = new ClassPathBeanDefinitionScanner(this)
  • 好多个方法重载
  • 接下来就可以看到 执行了一个 this.registerDefaultFilters() 方法
  • 在这个方法里面新建了一个 new AnnoationTypeFilter(Compent.class) 这样子在扫描的时候凡是发现了 @Component注解就生成Bean

网络异常,图片无法展示
|

网络异常,图片无法展示
|

FilterType类型

  • ANNOTATION:表示是否包含某个注解
  • ASSIGNABLE_TYPE:表示是否是某个类
  • ASPECTJ:表示否是符合某个Aspectj表达式
  • REGEX:表示是否符合某个正则表达式
  • CUSTOM:自定义

十、FactoryBean

我们都知道可以通过 @Bean, @Component等注解来生成bean, 那么有没有什么办法能完全由自己创造一个bean呢, 这个时候就用到了 FactoryBean

FactoryBean 一个能生产或修饰对象生成的工厂Bean, 能返回任何Bean的实例

FactoryBean生成的Bean和@Bean生成的bean有什么区别

通过@Bean生成的Bean是经过完整的生命周期的

通过FactoryBean生成的Bean只会经过初始化



目录
相关文章
|
2月前
|
缓存 安全 Java
Spring框架中Bean是如何加载的?从底层源码入手,详细解读Bean的创建流程
从底层源码入手,通过代码示例,追踪AnnotationConfigApplicationContext加载配置类、启动Spring容器的整个流程,并对IOC、BeanDefinition、PostProcesser等相关概念进行解释
147 24
Spring框架中Bean是如何加载的?从底层源码入手,详细解读Bean的创建流程
|
5月前
|
Java Maven 数据安全/隐私保护
详解 Java AOP:面向方面编程的核心概念与 Spring 实现
详解 Java AOP:面向方面编程的核心概念与 Spring 实现
78 1
|
26天前
|
XML Java 应用服务中间件
【Spring】运行Spring Boot项目,请求响应流程分析以及404和500报错
【Spring】运行Spring Boot项目,请求响应流程分析以及404和500报错
123 2
|
21天前
|
JSON 前端开发 JavaScript
优雅!Spring Boot 3.3 实现职责链模式,轻松应对电商订单流程
本文介绍如何使用 Spring Boot 3.3 实现职责链模式,优化电商订单处理流程。通过将订单处理的各个环节(如库存校验、优惠券核验、支付处理等)封装为独立的处理器,并通过职责链将这些处理器串联起来,实现了代码的解耦和灵活扩展。具体实现包括订单请求类 `OrderRequest`、抽象处理器类 `OrderHandler`、具体处理器实现(如 `OrderValidationHandler`、`VerifyCouponHandler` 等)、以及初始化职责链的配置类 `OrderChainConfig`。
|
3月前
|
XML Java 数据库
Spring5入门到实战------15、事务操作---概念--场景---声明式事务管理---事务参数--注解方式---xml方式
这篇文章是Spring5框架的实战教程,详细介绍了事务的概念、ACID特性、事务操作的场景,并通过实际的银行转账示例,演示了Spring框架中声明式事务管理的实现,包括使用注解和XML配置两种方式,以及如何配置事务参数来控制事务的行为。
Spring5入门到实战------15、事务操作---概念--场景---声明式事务管理---事务参数--注解方式---xml方式
|
4月前
|
Java 持续交付 Maven
Spring Boot程序的打包与运行:构建高效部署流程
构建高效的Spring Boot部署流程对于保障应用的快速、稳定上线至关重要。通过采用上述策略,您可以确保部署过程的自动化、可靠性和高效性,从而将专注点放在开发上面。无论是通过Maven的生命周期命令进行打包,还是通过容器技术对部署过程进行优化,选择正确的工具与实践是成功实现这一目标的关键。
172 2
|
5月前
|
Java 数据库连接 Spring
Spring底层架构核心概念总结
Spring底层架构核心概念总结
|
5月前
|
消息中间件 Java Maven
深入理解Spring Boot Starter:概念、特点、场景、原理及自定义starter
深入理解Spring Boot Starter:概念、特点、场景、原理及自定义starter
|
5月前
|
前端开发 安全 Java
Spring EL表达式:概念、特性与应用深入解析
Spring EL表达式:概念、特性与应用深入解析
|
5月前
|
XML 负载均衡 Java
Spring Boot 中实现负载均衡:概念、功能与实现
【6月更文挑战第28天】在分布式系统中,负载均衡(Load Balancing)是指将工作负载和流量分配到多个服务器或服务实例上,以提高系统可用性和响应速度。负载均衡器可以是硬件设备,也可以是软件解决方案。
274 0