开发的时候,写Mybatis Mapper.xml文件的时候,每次修改SQL都需要重启服务,感觉十分麻烦,于是尝试写了一个Mybatis的Mapper.xml热加载。

能在修改Mapper.xml之后重新加载Mybatis,开发的时候可以用一下。

Spring配置:

<bean id="MybatisMapperDynamicLoader" class="com.teststartup.MybatisMapperDynamicLoader" />

Java代码:

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask; import org.apache.ibatis.builder.xml.XMLMapperBuilder;
import org.apache.ibatis.executor.ErrorContext;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.NestedIOException;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver; public class MybatisMapperDynamicLoader implements InitializingBean, ApplicationContextAware { private final HashMap<String, String> mappers = new HashMap<String, String>();
private volatile ConfigurableApplicationContext context = null;
private volatile Scanner scanner = null; @Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.context = (ConfigurableApplicationContext) applicationContext;
} @Override
public void afterPropertiesSet() throws Exception {
try {
scanner = new Scanner();
new Timer(true).schedule(new TimerTask() {
public void run() {
try {
if (scanner.isChanged()) {
System.out.println("load mapper.xml");
scanner.reloadXML();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}, 10 * 1000, 5 * 1000);
} catch (Exception e1) {
e1.printStackTrace();
}
} @SuppressWarnings("unchecked")
class Scanner {
private static final String XML_RESOURCE_PATTERN = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + "**/*Sql.xml";
private final ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
public Scanner() throws IOException {
Resource[] resources = findResource();
if (resources != null) {
for (Resource resource : resources) {
String key = resource.getURI().toString();
String value = getMd(resource);
mappers.put(key, value);
}
}
}
public void reloadXML() throws Exception {
SqlSessionFactory factory = context.getBean(SqlSessionFactory.class);
Configuration configuration = factory.getConfiguration();
removeConfig(configuration);
for (Resource resource : findResource()) {
try {
XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(resource.getInputStream(), configuration, resource.toString(), configuration.getSqlFragments());
xmlMapperBuilder.parse();
} finally {
ErrorContext.instance().reset();
}
}
}
private void removeConfig(Configuration configuration) throws Exception {
Class<?> classConfig = configuration.getClass();
clearMap(classConfig, configuration, "mappedStatements");
clearMap(classConfig, configuration, "caches");
clearMap(classConfig, configuration, "resultMaps");
clearMap(classConfig, configuration, "parameterMaps");
clearMap(classConfig, configuration, "keyGenerators");
clearMap(classConfig, configuration, "sqlFragments");
clearSet(classConfig, configuration, "loadedResources");
}
private void clearMap(Class<?> classConfig, Configuration configuration, String fieldName) throws Exception {
Field field = classConfig.getDeclaredField(fieldName);
field.setAccessible(true);
((Map) field.get(configuration)).clear();
}
private void clearSet(Class<?> classConfig, Configuration configuration, String fieldName) throws Exception {
Field field = classConfig.getDeclaredField(fieldName);
field.setAccessible(true);
((Set) field.get(configuration)).clear();
}
public boolean isChanged() throws IOException {
boolean isChanged = false;
for (Resource resource : findResource()) {
String key = resource.getURI().toString();
String value = getMd(resource);
if (!value.equals(mappers.get(key))) {
isChanged = true;
mappers.put(key, value);
}
}
return isChanged;
}
private Resource[] findResource() throws IOException {
return resourcePatternResolver.getResources(XML_RESOURCE_PATTERN);
}
private String getMd(Resource resource) throws IOException {
return new StringBuilder().append(resource.contentLength()).append("-").append(resource.lastModified()).toString();
}
}
}

Mybatis热加载Mapper.xml的更多相关文章

  1. mybatis plus3.1.0 热加载mapper

    今天又开始写业务代码了,每次修改SQL都要重启服务,实在是浪费时间. 想起之前研究过的<mybatis plus3.1.0 热加载mapper>,一直没有成功,今天静下心来分析了问题,终于 ...

  2. DB数据源之SpringBoot+MyBatis踏坑过程(二)手工配置数据源与加载Mapper.xml扫描

    DB数据源之SpringBoot+MyBatis踏坑过程(二)手工配置数据源与加载Mapper.xml扫描 liuyuhang原创,未经允许进制转载  吐槽之后应该有所改了,该方式可以作为一种过渡方式 ...

  3. DB数据源之SpringBoot+MyBatis踏坑过程(三)手工+半自动注解配置数据源与加载Mapper.xml扫描

    DB数据源之SpringBoot+MyBatis踏坑过程(三)手工+半自动注解配置数据源与加载Mapper.xml扫描 liuyuhang原创,未经允许禁止转载    系列目录连接 DB数据源之Spr ...

  4. 在mybatis 中批量加载mapper.xml

    可以直接加载一个包文件名,将这个包里的所有*mapper.xml文件加载进来. 指定mapper接口的包名,mybatis自动扫描包下边所有mapper接口进行加载: 必须按一定的标准:即xml文件和 ...

  5. mybatis热加载的实现

    最近在使用mybatis,由于是刚刚开始用,用的并不顺手,目前是感觉有2个地方非常的不好用: 1.mybatis调试不方便 由于dao层只有接口,实现只是一个map的xml文件,想加断点都没有地方加, ...

  6. (转)mybatis热加载(依赖mybatis-plus插件)的实现

    最近在使用mybatis,由于是刚刚开始用,用的并不顺手,目前是感觉有2个地方非常的不好用: 1.mybatis调试不方便 由于dao层只有接口,实现只是一个map的xml文件,想加断点都没有地方加, ...

  7. 抛开 Spring ,你知道 MyBatis 加载 Mapper 的底层原理吗?

    原文链接:抛开 Spring ,你知道 MyBatis 加载 Mapper 的底层原理吗? 大家都知道,利用 Spring 整合 MyBatis,我们可以直接利用 @MapperScan 注解或者 @ ...

  8. 基于JRebel开发的MybatisPlus热加载插件

    前言 前天项目中使用了mybatis-plus,但是搭配Jrebel开发项目时,发现修改mapper的xml,或者mapper方法中的注解,Jrebel并没有能够reload mapper.于是就有了 ...

  9. mybatis配置加载源码概述

    Mybatis框架里,有两种配置文件,一个是全局配置文件config.xml,另一个是对应每个表的mapper.xml配置文件.Mybatis框架启动时,先加载config.xml, 在加载每个map ...

随机推荐

  1. jquery 获取父窗口的元素、父窗口、子窗口

    一.获取父窗口元素: $("#父窗口元素ID",window.parent.document):对应javascript版本为window.parent.document.getE ...

  2. 【转】Go maps in action

    原文: https://blog.golang.org/go-maps-in-action ------------------------------------------------------ ...

  3. in_array() 和array_search的区别

    在判断字符串是否在某个数组里面的时候,我们会经常用到in_array()和array_search这两个函数. 他们的用法都是在数组中搜索给定的值,但是不同的是, in_array()给定的值 val ...

  4. ssh远程连接

    SSH 是Secure Shell protocol 的简写,经由将联机的封包加密的技术,来进行资料的传递,安全. telnet: tcp:23 基于字符 任意客户端登录远程服务器 明文 无需验证 易 ...

  5. MP3中设置播放顺序的软件《闪存式MP3伴侣》

    给姥爷买了一个插卡音箱,里面拷贝了几百段评书,每一段评书都是一个mp3文件,虽然插卡音箱会自动一个文件一个文件自动播放,可是比较郁闷的是评书的播放顺序完全是乱的,毫无规律可寻,本来我的mp3文件的文件 ...

  6. ffmpeg怎么样处理网络流

    http://blog.sina.com.cn/s/blog_675142dc01010otk.html 最近遇到好几个人在问ffmpeg如何处理网络流,刚好前段时间也在做这方面,抽空整理了下,把主要 ...

  7. JMeter 九:给请求加断言

    参考:http://jmeter.apache.org/usermanual/component_reference.html#assertions 背景 在测试过程中,我们需要对某个请求的结果进行判 ...

  8. 两种方法连接MySql数据库

    .用MySQLDriverCS连接MySQL数据库 先下载和安装MySQLDriverCS,在安装文件夹下面找到MySQLDriver.dll,然后将MySQLDriver.dll添加引用到项目中. ...

  9. apache相关配置

    PHP配置 php.ini-development:开发时的php.ini配置 php.ini-production:项目运行时的php.ini配置 复制php.ini-development文件到C ...

  10. Docker学习笔记之一,搭建一个JAVA Tomcat运行环境(转)

    前言 Docker旨在提供一种应用程序的自动化部署解决方案,在 Linux 系统上迅速创建一个容器(轻量级虚拟机)并部署和运行应用程序,并通过配置文件可以轻松实现应用程序的自动化安装.部署和升级,非常 ...