阿毛
It's me !
想你所想

Apollo之配置${}变量取值问题

原先公司遇到的问题,当时总结的内容,这里迁移一下。

一、问题复现

在某个应用内,有一个namespace,application.yml 有如下配置

spring:
  application:
    name: wisdomclass-usercenter
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://${mysql.db.host}/${mysql.db.database}?useUnicode=true&characterEncoding=utf-8&mysqlEncoding=utf8&useSSL=false&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&useServerPrepStmts=true&cachePrepStmts=true&prepStmtCacheSize=250&prepStmtCacheSqlLimit=2048&autoReconnect=true&failOverReadOnly=false
    username: ${mysql.username}
    password: ${mysql.password}
    
eureka:
  instance:
    lease-renewal-interval-in-seconds: ${eureka.instance.lease-renewal-interval-in-seconds} #EurekaClient向EurekaServer发送心跳时间间隔
    prefer-ip-address: true
  client:
    registerWithEureka: true #是否注册自己
    fetchRegistry: ${eureka.client.fetchRegistry}  #是否拉取服务列表
    registry-fetch-interval-seconds: ${eureka.client.registry-fetch-interval-seconds} #Client向Server拉取服务信息的频率,防止新上线的服务拉取不到
    serviceUrl:
      #注册中心地址,默认zone是defaultZone
      defaultZone: ${eureka.client.serviceUrl.defaultZone}

在另一个namespace,backend.mysql中有如下配置:

https://file.blog.humh.cn/2020/06/d2b5ca33bd970f64a6301fa75ae2eb22.png

还有一个namespace,backend.springcloud有如下配置:

https://file.blog.humh.cn/2020/06/d2b5ca33bd970f64a6301fa75ae2eb22-1.png

现服务读取apollo去加载该应用,在配置文件这样配置
apollo.bootstrap.namespaces:application.yml,backend.mysql,backend.springcloud
会发现服务启动报错,异常的错误信息如下:

2020-02-19 21:22:40.568 WARN  [main] [Jdk14Logger.java:99] - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration$EurekaClientConfigurationRefresher': Unsatisfied dependency expressed through field 'autoRegistration'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'eurekaAutoServiceRegistration' defined in class path resource [org/springframework/cloud/netflix/eureka/EurekaClientAutoConfiguration.class]: Unsatisfied dependency expressed through method 'eurekaAutoServiceRegistration' parameter 2; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'eurekaRegistration' defined in class path resource [org/springframework/cloud/netflix/eureka/EurekaClientAutoConfiguration.class]: Unsatisfied dependency expressed through method 'eurekaRegistration' parameter 1; nested exception is org.springframework.boot.context.properties.ConfigurationPropertiesBindException: Error creating bean with name 'eurekaInstanceConfigBean': Could not bind properties to 'EurekaInstanceConfigBean' : prefix=eureka.instance, ignoreInvalidFields=false, ignoreUnknownFields=true; nested exception is org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'eureka.instance.lease-renewal-interval-in-seconds' to int

发现datasource初始化成功,但eureka失败。
其实这个问题就是在使用apollo过程中对于这种变量${}获取时可能存在的情况,当变量声明与变量获取同一key命名时,就很有可能会出现这种问题。

二、原因分析

这里,先说一下,客户端在对apollo namespace配置加载时的规则:

根据客户端配置的“apollo.bootstrap.namespaces”值来决定,namespace在前先加载,若有重复key的配置,只会加载第一次的值,第二次的值直接过滤掉。它会把所有namespace的配置加载完后,再去启动spring容器。

出现上述问题的原因是,变量的命名与获取的地方为同一key,如“testKey:${testKey}”,和“testKey:1”在两个namespace,如果“testKey:${testKey}”加载在前,“testKey:1”就不会再进行加载,然后在实例化读取配置时,显然“${testKey}”这种值是错误的,导致异常。而如果“testKey:1”在前,那么“testKey:${testKey}”就不会被加载,实例化也不会出错。而对于上面的“${mysql.name}”的情况,因为apollo客户端会在加载完所有namespace的配置后,才启动容器,而且命名并不重复,所以变量可以正常获取。

三、总结

如果有变量取值的情况时,尽量保证变量名不要与取值的key相同。若相同,务必保证变量值在前加载。

humh

文章作者

站长本人,一个憨批!

发表评论

textsms
account_circle
email

想你所想

Apollo之配置${}变量取值问题
原先公司遇到的问题,当时总结的内容,这里迁移一下。 一、问题复现 在某个应用内,有一个namespace,application.yml 有如下配置 spring: application: name: wisdomcl…
扫描二维码继续阅读
2020-06-01