范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

分享一个修改了xml文件再也不用重启的项目mybatisxmlrelaod

  自我18年使用 Mybaits 以来,开发环境中如果修改了 xml 文件后,只有重启项目才能生效,如果小项目重启还好,但是对于一个重启需要十几分钟的大型项目来说,这就非常耗时了。开发人员因为修改了xml 文件少量内容,比如添加一个逗号、查询增加一个字段或者修改一个 bug 等,就需要重启整个项目,这就非常痛苦了。
  所以在这里给大家推荐一个实现了 Mybatis xml文件热加载的项目, 「mybatis-xmlreload-spring-boot-starter」 。它能够帮助我们在「Spring Boot + Mybatis」 的开发环境中修改 xml 后,不需要重启项目就能让修改过后 xml 文件立即生效,实现热加载功能。这里给出项目地址: https://github.com/wayn111/mybatis-xmlreload-spring-boot-starter 欢迎大家关注,点个star
  ps: 「mybatis-xmlreload-spring-boot-starter」 目前 3.0.3.m1 版本实现了 xml 文件修改已有内容,比如修改 sql 语句、添加查询字段、添加查询条件等,可以实现热加载功能。但是对于 xml 文件添加 insert|update|delete|select  标签等内容后,是无法实现热加载的。众所周知,在 Idea 环境进行 Java 开发,在方法内修改方法内容是可以热加载的。但是添加新方法、添加方法参数,修改方法参数,修改方法返回值等都是无法直接热加载的。 一、mybatis-xmlreload-spring-boot-starter使用
  「mybatis-xmlreload-spring-boot-starter」 原理: 修改 xml 文件的加载逻辑。在普通的  mybatis-spring  项目中,默认只会加载项目编译过后的 xml 文件,也就是 target 目录下的 xml 文件。但是在「mybatis-xmlreload-spring-boot-starter」 中,修改了这一点,它会加载项目 resources 目录下的 xml 文件,这样用户对于 resources 目录下 xml 文件的修改操作是可以立即触发热加载的。 通过  io.methvin.directory-watcher  项目来监听 xml 文件的修改操作,它底层是通过 java.nio 的WatchService  来实现,当我们监听了整个 resources 目录后,xml 文件的修改会立马触发 MODIFY 事件。 通过  mybatis-spring  项目原生的 xmlMapperBuilder.parse()  方法重新加载解析修改过后的 xml 文件来保证项目对于 Mybatis 的兼容性处理。 二、技术原理
  「mybatis-xmlreload-spring-boot-starter」 代码结构如下:
  核心代码在 「MybatisXmlReload」 类中,执行逻辑: 通过项目初始化时传入  MybatisXmlReloadProperties prop, List sqlSessionFactories  参数,获取「mybatis-xmlreload-spring-boot-starter」 的配置信息,以及项目中的数据源配置 /**  * 是否启动以及xml路径的配置类  */ private MybatisXmlReloadProperties prop; /**  * 获取项目中初始化完成的SqlSessionFactory列表,对多数据源进行处理  */ private List sqlSessionFactories; public MybatisXmlReload(MybatisXmlReloadProperties prop,          List sqlSessionFactories) {     this.prop = prop;     this.sqlSessionFactories = sqlSessionFactories; }解析配置文件指定的 xml 路径,获取 xml 文件在 target 目录下的位置  // 解析项目所有xml路径,获取xml文件在target目录中的位置 List mapperLocationsTmp = Stream.of(   Optional.of(prop.getMapperLocations())   .orElse(new String[0]))   .flatMap(location -> Stream.of(getResources(patternResolver, location)))   .toList();根据 xml 文件在 target 目录下的位置,进行路径替换找到 xml 文件所在 resources 目录下的位置  // 根据xml文件在target目录下的位置,进行路径替换找到该xml文件在resources目录下的位置 for (Resource mapperLocation : mapperLocationsTmp) {     mapperLocations.add(mapperLocation);     String absolutePath = mapperLocation.getFile().getAbsolutePath();     File tmpFile = new File(absolutePath.replace(CLASS_PATH_TARGET,       MAVEN_RESOURCES));     if (tmpFile.exists()) {         locationPatternSet.add(Path.of(tmpFile.getParent()));         FileSystemResource fileSystemResource =            new FileSystemResource(tmpFile);         mapperLocations.add(fileSystemResource);     } }对 resources 目录的 xml 文件的修改操作进行监听  // 对resources目录的xml文件修改进行监听 List rootPaths = new ArrayList<>(); rootPaths.addAll(locationPatternSet); DirectoryWatcher watcher = DirectoryWatcher.builder()     .paths(rootPaths) // or use paths(directoriesToWatch)     .listener(event -> {         switch (event.eventType()) {             case CREATE: /* file created */                 break;             case MODIFY: /* file modified */                 Path modifyPath = event.path();                 String absolutePath = modifyPath.toFile().getAbsolutePath();                 logger.info("mybatis xml file has changed:" + modifyPath);                 // 执行热加载逻辑...                 break;             case DELETE: /* file deleted */                 break;         }     })     .build(); ThreadFactory threadFactory = r -> {     Thread thread = new Thread(r);     thread.setName("xml-reload");     thread.setDaemon(true);     return thread; }; watcher.watchAsync(new ScheduledThreadPoolExecutor(1, threadFactory));对多个数据源进行遍历,判断修改过的 xml 文件属于那个数据源  // 对多个数据源进行遍历,判断修改过的xml文件属于那个数据源 for (SqlSessionFactory sqlSessionFactory : sqlSessionFactories) {     ... }根据 Configuration 对象获取对应的标签属性  // 根据 Configuration 对象获取对应的标签属性 Configuration targetConfiguration = sqlSessionFactory.getConfiguration(); Class<?> tClass = targetConfiguration.getClass(),    aClass = targetConfiguration.getClass(); if (targetConfiguration.getClass().getSimpleName()                                   .equals("MybatisConfiguration")) {     aClass = Configuration.class; } Set loadedResources = (Set) getFieldValue(     targetConfiguration, aClass, "loadedResources"); loadedResources.clear();  Map resultMaps = (Map) getFieldValue(     targetConfiguration, tClass, "resultMaps"); Map sqlFragmentsMaps = (Map) getFieldValue(     targetConfiguration, tClass, "sqlFragments"); Map mappedStatementMaps =      (Map) getFieldValue(         targetConfiguration, tClass, "mappedStatements");遍历 resources 目录下 xml 文件列表  // 遍历 resources 目录下 xml 文件列表 for (Resource mapperLocation : mapperLocations) {     ... }判断是否是被修改过的 xml 文件,否则跳过  // 判断是否是被修改过的xml文件,否则跳过 if (!absolutePath.equals(mapperLocation.getFile().getAbsolutePath())) {     continue; }解析xml文件,获取修改后的xml文件标签对应的  resultMaps|sqlFragmentsMaps|mappedStatementMaps  的属性并执行替换逻辑,并且兼容 mybatis-plus  的替换逻辑 // 重新解析xml文件,替换Configuration对象的相对应属性 XPathParser parser = new XPathParser(mapperLocation.getInputStream(),      true,      targetConfiguration.getVariables(),      new XMLMapperEntityResolver()); XNode mapperXnode = parser.evalNode("/mapper"); String namespace = mapperXnode.getStringAttribute("namespace"); List resultMapNodes = mapperXnode.evalNodes("/mapper/resultMap"); for (XNode xNode : resultMapNodes) {     String id =          xNode.getStringAttribute("id", xNode.getValueBasedIdentifier());     resultMaps.remove(namespace + "." + id); }  List sqlNodes = mapperXnode.evalNodes("/mapper/sql"); for (XNode sqlNode : sqlNodes) {     String id =          sqlNode.getStringAttribute("id", sqlNode.getValueBasedIdentifier());     sqlFragmentsMaps.remove(namespace + "." + id); }  List msNodes = mapperXnode.evalNodes("select|insert|update|delete"); for (XNode msNode : msNodes) {     String id =          msNode.getStringAttribute("id", msNode.getValueBasedIdentifier());     mappedStatementMaps.remove(namespace + "." + id); }重新加载和解析被修改的 xml 文件  // 9. 重新加载和解析被修改的 xml 文件 try {     XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(         mapperLocation.getInputStream(),         targetConfiguration,         mapperLocation.toString(),          targetConfiguration.getSqlFragments());     xmlMapperBuilder.parse(); } catch (Exception e) {     logger.error(e.getMessage(), e); }三、安装方式在  Spring Boot3.0  中,「mybatis-xmlreload-spring-boot-starter」 在 Maven 项目提供坐标地址如下:      com.wayn     mybatis-xmlreload-spring-boot-starter     3.0.3.m1 在  Spring Boot2.0  Maven 项目提供坐标地址如下:      com.wayn     mybatis-xmlreload-spring-boot-starter     2.0.1.m1 四、使用配置
  「mybatis-xmlreload-spring-boot-starter」  目前只有两个配置属性。mybatis-xml-reload.enabled  默认是 false, 也就是不启用 xml 文件的热加载功能,想要开启的话通过在项目配置文件中设置 mybatis-xml-reload.enabled  为 true。还有一个配置属性是 mybatis-xml-reload.mapper-locations ,执行热加载的 xml 文件路径,这个属性需要手动填写,跟项目中的 mybatis.mapper-locations  保持一直即可。具体配置如下: # mybatis xml文件热加载配置 mybatis-xml-reload:   # 是否开启 xml 热更新,true开启,false不开启,默认为false   enabled: true    # xml文件路径,可以填写多个,逗号分隔。   # eg: `classpath*:mapper/**/*Mapper.xml,classpath*:other/**/*Mapper.xml`   mapper-locations: classpath:mapper/*Mapper.xml五、最后
  欢迎大家使用 「mybatis-xmlreload-spring-boot-starter」 ,这个项目我开源的的,使用中遇到问题可以提交 issue。提交的问题我都会一一查看并回复。再附项目地址: https://github.com/wayn111/mybatis-xmlreload-spring-boot-starter
  最后再说一句,感兴趣的朋友可以点赞加关注,你的支持将是我更新动力。

螃蟹虽香,但这4类人不能多吃大家好,我是中医张玉琴,今天和大家说说关于吃螃蟹的事,建议大家在看之前啊,先点赞收藏,免得等下找不到了!秋风起,蟹脚肥,中秋刚过,不知道大家的饭桌上有没有这样一道菜啊?那就是螃蟹,医生很少提及的天麻醒脑胶囊,不止滋补肝肾,还能治5种病大家好,我是和医生,今天给大家分享一个很不起眼的中成药,医生也很少提及它,今天我给大家讲一讲,它不止可以滋补肝肾,疏经活络,并且还可以调理5种病,建议点赞收藏!在此之前呢,先简单带中国金花绝境爆发!2比4后轰4比0,淘汰美网四强名将,兴奋怒吼作为中国金花前一姐,王蔷打出了一场个人标志性的比赛,首盘4比0大幅领先的情况下一度崩盘,虽然拼下首盘,但依然没顶住对手的疯狂反扑,被拖入决胜盘。第3盘,她在2比4落后的情况下绝境爆安吉透露爵士交易真因!队员之间互不信任,未来两年选秀质量更高北京时间9月13日,爵士队召开新闻发布会,CEO丹尼安吉和总经理扎尼克谈到爵士要进行大交易的原因。此前他们1换10送走戈贝尔,1换8送走了米切尔,还和湖人进行交易,送走贝弗利。我在邓亚萍一家三口近况!16岁儿子打球天赋高,因国籍问题备受质疑近日,不少乒乓球球迷都在关注成都团体世乒赛的举办情况,在北京时间9月11日的时候,国乒正式公布了世乒赛的参赛名单,随着陈幸同拿到阿曼挑战赛的冠军,她将自动获得第5人的资格,虽然小将罚款禁赛!NBA官方介入调查!状元郎这次真的玩大了北京时间9月13日,根据森林狼记者ChrisHine报道,NBA正在对球员爱德华兹社交媒体上发表的言论进行审查,他很有可能会面临罚款和禁赛的处理!状元郎这次真的玩大了事情是这样的,威少拒绝买断!湖人难觅交易第三方,安吉透露爵士交易双核真因虽然森林狼后卫爱德华兹已经为自己在个人社交媒体上发布恐同视频而道歉,但仍然遭来如潮水般的指责与谩骂,森林狼官方不得不对此做出回应,对爱德华兹个人所给同性恋群体造成的冒犯感到抱歉。虽ATP官宣!中国网球创新高,四大满贯官方盛赞大爆发,历史首次ATP官网更新了最新一期排名,张之臻创造中国大陆男子网球新高,世界排名第122位!刚刚结束的美网,中国网球整体表现出色,四大满贯官方如今回顾和盛赞了中国选手的表现。如今ATP最新世宜建立自主可控的车用芯片和操作系统技术体系万物互联时代,操作系统的边界在不断突破,面向人机物融合的泛在计算场景,能够支撑分布式人机物协同应用的操作系统将是产业未来之光。操作系统在经过主机时代PC互联时代移动互联时代之后,来李易峰塌房后,竟上线打了几把游戏,但上线时间暴露了他的焦虑这个中秋节假期,很多人没办法出门旅游,但应该也过得不无聊吧?李易峰的瓜,让很多人度过了这3天假期。先是被爆料塌房,然后李易峰发声明,结果被官方实锤,这一巴掌打的,真的是要多疼有多疼以光为刀!之江实验室研发出新装备将推动光子芯片等器件研发视频加载中9月上旬,之江实验室举行了成立以来最大规模的集中科研成果发布会,面向公众重磅发布了十余项科研成果,高通量激光直写光刻技术与装备就是其中之一。以光为刀,在特殊材料上雕刻出设
为什么要去迪拜旅游?这11个理由够不够!迪拜与您,只有一个心的距离。如果有人要评选全世界最土豪的城市,迪拜一定榜上有名!毕竟关于迪拜这个阿联酋的土豪城市的传奇,相信你们多少都听说过比如,这里的ATM机能吐金块,豪车多到扔奋进的春天丨云南省加快培育和壮大市场主体为高质量跨越式发展赋能高质量发展,拼的是营商环境,靠的是市场主体。近年来,我省市场主体保持平稳增长,但市场发育不足,市场主体总量偏少结构不优质量不高等问题仍然突出。每千人拥有市场主体数量低于全国平均水平消法疑难条款解读网购商品什么情况下可七日无理由退货?河南豫尊律师事务所尤超杰中华人民共和国消费者权益保护法(以下简称消法)是为了保护消费者的合法权益,维护社会经济秩序稳定,促进社会主义市场经济健康发展而制定的一部法律。该法对老百姓消节日文化火起来百姓精神富起来热点观察作者王黎平(黑龙江大学艺术学院副教授)刚刚过去的春节元宵节,各地迎来了久违的热闹景象。线下,丰富多彩的节庆活动在各地竞相开展,老百姓跟着唱起来跳起来舞起来,一片欢乐祥和线上李秀成供词为什么到60年代才公开?倘若早公布,曾国藩恐遭灭门历史开讲历史总会有这样一个周期,那就是每当朝纲混乱恶人当道以及各种自然灾害层出不穷之际,底层人民便会集合起来,为了生存而与当时的统治者展开斗争。中国历史上出现过不知凡几的农民起义,从新规与金融政策看2023年私募基金助力企业发展新趋势伴随着2023年经济温和复苏的预期和政策导向,金融监管也发布了一系列新规进一步维护金融市场稳定推进金融改革,助力实体经济产业升级。作为企业最重要的直接融资渠道之一的私募基金行业,也时装周现场,宋慧乔的刘海程潇身材宋雨琦的鞋,竟成最大关注近日,米兰时装周举办现场,邀请了各国知名明星前去参展,而韩星宋慧乔的出现,却成了全场热点。宋慧乔身穿灰色长款大衣,造型日常朴素,一改往日冷御风格,留起长发刘海造型,多了几分温婉邻家大禹治水13年,三过家门不入,他的儿子不是亲生的?传说在大禹治水的时候,三次路过家门都没有进去,那大禹的妻子是怎么给他生下孩子的呢?这个孩子,究竟是不是大禹的骨肉呢?那一年,中原大洪水,大禹的父亲去治水,九年后,水灾更严重了。当爹这才是春天该有的打扮,从色彩到挑款搭配,照着穿不出错气温慢慢的回暖,春天来了怎么能不准备几件衣服呢,很多人在这时候就有点迷茫了,不知道该怎么去选衣服或者是怎么去搭配,这时候,一个完整的从色彩到选款搭配,都为你一一准备好了,喜欢的可以大散文过一个不忧郁的春天(四章之四)大散文过一个不忧郁的春天(四章)作者崔洪国莺初解语。最是一年春好处。走,一起舞动和享受一个不忧郁的春天吧!在勃发的春意和涌动的春潮中,做一回春天的主人。题记四hr春天在那小朋友眼睛湛江的浪漫不止沙滩海风,藏在烟火气中的法式建筑别有韵味!广州湾不在广州而是湛江市区的旧称当漫步在如今的广州湾街道充满异国风情的法式建筑已融入到现代港城的烟火气中斑驳的墙壁生锈的铁栏带给游人无限遐想为这座城市增添了浓厚的历史韵味广州湾法国