異地加載Spring Boot配置文件

平時,項目的yaml格式或者properties格式的配置信息文件都固化在了項目jar包裏面,不便於動態更改。以前我寫過一小段時間的Go,我都是從Redis裏讀取了相關的配置以後,再完成項目的啓動。因而乎,我想在Spring Boot裏也搗鼓一下。java

要完成配置文件的替換,那麼必須在Spring Boot啓動以前完成,也就是說像這樣子git

@SpringBootApplication
class Application
fun main(args: Array<String>) {
  // 加載配置文件,而後再運行↓將Spring Boot跑起來
  runApplication<Application>(*args)
}

實現

思路有了以後就簡單了,一波操做github

val logger = LoggerFactory.getLogger(RedisConfigLoader::class.java)

val classLoader = RedisConfigLoader::class.java.classLoader
val url = classLoader.getResource("application.yaml")
  ?: throw ConfigLoadingException("Cannot find the resource") // 自定義的異常
val path = Paths.get(url.toURI())
logger.info("Resource file path is $path")
val channel = FileOutputStream(path.toFile()).channel

val host = args[0]
val port = args[1].toInt()
val password = args[2].toCharArray()
val key = args[3]

val redisURI = RedisURI(host, port, Duration.ofSeconds(5)).apply { this.password = password }
val redisClient = RedisClient.create(redisURI)
val conn = redisClient.connect()
logger.info("Connected to Redis")

val value = conn.sync().get(key)
if (value.isNullOrEmpty()) {
  throw ConfigLoadingException("Cannot read resource from redis with key named $key")
}
val buffer = ByteBuffer.wrap(value.toByteArray())
channel.write(buffer)

channel.close()
conn.close()
redisClient.shutdown()
logger.info("Replaced the resource file successfully!")

在Idea裏運行沒問題,跑起來了,可是,當打包成jar包以後就行不通了,會爆異常redis

Caused by: java.nio.file.FileSystemNotFoundException
        at jdk.zipfs/jdk.nio.zipfs.ZipFileSystemProvider.getFileSystem(ZipFileSystemProvider.java:166)

解決辦法也很簡單,把jar包解壓出來跑😂,實際上也不會很麻煩,解壓在CI構建階段完成便可。不過要完成項目的啓動,必須先找到Spring Boot的啓動類。打開jar包,查看裏面的META-INF/MENIFEST.MF文件,能夠看到Main-Class是org.springframework.boot.loader.JarLauncher
image.png
那麼咱們的啓動命令將改爲這樣就大功告成spring

java -cp /解壓出來的文件夾根目錄 org.springframework.boot.loader.JarLauncher redis 127.0.0.1 6379 redis_password app_config_key

重構

最後稍微重構一下代碼
定義一個配置加載器接口app

interface ConfigLoader {
  @Throws(ConfigLoadingException::class) // 自定義異常
  fun load(resourceName: String, args: Array<String>)
}

簡單寫個工廠ide

class ConfigLoaderFactory {
  companion object {
    fun loaderOf(type: String): ConfigLoader {
      return when (type) {
        "redis" -> RedisConfigLoader()
        else -> throw ConfigLoaderNotFoundException("Cannot find the config loader typed $type") // 自定義異常
      }
    }
  }
}

實現一個RedisConfigLoader,把以前的代碼拷貝的load方法裏,稍微改一下便可,完整代碼點這裏Gistthis

相關文章
相關標籤/搜索