如何异地加载 Spring Boot 配置文件?

本人花费半年的时间总结的《Java面试指南》已拿腾讯等大厂offer,已开源在github ,欢迎star!

本文GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录,这是我花了6个月总结的一线大厂Java面试总结,本人已拿大厂offer,欢迎star

原文链接:blog.ouyangsihai.cn >> 如何异地加载 Spring Boot 配置文件?

  点击上方 **好好学java **,选择 **星标 **公众号


重磅资讯、干货,第一时间送达
今日推荐:iphone 也是办公神器,用了就知道了,不行送你一个试试个人原创+1博客:点击前往,查看更多

链接:https://segmentfault.com/a/1190000022043836

平时,项目的yaml格式或者properties格式的配置信息文件都固化在了项目jar包里面,不便于动态更改。之前我写过一小段时间的Go,我都是从Redis里读取了相关的配置之后,再完成项目的启动。于是乎,我想在Spring Boot里也捣鼓一下。

要完成配置文件的替换,那么必须在Spring Boot启动之前完成,也就是说像这样子


@SpringBootApplication
class Application
fun main(args: Array<String>) {
  // 加载配置文件,然后再运行↓将Spring Boot跑起来
  runApplication<Application>(*args)
}

实现

思路有了之后就简单了,一波操作


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包之后就行不通了,会爆异常


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那么我们的启动命令将改成这样就大功告成


java -cp /解压出来的文件夹根目录 org.springframework.boot.loader.JarLauncher redis 127.0.0.1 6379 redis_password app_config_key

重构

最后稍微重构一下代码 定义一个配置加载器接口


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

简单写个工厂


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方法里,稍微改一下即可,完整代码点这里:https://gist.github.com/Nomyfan/5ec0d8f13b6f8e6faff1d14ac212377e

原文地址:https://sihai.blog.csdn.net/article/details/109465250

本人花费半年的时间总结的《Java面试指南》已拿腾讯等大厂offer,已开源在github ,欢迎star!

本文GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录,这是我花了6个月总结的一线大厂Java面试总结,本人已拿大厂offer,欢迎star

原文链接:blog.ouyangsihai.cn >> 如何异地加载 Spring Boot 配置文件?


 上一篇
Java 循环队列原理与用法详解 Java 循环队列原理与用法详解
  点击上方 **好好学java **,选择 **星标 **公众号 重磅资讯、干货,第一时间送达 今日推荐:iphone 也是办公神器,用了就知道了,不行送你一个试试个人原创+1博客:点击前往,查看更多 链接:https://segm
2021-04-04
下一篇 
reentrantLock 和 synchronized 哪个性能高? reentrantLock 和 synchronized 哪个性能高?
  点击上方 **好好学java **,选择 **星标 **公众号 重磅资讯、干货,第一时间送达 今日推荐:一个线程池 bug 引发的 GC 思考!个人原创+1博客:点击前往,查看更多 链接:https://segmentfault.
2021-04-04