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 之间的依赖关系。
相关推荐
:1211 分钟前
java面试基础
java·开发语言
_Evan_Yao4 分钟前
软件工程就是一场“抽象”游戏:从 abstract 关键字到架构设计的认知跃迁
java·后端·游戏·状态模式·软件工程
艾莉丝努力练剑4 分钟前
【Linux线程】Linux系统多线程(十):线程安全和重入、死锁相关话题
java·linux·运维·服务器·c++·学习·安全
QuZero9 分钟前
getCategoryData False Fault Alarm Process
java·经验分享
梦梦代码精10 分钟前
LikeShop 深度测评:开源电商的务实之选
java·前端·数据库·后端·云原生·小程序·php
likerhood11 分钟前
设计模式之建造者模式(Builder Pattern)java版本
java·设计模式·建造者模式
happymaker062615 分钟前
Nexus私服的使用(配合Maven)
java·maven
JAVA学习通15 分钟前
本地知识库接入大模型时的权限隔离与安全设计
java·人工智能·安全·spring
AbandonForce16 分钟前
C++ 多态(多态定义 多态应用 多态底层||final override关键字||抽象类)
java·开发语言·c++
阿丰资源20 分钟前
基于SpringBoot+MySQL+Maven的图书推荐系统项目文档(附源码)
spring boot·mysql·maven