非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
相关产品推荐
相关产品推荐

