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 团队更多权力。使用占位符表达式可以确保我们的配置保持清晰且易于维护。

相关推荐
我不只是切图仔32 分钟前
我只是想给网站加个注册验证码,咋就那么难!
前端·后端
专注VB编程开发20年32 分钟前
CSS 的命名方式像是 PowerShell 的动词-名词结构,缺乏面向对象的层级关系
开发语言·后端·rust
野犬寒鸦34 分钟前
力扣hot100:相交链表与反转链表详细思路讲解(160,206)
java·数据结构·后端·算法·leetcode
爱吃烤鸡翅的酸菜鱼1 小时前
【Spring】原理:Bean的作用域与生命周期
后端·spring
JohnYan1 小时前
工作笔记 - 微信消息发送和处理
javascript·后端·微信
该用户已不存在1 小时前
macOS是开发的终极进化版吗?
前端·后端
计算机毕业设计木哥1 小时前
计算机毕设选题:基于Python+Django的B站数据分析系统的设计与实现【源码+文档+调试】
java·开发语言·后端·python·spark·django·课程设计
歪歪1002 小时前
qt creator新手入门以及结合sql server数据库开发
c语言·开发语言·后端·qt·数据库开发
布列瑟农的星空2 小时前
大话设计模式——观察者模式和发布/订阅模式的区别
前端·后端·架构
Moonbit2 小时前
月报Vol.03: 新增Bitstring pattern支持,构造器模式匹配增强
后端·算法·github