自我18年使用Mybaits以来,开发环境中如果修改了xml文件后,只有重启项目才能生效,如果小项目重启还好,但是对于一个重启需要十几分钟的大型项目来说,这就非常耗时了。开发人员因为修改了xml文件少量内容,比如添加一个逗号、查询增加一个字段或者修改一个bug等,就需要重启整个项目,这就非常痛苦了。 所以在这里给大家推荐一个实现了Mybatisxml文件热加载的项目,mybatisxmlreloadspringbootstarter。它能够帮助我们在SpringBootMybatis的开发环境中修改xml后,不需要重启项目就能让修改过后xml文件立即生效,实现热加载功能。这里给出项目地址:https:github。comwayn111mybatisxmlreloadspringbootstarter欢迎大家关注,点个star ps:mybatisxmlreloadspringbootstarter目前3。0。3。m1版本实现了xml文件修改已有内容,比如修改sql语句、添加查询字段、添加查询条件等,可以实现热加载功能。但是对于xml文件添加insertupdatedeleteselect标签等内容后,是无法实现热加载的。众所周知,在Idea环境进行Java开发,在方法内修改方法内容是可以热加载的。但是添加新方法、添加方法参数,修改方法参数,修改方法返回值等都是无法直接热加载的。一、mybatisxmlreloadspringbootstarter使用 mybatisxmlreloadspringbootstarter原理:修改xml文件的加载逻辑。在普通的mybatisspring项目中,默认只会加载项目编译过后的xml文件,也就是target目录下的xml文件。但是在mybatisxmlreloadspringbootstarter中,修改了这一点,它会加载项目resources目录下的xml文件,这样用户对于resources目录下xml文件的修改操作是可以立即触发热加载的。通过io。methvin。directorywatcher项目来监听xml文件的修改操作,它底层是通过java。nio的WatchService来实现,当我们监听了整个resources目录后,xml文件的修改会立马触发MODIFY事件。通过mybatisspring项目原生的xmlMapperBuilder。parse()方法重新加载解析修改过后的xml文件来保证项目对于Mybatis的兼容性处理。二、技术原理 mybatisxmlreloadspringbootstarter代码结构如下: 核心代码在MybatisXmlReload类中,执行逻辑:通过项目初始化时传入MybatisXmlReloadPropertiesprop,ListsqlSessionFactories参数,获取mybatisxmlreloadspringbootstarter的配置信息,以及项目中的数据源配置是否启动以及xml路径的配置类privateMybatisXmlReloadPropertiesprop;获取项目中初始化完成的SqlSessionFactory列表,对多数据源进行处理privateListSqlSessionFactorysqlSessionFactories;publicMybatisXmlReload(MybatisXmlReloadPropertiesprop,ListSqlSessionFactorysqlSessionFactories){this。propprop;this。sqlSessionFactoriessqlSessionFactories;}解析配置文件指定的xml路径,获取xml文件在target目录下的位置解析项目所有xml路径,获取xml文件在target目录中的位置ListResourcemapperLocationsTmpStream。of(Optional。of(prop。getMapperLocations())。orElse(newString〔0〕))。flatMap(locationStream。of(getResources(patternResolver,location)))。toList();根据xml文件在target目录下的位置,进行路径替换找到xml文件所在resources目录下的位置根据xml文件在target目录下的位置,进行路径替换找到该xml文件在resources目录下的位置for(ResourcemapperLocation:mapperLocationsTmp){mapperLocations。add(mapperLocation);StringabsolutePathmapperLocation。getFile()。getAbsolutePath();FiletmpFilenewFile(absolutePath。replace(CLASSPATHTARGET,MAVENRESOURCES));if(tmpFile。exists()){locationPatternSet。add(Path。of(tmpFile。getParent()));FileSystemResourcefileSystemResourcenewFileSystemResource(tmpFile);mapperLocations。add(fileSystemResource);}}对resources目录的xml文件的修改操作进行监听对resources目录的xml文件修改进行监听ListPathrootPathsnewArrayList();rootPaths。addAll(locationPatternSet);DirectoryWatcherwatcherDirectoryWatcher。builder()。paths(rootPaths)orusepaths(directoriesToWatch)。listener(event{switch(event。eventType()){caseCREATE:filecreatedbreak;caseMODIFY:filemodifiedPathmodifyPathevent。path();StringabsolutePathmodifyPath。toFile()。getAbsolutePath();logger。info(mybatisxmlfilehaschanged:modifyPath);执行热加载逻辑。。。break;caseDELETE:filedeletedbreak;}})。build();ThreadFactorythreadFactoryr{ThreadthreadnewThread(r);thread。setName(xmlreload);thread。setDaemon(true);returnthread;};watcher。watchAsync(newScheduledThreadPoolExecutor(1,threadFactory));对多个数据源进行遍历,判断修改过的xml文件属于那个数据源对多个数据源进行遍历,判断修改过的xml文件属于那个数据源for(SqlSessionFactorysqlSessionFactory:sqlSessionFactories){。。。}根据Configuration对象获取对应的标签属性根据Configuration对象获取对应的标签属性ConfigurationtargetConfigurationsqlSessionFactory。getConfiguration();Classlt;?tClasstargetConfiguration。getClass(),aClasstargetConfiguration。getClass();if(targetConfiguration。getClass()。getSimpleName()。equals(MybatisConfiguration)){aClassConfiguration。class;}SetStringloadedResources(SetString)getFieldValue(targetConfiguration,aClass,loadedResources);loadedResources。clear();MapString,ResultMapresultMaps(MapString,ResultMap)getFieldValue(targetConfiguration,tClass,resultMaps);MapString,XNodesqlFragmentsMaps(MapString,XNode)getFieldValue(targetConfiguration,tClass,sqlFragments);MapString,MappedStatementmappedStatementMaps(MapString,MappedStatement)getFieldValue(targetConfiguration,tClass,mappedStatements);遍历resources目录下xml文件列表遍历resources目录下xml文件列表for(ResourcemapperLocation:mapperLocations){。。。}判断是否是被修改过的xml文件,否则跳过判断是否是被修改过的xml文件,否则跳过if(!absolutePath。equals(mapperLocation。getFile()。getAbsolutePath())){continue;}解析xml文件,获取修改后的xml文件标签对应的resultMapssqlFragmentsMapsmappedStatementMaps的属性并执行替换逻辑,并且兼容mybatisplus的替换逻辑重新解析xml文件,替换Configuration对象的相对应属性XPathParserparsernewXPathParser(mapperLocation。getInputStream(),true,targetConfiguration。getVariables(),newXMLMapperEntityResolver());XNodemapperXnodeparser。evalNode(mapper);StringnamespacemapperXnode。getStringAttribute(namespace);ListXNoderesultMapNodesmapperXnode。evalNodes(mapperresultMap);for(XNodexNode:resultMapNodes){StringidxNode。getStringAttribute(id,xNode。getValueBasedIdentifier());resultMaps。remove(namespace。id);}ListXNodesqlNodesmapperXnode。evalNodes(mappersql);for(XNodesqlNode:sqlNodes){StringidsqlNode。getStringAttribute(id,sqlNode。getValueBasedIdentifier());sqlFragmentsMaps。remove(namespace。id);}ListXNodemsNodesmapperXnode。evalNodes(selectinsertupdatedelete);for(XNodemsNode:msNodes){StringidmsNode。getStringAttribute(id,msNode。getValueBasedIdentifier());mappedStatementMaps。remove(namespace。id);}重新加载和解析被修改的xml文件9。重新加载和解析被修改的xml文件try{XMLMapperBuilderxmlMapperBuildernewXMLMapperBuilder(mapperLocation。getInputStream(),targetConfiguration,mapperLocation。toString(),targetConfiguration。getSqlFragments());xmlMapperBuilder。parse();}catch(Exceptione){logger。error(e。getMessage(),e);}三、安装方式在SpringBoot3。0中,mybatisxmlreloadspringbootstarter在Maven项目提供坐标地址如下:dependencygroupIdcom。wayngroupIdmybatisxmlreloadspringbootstarterartifactIdversion3。0。3。m1versiondependency在SpringBoot2。0Maven项目提供坐标地址如下:dependencygroupIdcom。wayngroupIdmybatisxmlreloadspringbootstarterartifactIdversion2。0。1。m1versiondependency四、使用配置 mybatisxmlreloadspringbootstarter目前只有两个配置属性。mybatisxmlreload。enabled默认是false,也就是不启用xml文件的热加载功能,想要开启的话通过在项目配置文件中设置mybatisxmlreload。enabled为true。还有一个配置属性是mybatisxmlreload。mapperlocations,执行热加载的xml文件路径,这个属性需要手动填写,跟项目中的mybatis。mapperlocations保持一直即可。具体配置如下:mybatisxml文件热加载配置mybatisxmlreload:是否开启xml热更新,true开启,false不开启,默认为falseenabled:truexml文件路径,可以填写多个,逗号分隔。eg:classpath:mapperMapper。xml,classpath:otherMapper。xmlmapperlocations:classpath:mapperMapper。xml五、最后 欢迎大家使用mybatisxmlreloadspringbootstarter,这个项目我开源的的,使用中遇到问题可以提交issue。提交的问题我都会一一查看并回复。再附项目地址:https:github。comwayn111mybatisxmlreloadspringbootstarter 最后再说一句,感兴趣的朋友可以点赞加关注,你的支持将是我更新动力。