平时,项目的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
那么咱们的启动命令将改为这样就大功告成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