likes
comments
collection
share

Spring Boot 源码分析(二)

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

应用程序环境配置

封装命令行参数

ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);

这个args就是main方法传入的args参数

准备应用程序的环境

ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
      ApplicationArguments applicationArguments) {
   // 准备环境(根据应用类型选择,Servlet类型返回StandardServletEnvironment对象)
   ConfigurableEnvironment environment = getOrCreateEnvironment();
   // 配置类型转换ApplicationConversionService(DCL单例模式)
   configureEnvironment(environment, applicationArguments.getSourceArgs());
   // 将配置属性源附加到Environment对象上
   ConfigurationPropertySources.attach(environment);
   // 发送环境准备好的事件给到监听器(最终执行监听器onApplicationEvent方法)
   listeners.environmentPrepared(environment);
   // 将配置绑定到SpringApplication
   bindToSpringApplication(environment);
   if (!this.isCustomEnvironment) {
      // 如果有需要转换environment对象
      environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
            deduceEnvironmentClass());
   }
   ConfigurationPropertySources.attach(environment);
   return environment;
}

问题一

StandardServletEnvironment初始化过程有哪些?

Spring Boot 源码分析(二)

注:其中StandardServletEnvironment继承自StandardEnvironment类

很显然执行StandardServletEnvironment会先调用最上级的构造函数(base:虽然AbstractEnvironment对象是个抽象类,不能被实例化,但可以有构造函数执行初始化逻辑)

StandardEnvironment构造函数:

private final MutablePropertySources propertySources = new MutablePropertySources();
...
public AbstractEnvironment() {
   customizePropertySources(this.propertySources);
}
public class MutablePropertySources implements PropertySources {
    private final List<PropertySource<?>> propertySourceList = new CopyOnWriteArrayList<>();
    ...
}

可以看到传入了propertySource参数,这个参数本质上是MutablePropertySources的实例 ,内部维护了propertySourceList集合。

customizePropertySources方法逻辑:

protected void customizePropertySources(MutablePropertySources propertySources) {
    propertySources.addLast(new PropertySource.StubPropertySource("servletConfigInitParams"));
    propertySources.addLast(new PropertySource.StubPropertySource("servletContextInitParams"));
    if (JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {
        propertySources.addLast(new JndiPropertySource("jndiProperties"));
    }

    super.customizePropertySources(propertySources);
}
protected void customizePropertySources(MutablePropertySources propertySources) {
   propertySources.addLast(
         new PropertiesPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
   propertySources.addLast(
         new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
}

可以看到将一些服务和系统的配置信息存入到了propertySources对象中。

问题二

以environmentPrepared方法为例,事件最终是如何到达监听器的?

private final SimpleApplicationEventMulticaster initialMulticaster;
...
public EventPublishingRunListener(SpringApplication application, String[] args) {
		this.application = application;
		this.args = args;
		this.initialMulticaster = new SimpleApplicationEventMulticaster();
		for (ApplicationListener<?> listener : application.getListeners()) {
			this.initialMulticaster.addApplicationListener(listener);
		}
	}
...
public void environmentPrepared(ConfigurableEnvironment environment) {
   this.initialMulticaster
         .multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
}

Spring SPI+反射机制调用了如上构造函数,SimpleApplicationEventMulticaster实现了ApplicationEventMulticaster接口,用于管理和广播应用程序事件。SimpleApplicationEventMulticaster 提供了注册、移除和触发应用程序事件监听器的方法。

SimpleApplicationEventMulticaster 提供的主要方法包括:

  • addApplicationListener(ApplicationListener<?> listener): 添加一个监听器以通知所有事件。
  • removeApplicationListener(ApplicationListener<?> listener): 移除一个已注册的监听器。
  • multicastEvent(ApplicationEvent event): 广播一个事件给所有注册的监听器。
@Override
public void multicastEvent(ApplicationEvent event) {
   multicastEvent(event, resolveDefaultEventType(event));
}

@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
   ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
   Executor executor = getTaskExecutor();
   for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
      if (executor != null) {
         executor.execute(() -> invokeListener(listener, event));
      }
      else {
         invokeListener(listener, event);
      }
   }
}

调用invokeListener(listener, event)方法,最终执行监听器onApplicationEvent方法

配置忽略BeanInfo

configureIgnoreBeanInfo(environment);

打印banner(启动图标)

Banner printedBanner = printBanner(environment);

应用上下文

// Servlet应用类型最终生成AnnotationConfigServletWebServerApplicationContext对象
context = createApplicationContext();

AnnotationConfigServletWebServerApplicationContext 用于配置基于注解的 Servlet Web 应用程序上下文。它是 Spring Boot 应用程序中常用的一个类,用于启动一个基于 Servlet 的 Web 服务器,并加载通过注解配置的 Spring 组件。

具体来说,AnnotationConfigServletWebServerApplicationContext 做了以下几件事:

  1. 注解配置:通过 Java 配置类而不是 XML 配置文件来定义和注册 Spring 的 bean。这些配置类通常使用 @Configuration 注解,并且可能包含 @Bean 方法来定义 bean。
  2. Servlet Web 服务器:这个类与 Servlet 容器集成,用于启动一个 Web 服务器。在 Spring Boot 中,这通常是一个内嵌的 Tomcat、Jetty 或 Undertow 服务器。
  3. 应用程序上下文:它提供了一个容器,用于管理应用程序的 bean 的生命周期,以及解决这些 bean 之间的依赖关系。