Spring Boot 源码分析(二)

应用程序环境配置

封装命令行参数

java 复制代码
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);

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

准备应用程序的环境

java 复制代码
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
java 复制代码
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初始化过程有哪些?

注:其中StandardServletEnvironment继承自StandardEnvironment类

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

StandardEnvironment构造函数:

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

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

customizePropertySources方法逻辑:

java 复制代码
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);
}
java 复制代码
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方法为例,事件最终是如何到达监听器的?

java 复制代码
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): 广播一个事件给所有注册的监听器。
java 复制代码
@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

java 复制代码
configureIgnoreBeanInfo(environment);

打印banner(启动图标)

java 复制代码
Banner printedBanner = printBanner(environment);

应用上下文

java 复制代码
// 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 之间的依赖关系。
相关推荐
NE_STOP16 小时前
Vide Coding--AI编程工具的选择
java
码云数智-园园17 小时前
C++20 Modules 模块详解
java·开发语言·spring
程序员黑豆17 小时前
JDK 下载安装与配置详细教程
java·前端·ai编程
霸道流氓气质17 小时前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务
小宇宙Zz17 小时前
Maven依赖冲突
java·服务器·maven
swordbob17 小时前
NIO的channel中什么是 fd(File Descriptor,文件描述符)
java·开发语言·nio
于先生吖17 小时前
SpringBoot对接大模型开发AI命理测算系统:八字排盘与AI解析接口源码全解
人工智能·spring boot·后端
咖啡八杯17 小时前
GoF设计模式——享元模式
java·spring·设计模式·享元模式
十五喵源码网18 小时前
基于springboot2+vue2的租房管理系统
java·毕业设计·springboot·论文笔记
摇滚侠18 小时前
IDEA 创建 Java 项目 手动整合 SSM 框架
java·ide·intellij-idea