当前位置: 首页 > article >正文

go项目多环境配置

1.java项目配置加载最佳实践

在 Spring Boot 项目中,配置文件的加载和管理是开发过程中不可或缺的一部分。Spring Boot 提供了一套灵活且强大的机制来加载配置文件,使得开发者能够根据不同的环境和需求轻松地管理配置。当多个位置存在相同的配置文件时,springboot会先加载优先级高的配置数据。

springboot加载的逻辑比较复杂,简化版的生产模式大致会以下面的思路:

  1. 对于应用程序本身的内部配置参数,不希望运维同学修改,例如关于spring本身的参数,这类配置统一放在application.xml或application.yml
    spring:
      profiles:
        active: dev
      servlet:
        multipart:
          max-file-size: 50MB
          max-request-size: 50MB
      main:
        banner-mode: off
      ##缓存
      cache:
        type: REDIS
        redis:
          timeToLive: 3600s
          cacheNullValues: true
  2. 在本地开发环境,通过配置spring变量,例如spring.profiles.active=dev,启用多环境配置,读取java项目resources目录下的pplication-dev. yml文件
  3. 在生产环境,如果运维希望覆盖某些配置,例如各种中间件(mysql,s3,redis等等)。则在可执行jar包同级目录下新建一个文件,例如application-prod. yml,并在启动脚本里显式申明 --spring.profiles.active=prod,启用环境变量

     nohup  java  $JVM_ARGS  -jar $jarName  --spring.profiles.active=prod  >  output.txt 2>&1  &

2.Go模仿springboot配置加载策略 

2.1.go项目多环境配置目标

在Go项目,我们也来模仿springboot的配置加载策略,实现以下的效果:

  1. 优先读default.yml文件,应用程序内部配置,项目打包成二进制可执行文件也会嵌入该配置
  2. 在开发环境,若环境变量为xxx,则读取config-xxx.yml(环境变量默认为dev) 
  3. 在生产环境(打包成二进制可执行文件),若环境变量为yyy,则读取config-yyy.yml(环境变量默认为dev)

2.2.使用viper加载配置

在 Go 项目中,Viper 是一个流行的库,用于处理配置文件。它支持多种格式的配置文件,包括 JSON、TOML、YAML 等,并且可以从不同的来源加载配置,如文件、环境变量、命令行参数等。Viper 也支持配置文件的热重载,这意味着在不重启应用程序的情况下,可以重新加载配置文件的更改。

安装命令: go get github.com/spf13/viper

假设我们有一个配置结构体,存储mysql的路径,以及绑定的socket服务地址,如下:

type Config struct {
	DbUrl     string
	ServerUrl string
}

在项目工程新建一个目录,叫做config,并新建一个default.yml的文件,文件内容

db:
  url: root:123456@tcp(localhost:3306)/game_user?charset=utf8mb4&parseTime=True&loc=Local

server:
  addr: 127.0.0.1:9090

 使用viper进行加载,相关代码如下:

    v := viper.New()
	// 设置配置文件名称(不包括扩展名)
	v.SetConfigName("default") // 配置文件名称(不包括扩展名)
	// 设置配置文件类型
	v.SetConfigType("yml")
	// 添加配置文件搜索路径
	v.AddConfigPath("./config")         
	// 读取配置文件
	if err := v.ReadInConfig(); err != nil {
		fmt.Printf("Error reading config: %s\n", err)
		return
	}
    ServerConfig = Config{
		DbUrl:     v.GetString("db.url"),
		ServerUrl: v.GetString("server.addr"),
	}
	fmt.Println("dbUrl", ServerConfig.DbUrl)
	fmt.Println("serverAddr", ServerConfig.ServerUrl)

在本地开发环境,程序运行正常,然而,当程序打包成二进制程序再执行,会报错表示找不到配置文件

这是因为,go build默认只会编译.go文件而不会处理其余静态资源,解决方案,可以引入go-bindata,将配置文件转化为go代码。从 Go 1.16 开始,也可以使用 embed 包将配置文件嵌入到二进制文件中。幸运的是,viper跟embed包搭配起来非常方便。

//go:embed default.yml
var configFS embed.FS

v := viper.New()
v.SetConfigType("yml")
f, err := configFS.Open("default.yml")
if err != nil {
	panic(fmt.Errorf("failed to open config file: %w", err))
}
defer f.Close()
// 从 io.Reader 读取配置
if err := v.ReadConfig(f); err != nil {
	panic(fmt.Errorf("failed to read config: %w", err))
}

根据环境变量读取对应的配置文件,覆盖同名参数

下面实现使用多环境配置,例如config-dev.yml,覆盖同名参数。在config目录下新建一个文件config-dev.yml,编辑内容

server:
  addr: 127.0.0.1:9091

追加代码,如下:

    // 允许 Viper 读取环境变量
	v.AutomaticEnv()
	replacer := strings.NewReplacer(".", "_")
	v.SetEnvKeyReplacer(replacer)

	// 获取环境变量,确定要加载的配置文件
	env := os.Getenv("ENV")
	if env == "" {
		env = "dev"
	}
	v.SetConfigName("config-" + env)
	// ./config路径在开发及部署环境均适用
	v.AddConfigPath("./config")
	// 再次读取配置文件,这次是根据环境变量,使用合并配置的方法确保旧配置被替换
	if err := v.MergeInConfig(); err != nil {
		panic(fmt.Errorf("failed to read config: %w", err))
	}

这里的代码  v.AddConfigPath("./config") 非常关键,它确保了无论是在开发环境还是生产环境,都能加载到对应的多环境配置文件。

在开发环境,由于main.go启动入口与config目录在同一级,且参数里的路径是相应于main函数,而不是代码所在的文件,开发环境加载成功。

在生产环境,我们只需在可执行程序,例如myapp.exe同级目录新建一个config目录,目录下添加一个config-prod.yml即可。

完整的代码如下,去掉注释,空行的话,也就区区50行左右,可以说,viper非常牛逼

package config

import (
	"embed"
	"fmt"
	"github.com/spf13/viper"
	"os"
	"strings"
)

type Config struct {
	DbUrl     string
	ServerUrl string
}

//go:embed default.yml
var configFS embed.FS

var (
	ServerConfig Config
)

// 多环境配置读取规则:
// 加载顺序: default -> 根据开发环境或者部署环境读取相应子目录config/config-env文件
// 先加载的配置会被后加载的同名配置所替换!!!!
// 1.优先读default.yml文件,应用程序内部配置,项目打包成二进制可执行文件也会嵌入该配置
// 2.在开发环境,若环境变量为xxx,则读取config-xxx.yml(环境变量默认为dev)
// 3.在部署环境(打包成二进制可执行文件),若环境变量为yyy,则读取config-yyy.yml(环境变量默认为dev)
func init() {
	// 创建 Viper 实例
	v := viper.New()
	v.SetConfigType("yml")
	// 打包后的二进制文件也要
	f, err := configFS.Open("default.yml")
	if err != nil {
		panic(fmt.Errorf("failed to open config file: %w", err))
	}
	defer f.Close()
	// 从 io.Reader 读取配置
	if err := v.ReadConfig(f); err != nil {
		panic(fmt.Errorf("failed to read config: %w", err))
	}

	// 允许 Viper 读取环境变量
	v.AutomaticEnv()
	replacer := strings.NewReplacer(".", "_")
	v.SetEnvKeyReplacer(replacer)

	// 获取环境变量,确定要加载的配置文件
	env := os.Getenv("ENV")
	if env == "" {
		env = "dev"
	}
	v.SetConfigName("config-" + env)
	// ./config路径在开发及部署环境均适用
	v.AddConfigPath("./config")
	// 再次读取配置文件,这次是根据环境变量,使用合并配置的方法确保旧配置被替换
	if err := v.MergeInConfig(); err != nil {
		panic(fmt.Errorf("failed to read config: %w", err))
	}

	ServerConfig = Config{
		DbUrl:     v.GetString("db.url"),
		ServerUrl: v.GetString("server.addr"),
	}
	fmt.Println("dbUrl", ServerConfig.DbUrl)
	fmt.Println("serverAddr", ServerConfig.ServerUrl)
}

 完整代码请移步:

--> go游戏服务器


http://www.kler.cn/a/315109.html

相关文章:

  • 2024-11-13 学习人工智能的Day26 sklearn(2)
  • 《新智慧》期刊的征稿范围主要包括哪些方面?
  • INQUIRE:一个包含五百万张自然世界图像,涵盖10,000个不同物种的专为专家级文本到图像检索任务设计的新型基准数据集。
  • vue2+ element ui 集成pdfjs-dist
  • LLMs 如何处理相互矛盾的指令?指令遵循优先级实验
  • MacOS 本地生成SSH key并关联Github
  • Redis中的数据结构详解与示例
  • Java笔试面试题AI答之单元测试JUnit(7)
  • Winform中使用MySQL数据库
  • Hutool:Java开发者的瑞士军刀
  • 2.使用 VSCode 过程中的英语积累 - Edit 菜单(每一次重点积累 5 个单词)
  • 如何在 Ubuntu 16.04 服务器上安装 Python 3 并设置编程环境
  • JUC并发编程
  • 第二十一节:学习Redis缓存数据库的Hash操作(自学Spring boot 3.x的第五天)
  • 深度学习02-pytorch-08-自动微分模块
  • OctoSQL 查询大量数据库和文件格式
  • Wireshark学习使用记录
  • 学习笔记JVM篇(三)
  • Jumpsever
  • yolov8改进|引入ScConv,轻量化网络
  • Go语言并发编程之Channels详解
  • windows安装Anaconda教程
  • 自学笔记之TVM编译器框架 ,核心特性,模型优化概述,AI应用落地
  • [001-02-001].第2节:java开发环境搭建
  • UE5学习笔记22-武器瞄准和武器自动开火
  • Python计算机视觉 第10章-OpenCV