【Spring Boot 源码学习】SpringApplication 的定制化介绍

2024-01-08 01:36

本文主要是介绍【Spring Boot 源码学习】SpringApplication 的定制化介绍,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Spring Boot 源码学习系列

在这里插入图片描述

SpringApplication 的定制化介绍

  • 一、引言
  • 二、往期内容
  • 三、主要内容
    • 1. 基础配置
      • 1.1 设置关闭 Banner
      • 1.2 设置自定义 Banner 打印对象
      • 1.3 设置应用程序主入口类
      • 1.4 设置用于创建应用程序上下文的工厂
      • 1.5 添加 BootstrapRegistry 初始化器实现
      • 1.6 设置或添加 ApplicationContext 初始化器实现
      • 1.7 设置 ApplicationListener 实现
      • 1.8 设置要运行的Web应用程序的类型
      • 1.9 设置 SpringApplication 中 各种 boolean 变量
        • 1.9.1 setAllowBeanDefinitionOverriding 方法
        • 1.9.2 setAllowCircularReferences 方法
        • 1.9.3 setLazyInitialization 方法
        • 1.9.4 setHeadless 方法
        • 1.9.5 setRegisterShutdownHook 方法
        • 1.9.6 setLogStartupInfo 方法
        • 1.9.7 setAddCommandLineProperties 方法
        • 1.9.8 setAddConversionService 方法
      • 1.10 设置默认的环境属性
      • 1.11 设置要使用的额外的配置文件值
      • 1.12 设置 bean 名称生成器
      • 1.13 设置底层环境
      • 1.14 设置资源加载器
      • 1.15 设置环境配置属性前缀
      • 1.16 设置应用启动指标对象
    • 2. 数据源配置
      • 2.1 通过 SpringApplication 构造方法参数
      • 2.2 通过 setSources 方法
      • 2.3 合并配置源信息
  • 四、总结

一、引言

前面的博文,Huazie 带大家从 Spring Boot 的启动类 SpringApplication 上入手,了解了 SpringApplication 的实例化过程。这实例化构造过程中包含了各种初始化的操作,都是 Spring Boot 默认配置的。如果我们需要定制化配置,SpringApplication 也提供了相关的入口,且看下面的介绍。

在这里插入图片描述

二、往期内容

在开始本篇的内容介绍之前,我们先来看看往期的系列文章【有需要的朋友,欢迎关注系列专栏】:

Spring Boot 源码学习
Spring Boot 项目介绍
Spring Boot 核心运行原理介绍
【Spring Boot 源码学习】@EnableAutoConfiguration 注解
【Spring Boot 源码学习】@SpringBootApplication 注解
【Spring Boot 源码学习】走近 AutoConfigurationImportSelector
【Spring Boot 源码学习】自动装配流程源码解析(上)
【Spring Boot 源码学习】自动装配流程源码解析(下)
【Spring Boot 源码学习】深入 FilteringSpringBootCondition
【Spring Boot 源码学习】OnClassCondition 详解
【Spring Boot 源码学习】OnBeanCondition 详解
【Spring Boot 源码学习】OnWebApplicationCondition 详解
【Spring Boot 源码学习】@Conditional 条件注解
【Spring Boot 源码学习】HttpEncodingAutoConfiguration 详解
【Spring Boot 源码学习】RedisAutoConfiguration 详解
【Spring Boot 源码学习】JedisConnectionConfiguration 详解
【Spring Boot 源码学习】初识 SpringApplication
【Spring Boot 源码学习】Banner 信息打印流程
【Spring Boot 源码学习】自定义 Banner 信息打印
【Spring Boot 源码学习】BootstrapRegistryInitializer 详解
【Spring Boot 源码学习】ApplicationContextInitializer 详解
【Spring Boot 源码学习】ApplicationListener 详解

三、主要内容

针对 SpringApplication 的定制化配置,Spring Boot 中也提供了不同的方式,比如通过入口类、配置文件、环境变量、命令行参数等等。

注意: 以下涉及 Spring Boot 源码 均来自版本 2.7.9,其他版本有所出入,可自行查看源码。

1. 基础配置

所谓基础配置,即是可以直接通过 setadd 方法来进行参数的配置,这些 setadd 方法修改的配置都是 Spring Boot 预定义的一些参数,有些也可以在 application.properties 文件中进行配置。

1.1 设置关闭 Banner

在笔者的《Banner 信息打印流程》 中,第 2 小节就介绍了如何关闭 Banner 信息打印。

通过 SpringApplication 提供的 setBannerMode 方法,我们就可以在启动入口类中,这样来编写:

@SpringBootApplication
public class DemoApplication {public static void main(String[] args) {SpringApplication springApplication = new SpringApplication(DemoApplication.class);springApplication.setBannerMode(Banner.Mode.OFF);springApplication.run(args);}
}

1.2 设置自定义 Banner 打印对象

在笔者的《自定义 Banner 信息打印》 中,第 4 小节就介绍了如何自定义 Banner 接口实现。

通过 SpringApplication 提供的 setBanner 方法,我们可以修改入口类,如下:

@SpringBootApplication
public class DemoApplication {public static void main(String[] args) {SpringApplication springApplication = new SpringApplication(DemoApplication.class);springApplication.setBanner(new CustomBanner());springApplication.run(args);}
}

1.3 设置应用程序主入口类

在笔者的《初识 SpringApplication》 中,2.6 小节介绍了 SpringApplication 实例化时,会自动推断应用入口类,最终会被赋值给 SpringApplication 的成员变量 mainApplicationClass

当然,通过 SpringApplication 提供的 setMainApplicationClass 方法,设置一个特定的主应用程序类,该类将用作日志源并获取版本信息。默认情况下,SpringApplication 实例化时,会自动推断主应用程序类。如果没有明确的应用程序类,我们可以设置为 null

1.4 设置用于创建应用程序上下文的工厂

public void setApplicationContextFactory(ApplicationContextFactory applicationContextFactory) {this.applicationContextFactory = (applicationContextFactory != null) ? applicationContextFactory: ApplicationContextFactory.DEFAULT;
}

通过 SpringApplication 提供的 setApplicationContextFactory 方法,我们可以用于创建应用程序上下文的工厂。如果没有设置,默认为一个工厂【即 DefaultApplicationContextFactory】,该工厂将为 Servlet Web 应用程序 创建 AnnotationConfigServletWebServerApplicationContext,为响应式 Web 应用程序 创建 AnnotationConfigReactiveWebServerApplicationContext,并为 非 Web 应用程序 创建 AnnotationConfigApplicationContext

在这里插入图片描述

1.5 添加 BootstrapRegistry 初始化器实现

Huazie 的《BootstrapRegistryInitializer 详解》中,介绍了 加载和初始化 BootstrapRegistryInitializer 的逻辑,有需要的小伙伴可以去瞅一眼。

那除了默认的加载过程,还有啥办法手动添加 BootstrapRegistryInitializer 呢?

通过 SpringApplicationaddBootstrapRegistryInitializer 方法,我们可以在 bootstrapRegistryInitializers 中添加额外的 BootstrapRegistry 初始化器实现。

public void addBootstrapRegistryInitializer(BootstrapRegistryInitializer bootstrapRegistryInitializer) {Assert.notNull(bootstrapRegistryInitializer, "BootstrapRegistryInitializer must not be null");this.bootstrapRegistryInitializers.addAll(Arrays.asList(bootstrapRegistryInitializer));
}

1.6 设置或添加 ApplicationContext 初始化器实现

Huazie 的《ApplicationContextInitializer 详解》中,介绍了加载和初始化 ApplicationContextInitializer 的逻辑,大家可以自行去回顾下。

除了默认的加载过程,我们还可以通过 SpringApplication 自身进行设置或添加

通过 SpringApplicationsetInitializers 方法,我们可以重新设置 initializers【注意: 调用 setInitializers 方法后,该变量之前的赋值都将丢失】。

private List<ApplicationContextInitializer<?>> initializers;public void setInitializers(Collection<? extends ApplicationContextInitializer<?>> initializers) {this.initializers = new ArrayList<>(initializers);
}

通过 SpringApplicationaddInitializers 方法,我们可以在 initializers 中添加额外的 ApplicationContextInitializer 数组。

public void addInitializers(ApplicationContextInitializer<?>... initializers) {this.initializers.addAll(Arrays.asList(initializers));
}

1.7 设置 ApplicationListener 实现

Huazie 的《ApplicationListener 详解》中,我们详细分析了 ApplicationListener 的加载和处理应用程序事件的逻辑,有需要可以去回顾下。

那除了默认的加载流程,我们还可以通过 SpringApplicationsetListeners 方法,重新设置 listeners注意: 调用 setListeners 方法后,listeners 之前的赋值都将丢失】。

private List<ApplicationListener<?>> listeners;public void setListeners(Collection<? extends ApplicationListener<?>> listeners) {this.listeners = new ArrayList<>(listeners);
}

当然也可以通过 SpringApplicationaddListeners 方法,在 listeners 中添加额外的 ApplicationListener 数组。

public void addListeners(ApplicationListener<?>... listeners) {this.listeners.addAll(Arrays.asList(listeners));
}

1.8 设置要运行的Web应用程序的类型

Huazie 的《初识 SpringApplication》中,2.2 小节分析了 SpringApplication 构造函数中默认的 Web 应用类型推断的逻辑。

当然,我们也可以通过 SpringApplicationsetWebApplicationType 方法,手动设置要运行的 Web 应用程序的类型。

public void setWebApplicationType(WebApplicationType webApplicationType) {Assert.notNull(webApplicationType, "WebApplicationType must not be null");this.webApplicationType = webApplicationType;
}

1.9 设置 SpringApplication 中 各种 boolean 变量

1.9.1 setAllowBeanDefinitionOverriding 方法
public void setAllowBeanDefinitionOverriding(boolean allowBeanDefinitionOverriding) {this.allowBeanDefinitionOverriding = allowBeanDefinitionOverriding;
}

设置是否允许通过注册一个与现有定义具有相同名称的定义来覆盖 bean 定义。默认为 false

具体可见 DefaultListableBeanFactory#setAllowBeanDefinitionOverriding(boolean)

1.9.2 setAllowCircularReferences 方法
public void setAllowCircularReferences(boolean allowCircularReferences) {this.allowCircularReferences = allowCircularReferences;
}

设置是否允许 bean 之间的循环引用,并自动尝试解析它们。默认为 false

具体可见 AbstractAutowireCapableBeanFactory#setAllowCircularReferences(boolean)

1.9.3 setLazyInitialization 方法
public void setLazyInitialization(boolean lazyInitialization) {this.lazyInitialization = lazyInitialization;
}

设置是否应延迟初始化 beans。默认为 false

具体可见 BeanDefinition#setLazyInit(boolean)

1.9.4 setHeadless 方法
public void setHeadless(boolean headless) {this.headless = headless;
}

设置应用程序是否为无头模式,即是否不应实例化 AWT。默认为 true,以防止出现 Java 图标。

1.9.5 setRegisterShutdownHook 方法
public void setRegisterShutdownHook(boolean registerShutdownHook) {this.registerShutdownHook = registerShutdownHook;
}

设置是否应注册一个关闭钩子(shutdown hook)到创建的 ApplicationContext。默认为 true,以确保 JVM 关闭时能够优雅地处理。

1.9.6 setLogStartupInfo 方法
public void setLogStartupInfo(boolean logStartupInfo) {this.logStartupInfo = logStartupInfo;
}

设置在应用程序启动时是否应记录应用程序信息。默认为 true

1.9.7 setAddCommandLineProperties 方法
public void setAddCommandLineProperties(boolean addCommandLineProperties) {this.addCommandLineProperties = addCommandLineProperties;
}

设置是否应将 CommandLinePropertySource 添加到应用程序上下文中,以便暴露参数。默认为 true

1.9.8 setAddConversionService 方法
public void setAddConversionService(boolean addConversionService) {this.addConversionService = addConversionService;
}

设置是否应将 ApplicationConversionService 添加到应用程序上下文的环境中。

Spring Boot 中,ApplicationConversionService 是一个重要的类型转换服务,用于实现应用程序中的数据转换。它提供了一种将一种类型的数据转换为另一种类型数据的方法,使得在不同组件或服务之间能够进行数据交互和集成。

1.10 设置默认的环境属性

public void setDefaultProperties(Map<String, Object> defaultProperties) {this.defaultProperties = defaultProperties;
}public void setDefaultProperties(Properties defaultProperties) {this.defaultProperties = new HashMap<>();for (Object key : Collections.list(defaultProperties.propertyNames())) {this.defaultProperties.put((String) key, defaultProperties.get(key));}
}

上述方法用于设置默认的环境属性,这些属性将在现有环境属性的基础上进行添加。

1.11 设置要使用的额外的配置文件值

public void setAdditionalProfiles(String... profiles) {this.additionalProfiles = Collections.unmodifiableSet(new LinkedHashSet<>(Arrays.asList(profiles)));
}

该方法用于设置要使用的额外的配置文件值,这些值将在系统或命令行属性的基础上进行补充。

1.12 设置 bean 名称生成器

public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {this.beanNameGenerator = beanNameGenerator;
}

设置在生成 bean 名称时应该使用的 bean 名称生成器。

1.13 设置底层环境

public void setEnvironment(ConfigurableEnvironment environment) {this.isCustomEnvironment = true;this.environment = environment;
}

设置与创建的应用程序上下文一起使用的底层环境。

1.14 设置资源加载器

public void setResourceLoader(ResourceLoader resourceLoader) {Assert.notNull(resourceLoader, "ResourceLoader must not be null");this.resourceLoader = resourceLoader;
}

设置在加载资源时应使用的 ResourceLoader

1.15 设置环境配置属性前缀

public void setEnvironmentPrefix(String environmentPrefix) {this.environmentPrefix = environmentPrefix;
}

设置从系统环境中获取配置属性时应使用的前缀。

1.16 设置应用启动指标对象

public void setApplicationStartup(ApplicationStartup applicationStartup) {this.applicationStartup = (applicationStartup != null) ? applicationStartup : ApplicationStartup.DEFAULT;
}

设置用于收集启动指标的 ApplicationStartup。如果没有指定,则默认使用 DefaultApplicationStartup

2. 数据源配置

除了上述直接通过 setadd 方法来进行参数的配置,SpringApplication 中还提供了可以通过设置配置源参数对整个配置文件或配置类进行配置。

2.1 通过 SpringApplication 构造方法参数

在 Huazie 的《初识 SpringApplication》中的 2.1 小节就介绍了可以通过其构造参数 primarySources 来配置普通类或指定某个配置类,但这种方式有其局限性,它无法指定 XML 配置和基于 package 的配置。

2.2 通过 setSources 方法

先来看看相关的源码:

private Set<String> sources = new LinkedHashSet<>();public void setSources(Set<String> sources) {Assert.notNull(sources, "Sources must not be null");this.sources = new LinkedHashSet<>(sources);
}

该方法的参数为 String 类型的 Set 集合,可以传类名、package 名 和 XML 配置文件资源。

下面我们来演示一下:

  • 首先,我们在 application.properties 中添加如下配置:

    author=huazie
    
  • 然后,新增一个普通类 CustomConfiguration,如下:

    public class CustomConfiguration {@Value("${author}")private String author;public CustomConfiguration() {System.out.println("CustomConfiguration已被创建");}public String getAuthor() {return author;}public void setAuthor(String author) {this.author = author;}
    }
    
  • 接着,我们重新编写 DemoApplication 类,如下所示:

    @SpringBootApplication
    public class DemoApplication {public static void main(String[] args) {SpringApplication springApplication = new SpringApplication(DemoApplication.class);Set<String> sources = new HashSet<>();sources.add(CustomConfiguration.class.getName());springApplication.setSources(sources);ConfigurableApplicationContext context = springApplication.run(args);CustomConfiguration customConfiguration = context.getBean(CustomConfiguration.class);System.out.println(customConfiguration.getAuthor());}
    }
    
  • 最后,我们运行 DemoApplication 中的 main 方法,从如下截图中可以看出这里已经打印了自定义类的属性值:
    在这里插入图片描述

2.3 合并配置源信息

无论是通过构造参数,还是通过 setSources 方法,对配置源信息进行指定,在 Spring Boot 中都会将其合并。

这里我们就不得不提,SpringApplication 提供的 getAllSources 方法,

在这里插入图片描述

该方法将构造函数中指定的任何主要源 primarySources 与已显式设置的任何其他源 sources 组合在一起。

四、总结

23 年 7 月Huazie 正式开启了【Spring 源码学习】系列,一路下来也有 22 篇文章了。24 年该系列将继续更新下去,希望阅读和订阅多多益善!!!

这篇关于【Spring Boot 源码学习】SpringApplication 的定制化介绍的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/581913

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

性能测试介绍

性能测试是一种测试方法,旨在评估系统、应用程序或组件在现实场景中的性能表现和可靠性。它通常用于衡量系统在不同负载条件下的响应时间、吞吐量、资源利用率、稳定性和可扩展性等关键指标。 为什么要进行性能测试 通过性能测试,可以确定系统是否能够满足预期的性能要求,找出性能瓶颈和潜在的问题,并进行优化和调整。 发现性能瓶颈:性能测试可以帮助发现系统的性能瓶颈,即系统在高负载或高并发情况下可能出现的问题