Spring 微服务技巧:使用环境变量抽象数据库主机名

为任何微服务安全地管理数据库连接字符串至关重要。通常,我们会使用环境变量来保护用户名和密码,却从未考虑过隐藏或掩码数据库主机名。在读写数据库实例中,有些组织会要求不得泄露主机名,并在应用程序启动时通过环境变量在运行时传递主机名。

本文讨论了如何在属性文件中通过环境变量配置主机名。

通过环境变量进行数据库配置

我们通常会以以下方式为 Spring 微服务配置默认连接字符串,数据库用户名和密码作为环境变量传递。

properties 复制代码
server.port=8081
server.servlet.context-path=/api/e-sign/v1
spring.esign.datasource.jdbc-url=jdbc:mysql://localhost:3306/e-sign?allowPublicKeyRetrieval=true&useSSL=false
spring.esign.datasource.username=${DB_USER_NAME}
spring.esign.datasource.password=${DB_USER_PASSWORD}
spring.esign.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.esign.datasource.minimumIdle=5
spring.esign.datasource.maxLifetime=120000

如果我们的微服务连接到一个访问受限的安全数据库,并且数据库管理员或基础设施团队不希望你提供数据库主机名,那么我们就遇到了问题。通常,生产环境下数据库主机名可能如下所示:

properties 复制代码
spring.esign.datasource.jdbc-url=jdbc:mysql://prod-db.fabrikam.com:3306/e-sign?allowPublicKeyRetrieval=true&useSSL=false
spring.esign.datasource.username=${DB_USER_NAME}
spring.esign.datasource.password=${DB_USER_PASSWORD}

使用 @Configuration 类

在这种情况下,管理员或云基础设施团队希望在容器启动时在运行时将主机名作为环境变量提供。其中一个选项是在配置类中构建并拼接连接字符串,如下所示:

java 复制代码
@Configuration
public class DatabaseConfig {

    private final Environment environment;

    public DatabaseConfig(Environment environment) {
        this.environment = environment;
    }

    @Bean
    public DataSource databaseDataSource() {
        String hostForDatabase = environment.getProperty("ESIGN_DB_HOST", "localhost:3306");
        String dbUserName = environment.getProperty("DB_USER_NAME", "user-name");
        String dbUserPassword = environment.getProperty("DB_USER_PASSWORD", "user-password");
        String url = String.format("jdbc:mysql://%s/e-sign?allowPublicKeyRetrieval=true&useSSL=false", hostForDatabase);

        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        dataSource.setUrl(url);
        dataSource.setUsername(dbUserName); // 替换为你的实际用户名
        dataSource.setPassword(dbUserPassword); // 替换为你的实际密码
        return dataSource;
    }
}

上述方法可以工作,但我更倾向于使用 application.properties 的方法,这种方法易于使用且相当灵活。属性文件允许你以集中方式整合所有配置,使其更易于更新和管理。它还通过将配置与代码分离来提高可读性。DevOps 团队可以在不更改代码的情况下更新环境变量的值。

通常,我们使用环境变量来设置数据库用户名和密码,并在 application.properties 文件中使用相应的表达式占位符 ${}

properties 复制代码
spring.esign.datasource.username=${DB_USER_NAME}
spring.esign.datasource.password=${DB_USER_PASSWORD}

然而,对于数据库 URL,我们只需要在环境变量中使用主机名,而不是连接字符串,因为不同微服务的每个连接字符串都会有不同的参数。因此,为了解决这个问题,Spring 允许你在连接字符串中使用占位符表达式,如下所示;这提供了灵活性,并且能够继续使用 application.properties 文件的方法,而不是通过数据库配置类来实现。

properties 复制代码
spring.esign.datasource.jdbc-url=jdbc:mysql://${ESIGN_DB_HOST}:3306/e-sign?allowPublicKeyRetrieval=true&useSSL=false

一旦我们决定了上述方法,并且如果出于某种原因需要在较低环境中排查问题,我们就可以使用 ApplicationListener 接口来查看解析后的 URL:

java 复制代码
@Component
public class ApplicationReadyLogger implements ApplicationListener<ApplicationReadyEvent> {

    private final Environment environment;

    public ApplicationReadyLogger(Environment environment) {
        this.environment = environment;
    }

    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        String jdbcUrl = environment.getProperty("spring.esign.datasource.jdbc-url");
        System.out.println("Resolved JDBC URL: " + jdbcUrl);
    }
}

如果主机名配置存在问题,它将在应用程序启动时显示为错误。然而,在应用程序启动后,多亏了上述 ApplicationReadyLogger 实现,我们可以在应用程序日志中看到数据库 URL。请注意,我们不应在生产环境中这样做,因为基础设施团队希望对数据库写入主机名保密。

通过上述步骤,我们可以在 application.properties 文件的连接字符串中将数据库主机名配置为环境变量。

总结

使用环境变量为连接数据敏感数据库的主机名可以增强安全性和灵活性,并赋予云基础设施和 DevOps 团队更多权力。使用占位符表达式可以确保我们的配置保持清晰且易于维护。

相关推荐
gCode Teacher 格码致知36 分钟前
《Asp.net Mvc 网站开发》复习试题
后端·asp.net·mvc
Moshow郑锴3 小时前
Spring Boot 3 + Undertow 服务器优化配置
服务器·spring boot·后端
Chandler243 小时前
Go语言即时通讯系统 开发日志day1
开发语言·后端·golang
有梦想的攻城狮4 小时前
spring中的@Lazy注解详解
java·后端·spring
野犬寒鸦4 小时前
Linux常用命令详解(下):打包压缩、文本编辑与查找命令
linux·运维·服务器·数据库·后端·github
huohuopro5 小时前
thinkphp模板文件缺失没有报错/thinkphp无法正常访问控制器
后端·thinkphp
cainiao0806057 小时前
《Spring Boot 4.0新特性深度解析》
java·spring boot·后端
-曾牛8 小时前
Spring AI 与 Hugging Face 深度集成:打造高效文本生成应用
java·人工智能·后端·spring·搜索引擎·springai·deepseek
南玖yy8 小时前
C/C++ 内存管理深度解析:从内存分布到实践应用(malloc和new,free和delete的对比与使用,定位 new )
c语言·开发语言·c++·笔记·后端·游戏引擎·课程设计
计算机学姐8 小时前
基于SpringBoot的小区停车位管理系统
java·vue.js·spring boot·后端·mysql·spring·maven