[JAVA]Spring IOC 核心概念

Spring 中被广为所知的核心概念IOC(Inverse Of Control),它的目标是让开发人员不需要手动创建对象,对Bean的创建维护操作完全交由Spring控制完成,因此得名IOC控制反转,而实现这一能力的容器也被称之为IOC容器。

Spring为实现IOC设计了一批接口和类,例如核心接口 BeanFactory,Bean的元数据定义接口 BeanDefinition和Spring中最被熟知的应用上下文ApplicationContext等等,为了更好的理解IOC则需要充分了解这些接口和类设计的底层逻辑,并通过梳理这些概念设计的关系了解IOC 容器的运作原理,可以帮助开发人员更加透明清晰的使用Spring。

Bean定义 BeanDefinition

BeanDefinition是spring中一个非常重要的概念,也是核心数据结构。见名知意 BeanDefinition 就是Bean定义描述信息,主要包括Bean名称,构造参数,作用域与初始方法、销毁方法等元信息,这些信息在Bean 的整个生命周期中被使用。

以一个Spring 中通过xml 文件注册Bean实例方式举例

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="tom" class="io.fxtahe.ioc.bean.User" lazy-init="true"  init-method="init" destroy-method="destroy">
        <property name="id" value="1"/>
        <property name="userName" value="tom"/>
    </bean>
</beans>

文件中了bean的名称,指定加载类,懒加载并指定了bean的初始化方法和销毁方法,Spring 解析XML 并转换成BeanDefintion存储在Spring的容器中,为Bean 的实例化做准备。BeanDefinition 的配置方式不仅仅局限于xml文件配置,还有其他诸如 Spring 注解、类扫描、Properties文件、Groovy DSL等等方式,也可以根据需求自定义配置方式。Spring根据不同的用途和场景实现了不同子类

  • AnnotatedBeanDefinition:BeanDefinition 的扩展接口,增加了对注解的支持
  • AbstractBeanDefinition:这是 BeanDefinition 的抽象实现类,提供了大部分 BeanDefinition 接口的实现
  • RootBeanDefinition:AbstractBeanDefinition 子类实现类,用于表示顶级的 bean 定义
  • ConfigurationClassBeanDefinition: 继承自 RootBeanDefinition,并实现了 AnnotatedBeanDefinition 接口。用于通过 @Bean 注解配置的实例化方式
  • GenericBeanDefinition:BeanDefinition 通用实现,支持动态设置父类,支持继承关系
  • ScannedGenericBeanDefinition:用于表示通过组件扫描(component scanning)发现的Bean定义的实现类。它用于将扫描到的类转换为 BeanDefinition 对象
  • AnnotatedGenericBeanDefinition:用于通过 @Configuration 配置的bean 定义信息类

Bean定义读取器 BeanDefinitionReader

BeanDefinition 的配置方式不仅仅支持xml文件,还有其他诸如 Spring 注解、类扫描、Properties文件、Groovy DSL等等多种方式,开发者也可以根据需求自定义配置方式。当然不管是通过哪种方式,其最终目的都是将各种配置信息转换为BeanDefinition。 而将配置信息转换为Bean Definition的过程一般需要通过BeanDefinitionReader 的组件协助完成。

    DefaultListableBeanFactory df = new DefaultListableBeanFactory();
    BeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(df);
    beanDefinitionReader.loadBeanDefinitions(new ClassPathResource("beans.xml"));
    User tom = df.getBean("tom", User.class);

通过类名也可以大致猜想出不同实现类提供的能力,资源类型的配置文件读取组件一般实现BeanDefinitionReader接口,比如XmlBeanDefinitionReader。而AnnotatedBeanDefinitionReader、classPathBeanDefinitionScanner 则用于注解方式的bean配置方式,需要配合ApplicationContext使用。

了解上述信息后注册Bean的流程也变得清晰起来,BeanDefinitionReader将配置信息转换为BeanDefinition后 通过BeanDefinitionRegistry组件注册到容器工厂中,在实例化Bean时则会从容器中根据名称获取BeanDenifition,针对各种属性配置去创建实例Bean。

容器工厂 BeanFactory

BeanFactory 是IOC容器的核心接口,定义了对于bean的一些基本操作方法,比如通过bean名称获取实例,是否单例,获取bean类型等,而该接口的默认实现类为DefaultListableBeanFactory,该类不仅实现了BeanFactory接口,同时集成实现了各种接口及抽象类,对BeanFactory核心接口进行了扩展增强

Spring 为完整实现容器工厂定义了一系列错综复杂但又职责分明的接口类,下面简单描述了各接口的作用

  • AliasRegistry:通用的别名注册接口
  • BeanDefinitionRegistry:注册BeanDefinition 接口,定义对BeanDefinition 包括注册、获取、移除的基本操作方法
  • SimpleAliasRegistry: 对AliasRegistry 接口的简单实现类
  • SingletonBeanRegistry: 单例Bean注册接口,定义对单例bean的注册获取方法
  • DefaultSingletonBeanRegistry:SingletonBeanRegistry的默认实现类,是bean 注册存储的真实容器类
  • FactoryBeanRegistrySupport: 针对FactoryBean 的处理定义类
  • ListableBeanFactory:BeanFactory的扩展接口,可以通过类型或者注解等方式获取符合条件的一组bean
  • HierarchicalBeanFactory:对BeanFactory 的层级结构扩展接口,支持父BeanFactory
  • ConfigurableBeanFactory:扩展对BeanFactory 即插即用的配置与特定的访问方式,例如设置父容器,设置加载Bean 的ClassLoader,BeanPostProcessor 等
  • AutowireCapableBeanFactory:主要用于集成其他框架,自动装配充并不由Spring管理生命周期并已存在的实例Bean。
  • ConfigurableListableBeanFactory:支持分析和修改BeanDefinition,以及预实例化单例bean
  • AbstractBeanFactory:BeanFactory 的核心实现,完整实现了ConfigurableBeanFactory,及父子容器的功能,并定义了getBeanDefinition(根据beanName 获取BeanDefinition)和createBean(根据beanname,BeanDefinition,构造参数获取实例bean)的模板方法供子类去实现
  • AbstractAutowireCapableBeanFactory:AutowireCapableBeanFactory接口定义操作的实现抽象类,并提供了AbstractBeanFactory createBean方法的默认实现
  • DefaultListableBeanFactory:Spring BeanFactory 的核心实现类,并完整实现了BeanDefinitionRegistry BeanDefinition操作方法

BeanFactory 子接口根据不同场景扩展了不同的接口方法,例如HierarchicalBeanFactory 支持父子级的容器,ListableBeanFactory 提供类型获取一组Bean的接口方法(注意:如果子类同时为HierarchicalBeanFactory 类型则不支持从父级获取 Bean 实例),SingletonBeanRegistry 接口定义了对单例Bean的注册方式等。

通过简单了解 Spring BeanFactory 接口设计,根据不同的责任分配划分不同的接口,每个接口分别定义了各自对bean或者相关数据的操作方法,遵从单一职责原则,使得Spring在功能扩展中可以更加灵活多变。

应用上下文 ApplicationContext

BeanFactory 容器工厂已经提供了完整的Bean 操作,但是在实际应用中我们不会直接操作该类,而是通过 ApplicationContext 完成,因为ApplicationContext 不仅实现了BeanFactory 的能力而且提供了更加完备的应用开发能力。

  • Bean 的生命周期管理:Bean 的注册、初始化、销毁、依赖注入。
  • 国际化支持:支持消息资源文件,用于国际化和本地化。
  • 事件发布和监听:支持应用事件的发布和监听机制。
  • AOP 支持:简化面向切面开发编程难度。
  • Web支持:针对web应用提供特定能力。

而我们常说的IOC容器多是指 ApplicationContext 。

ApplicationContext 针对不同的应用场景提供不同的实现方案,以下简单介绍下那些常用的实现类

  • AbstractApplicationContext:这是下述所有 ApplicationContext 实现类的基类,它提供了 ApplicationContext 的基本功能和生命周期管理。
  • ClassPathXmlApplicationContext:这是一个从类路径下加载XML配置文件的 ApplicationContext 实现。它允许通过XML配置文件定义Bean和上下文参数。
  • FileSystemXmlApplicationContext:类似于 ClassPathXmlApplicationContext,但它从文件系统指定路径加载XML配置文件。
  • AnnotationConfigApplicationContext:这个 ApplicationContext 实现用于基于Java的配置,它允许通过 @Configuration 类来定义Bean和上下文参数。
  • AnnotationConfigWebApplicationContext:这是用于Web应用程序的 ApplicationContext 实现,它同样支持基于Java的配置,并且可以与Spring的 WebApplicationInitializer 接口配合使用进行Web应用程序的初始化。
  • XmlWebApplicationContext:这是一个用于Web环境的 ApplicationContext 实现,它通过XML配置文件来加载上下文定义。
  • GenericApplicationContext:这是一个通用的 ApplicationContext 实现,可以用于编程式地注册Bean定义,不依赖于任何特定的配置方式。
  • AbstractRefreshableApplicationContext:这是一个抽象类,它提供了刷新配置的能力,用于那些需要动态刷新配置的 ApplicationContext 实现。
  • ServletWebServerApplicationContext:这是一个用于Servlet环境的 ApplicationContext 实现,它通常与Spring的 DispatcherServlet 一起使用,用于Web应用程序的上下文管理。

BeanFactoryPostProcessor

BeanFactorPostprocesserBeanFactory的扩展点接口,允许开发者在Spring容器实例化任何其他bean之前,修改应用程序上下文的 BeanDefinition 。BeanFactoryPostProcessor 接口定义了一个方法 postProcessBeanFactory,该方法在Spring容器创建bean之前被调用,开发者可以对bean的定义进行自定义修改,比如修改bean的属性、作用域等。

@FunctionalInterface
public interface BeanFactoryPostProcessor {


	void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

}

BeanDefinitionRegistryPostProcessor

BeanDefinitionRegistryPostProcessorBeanFactorPostprocesser 的子接口,另外提供了一个postProcessBeanDefinitionRegistry方法, 它不仅能够修改已经注册的 bean 定义,还能向注册中心 BeanDefinitionRegistry 中动态地添加或移除 bean 定义。

public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {

	void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;

}

BeanPostProcessor

BeanPostProcessor 是针对bean 在实例之后、初始化前后对其进行自定义处理的扩展接口,它提供了两个方法

  • postProcessBeforeInitialization:在 bean 的初始化方法(即配置声明的 init-method 或使用 @PostConstruct 注解的方法)被调用之前调用此方法。
  • postProcessAfterInitialization: 在 bean 的初始化方法被调用之后调用此方法。
public interface BeanPostProcessor {

	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
}

总结

通过上述Spring接口定义可以大致了解Spring 容器运行的逻辑思路,首先通过文件或者类注解定义的Bean 定义信息,然后 BeanDefinitionReader 读取这些信息转换为 BeanDefinition 并通过 BeanDefinitionRegistry 注册到 BeanFactory 中,而BeanFactory 则通过Bean定义信息去实例化Bean。而 ApplicationContext 则控制整个过程,并提供了多种扩展接口,从而实现了对Bean的生命周期管理,也就是Spring 的 IOC 容器。

通过了解Spring核心的接口和数据结构设计,可以帮助开发人员更清晰的学习Spring容器运行流程和实现原理。而学习这些高维度的接口设计与接口职责划分也可以提升开发人员的程序设计能力。

标签

发表评论