关于后端:quarkus实战之七使用配置

56次阅读

共计 8853 个字符,预计需要花费 23 分钟才能阅读完成。

欢送拜访我的 GitHub

这里分类和汇总了欣宸的全副原创 (含配套源码):https://github.com/zq2599/blog_demos

本篇概览

  • 本文是《quarkus 实战》系列的第七篇,前文讲述了如何在将配置信息传入 quarkus 利用,明天要练习的是如何应用这些配置信息
  • 整篇文章由以下内容形成:
  • 创立工程,作为演示应用配置项操作的代码
  • 演示最根本的应用配置项操作
  • 展现配置项不存时会导致什么问题
  • 演示如何设置默认值,这样配置项不存在也不会出错
  • 默认值是字符串,而理论的变量能够是多种类型,它们之间的关系
  • Optional 类型的配置注入
  • 不必注解注入,也能够写代码获取配置
  • 针对雷同前缀的配置项,应用配置接口简化代码
  • 应用配置接口嵌套,简化多级的雷同前缀配置项
  • 用 map 承受配置信息(缩小配置项相干代码量)
  • quarkus 及其扩大组件的内置配置项
  • 接下来从创立 demo 工程开始吧

    演示代码

  • 创立一个 demo 工程,参考上面的命令,这样的工程会自带一个 web 服务类 HobbyResource.java

    mvn "io.quarkus:quarkus-maven-plugin:create" \
    -DprojectGroupId="com.bolingcavalry" \
    -DprojectArtifactId="hello-quarkus" \
    -DprojectVersion="1.0-SNAPSHOT" \
    -DclassName="HobbyResource" \
    -Dpath="actions"

    最根本的配置

  • 先来看看最罕用最根本的配置文件应用形式
  • 关上文件 <font color=”blue”>src/main/resources/application.properties</font>,减少上面这行配置

    greeting.message = hello from application.properties
  • 关上 HobbyResource.java,减少如下成员变量,应用了注解 ConfigProperty

    @ConfigProperty(name = "greeting.message") 
    String message;
  • 以上就是最简略的应用配置项的形式,程序运行后,application.properties 中 greeting.message 的值就会被 quarkus 框架注入到 message 成员变量中

    配置项不存在导致的异样

  • 如果 ConfigProperty 注解的配置项在配置文件中不存在,利用启动会报错,来看看是什么谬误
  • 将 HobbyResource.java 的代码改成上面这样,成员变量 notExistsConfig 的配置项是 <font color=”blue”>not.exists.config</font>,这个配置项在配置文件中并不存在

    @Path("/actions")
    public class HobbyResource {
    
      // 配置文件中不存在名为 not.exists.config 的配置项
      @ConfigProperty(name = "not.exists.config")
      String notExistsConfig;
    
      @GET
      @Produces(MediaType.TEXT_PLAIN)
      public String hello() {return "Hello RESTEasy," + LocalDateTime.now() + ", [" + notExistsConfig + "]";
      }
    }
  • 启动利用时报错如下图所示,红框中提醒加载配置项失败

    带默认值的配置

  • 对于下面演示的配置项不存在导致启动失败问题,能够给 ConfigProperty 注解设置默认值,这样一旦找不到配置项,就应用默认值注入,能够防止启动失败了
  • HobbyResource.java 的源码如下,成员变量 notExistsConfig 的注解了减少属性 <font color=”red”>defaultValue</font>

    @Path("/actions")
    public class HobbyResource {
    
      // 配置文件中不存在名为 not.exists.config 的配置项
      @ConfigProperty(name = "not.exists.config", defaultValue = "112233")
      String notExistsConfig;
    
      @GET
      @Produces(MediaType.TEXT_PLAIN)
      public String hello() {return "Hello RESTEasy," + LocalDateTime.now() + ", [" + notExistsConfig + "]";
      }
    }
  • 再次启动利用,这次不报错了,浏览器拜访后果如下图,defaultValue 曾经失效

    defaultValue 属性的主动转换

  • 对于 ConfigProperty 注解的 defaultValue 属性还有一点要留神,来看 ConfigProperty 的源码,如下图,红框显示 defaultValue 的类型是 String
  • 上图中,defaultValue 的正文有阐明:如果 ConfigProperty 注解润饰的变量并非 String 型,那么 defaultValue 的字符串就会被主动 quarkus 字符转换
  • 例如润饰的变量是 int 型,那么 defaultValue 的 String 类型的值会被转为 int 型再赋给变量,如下所示,notExistsConfig 是 int 型,defaultValue 的字符串能够被转为 int:

    // 配置文件中不存在名为 not.exists.config 的配置项
    @ConfigProperty(name = "not.exists.config", defaultValue = "123")
    int notExistsConfig;
  • 如果把下面代码中的 defaultValue 的值从 <font color=”blue”>123</font> 改为 <font color=”red”>xxx</font>,此时利用启动就会失败,因为“xxx”转为 int 的过程中抛出了异样,如下图:
  • 除了上面试过的 int,还有很多种类型都反对从 defaultValue 的字符串值被主动转换,它们是:
  • 根底类型:如 boolean, byte, short
  • 装箱类型:如 java.lang.Boolean, java.lang.Byte, java.lang.Short
  • Optional 类型:java.util.Optional, java.util.OptionalInt, java.util.OptionalLong, and java.util.OptionalDouble
  • java 枚举
  • java.time.Duration
  • JDK 网络对象:如 java.net.SocketAddress, java.net.InetAddress
  • 例如,上面是字符串主动转 InetAddress 的例子,能够失常运行:

    @ConfigProperty(name = "server.address", defaultValue = "192.168.1.1")
    InetAddress serverAddress;
  • 如果 ConfigProperty 润饰的变量是 boolean 型,或者 Boolean 型,则 defaultValue 值的主动转换逻辑有些特地:“true”, “1”, “YES”, “Y” “ON” 这些都会被转为 true(而且不辨别大小写,”on” 也被转为 true),其余值会被转为 false
  • 还有一处要留神的:defaultValue 的值如果是空字符串,就相当于没有设置 defaultValue,此时如果在配置文件中没有该配置项,启动利用会报错

    反对 Optional

  • 反对 Optional 这个个性很赞,首先 Optional 类型的成员变量可间接用于函数式编程,其次配置项不存在时又能防止启动失败
  • 接下来试试用 ConfigProperty 注解润饰 Optional 类型的成员变量
  • HobbyResource.java 的源码如下,<font color=”blue”>optionalMessage</font> 是 Optional 类型的成员变量,配置项 <font color=”red”>optional.message</font> 就算不存在,利用也能失常启动,并且 optionalMessage 间接用于函数式编程中(optionalMessage.ifPresent)

    @Path("/actions")
    public class HobbyResource {
    
      // 配置文件中存在名为 greeting.message 的配置项
      @ConfigProperty(name = "greeting.message")
      String message;
    
      // 配置文件中,不管是否存在名为 optional.message 的配置项,利用都不会抛出异样
      @ConfigProperty(name = "optional.message")
      Optional<String> optionalMessage;
    
      @GET
      @Produces(MediaType.TEXT_PLAIN)
      public String hello() {List<String> list = new ArrayList<>();
          list.add(message);
    
          // 只有配置项 optional.message 存在的时候,才会执行 list.add 办法
          optionalMessage.ifPresent(list::add);
    
          return "Hello RESTEasy," + LocalDateTime.now() + "," + list;}
    }
  • 先看配置项 optional.message 存在的状况,如下图红框所示,optional.message 在配置文件中是个失常的配置项
  • 启动利用,浏览器拜访 web 接口,如下图,<font color=”blue”>optional info</font> 是配置项 optional.message 的值
  • 当初将 <font color=”blue”>optional info</font> 从文件 <font color=”red”>application.properties</font> 中删除,重启利用,再次拜访浏览器,如下图,利用仍然失常响应,list 中只有成员变量 message 的内容:

    编码获取配置项

  • 除了用 ConfigProperty 注解来获取配置项的值,还能够用写代码的形式获取
  • 上面的代码展现了通过 API 获取配置项的操作,请留神代码中的正文

    @Path("/actions")
    public class HobbyResource {
    
      @GET
      @Produces(MediaType.TEXT_PLAIN)
      public String hello() {List<String> list = new ArrayList<>();
    
          // 能够用静态方法获得 Config 实例
          Config config = ConfigProvider.getConfig();
    
          // getValue 可获得指定配置项的指定类型值
          String greet = config.getValue("greeting.message", String.class);
    
          list.add(greet);
    
          // getOptionalValue 能够将配置项的值包状为 Optional 对象,如果配置项不存在,也不会报错
          Optional<String> optional = config.getOptionalValue("not.exists.config", String.class);
    
          // 函数式编程:只用 optional 中有对象时,才会执行 list.add 办法
          optional.ifPresent(list::add);
    
          return "Hello RESTEasy," + LocalDateTime.now() + "," + list;}
    }
  • 当配置项 not.exists.config 不存在时,页面响应如下,只有 greeting.message 配置项的值:
  • 配置项 not.exists.config=123456 时,页面响应如下,两个配置项的值都能胜利获取:
  • 另外,官网倡议不要应用 <font color=”blue”>System.getProperty(String) </font> 和 <font color=”blue”> System.getEnv(String)</font> 去获取配置项了,它们并非 quarkus 的 API,因而 quarkus 配置相干的性能与它们并无关系(例如感知配置变动、主动转换类型等)

    配置接口

  • 假如配置项如下,都是雷同的前缀 <font color=”blue”>student</font>
student.name=Tom
student.age=11
student.description=He is a good boy
  • 针对上述配置项,能够用注解 <font color=”red”>ConfigMapping</font> 将这些它们集中在一个接口类中获取,接口类 StudentConfiguration.java 如下
package com.bolingcavalry;

import io.smallrye.config.ConfigMapping;
import io.smallrye.config.WithDefault;
import io.smallrye.config.WithName;

@ConfigMapping(prefix = "student")
public interface StudentConfiguration {
    /**
     * 名字与配置项统一
     * @return
     */
    String name();

    /**
     * 名字与配置项统一,主动转为 int 型
     * @return
     */
    int age();

    /**
     * 名字与配置项不统一时,用 WithName 注解指定配置项
     * @return
     */
    @WithName("description")
    String desc();

    /**
     * 用 WithDefault 注解设置默认值,如果配置项 "student.favorite" 不存在,则默认值失效
     * @return
     */
    @WithDefault("default from code")
    String favorite();}
  • 从上述代码可见,一个接口即可实现所有配置项的注入,在应用这些配置项的时候,只有注入 StudentConfiguration 实例即可
  • 首先要用 ConfigMapping 指明配置项的前缀,该接口中的办法都对应具备此前缀的配置项
  • 个别状况下,办法名就等于配置项的名称,也能够用 <font color=”blue”>WithName</font> 指定配置项名称
  • 用 <font color=”blue”>WithDefault</font> 指定默认值,如果找不到配置项就用此默认值
  • 来看看如何应用这个配置接口,web 服务代码如下,只有依赖注入 StudentConfiguration 即可,不在须要为每个配置项都用成员变量和 ConfigProperty 注解了
package com.bolingcavalry;

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import java.time.LocalDateTime;

@Path("/actions")
public class HobbyResource {

    @Inject
    StudentConfiguration student;

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String hello() {

        return "Hello RESTEasy,"
                + LocalDateTime.now()
                + "[" + student.name() + "],"
                + "[" + student.age() + "],"
                + "[" + student.desc() + "],"
                + "[" + student.favorite() + "]";
    }
}
  • 运行代码,用浏览器拜访 web 接口试试,如下图,所有配置项都能正确获取

配置项是多个单词时,如何对应配置接口的办法?

  • 回顾方才的配置,name、age、description 这些都是单个单词,当初如果有个配置项是多个单词,例如 <font color=”blue”> 学号 </font> 的英文是 <font color=”red”>student number</font>,应该如何转为 StudentConfiguration 接口的办法呢?
  • 首先要看您的匹配项的命名格调,对多个单词是如何分隔的,个别有这三种:
  • 减号分隔:student-number
  • 下划线分隔:student_number
  • 驼峰命名:studentNumber
  • ConfigMapping 注解提供了 namingStrategy 的属性,其值有三种,别离对应上述三种命名格调,您依据本身状况选用即可
  1. KEBAB_CASE(默认值):减号分隔的配置项转为驼峰命令的办法,配置项 student-number 对应的办法是 studentNumber
  2. SNAKE_CASE:下划线分隔的配置项转为驼峰命令的办法,配置项 student_number 对应的办法是 studentNumber
  3. VERBATIM:齐全对应,不做任何转换,配置项 student_number 对应的办法是 student_number
  • 应用 namingStrategy 属性的示例代码如下
@ConfigMapping(prefix = "student", namingStrategy = ConfigMapping.NamingStrategy.SNAKE_CASE)
public interface StudentConfiguration {
    /**
     * 名字与配置项统一
     * @return
     */
    String name();
    ...

配置接口嵌套

  • 再来看上面的配置,有两个配置项的前缀都是 <font color=”blue”>student.address</font>,给人的感觉像是 student 对象外面有个成员变量是 address 类型的,而 address 有两个字段:province 和 city
student.name=Tom
student.age=11
student.description=He is a good boy

student.address.province=guangdong
student.address.city=shenzhen
  • 针对上述配置,quarkus 反对用接口嵌套来导入,具体做法分为两步,首先新增一个接口 Address.java,源码如下
package com.bolingcavalry;

public interface Address {String province();
    String city();}
  • 第二步,在配置接口 StudentConfiguration.java 中,减少下图红框中的一行代码(接口中返回接口,造成接口嵌套)
  • 最初,批改 HobbyResource.java 代码,减少下图红框中的两行,验证是否失常获得 address 前缀的配置我的项目
  • 重启利用,如下图,配置项能够失常获取

配置项转为 map

  • 后面的接口嵌套,尽管将多层级的配置以对象的模式清晰的表达出来,但也引出一个问题:配置越多,接口定义或者接口办法就越多,代码随之减少
  • 如果配置项的层级简略,还有种简略的形式将其映射到配置接口中:转为 map
  • 仍然以上面的配置项为例
student.address.province=guangdong
student.address.city=shenzhen
  • 对应的代码改变如下图,只有把 address 办法的返回值从 <font color=”blue”>Address</font> 改为 <font color=”red”>Map<String, String></font> 即可,这样批改后,address 层级上面再减少配置项,也不必批改配置项无关的代码了:
  • 应用配置的业务代码也要改,如下图,改为从 map 中获取
  • 部署运行验证,能够失常取值

内置配置项

  • quarkus 有很多内置的配置项,例如 web 服务的端口 <font color=”blue”>quarkus.http.port</font> 就是其中一个,如果您相熟 SpringBoot 的话,对这些内置配置项应该很好了解,数据库、音讯、缓存,都有对应配置项
  • 篇幅所限就不在此解说 quarkus 内置的配置项了,您能够参考这份官网提供的配置项列表,外面有具体阐明:https://quarkus.io/guides/all-config
  • 上述文档中,有很多配置项带有加锁的图标,如下图红框所示,有这个图标的配置项,其值在利用构建的时候曾经固定了,在利用运行期间始终保持只读状态
  • 这种带有加锁图标的配置项的值,在利用运行期间真的不能扭转了吗?其实还是有方法的,官网文档指明,如果业务的状况非凡,肯定要变,就走热部署的路径,您能够参考《quarkus 实战之四:近程热部署》
  • 官网对开发者的倡议:在开发 quarkus 利用的时候,<font color=”red”> 不要应用 quarkus 作为配置项的前缀 </font>,因为目前 quarkus 框架及其插件们的配置项的前缀都是 <font color=”blue”>quarkus</font>,利用开发应该防止和框架应用雷同的配置项前缀,免得抵触
  • 至此,咱们曾经学习了如何在 quarkus 利用中应用配置项,接下来还会一起实际更多的 quarkus 基础知识,锁定《quarkus 实战》专辑,欣宸不会辜负您的期待

欢送关注思否:程序员欣宸

学习路上,你不孤独,欣宸原创一路相伴 …

正文完
 0