[Java/Spring] 深入理解 : Spring 的 BeanFactory / ApplicationContext、Environment、PropertySource 、MessageSource 、ResourcePatternResolver的关系

千千寰宇 / 2024-10-11 / 原文

1 辨析

PropertySource

  • PropertySource : 解析环境资源及配置的底层组件
  • org.springframework.core.env.PropertyResolver

Environment

  • Environment : 管理环境的配置与资源
  • org.springframework.core.env.Environment
  • 其继承接口 PropertyResolver 属性解析器,用来解析不同属性源 PropertySource 里的 key-value。
  • org.springframework.core.env.AbstractEnvironment implements ConfigurableEnvironment
  • 实现子类 :
  • org.springframework.core.env.StandardEnvironment extends AbstractEnvironment
  • org.springframework.boot.web.reactive.context.StandardReactiveWebEnvironment extends StandardEnvironment implements ConfigurableReactiveWebEnvironment
  • org.springframework.web.context.support.StandardServletEnvironment extends StandardEnvironment implements ConfigurableWebEnvironment
  • 内部属性 :
private final Set<String> activeProfiles = new LinkedHashSet<>();

private final Set<String> defaultProfiles = new LinkedHashSet<>(getReservedDefaultProfiles());

private final MutablePropertySources propertySources = new MutablePropertySources();

private final ConfigurablePropertyResolver propertyResolver = new PropertySourcesPropertyResolver(this.propertySources);
  • 与 environment 关系
Environment -> ConfigurableEnvironment -> AbstractEnvironment -> StandardEnvironment -> StandardReactiveWebEnvironment: 父子层次

ConfigurableEnvironment -> MutablePropertySources: 获取可变多个配置源 ( ConfigurableEnvironment#getPropertySources() )

MutablePropertySources extends PropertySources ( PropertySources extends Iterable<PropertySource<?>> ) : 包含多个 PropertySource

BeanFactory

  • BeanFactory : Spring IOC 容器的顶级抽象接口
  • org.springframework.beans.factory.BeanFactory
  • BeanFactory 中 Bean 的生命周期
  • 2个重要的后置处理器: BeanFactoryPostProcessor、BeanPostProcessor

ApplicationContext

  • ApplicationContext : Spring IOC 容器的默认实现、基于 Environment 创建 上下文、跨语言/地区支持、应用事件发布支持、
  • org.springframework.context.ApplicationContext
  • ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver
  • org.springframework.context.support.AbstractApplicationContext
  • ApplicationContext 本质是一个维护 Bean 定义以及对象之间协作关系的接口,或者说为应用 application 提供配置的核心接口。

1、Bean 容器(ListableBeanFactory / HierarchicalBeanFactory).

ApplicationContext 继承 ListableBeanFactory 和 HierarchicalBeanFactory ,实现了 Bean 的生命周期管理(BeanFactoy)、有序性(ListableBeanFactory)和层次性(HierarchicalBeanFactory),并进行扩展。
Spring也为我们提供了 ApplicationContext 的多种类型的容器实现,供我们在不同的应用场景选择。例如:

AnnotationConfigApplicationContext:从一个或多个基于 Java 的配置类中加载上下文定义,适用于 Java 注解的方式
AnnotationConfigWebApplicationContext:专门为 web 应用准备的,适用于注解方式

2、ApplicationContext 继承 EnvironmentCapable 接口:

带有Capable后缀的接口在Spring中带有getXXX的含义,也就是实现了这个接口,就可以通过该接口的实例获取到XXX,这个和Aware接口很类似

换言之,通过 ApplicationContext 可获得 Environment 对象。
所有的Spring应用上下文都实现了 EnvironmentCapable 接口, 这个接口主要用于检查接受了 BeanFactory 接口的框架方法,不管这些接口是不是 ApplicationContext ,为了与 environment 交互,如果这些接口确实是可用的。
例如: (new ClassPathXmlApplicationContext("bean.xml") ).getEnvironment().getProperty("key");

在 Spring Boot 的启动方法 run() 我们可以看到 Spring Boot 根据当前应用环境 webApplicationType 决定创建相应的 ConfigurableApplicationContext 对象
run() 内的 prepareEnvironment 监听 ApplicationEnvironmentPreparedEvent 事件,由 listeners 处理,然后 createApplicationContext() 创建上下文

3、跨语言/地区支持(MessageSource)

4、应用事件发布支持(ApplicationEventPublisher)

5、资源模式解析支持(ResourcePatternResolver)

MessageSource

  • MessageSource
org.springframework.context.MessageSource;

public interface MessageSource {
    @Nullable
    String getMessage(String code, @Nullable Object[] args, @Nullable String defaultMessage, Locale locale);
    String getMessage(String code, @Nullable Object[] args, Locale locale) throws NoSuchMessageException;
    String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException;
}

Use Demo

code = "application.version";
Locale locale = getUserLocale(httpRequest); // Locale对象标定了当前使用哪种语言
text = messageSource.getMessage(code, locale);

ApplicationEventPublisher

  • ApplicationEventPublisher : 应用事件发布支持
public interface ApplicationEventPublisher {
 
    default void publishEvent(ApplicationEvent event) {
        publishEvent((Object) event);
    }
 
    void publishEvent(Object event);
}

事件发布是一种编程模式,是回调编程的一个变种。具体而言,就是我们可以在Spring上发布一个事件,然后Spring会寻找这个容器的监听器,然后调用监听器的代码。
例如,Spring 应用关闭后,会发布一个应用关闭事件。 应用代码可以注册这个事件的监听器, 处理一些资源关闭事件。
但这个模式最强的地方在于,它能把业务逻辑流程高度抽象起来,然后在这些抽象的流程中间插入事件发布。

例如一个订单业务,遵循下单-付款-发货-收货,即可以抽象出对应的事件,如果我们想在用户下单时,弹出一些优惠提示,我们就可以注册一个下单事件的监听器来进行这个工作。一旦优惠截止,只需要卸载这个监听器即可。
事件流描述了一个应用逻辑流程的生命周期各个重要的节点。
所以经常的,当你发现只要是涉及生命周期这个话题时,事件出镜率总是非常高。
事实上,对于这个模式强编码出类似于"publish"和"event"的描述,确实有些过度抽象的嫌疑。

ResourcePatternResolver

  • ResourcePatternResolver : 资源模式解析器

一个ResourcePatternResolver是一个ResourceLoader。但前者比后者比多一个模式匹配的接口。通常,我们认为一个资源位置字符串代表了一个资源,但一个模式字符串可以匹配多个资源。
Resource[] getResources(String locationPattern) throws IOException;

所谓资源,在java的定义中,是一段字节流。文件是一段命名字节流,网络消息是一段字节流,内存是一块大字节数组……诸如此类,Resource接口抽象出这些来源,提供共同的操作接口。即从应用代码的角度出发,你不再需要管它是一个File还是一个URI,只需要老实调用getInputStream()或readableChannel()方法就可以了。
Spring的配置文件就是通过 ResourcePatternResolver 读取的。触类旁通,你当然也可以通过它来获得你想要的文件,无论它在classpath下、一个本地文件还是一个网络位置。

2 Spring Framework 模块

重点关注:模块间的依赖关系

X 参考文献

  • Spring environment 和 applicationContext - 博客园
  • spring environment_Spring 中的 ApplicationContext - CSDN 【推荐】