【JAVA】springcloud 动态加载外部配置到Bean,vault客户端最佳实践

4 篇文章 0 订阅

目录

一、适应场景

二、制作依赖

1、pom.xml添加依赖

2、初始化vault动态配置,并配置文件监听(此处为源码)

3、使用配置热加载功能

三、问题与思考


一、适应场景

原始需求:配置内容为外部文件,文件出现变更时能够自行刷新spring容器中的bean。

此源码初衷为应用于敏感信息治理Vault,客户端能够随着vault密钥的轮转,在不重启的情况下自动刷新密钥。

二、制作依赖

方式:源码引入,通过archiaus加载动态配置,通过springcloud context刷新bean。

1、pom.xml添加依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>com.netflix.archaius</groupId>
        <artifactId>archaius-core</artifactId>
        <version>0.7.5</version>
    </dependency>
    <dependency>
        <groupId>commons-configuration</groupId>
        <artifactId>commons-configuration</artifactId>
        <version>1.10</version>
    </dependency>
</dependencies>
<dependencyManagement>
      <dependencies>
          <dependency>
              <groupId>org.springframework.cloud</groupId>
              <artifactId>spring-cloud-dependencies</artifactId>
              <version>2020.0.5</version>
              <type>pom</type>
              <scope>import</scope>
          </dependency>
      </dependencies>
  </dependencyManagement>

注意:springcloud相关依赖为选填,原先是springcloud项目的不需要引入springcloud相关依赖
 

2、初始化vault动态配置,并配置文件监听(此处为源码)

import com.netflix.config.ConcurrentCompositeConfiguration;
import com.netflix.config.ConfigurationManager;
import com.netflix.config.DynamicURLConfiguration;
import org.apache.commons.configuration.event.ConfigurationEvent;
import org.apache.commons.configuration.event.ConfigurationListener;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.refresh.ContextRefresher;
import org.springframework.context.annotation.Configuration;
 
import javax.annotation.PostConstruct;
 
/**
 * Title: 动态加载vault配置文件,并刷新
 * Description:
 * author :xbl
 * Date:2023/2/8
 * Time:10:37
 */
@Configuration
public class VaultConfigProcessor {
 
    private static final Log log = LogFactory.getLog(VaultConfigProcessor.class);
 
    @Autowired
    private ContextRefresher refresher;
 
    @Value("${vault.secretPath}")
    private String vaultFile;
 
    @Value("${vault.secretKeys}")
    private String secretKeys;
 
    @PostConstruct
    public void initVaultArchiausProcessor() {
        try {
            log.info("[VAULT-ARCHIAUS] - Dynamic property file is {}" + vaultFile);
            DynamicURLConfiguration dynamicURLConfiguration = new DynamicURLConfiguration(10000, 10000, false, vaultFile);
            ConcurrentCompositeConfiguration finalConfig = new ConcurrentCompositeConfiguration();
            finalConfig.addConfiguration(dynamicURLConfiguration);
            ConfigurationManager.install(finalConfig);
            ConfigurationManager.getConfigInstance().addConfigurationListener(new VaultConfigurationListener());
        } catch (RuntimeException e) {
            log.error("###############");
            log.error("[VAULT-ARCHIAUS] - project: initialization failed. Forcing shutdown now.");
            log.error("###############");
            e.printStackTrace();
            System.exit(0);
        }
    }
 
    class VaultConfigurationListener implements ConfigurationListener {
        @Override
        public void configurationChanged(ConfigurationEvent event) {
            if (!event.isBeforeUpdate()) {
                if (!StringUtils.isEmpty(event.getPropertyName())&&
                        secretKeys.contains(event.getPropertyName())) {
                    log.info("[VAULT-ARCHIAUS] - " + event.getPropertyName() + " will refreshing! ");
                    refresher.refresh();
                }
            }
        }
    }
}

3、使用配置热加载功能

1> 定位vault生成的配置文件地址,填写要求的静态配置到启动配置application.yml中
 

vault:
  #动态配置目录,即vault目标文件地址
  secretPath: file:/D:\project\src\main\resources\vault-secret.properties
  #监听哪些Key触发刷新,逗号分隔
  secretKeys: secretId,secretKey

2>vault-secret.properties(动态配置的真实内容,接入vault时会将配置落到此文件)
 

secretId=aaaaaaaavvvvvv
secretKey=acccccccckkkkk

3>客户端使用动态配置

bean初始化时使用archaius获取配置内容,添加@RefreshScope注解实现动态刷新,参考如下:
 

//bean对象案例
public class ClientEntity {
    private String secretId;
    public String getSecretId() {
        return secretId;
    }
    public void setSecretId(String secretId) {
        this.secretId = secretId;
    }
}
 
//构建bean示例
@Bean
@RefreshScope
public ClientEntity clientEntity() {
    //取账号密钥
    String secretId = DynamicPropertyFactory.getInstance().getStringProperty("key", null).get();
 
    ClientEntity entity = new ClientEntity();
    entity.setSecretId(secretId);
    return entity;
}
 
//使用单例bean
@Autowired
private ClientEntity clientEntity;

达到的效果:vault-secret.properties 触发变更时,spring容器内的 tencentClientEntity 也会更新 secretId,实现热加载。

对于使用者来说,只需要将密钥信息使用archiaus进行动态加载,并且加入@RefreshScope注解即可。

如果是非spring体系,不需要刷新bean,使用archiaus即可。

三、问题与思考

1、为什么不直接使用spring-cloud的动态配置加载能力,反而引入archiaus?

答:它需要在启动时指向配置文件,不够友好,我需要的是更灵活的外部配置;其次,它所提供配置的更新一般是集成actuator使用,需要对外暴露接口,需要手动触发更新,对于vault来说这种方式的接入太复杂,而archiaus能自己吃掉这个问题,解决耦合度的问题,同时使用起来更舒适。

2、为什么要使用springcloud去做bean的热更新?自己手动实现热加载不行吗?

答:原计划是手动刷新bean,从context获取到的bean能够实现热更新,这个已经跑通了,但是某些注解比如@autowired,它做的自动装配会有一层bean缓存,手动更新bean更新不了它,springcloud的RefreshScope就是用来处理这个问题的,如果自己去实现,也是参考cloud的方式。综合springcloud体系的覆盖面,决定直接使用springcloud解决这个问题。
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值