Java 项目中一种简单的动态修改配置即时生效的方式 WatchService
这种方式仅适合于比较小的项目,例如只有一两台服务器,而且配置文件是可以直接修改的。例如 Spring mvc 以 war 包的形式部署,可以直接修改resources 中的配置文件。如果是 Spring boot 项目,还想用这种方式的话,就要引用一个外部可以编辑的文件,比如一个固定的目录,因为 spring boot 大多数以 jar 包部署,打到包里的配置文件没办法直接修改。如果是比较大的项目,最好还是用配置中心,例如携程的 Apollo、Consul 等。
原始方式
原始方式指的是每次要修改配置的时候,都要重新打包发布或者重启服务器。
假设我们用 spring mvc 开发,开发完成后打成 war 包部署到 tomcat 上,如果这时我们修改一个短信接口地址。
我们要做如下操作:
1、打开配置文件,修改配置信息;
2、编译打包;
3、停止 tomcat ,删除旧的项目目录;
4、将新的 war 包放到 webapps ,启动 tomcat。
当然,可以直接在 tomcat 中找到这个项目的配置文件,然后修改,但同样需要重启 tomcat 。
如果只是单纯做开发或者测试,除了有点浪费时间外,当然可以接受。那么,既不想浪费时间又不想重启 tomcat 呢,有没有办法呢。这就轮到本文介绍的这种方式了。
WatchService 方式
Java 提供了 WatchService 接口,这个接口是利用操作系统本身的文件监控器对目录和文件进行监控,当被监控对象发生变化时,会有信号通知,从而可以高效的发现变化。
这种方式大致的原理:先根据操作系统 new 一个监控器( WatchService ),然后选择要监控的配置文件所在目录或文件,然后订阅要监控的事件,例如创建、删除、编辑,最后向被监控位置注册这个监控器。一旦触发对应我们所订阅的事件时,执行相应的逻辑即可。
先上代码吧,这是在一个 spring mvc 项目里,监控的是 resources 目录。
@Repository public class ConfigWatcher { private static final Logger logger = LoggerFactory.getLogger(ConfigWatcher.class); private static WatchService watchService; @PostConstruct public void init() { logger.info("启动配置文件监控器"); try { watchService = FileSystems.getDefault().newWatchService(); URL url = ConfigWatcher.class.getResource("/"); Path path = Paths.get(url.toURI()); path.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY, StandardWatchEventKinds.ENTRY_CREATE); } catch (Exception e1) { e1.printStackTrace(); } /** * 启动监控线程 */ Thread watchThread = new Thread(new WatchThread()); watchThread.setDaemon(true); watchThread.start(); /**注册关闭钩子*/ Thread hook = new Thread(new Runnable() { @Override public void run() { try { watchService.close(); } catch (IOException e) { e.printStackTrace(); } } }); Runtime.getRuntime().addShutdownHook(hook); } public class WatchThread implements Runnable { @Override public void run() { while (true) { try { // 尝试获取监控池的变化,如果没有则一直等待 WatchKey watchKey = watchService.take(); for (WatchEvent<?> event : watchKey.pollEvents()) { String editFileName = event.context().toString(); logger.info(editFileName); /** * 重新加载配置 */ } watchKey.reset();//完成一次监控就需要重置监控器一次 } catch (Exception e) { e.printStackTrace(); } } } } }
代码非常简单,一看就懂,在项目启动的时候,用 FileSystems.getDefault().newWatchService() 创建一个 WatchService,这是根据操作系统来的。然后获取 resources 目录的 URL,并由此获取 Path,然后调用 Path 对象的 register 方法,注册监控器,订阅了编辑和创建事件。事件在 StandardWatchEventKinds 类中定义,共有四种:
1、StandardWatchEventKinds#OVERFLOW
2、StandardWatchEventKinds#ENTRY_CREATE
3、StandardWatchEventKinds#ENTRY_DELETE
4、StandardWatchEventKinds#ENTRY_MODIFY
然后单独启动了一个 WatchThread 线程来处理变化逻辑,在一个 while 无限循环中调用 take() 方法,直到有变化发生,一旦是我们监控的配置文件发生了变化,则调用我们的逻辑重新加载配置。另外,每次有变化发生后,要调用 watchKey.reset() 方法来重置监控器。
最后,还要注册一个 hook,在 jvm 关闭的时候可以关闭监控器。
有了这种方式,当我们有一些配置变化的时候,就可以直接到 tomcat 下修改配置文件,不用重启就可以生效了。
本文主要介绍的是这种方式,上面也说了,这种方式只适合非常简单的项目,对于大型项目,就需要用到更高级的方式了。
配置中心的方式
当项目复杂度变高,配置修改后实时生效,灰度发布,分环境、分集群管理配置,完善的权限、审核机制可能都变成项目中要考虑的问题,这个时候,单纯依赖配置文件就显得力不从心了。
目前比较用的比较多的配置中心有etcd、zookeeper、disconf、Apollo 等。disconf、Apollo 都是属于拿来即用的,功能完善,而且有配套的 UI。而 etcd 和 zookeeper 需要一些定制开发。
各位同学可以根据需要自行选择,更详细的内容可以自行搜索和实践。
最后,各位同学不妨到我的公众号里互动一下 :古时的风筝
- Java动态修改配置即时生效的方式WatchService
- java应用(非web应用)中log4j.properties动态修改配置文件,无需重启,就能立即生效,如何实现?
- java应用(非web应用)中log4j.properties动态修改配置文件,无需重启,就能立即生效,如何实现?
- 项目中动态修改加载环境配置的几种方式
- java项目配置dll,so动态库文件方式
- java开源框架应用技巧之spring配置文件中如果有多个.hbm.xml文件的话,无论是项目开发过程中还是维护过程中修改起来都会很麻烦切容易出错
- 用 Java 技术创建 RESTful Web (服务 JAX-RS:一种更为简单、可移植性更好的替代方式)
- weblogic配置修改java代码后不需要重启热部署方式
- 在使用spring构建项目中,将db配置与程序jar包分离的一种方式
- java 声明静态Map常量的一种简单方式
- JAVA_WEB项目之使用Spring的xml配置方式在项目中管理Lucene检索框架
- 基于Proguard软件基础上,针对Web项目xml配置文件修改的java项目。
- weblogic配置修改java代码后不需要重启热部署方式
- weblogic配置修改java代码后不需要重启热部署方式
- java.lang.OutOfMemoryError: PermGen space修改启动配置的解决方式
- 一种最简单的Java环境变量配置
- tomcat6配置java项目启动动态加载配置文件
- weblogic下开发web项目时修改java文件不用重启的绿色方法,不用修改weblogic的配置文件、不用jar
- java非web应用修改 properties/xml配置文件后,无需重启应用即可生效---自动加载
- 修改配置文件后不重启程序即时生效