You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

非SpringBoot的Spring应用从Azure Key Vault加载密钥配置数据源求助

解决方案

要在非SpringBoot的Spring应用上下文初始化阶段,从Azure Key Vault加载密钥并注入到数据源配置中,核心思路是提前将Key Vault密钥加载到Spring环境变量中,让Spring解析${}占位符时能直接获取到密钥值。具体实现步骤如下:


1. 实现ApplicationContextInitializer,提前加载Key Vault密钥

创建一个实现ApplicationContextInitializer的类,在Spring上下文刷新前(所有Bean创建前)拉取密钥并注册为Spring的属性源:

import com.azure.security.keyvault.secrets.SecretClient;
import com.azure.security.keyvault.secrets.SecretClientBuilder;
import com.azure.security.keyvault.secrets.models.SecretProperties;
import com.azure.identity.DefaultAzureCredentialBuilder;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import java.util.HashMap;
import java.util.Map;

public class KeyVaultPropertyInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        ConfigurableEnvironment environment = applicationContext.getEnvironment();
        
        // 从现有配置(如application.properties)读取Key Vault地址
        String keyVaultUri = environment.getProperty("spring.cloud.azure.keyvault.secret.endpoint");
        
        // 创建SecretClient
        SecretClient secretClient = new SecretClientBuilder()
                .vaultUrl(keyVaultUri)
                .credential(new DefaultAzureCredentialBuilder().build())
                .buildClient();
        
        // 拉取Key Vault中的所有密钥(可按需指定单个密钥)
        Map<String, Object> secretProperties = new HashMap<>();
        secretClient.listPropertiesOfSecrets().forEach(secretProp -> {
            String secretName = secretProp.getName();
            // 将密钥名称中的连字符转为点号,适配Spring属性命名规则(如db-username → db.username)
            String propertyName = secretName.replace("-", ".");
            secretProperties.put(propertyName, secretClient.getSecret(secretName).getValue());
        });
        
        // 将密钥注册为Spring属性源,优先级设为最高(覆盖其他属性源)
        environment.getPropertySources().addFirst(new MapPropertySource("azure-keyvault", secretProperties));
    }
}

2. 注册Initializer到Spring上下文

根据应用类型,将Initializer注册到Spring上下文:

(1)Web应用(通过web.xml配置)

在web.xml中添加上下文参数:

<context-param>
    <param-name>contextInitializerClasses</param-name>
    <param-value>com.yourpackage.KeyVaultPropertyInitializer</param-value>
</context-param>

(2)独立应用(代码方式注册)

创建ApplicationContext时手动添加Initializer:

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class AppMain {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.addApplicationContextInitializer(new KeyVaultPropertyInitializer());
        context.register(AppConfig.class); // 注册你的配置类
        context.refresh();
    }
}

3. 验证与权限配置

  • 权限配置:确保应用拥有Azure Key Vault的访问权限(生产环境用Managed Identity,本地开发可通过Azure CLI登录)。
  • 原有代码调整:原KeyVaultConfig类可移除,其他需要密钥的地方直接通过@Value("${db.username}")注入即可,无需手动调用SecretClient。

此时Spring解析app-context.xml中的数据源配置时,会自动从Key Vault拉取的属性源中获取db.username、db.password等值,确保数据源在上下文创建时就能正确初始化。

内容的提问来源于stack exchange,提问作者Sal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 17:54:51