likes
comments
collection
share

Spring之概念和工作流程

作者站长头像
站长
· 阅读数 17

一、前言

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

二、Beandefinition

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

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

Spring之概念和工作流程

在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为例, 可以跟着下面几张图进入源代码看一遍

Spring之概念和工作流程

Spring之概念和工作流程

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

Spring之概念和工作流程

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

Spring之概念和工作流程

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具体实现的几个接口功能如图所示

Spring之概念和工作流程

强大的 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具体实现的一些接口功能简介

Spring之概念和工作流程

文字版:

  • 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的时候会排除 Spring之概念和工作流程

如下图所示, 在扫描类的时候, 哪怕JuejinService类没有使用@Component也会将其声明为注解 Spring之概念和工作流程

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

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

Spring之概念和工作流程

Spring之概念和工作流程

Spring之概念和工作流程

Spring之概念和工作流程

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

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

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

Spring之概念和工作流程

Spring之概念和工作流程

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只会经过初始化

本文内容到此结束了

如有收获欢迎点赞👍收藏💖关注✔️,您的鼓励是我最大的动力。

如有错误❌疑问💬欢迎各位大佬指出。

我是 宁轩 , 我们下次再见