likes
comments
collection
share

第6节 Spring源码之 prepareRefresh 方法

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

Spring 容器启动核心方法:refresh(),它内部的流程如下所示:

第6节 Spring源码之 prepareRefresh 方法

prepareRefresh()方法是容器加载核心方法refresh()方法的第一步流程,主要任务是容器刷新前的准备工作,包括以下几点:

  1. 设置容器的启动时间
  2. 设置活跃状态为true
  3. 设置关闭状态为false
  4. 获取 Environment 对象,并加载当前系统属性值到 Environment 对象中
  5. 准备监听器和事件的集合对象,默认空集合

一、prepareRefresh() 实现

protected void prepareRefresh() {
   this.startupDate = System.currentTimeMillis();
   this.closed.set(false);
   this.active.set(true);

   /**
    * Initialize any placeholder property sources in the context environment.
    * 模板方法:初始化占位符资源;spring 预留的扩展点
    */
   initPropertySources();

   // Validate that all properties marked as required are resolvable: see ConfigurablePropertyResolver#setRequiredProperties
   // 创建并获取环境对象,验证需要的属性文件是否都已经放入到环境中
   getEnvironment().validateRequiredProperties();

   // 设置事件监听器集合;在 spring boot 应用启动时, applicationListeners 是有值的,但 spring 启动是没有监听器的
   // 因为 spring boot 启动时默认注入了一大堆的 ApplicationListener ,它定义在 spring.factories 文件中
   if (this.earlyApplicationListeners == null) {
      this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
   } else {
      this.applicationListeners.clear();
      this.applicationListeners.addAll(this.earlyApplicationListeners);
   }

   // Allow for the collection of early ApplicationEvents,to be published once the multicaster is available...
   // 创建事件集合
   this.earlyApplicationEvents = new LinkedHashSet<>();
}

prepareRefresh() 方法内部逻辑相对来说比较简单,但是也给我们预留了一些比较有意思的扩展点。

1. initPropertySources() 方法

这是一个模板方法,需要自定义子类去实现你自己的逻辑

2. validateRequiredProperties() 方法

该方法其实也是一个扩展,它的作用就是容器启动会验证你设置的环境变量或者系统变量,如果没有设置就会报错Spring 容器启动时有系统变量:systemEnvironment环境变量:systemProperties,它们在 StandardEnvironment中定义 第6节 Spring源码之 prepareRefresh 方法

所以当调用 getEnvironment().validateRequiredProperties(); 方法时首先是获取系统环境和环境变量:

第6节 Spring源码之 prepareRefresh 方法

3. initPropertySources()validateRequiredProperties() 扩展验证

public class CustomizeClassPathXmlApplication extends ClassPathXmlApplicationContext {

   public CustomizeClassPathXmlApplication(String configLocation) {
      super(configLocation);
   }

   @Override
   protected void initPropertySources() {
      // 这里定制自己的业务逻辑
      System.out.println("扩展 initPropertySources");

      // 设置容器启动必要参数
      getEnvironment().setRequiredProperties("docker_env");
   }
}
public class TestProp {

   public static void main(String[] args) {
      testInitPropertySources();
   }

   public static void testInitPropertySources() {
      ApplicationContext cx = new CustomizeClassPathXmlApplication("application-bean.xml");
      User user = cx.getBean("user", User.class);
      System.out.println(user.getUsername());
   }
}

运行结果,提示缺少属性参数:docker_env

Exception in thread "main" org.springframework.core.env.MissingRequiredPropertiesException: 
The following properties were declared as required but could not be resolved: [docker_env]

一般实际业务开发使用较少,没有人真的会去强制校验。一般当你的应用程序少了某个环境变量,你启动容器也会失败,只不过这种方式只是Spring给你提供的扩展功能而已。