这种方式仅适合于比较小的项目,例如只有一两台服务器,而且配置文件是可以直接修改的。例如 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;@PostConstructpublic 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() {@Overridepublic void run() {try {watchService.close();} catch (IOException e) {e.printStackTrace();}}});Runtime.getRuntime().addShutdownHook(hook);}public class WatchThread implements Runnable {@Overridepublic 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工程师朋友们加入Java架构开发: 854393687 群内提供免费的Java架构学习资料(里面有高可用、高并发、高性能及分布式、Jvm性能调优、Spring源码,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多个知识点的架构资料)合理利用自己每一分每一秒的时间来学习提升自己,不要再用"没有时间“来掩饰自己思想上的懒惰!趁年轻,使劲拼,给未来的自己一个交代!

转载于:https://juejin.im/post/5be7f565e51d457e90195251

Java 项目中一种简单的动态修改配置即时生效的方式 WatchService相关推荐

  1. python图表制作方法_Python中一种简单的动态图表制作方法

    在读技术博客的过程中,我们会发现那些能够把知识.成果讲透的博主很多都会做动态图表.他们的图是怎么做的?难度大吗?这篇文章就介绍了Python中一种简单的动态图表制作方法. 数据暴增的年代,数据科学家. ...

  2. kindeditor java_kindeditor在Java项目中的应用以及图片上传配置

    在官网下载Kindededitor的开发包 在项目中javaweb项目中导入kindeditor必须要使用的Jar包(用于文件上传,除非你的富文本编辑器不使用图片上传)jar包可以在官网的开发包中找到 ...

  3. java : enum、创建文件和文件夹、删除文件和文件夹、获得项目绝对路径、写入数据到excel中、java代码中两种路径符号写法、读取、写入text文件...

    java : enum http://www.cnblogs.com/hyl8218/p/5088287.html 创建文件和文件夹.删除文件和文件夹 http://www.cnblogs.com/m ...

  4. Java项目中利用Freemarker模板引擎导出--生成Word文档

    应邀写的一篇文章:Java项目中利用Freemarker模板引擎导出--生成Word文档 资源下载:https://download.csdn.net/download/weixin_41367523 ...

  5. Redis学习笔记之二 :在Java项目中使用Redis

    成功配置redis之后,便来学习使用redis.首先了解下redis的数据类型. Redis的数据类型 Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set( ...

  6. redis java驱动_Redis学习笔记之二 :在Java项目中使用Redis

    成功配置redis之后,便来学习使用redis.首先了解下redis的数据类型. Redis的数据类型 Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set( ...

  7. 为什么在2012/2013年我将在新的Enterprise Java项目中继续使用Spring *和* Java EE

    自从我担任技术决策职务以来已经过去了一年多,很高兴看到我仍然与之保持着完美的和谐. 几个月前,我在KaiWähner的一个不错的博客中写了一个有关JEE与Spring的答案. 如果观点没有不同,那么讨 ...

  8. 为什么我会在2012年的新企业Java项目中使用Java EE而不是Spring

    这个问题经常出现. 我的新项目也在2011年11月发布. 在这个新的Enterprise Java项目中,我将使用Java EE(JEE)代替Spring框架. 我知道:关于此主题的文章,博客和论坛讨 ...

  9. mybatis手动切换数据库_在Spring项目中使用 Mybatis 如何实现动态切换数据源

    在Spring项目中使用 Mybatis 如何实现动态切换数据源 发布时间:2020-11-17 16:20:11 来源:亿速云 阅读:108 作者:Leah 这篇文章将为大家详细讲解有关在Sprin ...

最新文章

  1. 一批高校调整国庆假期!教育部回应,大学生国庆假期能否离校?
  2. 手机python软件怎么创建项目_创建成功的 Python 项目
  3. php根据键值去除数组中的某个元素_php删除数组中指定值的元素的几种方法
  4. ubuntu卸载openjdk-11
  5. 不是linux内核的国产系统,国产操作系统都是山寨Windows的?为何用Linux内核?
  6. ASP.NET MVC区域
  7. CodeForces - 468B Two Sets(并查集+思维)
  8. SQLServer之深度分析Insert
  9. Ubuntu16.04下在Anaconda里面安装opencv
  10. 持续集成部署Jenkins工作笔记0007---配置JDK和Maven并安装Deploy插件
  11. MySQL统计每月数量并计算同比增长率
  12. TI达芬奇系列TMS320DM8168浮点DSP C674x + ARM Cortex-A8高性能视频处理器,用于视频基础设施
  13. 详解抖音壁纸号的具体玩法,变现方法容易吗?
  14. 实用电路:用MOS管模拟的可调功率电阻
  15. 计算机cpu基本功能,cpu的基本功能包括
  16. 微信第 1 行代码曝光!
  17. Python打包出现 failed to execute script xxx解决方法
  18. jpeg压缩解压缩简介
  19. 使用requests和re正则表达式库爬虫小说‘斗破苍穹’,可选取任意章节下载到本地
  20. HTML和CSS3写的switch插件

热门文章

  1. 查询2019-06-20日 和 2019-06-23  每个商品每天的入库情况
  2. Stopping ADB server failed(code -1)
  3. 深入理解K8S网络原理下
  4. 实战系列-分布式缓存
  5. 12款程序员专用chrome插件神器推荐
  6. linux时间函数详解
  7. 读者专属福利: Git面试宝典分享
  8. 数据库性能怎么提升?
  9. 88.搭建git服务器 安装与使用gitlab gitlab备份与恢复
  10. 关于runc漏洞CVE-2019-5736的修复公告