开发的时候,写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. solr 高亮显示

    官网:https://lucene.apache.org/solr/guide/6_6/highlighting.html#Highlighting-TheUnifiedHighlighter 前言 ...

  2. Spark Streaming数据清理内幕彻底解密

    本讲从二个方面阐述: 数据清理原因和现象 数据清理代码解析 Spark Core从技术研究的角度讲 对Spark Streaming研究的彻底,没有你搞不定的Spark应用程序. Spark Stre ...

  3. mybatis paramType String Error

    我这么写的 <select id="getHotPlayersByDate" parameterType="java.lang.String" resul ...

  4. keepalived 配置需要注意的问题

    keepalived 配置过程中遇到了一些问题,做个记录: 1.selinux的影响:keepalived配置了vrrp_script脚本总是无效      注:脚本返回值0代表成功,1或其他非0值代 ...

  5. 虚拟机VMware12.0安装centos 6.5+VMware中虚拟机网络模式区分

    之前的步骤一路next,有设置内存大小的根据机器的配置设置一下即可. 需要注意的地方, 下面是对于简化版进行设置的步骤 虚拟机网络模式 1.桥接模式 在桥接模式下,VMware虚拟机里的系统就像是 局 ...

  6. 嵌入web字体

    @font-face模块         可以帮助我们轻松解决Web页面中使用优雅字体的方式,而且我们可以根据需要自定义多种字体,但是每个@font-face只能定义一种,若需要多个字体就启用多个@f ...

  7. location.href

      location.href用法 CreateTime--2018年2月22日15:22:02 Author:Marydon 1.在当前页面打开URL页面 // 方式一 window.locatio ...

  8. oracle expdp导入时 提示“ORA-39002: 操作无效 ORA-39070: 无法打开日志文件 ”

    1.导出数据库的时候报错 expdp zz/zz@orcl directory=exp_dp dumpfile=zz_20170520.dump logfile=zz_20170520.log   2 ...

  9. 无法删除尚未附加的实体-linq中使用反射删除记录出现错误,应该如何解决。

    db.airports.Attach(data); db.airports.DeleteOnSubmit(data); db.SubmitChanges();

  10. C#线程同步技术(一) lock 语句

    开篇语: 上班以后,烦恼少了,至少是没有什么好烦的了,只要负责好自己的工作就可以了,因此也有更多的时间去探索自己喜欢的程序.买回来的书已经看了一半,DEMO也敲了不少,昨晚终于在这里开BLOG,记录一 ...