Spring IOC源码分析(六):BeanFactory体系结构与IOC容器的核心组件分析

本文主要是介绍Spring IOC源码分析(六):BeanFactory体系结构与IOC容器的核心组件分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一. 概述

  • Spring容器通常指的是ApplicationContext的体系结构设计,即整个Spring框架的IOC功能,是通过ApplicationContext接口实现类来提供给应用程序使用的。应用程序通过ApplicationContext提供方法来间接与内部Bean工厂交互,如获取Bean对象实例等。
  • 在Spring框架内部设计当中,ApplicationContext是Spring容器所管理、维护的beans对象的一个运行环境,即ApplicationContext包含一些功能组件:保存外部属性文件(properties文件,yml文件等)的属性键值对集合的Environment,容器配置的位置contextConfigLocation等等,用于创建bean对象需要的一些外部依赖;
  • 而ApplicationContext内部最重要的组件,就是BeanFactory体系结构,ApplicationContext通过BeanFactory来维护Spring容器所管理的类对应的BeanDefintions,通过BeanFactory来获取类对象bean。与BeanFactory配套的就是ApplicationContext维护多个BeanFactoryPostProcessor,BeanPostProcessor来对BeanFactory进行拓展,对BeanFactory自身或所创建的bean对象实例进行加工、功能拓展,实现整体设计的高拓展性。

二. bean元数据和对象实例工厂:BeanFactory

BeanFactory
  • 顶层接口,主要提供getBean方法,从该BeanFactory获取给定beanName,对应的bean对象实例;
ListableBeanFactory
  • 继承于BeanFactory,主要提供根据给定条件,如type,Annotation,获取对应的所有beans列表的接口;
HierarchicalBeanFactory
  • 继承于BeanFactory,提供获取parentBeanFactory的方法,实现BeanFactory的层次化功能;
ConfigurableBeanFactory
  • 继承于HierarchicalBeanFactory接口,主要提供对BeanFactory进行相关配置的接口,如类加载器classLoader,beanPostProcessor,类型转换器,属性编辑器等在加载、创建和初始化bean实例时,需要用到的一些功能组件;
AutowireCapableBeanFactory
  • 继承于BeanFactory,主要提供对于BeanFactory创建的bean,使用autowire的方式对其所依赖的beans进行依赖注入。
接口具体实现类
1. DefaultListableBeanFactory
  • BeanFactory接口体系的默认实现类,实现以上接口的功能,提供BeanDefinition的存储map,Bean对象对象的存储map。

  • 其中Bean对象实例的存储map,定义在FactoryBeanRegistrySupport,FactoryBeanRegistrySupport实现了SingletonBeanRegistry接口,而DefaultListableBeanFactory的基类AbstractBeanFactory,继承于FactoryBeanRegistrySupport。

    public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactoryimplements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {.../** Map from serialized id to factory instance. */private static final Map<String, Reference<DefaultListableBeanFactory>> serializableFactories =new ConcurrentHashMap<>(8);.../** Map from dependency type to corresponding autowired value. */private final Map<Class<?>, Object> resolvableDependencies = new ConcurrentHashMap<>(16);/** Map of bean definition objects, keyed by bean name. */private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);/** Map of singleton and non-singleton bean names, keyed by dependency type. */private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<>(64);/** Map of singleton-only bean names, keyed by dependency type. */private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap<>(64);/** List of bean definition names, in registration order. */private volatile List<String> beanDefinitionNames = new ArrayList<>(256);/** List of names of manually registered singletons, in registration order. */private volatile Set<String> manualSingletonNames = new LinkedHashSet<>(16);/** Cached array of bean definition names in case of frozen configuration. */@Nullableprivate volatile String[] frozenBeanDefinitionNames;/** Whether bean definition metadata may be cached for all beans. */private volatile boolean configurationFrozen = false;...}
    
2. StaticListableBeanFactory
  • 用于存储给定的bean对象实例,不支持动态注册功能,是ListableBeanFactory接口的简单实现。

    public class StaticListableBeanFactory implements ListableBeanFactory {/** Map from bean name to bean instance. */private final Map<String, Object> beans;...}
    
Bean的获取与注册的接口设计隔离
  • 以上BeanFactory接口层次主要是以Bean的获取为主的设计。而注册是在BeanDefinitionRegistr和SingletonBeanRegistry中设计的。
bean的获取
  • 在BeanFactory的接口继承体系中,主要是提供获取bean,如getBean;列举bean,如ListableBeanFactory;提供BeanFactory创建bean需要的组件的ConfigurableBeanFactory;以及对bean注入其他beans的AutowireCapableBeanFactory。
  • 但是没有提供注册bean的方法声明,即将BeanDefinition注册到BeanFactory实现类内部维护的ConcurrentHashMap类型的map中。
bean的注册
1. BeanDefinition的注册
  • 提供BeanDefinition注册功能的是BeanDefinitionRegistry接口,在这个接口定义注册beanDefinition到BeanFactory的方法声明。
  • BeanFactory的实现类会实现BeanDefinitionRegistry,并实现BeanDefinitionRegistry接口的registerBeanDefinition系列方法来将给定的BeanDefinition注册到BeanFactory中。
2. Bean对象实例的注册
  • 在SingletonBeanRegistry接口的实现类中提供存储的map和注册方法,BeanFactory实现SingletonBeanRegistry接口。

三. bean元数据的注册:BeanDefinitionRegistry

  • 注册BeanDefinitions。提供registerBeanDefinition,removeBeanDefinition等方法,用来从BeanFactory注册或移除BeanDefinition。
  • 通常BeanFactory接口的实现类需要实现这个接口。
  • 实现类(通常为BeanFactory接口实现类)的对象实例,被DefinitionReader接口实现类引用,DefinitionReader将BeanDefintion注册到该对象实例中。

四. 单例bean元数据注册:SingletonBeanRegistry

  • 用于注册单例Bean对象实例,实现类定义存储Bean对象实例的map,BeanFactory的类层次结构中需要实现这个接口,来提供Bean对象的注册和从Bean对象实例的map获取bean对象。

    /*** Support base class for singleton registries which need to handle* {@link org.springframework.beans.factory.FactoryBean} instances,* integrated with {@link DefaultSingletonBeanRegistry}'s singleton management.** <p>Serves as base class for {@link AbstractBeanFactory}.** @author Juergen Hoeller* @since 2.5.1*/
    public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanRegistry {/** Cache of singleton objects created by FactoryBeans: FactoryBean name to object. */private final Map<String, Object> factoryBeanObjectCache = new ConcurrentHashMap<>(16);...}
    

五. bean元数据解析主入口:BeanDefinitionReader

  • 从xml文件、类路径下使用了@Component系列注解的类、或者从@Configuration注解的配置类,获取BeanDefintiions,然后注册到BeanFactory中。
1. XmlBeanDefinitionReader:基于XML文件
  • 读取解析xml文件,通过Parser解析xml文件的标签。
  • 针对beans标签,生成对应的BeanDefintions,然后注册到BeanFactory中。
  • 针对其他有特殊功能的标签,如context:component-scan,context:anotation-config,还可以生成BeanFactoryPostProcessor,BeanPostProcessor接口实现类的bean等;除了可以生成BeanDefinitions之外,还可以实现其他功能。
NamespaceHandler:XML标签名称空间处理器
  • 被XmlBeanDefinitionReader使用,XmlBeanDefinitionReader在处理每个XML标签名称空间的时候,如applicationContext.xml的context:,mvc:,通过一个DefaultNamespaceHandlerResolver来获取对应的NamespaceHandler实现类,然后通过这个NamespaceHandler实现类,进一步获取该命名空间的内部标签对应的BeanDefinitionParser实现类。
  • NamespaceHandler详细设计与实现,可以阅读我的另外一篇文章:Spring源码分析:XML标签名称空间处理器-NamespaceHandler
BeanDefinitionDocumentReader
  • 被XmlBeanDefinitionReader使用,专门用于处理xml文件的beans标签的标签处理器。即XmlBeanDefinitionReader读取xml文件,创建Document对象,然后交给BeanDefinitionDocumentReader处理。
  • BeanDefinitionDocumentReader解析Document对象的Element节点,然后创建BeanDefinitions集合,通过XmlBeanDefinitionReader注册到XmlBeanDefinitionReader所在的BeanFactory。
2. AnnotatedBeanDefinitionReader:注册指定的类列表annotatedClasses
  • 可以使用编程方法,显示指定将哪些类需要注册到BeanFactory。
  • 主要是被AnnotationConfigApplicationContext使用,即基于注解配置的ApplicationContext,这是SpringBoot的默认ApplicationContext。典型使用为:先获取所有使用了@Configuration注解的类,然后通过AnnotatedBeanDefinitionReader生成与这些类对应的BeanDefinitions,并注册到BeanFactory。
3. ClassPathBeanDefinitionScanner:注册指定的basePackages下面的类
  • 扫描指定类路径(包)下面的类,检测是否存在@Component注解及其子注解,从而生成BeanDefinition,然后注册到BeanFactory。
  • 没有实现BeanDefinitionReader接口,但基于相同的设计思路:BeanDefinitionReader。
  • 与AnnotatedBeanDefinitionReader一样,都是获取指定类,生成该类的BeanDefinition注册到BeanFactory,而不是像xml文件一样已经通过bean标签显示说明这个就是bean。
  • 也是主要是被AnnotationConfigApplicationContext使用。与其他两种也是基于basePackages类路径扫描的方式不同之处为:
    1. context:component-scan标签:基于XML的ApplicationContext,实现类路径扫描,底层使用ComponentScanBeanDefinitionParser这个parser来处理。
    2. @ComponentScan:对于处理@Configuration配置类上面的@ComponentScan注解,则是通过ComponentScanAnnotationParser来处理的。
4. ConfigurationClassBeanDefinitionReader:基于@Configuration注解的类配置
  • 处理@Configuration注解的配置类,加在这些配置类上面的注解,即与@Configuration一起使用的注解,如@ComponentScan,@PropertySource,@Import,@Profile等。
  • ConfigurationClassBeanDefinitionReader主要被ConfigurationClassPostProcessor调用,ConfigurationClassPostProcessor为BeanFactoryPostProcessor,详细可以看我的另外一篇文章:Spring基于@Configuration的类配置的内部源码实现

六. bean元数据解析执行者:BeanDefinitionParser

  • xml文件的标签的解析处理器,通过实现 BeanDefinitionParser接口,来针对每个标签进行特定。
  • 典型用途包括:生成BeanDefintion对象,或BeanFactoryPostProcessor对象,或BeanPostProcessor对象,或者为针对标签定义特定的功能,自定义该标签的用途。
  • Parser可以同时生成这三种类型中的一个或多个。如ComponentScanBeanDefinitionParser既生成BeanDefinitions,又生成ConfigurationClassPostProcessor(BeanFactoryPostProcessor接口实现类)。AnnotationConfigBeanDefinitionParser既生成BeanPostProcessor,又生成ConfigurationClassPostProcessor。
1. 直接创建BeanDefintion
DefaultBeanDefinitionDocumentReader:xml文件解析
  • 本身不是BeanDefinitionParser接口的实现类,而是利用BeanDefinitionParser接口的实现类,解析xml文件的beans标签,及其里边嵌套的bean标签,获取BeanDefinitions。
ComponentScanBeanDefinitionParser
  • 处理xml文件的context:component-scan标签,扫描basePackages属性指定的路径下面的类,检测并获取使用了@Component注解及其子注解的类,生成对应的BeanDefinitions。
ComponentScanAnnotationParser
  • 处理@ComponentScan注解,与ComponentScanBeanDefinitionParser功能一样,一般是与@Configuration注解一起使用。在ConfigurationClassParser中创建ComponentScanAnnotationParser对象实例并在parse方法中调用,ConfigurationClassParser为处理@Configuration注解的类。
2. 创建BeanFactoryPostProcessor
ConfigurationClassPostProcessor:间接创建BeanDefinition
  • ConfigurationClassPostProcessor是一个BeanFactoryPostProcessor接口的实现类。

  • 在ComponentScanBeanDefinitionParser和AnnotationConfigBeanDefinitionParser中会创建ConfigurationClassPostProcessor对象实例:这样由这些parser创建的BeanDefinitions,就可以被ConfigurationClassPostProcessor进一步处理,创建更多的BeanDefintions。

    1、ComponentScanBeanDefinitionParser:对应context:component-scan,在parse方法调用;
    2、AnnotationConfigBeanDefinitionParser:对应context:annotation-config,在parse方法调用;
    3、ClassPathBeanDefinitionScanner:在scan方法调用,该类在AnnotationConfigApplicationContext中使用;
    4、AnnotatedBeanDefinitionReader:在构造函数调用,该类在AnnotationConfigApplicationContext中使用。

  • 从BeanFactory的BeanDefintions集合,过滤获取使用了@Configuration注解的类,然后从这些类的@Bean方法获取BeanDefintions。

3. 创建BeanPostProcessor
  • AnnotationConfigBeanDefinitionParser:处理context:annotation-config标签,产生相关的BeanPostProcessor:

  • ComponentScanBeanDefinitionParser:处理xml文件的context:component-scan标签。

    以上两个parser都会产生以下两个BeanPostProcessor:
    1、CommonAnnotationBeanPostProcessor:处理bean对象及其方法中的JDK自身的注解;
    2、AutowiredAnnotationBeanPostProcessor:bean对象的依赖注入处理,如@Autowired。

4. 自定义功能拓展
  • 可以通过自定义标签和自定义Parser接口的实现类,并结合NamespaceHandler来实现自动融入spring框架。如dubbo框架就利用了这个特性来实现自动融入spring框架。Spring源码分析:XML标签名称空间处理器-NamespaceHandler

七. bean工厂后置处理器: BeanFactoryPostProcessor

  • BeanFactory后置处理器:bean元数据注册的拓展

    在BeanFactory创建好,加载好其所包含的所有beanDefinitions,但是还没有实例化bean之前,执行,具体为调用postProcessBeanFactory方法。

  • ApplicationContext会自动检测当前存在的BeanFactoryPostProcessors,并在创建bean实例之前执行。除此之外也可以对BeanFactory进行其他拓展实现。

  • 典型用实现类和用途:

1. 加载更多的bean元数据
  • ConfigurationClassPostProcessor,用于从BeanFactory中检测使用了@Configuration注解的类,对于这些类对应的BeanDefinitions集合,遍历并依次交给ConfigurationClassParser,ConfigurationClassBeanDefinitionReader处理,分别是处理与@Configuration同时使用的其他注解和将类内部的使用@Bean注解的方法,生成BeanDefinition,注册到BeanFactory。
2. 对bean元数据进行加工处理
  • BeanDefinition属性填充、修改:在postProcessBeanFactory方法中,可以对beanFactory所包含的beanDefinitions的propertyValues和构造函数参数值进行修改,如使用PropertyPlaceHolderConfigurer来对BeanDefinition的propertyValues的占位符进行填充、赋值。或者使用PropertyResourceConfigurer获取config文件中属性,对BeanDefinitions的相关属性进行赋值或者值覆盖。

八. bean对象后置处理器:BeanPostProcessor

  • Bean后置处理器:负责对已创建好的bean对象进行加工处理。

    主要是可以对新创建的bean实例进行修改,提供了一个类似于hook机制,对创建好的bean对象实例进行修改。

  • ApplicationContext会自动检测当前存在的beanPostProcessors,并应用在创建的bean实例上。

核心方法
  • postProcessBeforeInitialization:在创建好bean实例,但是在任何初始化回调执行之前,如InitializingBean的afterPropertiesSet,先执行该方法。
  • postProcessAfterInitialization:在创建好bean实例,并且所有的初始化回调都执行完了,如InitializingBean的afterPropertiesSet,再执行该方法。
注解处理相关的BeanPostProcessor
  • 通常用于在创建好bean对象实例后,处理这个bean上面的注解。同时也可以对bean对象进行其他功能拓展。
  • BeanPostProcessor的注册
    1. 定义:在注解配置工具类AnnotationConfigUtils的静态方法registerAnnotationConfigProcessors方法中,定义注解的处理器的注册逻辑。
    2. 调用:在BeanFactoryPostProcessor中调用这个静态方法来完成将特定的BeanPostProcessor实现类,注册到ApplicationContext的BeanPostProcessor列表。
  1. AutowiredAnnotationBeanPostProcessor:处理bean对象的依赖注入关系,即从BeanFactory获取该bean所依赖的bean,然后注入到该bean对应的成员变量中。

  2. CommonAnnotationBeanPostProcessor:该bean中所使用了的JDK定义的注解的处理,如方法中的@PostConstruct,@PreDestroy,成员变量上的@Resource等。

  3. PersistenceAnnotationBeanPostProcessor(JPA时添加):JPA相关bean的持久化处理。

这篇关于Spring IOC源码分析(六):BeanFactory体系结构与IOC容器的核心组件分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/957126

相关文章

Java实现Excel与HTML互转

《Java实现Excel与HTML互转》Excel是一种电子表格格式,而HTM则是一种用于创建网页的标记语言,虽然两者在用途上存在差异,但有时我们需要将数据从一种格式转换为另一种格式,下面我们就来看看... Excel是一种电子表格格式,广泛用于数据处理和分析,而HTM则是一种用于创建网页的标记语言。虽然两

java图像识别工具类(ImageRecognitionUtils)使用实例详解

《java图像识别工具类(ImageRecognitionUtils)使用实例详解》:本文主要介绍如何在Java中使用OpenCV进行图像识别,包括图像加载、预处理、分类、人脸检测和特征提取等步骤... 目录前言1. 图像识别的背景与作用2. 设计目标3. 项目依赖4. 设计与实现 ImageRecogni

Java中Springboot集成Kafka实现消息发送和接收功能

《Java中Springboot集成Kafka实现消息发送和接收功能》Kafka是一个高吞吐量的分布式发布-订阅消息系统,主要用于处理大规模数据流,它由生产者、消费者、主题、分区和代理等组件构成,Ka... 目录一、Kafka 简介二、Kafka 功能三、POM依赖四、配置文件五、生产者六、消费者一、Kaf

Java访问修饰符public、private、protected及默认访问权限详解

《Java访问修饰符public、private、protected及默认访问权限详解》:本文主要介绍Java访问修饰符public、private、protected及默认访问权限的相关资料,每... 目录前言1. public 访问修饰符特点:示例:适用场景:2. private 访问修饰符特点:示例:

详解Java如何向http/https接口发出请求

《详解Java如何向http/https接口发出请求》这篇文章主要为大家详细介绍了Java如何实现向http/https接口发出请求,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 用Java发送web请求所用到的包都在java.net下,在具体使用时可以用如下代码,你可以把它封装成一

SpringBoot使用Apache Tika检测敏感信息

《SpringBoot使用ApacheTika检测敏感信息》ApacheTika是一个功能强大的内容分析工具,它能够从多种文件格式中提取文本、元数据以及其他结构化信息,下面我们来看看如何使用Ap... 目录Tika 主要特性1. 多格式支持2. 自动文件类型检测3. 文本和元数据提取4. 支持 OCR(光学

Java内存泄漏问题的排查、优化与最佳实践

《Java内存泄漏问题的排查、优化与最佳实践》在Java开发中,内存泄漏是一个常见且令人头疼的问题,内存泄漏指的是程序在运行过程中,已经不再使用的对象没有被及时释放,从而导致内存占用不断增加,最终... 目录引言1. 什么是内存泄漏?常见的内存泄漏情况2. 如何排查 Java 中的内存泄漏?2.1 使用 J

JAVA系统中Spring Boot应用程序的配置文件application.yml使用详解

《JAVA系统中SpringBoot应用程序的配置文件application.yml使用详解》:本文主要介绍JAVA系统中SpringBoot应用程序的配置文件application.yml的... 目录文件路径文件内容解释1. Server 配置2. Spring 配置3. Logging 配置4. Ma

Java 字符数组转字符串的常用方法

《Java字符数组转字符串的常用方法》文章总结了在Java中将字符数组转换为字符串的几种常用方法,包括使用String构造函数、String.valueOf()方法、StringBuilder以及A... 目录1. 使用String构造函数1.1 基本转换方法1.2 注意事项2. 使用String.valu

java脚本使用不同版本jdk的说明介绍

《java脚本使用不同版本jdk的说明介绍》本文介绍了在Java中执行JavaScript脚本的几种方式,包括使用ScriptEngine、Nashorn和GraalVM,ScriptEngine适用... 目录Java脚本使用不同版本jdk的说明1.使用ScriptEngine执行javascript2.