iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >mybatis xml文件热加载怎么实现
  • 389
分享到

mybatis xml文件热加载怎么实现

2023-07-05 17:07:53 389人浏览 独家记忆
摘要

这篇文章主要介绍了mybatis xml文件热加载怎么实现的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇mybatis xml文件热加载怎么实现文章都会有所收获,下面我们一起来看看吧。一、x

这篇文章主要介绍了mybatis xml文件热加载怎么实现的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇mybatis xml文件热加载怎么实现文章都会有所收获,下面我们一起来看看吧。

    一、xml 文件热加载实现原理

    1.1 xml 文件怎么样解析

    Spring Boot + Mybatis的常规项目中,通过 org.mybatis.spring.sqlSessionFactoryBean 这个类的 buildSqlSessionFactory() 方法完成对 xml 文件的加载逻辑,这个方法只会在自动配置类 MybatisAutoConfiguration 初始化操作时进行调用。这里把 buildSqlSessionFactory() 方法中 xml 解析核心部分进行展示如下:

    mybatis xml文件热加载怎么实现

    • 通过遍历 this.mapperLocations 数组(这个对象就是保存了编译后的所有 xml 文件)完成对所有 xml 文件的解析以及加载进内存。this.mapperLocations 解析逻辑在 MybatisProperties 类的 resolveMapperLocations() 方法中,它会解析 mybatis.mapperLocations 属性中的 xml 路径,将编译后的 xml 文件读取进 Resource 数组中。路径解析的核心逻辑在 PathMatchingResourcePatternResolver 类的 getResources(String locationPattern) 方法中。大家有兴趣可以自己研读一下,这里不多做介绍。

    通过 xmlMapperBuilder.parse() 方法解析 xml 文件各个节点,解析方法如下:

    mybatis xml文件热加载怎么实现

    简单来说,这个方法会解析 xml 文件中的 mapper|resultMap|cache|cache-ref|sql|select|insert|update|delete 等标签。将他们保存在 org.apache.ibatis.session.Configuration 类的对应属性中,如下展示:

    mybatis xml文件热加载怎么实现

    到这里,我们就知道了 Mybatis 对 xml 文件解析是通过 xmlMapperBuilder.parse() 方法完成并且只会在项目启动时加载 xml 文件。

    1.2 实现思路

    通过对上述 xml 解析逻辑进行分析,我们可以通过监听 xml 文件的修改,当监听到修改操作时,直接调用 xmlMapperBuilder.parse() 方法,将修改过后的 xml 文件进行重新解析,并替换内存中的对应属性以此完成热加载操作。这里也就引出了本文所讲的主角:mybatis-xmlreload-spring-boot-starter

    二、mybatis-xmlreload-spring-boot-starter 登场

    mybatis-xmlreload-spring-boot-starter 这个项目完成了博主上述的实现思路,使用技术如下:

    • 修改 xml 文件的加载逻辑。在原用 mybatis-spring 中,只会加载项目编译过后的 xml 文件,也就是 target 目录下的 xml 文件。但是在mybatis-xmlreload-spring-boot-starter中,我修改了这一点,它会加载项目 resources 目录下的 xml 文件,这样对于 xml 文件的修改操作是可以立马触发热加载的。

    • 通过 io.methvin.directory-watcher 来监听 xml 文件的修改操作,它底层是通过 java.NIOWatchService 来实现。

    • 兼容 Mybatis-plus3.0,核心代码兼容了 Mybatis-plus 自定义的 com.baomidou.mybatisplus.core.MybatisConfiguration 类,任然可以使用 xml 文件热加载功能。

    2.1 核心代码

    项目的结构如下:

    mybatis xml文件热加载怎么实现

    核心代码在 MybatisXmlReload 类中,代码展示:

    public class MybatisXmlReload {    private static final Logger logger = LoggerFactory.getLogger(MybatisXmlReload.class);        private MybatisXmlReloadProperties prop;        private List<SqlSessionFactory> sqlSessionFactories;    public MybatisXmlReload(MybatisXmlReloadProperties prop, List<SqlSessionFactory> sqlSessionFactories) {        this.prop = prop;        this.sqlSessionFactories = sqlSessionFactories;    }    public void xmlReload() throws IOException {        PathMatchingResourcePatternResolver patternResolver = new PathMatchingResourcePatternResolver();        String CLASS_PATH_TARGET = File.separator + "target" + File.separator + "classes";        String Maven_RESOURCES = "/src/main/resources";        // 1. 解析项目所有xml路径,获取xml文件在target目录中的位置        List<Resource> mapperLocationsTmp = Stream.of(Optional.of(prop.getMapperLocations()).orElse(new String[0]))                .flatMap(location -> Stream.of(getResources(patternResolver, location))).toList();        List<Resource> mapperLocations = new ArrayList<>(mapperLocationsTmp.size() * 2);        Set<Path> locationPatternSet = new HashSet<>();        // 2. 根据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);            }        }        // 3. 对resources目录的xml文件修改进行监听        List<Path> rootPaths = new ArrayList<>();        rootPaths.addAll(locationPatternSet);        DirectoryWatcher watcher = DirectoryWatcher.builder()                .paths(rootPaths) // or use paths(directoriesToWatch)                .listener(event -> {                    switch (event.eventType()) {                        case CREATE:                             break;                        case MODIFY:                             Path modifyPath = event.path();                            String absolutePath = modifyPath.toFile().getAbsolutePath();                            logger.info("mybatis xml file has changed:" + modifyPath);                            // 4. 对多个数据源进行遍历,判断修改过的xml文件属于那个数据源                            for (SqlSessionFactory sqlSessionFactory : sqlSessionFactories) {                                try {                                    // 5. 获取Configuration对象                                    Configuration targetConfiguration = sqlSessionFactory.getConfiguration();                                    Class<?> tClass = targetConfiguration.getClass(), aClass = targetConfiguration.getClass();                                    if (targetConfiguration.getClass().getSimpleName().equals("MybatisConfiguration")) {                                        aClass = Configuration.class;                                    }                                    Set<String> loadedResources = (Set<String>) getFieldValue(targetConfiguration, aClass, "loadedResources");                                    loadedResources.clear();                                    Map<String, ResultMap> resultMaps = (Map<String, ResultMap>) getFieldValue(targetConfiguration, tClass, "resultMaps");                                    Map<String, Xnode> sqlFragmentsMaps = (Map<String, XNode>) getFieldValue(targetConfiguration, tClass, "sqlFragments");                                    Map<String, MappedStatement> mappedStatementMaps = (Map<String, MappedStatement>) getFieldValue(targetConfiguration, tClass, "mappedStatements");                                    // 6. 遍历xml文件                                    for (Resource mapperLocation : mapperLocations) {                                        // 7. 判断是否是被修改过的xml文件,否则跳过                                        if (!absolutePath.equals(mapperLocation.getFile().getAbsolutePath())) {                                            continue;                                        }                                        // 8. 重新解析xml文件,替换Configuration对象的相对应属性                                        XPathParser parser = new XPathParser(mapperLocation.getInputStream(), true, targetConfiguration.getVariables(), new XMLMapperEntityResolver());                                        XNode mapperXnode = parser.evalNode("/mapper");                                        List<XNode> resultMapNodes = mapperXnode.evalNodes("/mapper/resultMap");                                        String namespace = mapperXnode.getStringAttribute("namespace");                                        for (XNode xNode : resultMapNodes) {                                            String id = xNode.getStringAttribute("id", xNode.getValueBasedIdentifier());                                            resultMaps.remove(namespace + "." + id);                                        }                                        List<XNode> sqlNodes = mapperXnode.evalNodes("/mapper/sql");                                        for (XNode sqlNode : sqlNodes) {                                            String id = sqlNode.getStringAttribute("id", sqlNode.getValueBasedIdentifier());                                            sqlFragmentsMaps.remove(namespace + "." + id);                                        }                                        List<XNode> msNodes = mapperXnode.evalNodes("select|insert|update|delete");                                        for (XNode msNode : msNodes) {                                            String id = msNode.getStringAttribute("id", msNode.getValueBasedIdentifier());                                            mappedStatementMaps.remove(namespace + "." + id);                                        }                                        try {                                            // 9. 重新加载和解析被修改的 xml 文件                                            XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(),                                                    targetConfiguration, mapperLocation.toString(), targetConfiguration.getSqlFragments());                                            xmlMapperBuilder.parse();                                        } catch (Exception e) {                                            logger.error(e.getMessage(), e);                                        }                                        logger.info("Parsed mapper file: '" + mapperLocation + "'");                                    }                                } catch (Exception e) {                                    logger.error(e.getMessage(), e);                                }                            }                            break;                        case DELETE:                             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));    }        private Resource[] getResources(PathMatchingResourcePatternResolver patternResolver, String location) {        try {            return patternResolver.getResources(location);        } catch (IOException e) {            return new Resource[0];        }    }        private static Object getFieldValue(Configuration targetConfiguration, Class<?> aClass,                                        String filed) throws NoSuchFieldException, IllegalAccessException {        Field resultMapsField = aClass.getDeclaredField(filed);        resultMapsField.setAccessible(true);        return resultMapsField.get(targetConfiguration);    }}

    代码执行逻辑:

    • 解析配置文件指定的 xml 路径,获取 xml 文件在 target 目录下的位置

    • 根据 xml 文件在 target 目录下的位置,进行路径替换找到 xml 文件所在 resources 目录下的位置

    • 对 resources 目录的 xml 文件的修改操作进行监听

    • 对多个数据源进行遍历,判断修改过的 xml 文件属于那个数据源

    • 根据 Configuration 对象获取对应的标签属性

    • 遍历 resources 目录下 xml 文件列表

    • 判断是否是被修改过的 xml 文件,否则跳过

    • 解析被修改的 xml 文件,替换 Configuration 对象中的相对应属性

    • 重新加载和解析被修改的 xml 文件

    2.2 安装方式

    • Spring Boot3.0 中,当前博主提供了mybatis-xmlreload-spring-boot-starter在 Maven 项目中的坐标地址如下

    <dependency>    <groupId>com.wayn</groupId>    <artifactId>mybatis-xmlreload-spring-boot-starter</artifactId>    <version>3.0.3.m1</version></dependency>
    • Spring Boot2.0 Maven 项目中的坐标地址如下

    <dependency>    <groupId>com.wayn</groupId>    <artifactId>mybatis-xmlreload-spring-boot-starter</artifactId>    <version>2.0.1.m1</version></dependency>

    2.3 使用配置

    Maven 项目写入mybatis-xmlreload-spring-boot-starter坐标后即可使用本项目功能,默认是不启用 xml 文件的热加载功能,想要开启的话通过在项目配置文件中设置 mybatis-xml-reload.enabled 为 true,并指定 mybatis-xml-reload.mapper-locations 属性,也就是 xml 文件位置即可启动。具体配置如下:

    # 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 xml文件热加载怎么实现”这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对“mybatis xml文件热加载怎么实现”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注编程网精选频道。

    --结束END--

    本文标题: mybatis xml文件热加载怎么实现

    本文链接: https://www.lsjlt.com/news/353435.html(转载时请注明来源链接)

    有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

    本篇文章演示代码以及资料文档资料下载

    下载Word文档到电脑,方便收藏和打印~

    下载Word文档
    猜你喜欢
    • mybatis xml文件热加载怎么实现
      这篇文章主要介绍了mybatis xml文件热加载怎么实现的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇mybatis xml文件热加载怎么实现文章都会有所收获,下面我们一起来看看吧。一、x...
      99+
      2023-07-05
    • 关于MyBatis中Mapper XML热加载优化
      前几天在琢磨mybatis xml热加载的问题,原理还是通过定时扫描xml文件去跟新,但放到项目上就各种问题,由于用了mybatisplus死活不生效。本着"即插即用&qu...
      99+
      2024-04-02
    • Mybatis中mapper.xml实现热加载介绍
      目录背景目的实现方式总结背景 有些需求可能更新sql的频率较高,但又不想频繁发布java应用程序,所以mybatis-mapper.xml热加载的需求顺势而出。 目的 只需调起加载m...
      99+
      2024-04-02
    • java热加载怎么实现的
      Java的热加载可以通过使用Java的反射机制和自定义的类加载器来实现。下面是一种常见的实现方式: 创建一个自定义的类加载器,继...
      99+
      2023-10-25
      java
    • mybatis一直加载xml怎么解决
      这篇文章主要讲解了“mybatis一直加载xml怎么解决”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“mybatis一直加载xml怎么解决”吧!mybatis一直加载xml,找到错误我们在写...
      99+
      2023-06-29
    • LINQ XML树加载怎么实现
      本篇内容介绍了“LINQ XML树加载怎么实现”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!LINQ XML树加载通过XElement类,有...
      99+
      2023-06-17
    • JS如何实现加载和读取XML文件
      这篇文章给大家分享的是有关JS如何实现加载和读取XML文件的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。有时在开发时用到 JS 加载和读取XML文件的情况,写下提供参考,这里主要...
      99+
      2024-04-02
    • spring中怎么加载xml配置文件
      这篇文章主要讲解了“spring中怎么加载xml配置文件”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“spring中怎么加载xml配置文件”吧!spring 中加载xml配置文件的方式spr...
      99+
      2023-06-03
    • java热加载是怎么实现的
      Java热加载是通过类加载器(ClassLoader)实现的。在Java应用程序运行时,类加载器负责加载类文件并将其转换为字节码。当...
      99+
      2024-04-02
    • MyBatis中怎么实现懒加载
      在MyBatis中,可以通过配置来实现懒加载。在映射文件中使用lazyLoadingEnabled来配置是否启用懒加载,以及使用se...
      99+
      2024-04-08
      MyBatis
    • Angular4如何实现热加载
      这篇文章将为大家详细讲解有关Angular4如何实现热加载,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。安装插件npm install @angula...
      99+
      2024-04-02
    • MyBatis加载映射文件和动态代理的实现
      目录前言正文一. 映射文件/映射接口的配置二. 加载映射文件的源码分析三. MyBatis中的动态代理总结前言 本篇文章将分析MyBatis在配置文件加载的过程中,如何解析映射文件中...
      99+
      2023-05-19
      MyBatis加载映射文件 MyBatis动态代理
    • jQuery如何加载及解析XML文件
      这篇文章将为大家详细讲解有关jQuery如何加载及解析XML文件,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。具体如下:1、简述XML(eXtensible Markup...
      99+
      2024-04-02
    • MyBatis懒加载如何实现
      这篇文章主要介绍“MyBatis懒加载如何实现”,在日常操作中,相信很多人在MyBatis懒加载如何实现问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”MyBatis懒加载如何实现”的疑惑有所帮助!接下来,请跟...
      99+
      2023-06-30
    • Python怎么实现从文件中加载数据
      这篇文章主要介绍“Python怎么实现从文件中加载数据”,在日常操作中,相信很多人在Python怎么实现从文件中加载数据问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Python怎么实现从文件中加载数据”的疑...
      99+
      2023-06-30
    • Spring Boot热加载jar实现动态插件的思路
      目录一、背景二、热加载 jar 包三、动态注册 Bean3.1. 启动时注册 Bean3.2. 运行时注册 Bean四、总结五、完整 demo 一、背景 动态插件化编程是一件很酷的事...
      99+
      2024-04-02
    • pytorch怎么实现加载保存查看checkpoint文件
      这篇“pytorch怎么实现加载保存查看checkpoint文件”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“pytorch...
      99+
      2023-07-02
    • Mybatis中xml的动态sql怎么实现
      这篇文章主要介绍“Mybatis中xml的动态sql怎么实现”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Mybatis中xml的动态sql怎么实现”文章能帮助大家解决问题。动态SQL简介动态 SQ...
      99+
      2023-07-02
    • 怎么在mybatis框架中查询xml映射文件
      本篇文章为大家展示了怎么在mybatis框架中查询xml映射文件,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。什么是Mybatis框架?MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、...
      99+
      2023-06-14
    • Node.js怎么实现热重载页面
      这篇文章主要介绍了Node.js怎么实现热重载页面的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Node.js怎么实现热重载页面文章都会有所收获,下面我们一起来看看吧。热重载所谓热重载就是页面每次改动,不需要手...
      99+
      2023-07-04
    软考高级职称资格查询
    编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
    • 官方手机版

    • 微信公众号

    • 商务合作