【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

相关文章

Java图片压缩三种高效压缩方案详细解析

《Java图片压缩三种高效压缩方案详细解析》图片压缩通常涉及减少图片的尺寸缩放、调整图片的质量(针对JPEG、PNG等)、使用特定的算法来减少图片的数据量等,:本文主要介绍Java图片压缩三种高效... 目录一、基于OpenCV的智能尺寸压缩技术亮点:适用场景:二、JPEG质量参数压缩关键技术:压缩效果对比

Java调用C++动态库超详细步骤讲解(附源码)

《Java调用C++动态库超详细步骤讲解(附源码)》C语言因其高效和接近硬件的特性,时常会被用在性能要求较高或者需要直接操作硬件的场合,:本文主要介绍Java调用C++动态库的相关资料,文中通过代... 目录一、直接调用C++库第一步:动态库生成(vs2017+qt5.12.10)第二步:Java调用C++

springboot+dubbo实现时间轮算法

《springboot+dubbo实现时间轮算法》时间轮是一种高效利用线程资源进行批量化调度的算法,本文主要介绍了springboot+dubbo实现时间轮算法,文中通过示例代码介绍的非常详细,对大家... 目录前言一、参数说明二、具体实现1、HashedwheelTimer2、createWheel3、n

Java利用docx4j+Freemarker生成word文档

《Java利用docx4j+Freemarker生成word文档》这篇文章主要为大家详细介绍了Java如何利用docx4j+Freemarker生成word文档,文中的示例代码讲解详细,感兴趣的小伙伴... 目录技术方案maven依赖创建模板文件实现代码技术方案Java 1.8 + docx4j + Fr

SpringBoot首笔交易慢问题排查与优化方案

《SpringBoot首笔交易慢问题排查与优化方案》在我们的微服务项目中,遇到这样的问题:应用启动后,第一笔交易响应耗时高达4、5秒,而后续请求均能在毫秒级完成,这不仅触发监控告警,也极大影响了用户体... 目录问题背景排查步骤1. 日志分析2. 性能工具定位优化方案:提前预热各种资源1. Flowable

基于SpringBoot+Mybatis实现Mysql分表

《基于SpringBoot+Mybatis实现Mysql分表》这篇文章主要为大家详细介绍了基于SpringBoot+Mybatis实现Mysql分表的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可... 目录基本思路定义注解创建ThreadLocal创建拦截器业务处理基本思路1.根据创建时间字段按年进

Java编译生成多个.class文件的原理和作用

《Java编译生成多个.class文件的原理和作用》作为一名经验丰富的开发者,在Java项目中执行编译后,可能会发现一个.java源文件有时会产生多个.class文件,从技术实现层面详细剖析这一现象... 目录一、内部类机制与.class文件生成成员内部类(常规内部类)局部内部类(方法内部类)匿名内部类二、

SpringBoot实现数据库读写分离的3种方法小结

《SpringBoot实现数据库读写分离的3种方法小结》为了提高系统的读写性能和可用性,读写分离是一种经典的数据库架构模式,在SpringBoot应用中,有多种方式可以实现数据库读写分离,本文将介绍三... 目录一、数据库读写分离概述二、方案一:基于AbstractRoutingDataSource实现动态

Springboot @Autowired和@Resource的区别解析

《Springboot@Autowired和@Resource的区别解析》@Resource是JDK提供的注解,只是Spring在实现上提供了这个注解的功能支持,本文给大家介绍Springboot@... 目录【一】定义【1】@Autowired【2】@Resource【二】区别【1】包含的属性不同【2】@

springboot循环依赖问题案例代码及解决办法

《springboot循环依赖问题案例代码及解决办法》在SpringBoot中,如果两个或多个Bean之间存在循环依赖(即BeanA依赖BeanB,而BeanB又依赖BeanA),会导致Spring的... 目录1. 什么是循环依赖?2. 循环依赖的场景案例3. 解决循环依赖的常见方法方法 1:使用 @La