大家好,我是小富~

从配置文件中获取属性应该是SpringBoot开发中最为常用的功能之一,但就是这么常用的功能,仍然有很多开发者在这个方面踩坑。

我整理了几种获取配置属性的方式,目的不仅是要让大家学会如何使用,更重要的是弄清配置加载、读取的底层原理,一旦出现问题可以分析出其症结所在,而不是一报错取不到属性,无头苍蝇般的重启项目,在句句卧槽中逐渐抓狂~

以下示例源码 Springboot 版本均为 2.7.6

下边我们一一过下这几种玩法和原理,看看有哪些是你没用过的!话不多说,开始搞~

一、Environment

使用 Environment 方式来获取配置属性值非常简单,只要注入Environment类调用其方法getProperty(属性key)即可,但知其然知其所以然,简单了解下它的原理,因为后续的几种获取配置的方法都和它息息相关。

  1. @Slf4j
  2. @SpringBootTest
  3. public class EnvironmentTest {
  4. @Resource
  5. private Environment env;
  6. @Test
  7. public void var1Test() {
  8. String var1 = env.getProperty("env101.var1");
  9. log.info("Environment 配置获取 {}", var1);
  10. }
  11. }

1、什么是 Environment?

Environment 是 springboot 核心的环境配置接口,它提供了简单的方法来访问应用程序属性,包括系统属性、操作系统环境变量、命令行参数、和应用程序配置文件中定义的属性等等。

2、配置初始化

Springboot 程序启动加载流程里,会执行SpringApplication.run中的prepareEnvironment()方法进行配置的初始化,那初始化过程每一步都做了什么呢?

  1. private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
  2. DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
  3. /**
  4. * 1、创建 ConfigurableEnvironment 对象:首先调用 getOrCreateEnvironment() 方法获取或创建
  5. * ConfigurableEnvironment 对象,该对象用于存储环境参数。如果已经存在 ConfigurableEnvironment 对象,则直接使用它;否则,根据用户的配置和默认配置创建一个新的。
  6. */
  7. ConfigurableEnvironment environment = getOrCreateEnvironment();
  8. /**
  9. * 2、解析并加载用户指定的配置文件,将其作为 PropertySource 添加到环境对象中。该方法默认会解析 application.properties 和 application.yml 文件,并将其添加到 ConfigurableEnvironment 对象中。
  10. * PropertySource 或 PropertySourcesPlaceholderConfigurer 加载应用程序的定制化配置。
  11. */
  12. configureEnvironment(environment, applicationArguments.getSourceArgs());
  13. // 3、加载所有的系统属性,并将它们添加到 ConfigurableEnvironment 对象中
  14. ConfigurationPropertySources.attach(environment);
  15. // 4、通知监听器环境参数已经准备就绪
  16. listeners.environmentPrepared(bootstrapContext, environment);
  17. /**
  18. * 5、将默认的属性源中的所有属性值移到环境对象的队列末尾,
  19. 这样用户自定义的属性值就可以覆盖默认的属性值。这是为了避免用户无意中覆盖了 Spring Boot 所提供的默认属性。
  20. */
  21. DefaultPropertiesPropertySource.moveToEnd(environment);
  22. Assert.state(!environment.containsProperty("spring.main.environment-prefix"),
  23. "Environment prefix cannot be set via properties.");
  24. // 6、将 Spring Boot 应用程序的属性绑定到环境对象上,以便能够正确地读取和使用这些配置属性
  25. bindToSpringApplication(environment);
  26. // 7、如果没有自定义的环境类型,则使用 EnvironmentConverter 类型将环境对象转换为标准的环境类型,并添加到 ConfigurableEnvironment 对象中。
  27. if (!this.isCustomEnvironment) {
  28. EnvironmentConverter environmentConverter = new EnvironmentConverter(getClassLoader());
  29. environment = environmentConverter.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
  30. }
  31. // 8、再次加载系统配置,以防止被其他配置覆盖
  32. ConfigurationPropertySources.attach(environment);
  33. return environment;
  34. }

看看它的配置加载流程步骤:

  • 创建 环境对象 ConfigurableEnvironment 用于存储环境参数;
  • configureEnvironment 方法加载默认的 application.propertiesapplication.yml 配置文件;以及用户指定的配置文件,将其封装为 PropertySource 添加到环境对象中;
  • attach(): 加载所有的系统属性,并将它们添加到环境对象中;
  • listeners.environmentPrepared(): 发送环境参数配置已经准备就绪的监听通知;
  • moveToEnd(): 将 系统默认 的属性源中的所有属性值移到环境对象的队列末尾,这样用户自定义的属性值就可以覆盖默认的属性值。
  • bindToSpringApplication: 应用程序的属性绑定到 Bean 对象上;
  • attach(): 再次加载系统配置,以防止被其他配置覆盖;

上边的配置加载流程中,各种配置属性会封装成一个个抽象的数据结构 PropertySource中,这个数据结构代码格式如下,key-value形式。


  1. public abstract class PropertySource<T> {
  2. protected final String name; // 属性源名称
  3. protected final T source; // 属性源值(一个泛型,比如Map,Property)
  4. public String getName(); // 获取属性源的名字
  5. public T getSource(); // 获取属性源值
  6. public boolean containsProperty(String name); //是否包含某个属性
  7. public abstract Object getProperty(String name); //得到属性名对应的属性值
  8. }

PropertySource 有诸多的实现类用于管理应用程序的配置属性。不同的 PropertySource 实现类可以从不同的来源获取配置属性,例如文件、环境变量、命令行参数等。其中涉及到的一些实现类有:

  • MapPropertySource: Map 键值对的对象转换为 PropertySource 对象的适配器;
  • PropertiesPropertySource: Properties 对象中的所有配置属性转换为 Spring 环境中的属性值;
  • ResourcePropertySource: 从文件系统或者 classpath 中加载配置属性,封装成 PropertySource对象;
  • ServletConfigPropertySource: Servlet 配置中读取配置属性,封装成 PropertySource 对象;
  • ServletContextPropertySource: Servlet 上下文中读取配置属性,封装成 PropertySource 对象;
  • StubPropertySource: 是个空的实现类,它的作用仅仅是给 CompositePropertySource 类作为默认的父级属性源,以避免空指针异常;
  • CompositePropertySource: 是个复合型的实现类,内部维护了 PropertySource集合队列,可以将多个 PropertySource 对象合并;
  • SystemEnvironmentPropertySource: 操作系统环境变量中读取配置属性,封装成 PropertySource 对象;

上边各类配置初始化生成的 PropertySource 对象会被维护到集合队列中。

  1. List<PropertySource<?>> sources = new ArrayList<PropertySource<?>>()

配置初始化完毕,应用程序上下文AbstractApplicationContext会加载配置,这样程序在运行时就可以随时获取配置信息了。

  1. private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
  2. ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
  3. ApplicationArguments applicationArguments, Banner printedBanner) {
  4. // 应用上下文加载环境对象
  5. context.setEnvironment(environment);
  6. postProcessApplicationContext(context);
  7. .........
  8. }

3、读取配置

看明白上边配置加载的流程,其实读取配置就容易理解了,无非就是遍历队列里的PropertySource,拿属性名称name匹配对应的属性值source

PropertyResolver是获取配置的关键类,其内部提供了操作PropertySource 队列的方法,核心方法getProperty(key)获取配置值,看了下这个类的依赖关系,发现 Environment 是它子类。

那么直接用 PropertyResolver 来获取配置属性其实也是可以的,到这我们就大致明白了 Springboot 配置的加载和读取了。

  1. @Slf4j
  2. @SpringBootTest
  3. public class EnvironmentTest {
  4. @Resource
  5. private PropertyResolver env;
  6. @Test
  7. public void var1Test() {
  8. String var1 = env.getProperty("env101.var1");
  9. log.info("Environment 配置获取 {}", var1);
  10. }
  11. }

二、@Value 注解

@Value注解是Spring框架提供的用于注入配置属性值的注解,它可用于类的成员变量方法参数构造函数参数上,这个记住很重要!

在应用程序启动时,使用 @Value 注解的 Bean 会被实例化。所有使用了 @Value 注解的 Bean 会被加入到 PropertySourcesPlaceholderConfigurer 的后置处理器集合中。

当后置处理器开始执行时,它会读取 Bean 中所有 @Value 注解所标注的值,并通过反射将解析后的属性值赋值给标有 @Value 注解的成员变量、方法参数和构造函数参数。

需要注意,在使用 @Value 注解时需要确保注入的属性值已经加载到 Spring 容器中,否则会导致注入失败。

如何使用

src/main/resources目录下的application.yml配置文件中添加env101.var1属性。

  1. env101:
  2. var1: var1-公众号:程序员小富

只要在变量上加注解 @Value("${env101.var1}")就可以了,@Value 注解会自动将配置文件中的env101.var1属性值注入到var1字段中,跑个单元测试看一下结果。

  1. @Slf4j
  2. @SpringBootTest
  3. public class EnvVariablesTest {
  4. @Value("${env101.var1}")
  5. private String var1;
  6. @Test
  7. public void var1Test(){
  8. log.info("配置文件属性: {}",var1);
  9. }
  10. }

毫无悬念,成功拿到配置数据。

虽然@Value注解方式使用起来很简单,如果使用不当还会遇到不少坑。

1、缺失配置

如果在代码中引用变量,配置文件中未进行配值,就会出现类似下图所示的错误。

为了避免此类错误导致服务启动异常,我们可以在引用变量的同时给它赋一个默认值,以确保即使在未正确配值的情况下,程序依然能够正常运行。

  1. @Value("${env101.var1:我是小富}")
  2. private String var1;

2、静态变量(static)赋值

还有一种常见的使用误区,就是将 @Value 注解加到静态变量上,这样做是无法获取属性值的。静态变量是类的属性,并不属于对象的属性,而 Spring是基于对象的属性进行依赖注入的,类在应用启动时静态变量就被初始化,此时 Bean还未被实例化,因此不可能通过 @Value 注入属性值。

  1. @Slf4j
  2. @SpringBootTest
  3. public class EnvVariablesTest {
  4. @Value("${env101.var1}")
  5. private static String var1;
  6. @Test
  7. public void var1Test(){
  8. log.info("配置文件属性: {}",var1);
  9. }
  10. }

即使 @Value 注解无法直接用在静态变量上,我们仍然可以通过获取已有 Bean实例化后的属性值,再将其赋值给静态变量来实现给静态变量赋值。

我们可以先通过 @Value 注解将属性值注入到普通 Bean中,然后在获取该 Bean对应的属性值,并将其赋值给静态变量。这样,就可以在静态变量中使用该属性值了。

  1. @Slf4j
  2. @SpringBootTest
  3. public class EnvVariablesTest {
  4. private static String var3;
  5. private static String var4;
  6. @Value("${env101.var3}")
  7. public void setVar3(String var3) {
  8. var3 = var3;
  9. }
  10. EnvVariablesTest(@Value("${env101.var4}") String var4){
  11. var4 = var4;
  12. }
  13. public static String getVar4() {
  14. return var4;
  15. }
  16. public static String getVar3() {
  17. return var3;
  18. }
  19. }

3、常量(final)赋值

@Value 注解加到final关键字上同样也无法获取属性值,因为 final 变量必须在构造方法中进行初始化,并且一旦被赋值便不能再次更改。而 @Value 注解是在 bean 实例化之后才进行属性注入的,因此无法在构造方法中初始化 final 变量。

  1. @Slf4j
  2. @SpringBootTest
  3. public class EnvVariables2Test {
  4. private final String var6;
  5. @Autowired
  6. EnvVariables2Test( @Value("${env101.var6}") String var6) {
  7. this.var6 = var6;
  8. }
  9. /**
  10. * @value注解 final 获取
  11. */
  12. @Test
  13. public void var1Test() {
  14. log.info("final 注入: {}", var6);
  15. }
  16. }

4、非注册的类中使用

只有标注了@Component@Service@Controller@Repository@Configuration容器管理注解的类,由 Spring 管理的 bean 中使用 @Value注解才会生效。而对于普通的POJO类,则无法使用 @Value注解进行属性注入。

  1. /**
  2. * @value注解 非注册的类中使用
  3. * `@Component`、`@Service`、`@Controller`、`@Repository` 或 `@Configuration` 等
  4. * 容器管理注解的类中使用 @Value注解才会生效
  5. */
  6. @Data
  7. @Slf4j
  8. @Component
  9. public class TestService {
  10. @Value("${env101.var7}")
  11. private String var7;
  12. public String getVar7(){
  13. return this.var7;
  14. }
  15. }

5、引用方式不对

如果我们想要获取 TestService 类中的某个变量的属性值,需要使用依赖注入的方式,而不能使用 new 的方式。通过依赖注入的方式创建 TestService 对象,Spring 会在创建对象时将对象所需的属性值注入到其中。


  1. /**
  2. * @value注解 引用方式不对
  3. */
  4. @Test
  5. public void var7_1Test() {
  6. TestService testService = new TestService();
  7. log.info("引用方式不对 注入: {}", testService.getVar7());
  8. }

最后总结一下 @Value注解要在 Bean的生命周期内使用才能生效。

三、@ConfigurationProperties 注解

@ConfigurationProperties注解是 SpringBoot 提供的一种更加便捷来处理配置文件中的属性值的方式,可以通过自动绑定和类型转换等机制,将指定前缀的属性集合自动绑定到一个Bean对象上。

加载原理

在 Springboot 启动流程加载配置的 prepareEnvironment() 方法中,有一个重要的步骤方法 bindToSpringApplication(environment),它的作用是将配置文件中的属性值绑定到被 @ConfigurationProperties 注解标记的 Bean对象中。但此时这些对象还没有被 Spring 容器管理,因此无法完成属性的自动注入。

那么这些Bean对象又是什么时候被注册到 Spring 容器中的呢?

这就涉及到了 ConfigurationPropertiesBindingPostProcessor 类,它是 Bean后置处理器,负责扫描容器中所有被 @ConfigurationProperties 注解所标记的 Bean对象。如果找到了,则会使用 Binder 组件将外部属性的值绑定到它们身上,从而实现自动注入。

  • bindToSpringApplication 主要是将属性值绑定到 Bean 对象中;
  • ConfigurationPropertiesBindingPostProcessor 负责在 Spring 容器启动时将被注解标记的 Bean 对象注册到容器中,并完成后续的属性注入操作;

如何使用

演示使用 @ConfigurationProperties 注解,在 application.yml 配置文件中添加配置项:

  1. env101:
  2. var1: var1-公众号:程序员小富
  3. var2: var2-公众号:程序员小富

创建一个 MyConf 类用于承载所有前缀为env101的配置属性。

  1. @Data
  2. @Configuration
  3. @ConfigurationProperties(prefix = "env101")
  4. public class MyConf {
  5. private String var1;
  6. private String var2;
  7. }

在需要使用var1var2属性值的地方,将 MyConf 对象注入到依赖对象中即可。

  1. @Slf4j
  2. @SpringBootTest
  3. public class ConfTest {
  4. @Resource
  5. private MyConf myConf;
  6. @Test
  7. public void myConfTest() {
  8. log.info("@ConfigurationProperties注解 配置获取 {}", JSON.toJSONString(myConf));
  9. }
  10. }

四、@PropertySources 注解

除了系统默认的 application.yml 或者 application.properties 文件外,我们还可能需要使用自定义的配置文件来实现更加灵活和个性化的配置。与默认的配置文件不同的是,自定义的配置文件无法被应用自动加载,需要我们手动指定加载。

@PropertySources 注解的实现原理相对简单,应用程序启动时扫描所有被该注解标注的类,获取到注解中指定自定义配置文件的路径,将指定路径下的配置文件内容加载到 Environment 中,这样可以通过 @Value 注解或 Environment.getProperty() 方法来获取其中定义的属性值了。

如何使用

在 src/main/resources/ 目录下创建自定义配置文件 xiaofu.properties,增加两个属性。

  1. env101.var9=var9-程序员小富
  2. env101.var10=var10-程序员小富

在需要使用自定义配置文件的类上添加 @PropertySources 注解,注解 value属性中指定自定义配置文件的路径,可以指定多个路径,用逗号隔开。

  1. @Data
  2. @Configuration
  3. @PropertySources({
  4. @PropertySource(value = "classpath:xiaofu.properties",encoding = "utf-8"),
  5. @PropertySource(value = "classpath:xiaofu.properties",encoding = "utf-8")
  6. })
  7. public class PropertySourcesConf {
  8. @Value("${env101.var10}")
  9. private String var10;
  10. @Value("${env101.var9}")
  11. private String var9;
  12. }

成功获取配置了

但是当我试图加载.yaml文件时,启动项目居然报错了,经过一番摸索我发现,@PropertySources 注解只内置了PropertySourceFactory适配器。也就是说它只能加载.properties文件。

那如果我想要加载一个.yaml类型文件,则需要自行实现yaml的适配器 YamlPropertySourceFactory

  1. public class YamlPropertySourceFactory implements PropertySourceFactory {
  2. @Override
  3. public PropertySource<?> createPropertySource(String name, EncodedResource encodedResource) throws IOException {
  4. YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
  5. factory.setResources(encodedResource.getResource());
  6. Properties properties = factory.getObject();
  7. return new PropertiesPropertySource(encodedResource.getResource().getFilename(), properties);
  8. }
  9. }

而在加载配置时要显示的指定使用 YamlPropertySourceFactory适配器,这样就完成了@PropertySource注解加载 yaml 文件。

  1. @Data
  2. @Configuration
  3. @PropertySources({
  4. @PropertySource(value = "classpath:xiaofu.yaml", encoding = "utf-8", factory = YamlPropertySourceFactory.class)
  5. })
  6. public class PropertySourcesConf2 {
  7. @Value("${env101.var10}")
  8. private String var10;
  9. @Value("${env101.var9}")
  10. private String var9;
  11. }

五、YamlPropertiesFactoryBean 加载 YAML 文件

我们可以使用 YamlPropertiesFactoryBean 类将 YAML 配置文件中的属性值注入到 Bean 中。

  1. @Configuration
  2. public class MyYamlConfig {
  3. @Bean
  4. public static PropertySourcesPlaceholderConfigurer yamlConfigurer() {
  5. PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
  6. YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
  7. yaml.setResources(new ClassPathResource("xiaofu.yml"));
  8. configurer.setProperties(Objects.requireNonNull(yaml.getObject()));
  9. return configurer;
  10. }
  11. }

可以通过 @Value 注解或 Environment.getProperty() 方法来获取其中定义的属性值。

  1. @Slf4j
  2. @SpringBootTest
  3. public class YamlTest {
  4. @Value("${env101.var11}")
  5. private String var11;
  6. @Test
  7. public void myYamlTest() {
  8. log.info("Yaml 配置获取 {}", var11);
  9. }
  10. }

六、自定义读取

如果上边的几种读取配置的方式你都不喜欢,就想自己写个更流批的轮子,那也很好办。我们直接注入PropertySources获取所有属性的配置队列,你是想用注解实现还是其他什么方式,就可以为所欲为了。

  1. @Slf4j
  2. @SpringBootTest
  3. public class CustomTest {
  4. @Autowired
  5. private PropertySources propertySources;
  6. @Test
  7. public void customTest() {
  8. for (PropertySource<?> propertySource : propertySources) {
  9. log.info("自定义获取 配置获取 name {} ,{}", propertySource.getName(), propertySource.getSource());
  10. }
  11. }
  12. }

总结

我们可以通过 @Value 注解、Environment 类、@ConfigurationProperties 注解、@PropertySource 注解等方式来获取配置信息。

其中,@Value 注解适用于单个值的注入,而其他几种方式适用于批量配置的注入。不同的方式在效率、灵活性、易用性等方面存在差异,在选择配置获取方式时,还需要考虑个人编程习惯和业务需求。

如果重视代码的可读性和可维护性,则可以选择使用 @ConfigurationProperties 注解;如果更注重运行效率,则可以选择使用 Environment 类。总之,不同的场景需要选择不同的方式,以达到最优的效果。

我是小富,下期见~

以上案例地址:https://github.com/chengxy-nds/Springboot-Notebook

6 种方式读取 Springboot 的配置,老鸟都这么玩(原理+实战)的更多相关文章

  1. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件

    精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件 内容简介:本文介绍 Spring Boot 的配置文件和配置管理,以及介绍了三种读取配置文 ...

  2. 将图片base64格式转换为file对象并读取(两种方式读取)

    两种方式读取,一种URL.createObjectURL,另一种fileReader   var base64 = ` data:image/jpeg;base64,/9j/4AAQSkZJRgABA ...

  3. 6.redis 的持久化有哪几种方式?不同的持久化机制都有什么优缺点?持久化机制具体底层是如何实现的?

    作者:中华石杉 面试题 redis 的持久化有哪几种方式?不同的持久化机制都有什么优缺点?持久化机制具体底层是如何实现的? 面试官心理分析 redis 如果仅仅只是将数据缓存在内存里面,如果 redi ...

  4. 第二种方式读取并显示HDFS中的内容

    1.讀取HDFS内容的java客戶端代碼: package Hdfs; import java.io.InputStream; import java.net.URI; import org.apac ...

  5. @Autowired注解和启动自动扫描的三种方式(spring bean配置自动扫描功能的三种方式)

    前言: @Autowired注解代码定义 @Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD, Elemen ...

  6. 引入springboot的两种方式以及springboot容器的引入

    一.在项目中引入springboot有两种方式: 1.引入spring-boot-starter-parent 要覆盖parent自带的jar的版本号有两种方式: (1)在pom中重新引入这个jar, ...

  7. 在.NET Core中用最原生的方式读取Nacos的配置

    背景 之前老黄写过一篇<ASP.NET Core结合Nacos来完成配置管理和服务发现>简单介绍了如何让.NET Core程序接入Nacos,之前的SDK里面更多的是对Nacos的Open ...

  8. 用类加载器的5种方式读取.properties文件

    用类加载器的5中形式读取.properties文件(这个.properties文件一般放在src的下面) 用类加载器进行读取:这里采取先向大家讲读取类加载器的几种方法:然后写一个例子把几种方法融进去, ...

  9. java 4种方式读取配置文件 + 修改配置文件

    版权声明:本文为博主原创文章,未经博主允许不得转载.   目录(?)[-] 方式一采用ServletContext读取读取配置文件的realpath然后通过文件流读取出来 方式二采用ResourceB ...

  10. 比较Class.getResource与Class.getClassLoader().getResource两种方式读取资源文件

    /** * @author zhangboqing * @date 2018/7/10 */ public class FileDemo { public static void main(Strin ...

随机推荐

  1. ChatGPT与码农的机会

    之前一篇博客已经写了有关AI在博客编写方面的优势与对未来博客的编写方面的思考.这篇文档我继续分享一个我在开发中的一个案例和相关的感想. 事件还原 我发现ChatGPT也可以帮助我编写OData,于是我 ...

  2. 线性规划的单纯形法—R实现

    table { margin: auto } 线性规划的单纯形法 线性规划是运筹学中的一个基本分支,它广泛应用现有的科学技术和数学方法,解决实际中的问题,帮助决策人员选择最优方针和决策,自1947年丹 ...

  3. python进程之进程池、线程池与异步回调机制

    进程线程不可以无限制的创建,因为有硬件的限制.为了避免资源被程序消耗过度,可以使用进程池或线程池的技术. 池     降低程序的执行效率,但是保证了计算机硬件的安全 进程池     提前创建好固定数量 ...

  4. [Linux]CentOS7(LiveGnome版)配置网络

    话接上一回合,刚通过U盘启动盘安装CentOS7(LiveGnome)完成后,访问不了网络.肿么办?且听咱慢慢道来. 咱平时都是使用(有线网络)网卡,通过公司分配的固定IP地址(包括:固定主机IP.固 ...

  5. ChatGPT4实现前一天

    目录 提出需求 代码实现 需求分析 单元测试 等价类划分 决策表 软件测试作业,用ChatGPT4来帮个小忙,小划水,勿喷勿喷,近期有相关作业的同学看到我的文章,建议修改一下,别撞车了,哈哈哈~ 提出 ...

  6. Docker Go语言程序的编译与打包

    使用Docker打包Go程序的镜像 Golang镜像 首先使用docker pull获取golang镜像 $ sudo docker pull golang:1.18.3 查看镜像: $ sudo d ...

  7. json解析异常显示

    解决方案 1.取消FastJson的循环引用的检查:JSONObject.toJSONString(guardVoList,SerializerFeature.DisableCircularRefer ...

  8. JS中的Map、Set、WeakMap和WeakSet

    在JavaScript中,Map.Set.WeakMap和WeakSet是四个不同的数据结构,它们都有不同的特点和用途: 1. Map :Map是一种键值对的集合,其中的键和值可以是任意类型的.与对象 ...

  9. RTSP Server(LIVE555)源码分析(二)-服务器创建

    一. 设置RTSP服务器配置 步骤1.5:rtspServer_Init--->BasicTaskScheduler::createNew()时序图如下: 1)步骤1.54,BasicTaskS ...

  10. 一站式统一返回值封装、异常处理、异常错误码解决方案—最强的Sping Boot接口优雅响应处理器

    作者:京东物流 覃玉杰 1. 简介 Graceful Response是一个Spring Boot体系下的优雅响应处理器,提供一站式统一返回值封装.异常处理.异常错误码等功能. 使用Graceful ...