代码

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.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.stereotype.Repository; /**
* 定时扫描并动态加载mybatis的SQL配置文件,刷新sql mapper cache,可以在修改xml后不用重启tomcat也能生效
*
* 扫描参数:<br/>
* 1.RELOAD_INTERVAL:扫描时间间隔=3s<br/>
* 2.XML_RESOURCE_PATTERN:当前CLASSPATH下xml通配符<br/>
* 3.SESSION_FACTORY_BEAN_NAME:数据源session factory名称<br/>
* 备注:本类在开发环境下使用,正式发布后注释掉applicationContext.xml中id=MyBatisDynamicLoader的bean
*
* @author MF
* @version 1.0
*/
@Repository("XMLMapperLoader")
public class XMLMapperLoader implements InitializingBean, ApplicationContextAware {
// 扫描时间间隔
private static final long RELOAD_INTERVAL = 3000; 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()) {
scanner.reloadXML();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}, 5 * 1000, RELOAD_INTERVAL);
} catch (Exception e1) {
e1.printStackTrace();
}
} class Scanner {
private static final String XML_RESOURCE_PATTERN =
ResourcePatternResolver.CLASSPATH_URL_PREFIX + "mapper/*/*.xml";
private static final String SESSION_FACTORY_BEAN_NAME = "sqlSessionFactory"; 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);
/* 这里指定数据源,多数据源环境使用 */
System.out.println("========== Reload SQL Cache on [" + SESSION_FACTORY_BEAN_NAME + "] ==========");
SqlSessionFactory factory = (SqlSessionFactory) context.getBean(SESSION_FACTORY_BEAN_NAME);
Configuration configuration = factory.getConfiguration();
removeConfig(configuration);
for (Resource resource : findResource()) {
System.out.println(resource.getFilename());
try {
XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(resource.getInputStream(), configuration,
resource.toString(), configuration.getSqlFragments());
xmlMapperBuilder.parse();
} finally {
ErrorContext.instance().reset();
}
}
System.out.println("========== Reload end ==========");
} 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");
} @SuppressWarnings("rawtypes")
private void clearMap(Class<?> classConfig, Configuration configuration, String fieldName) throws Exception {
Field field = classConfig.getDeclaredField(fieldName);
field.setAccessible(true);
((Map) field.get(configuration)).clear();
} @SuppressWarnings("rawtypes")
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();
}
}
}

Spring加载方式

加载方式:在Spring XML文件中加入:(发布生产时要注释掉,不启动)
<!-- MyBatis 热加载,修改无需重新部署web容器的bean -->
<bean id ="MyBatisDynamicLoader" class= "com.xxx.XMLMapperLoader"/>

MyBatis热部署的更多相关文章

  1. MyBatis-HotSwap, MyBatis热部署

    https://github.com/xiaochenxinqing/MyBatis-HotSwap   1 https://github.com/xiaochenxinqing/MyBatis-Ho ...

  2. mybatis 热部署xml文件(spring boot和springmvc两种方式)

    参考:http://thinkgem.iteye.com/blog/2304557 步骤:1.创建两个java类 (1)MapperRefresh.java   :用于刷新mapper (2)SqlS ...

  3. springboot集成mybatis(逆向工程),热部署以及整合Swagger2

    本文是作者原创,版权归作者所有.若要转载,请注明出处. springboot集成mybatis和mybatis-generator插件 1.新建Springboot项目(略) 2.导入相关依赖 < ...

  4. springboot整合mybatis增删改查(二):springboot热部署

    SpringBoot整合热部署 传统情况下, 我们用idea运行springboot程序时, 如果我们需要修改类里的方法,或者其他信息 我们需要修改完保存,并且重启springboot,有时候会很浪费 ...

  5. SpringBoot+gradle+idea实现热部署和热加载

    前言 因为之前使用myeclipes的同学就知道,在使用myeclipes的时候,java文件或者jsp文件写完之后会被直接热加载到部署的容器中,从而在开发的时候,不同经常去重启项目,从而达到了增加开 ...

  6. SpringBoot03 项目热部署

    1 问题 在编写springBoot项目时,经常需要修改代码:但是每次修改代码后都需重新启动,修改的代码才会生效 2 这么实现IDEA能够像Eclipse那样保存过后就可以自动进行刷新呢 将sprin ...

  7. SpringBoot实现热部署(修改class不需要重启)

    热部署: devtools可以实现页面热部署(即页面修改后会立即生效, 这个可以直接在application.properties文件中配置spring.thymeleaf.cache=false来实 ...

  8. SpringBoot热部署的实现方式

    一:热部署的实现 1.使用Spring-boot-devtools 2.使用Spring Loaded 二:devtools(推荐) 一般情况下直接在pom.xml文件添加下面的依赖即可,但eclip ...

  9. IDEA 热部署- 自动编译设置

    原文:https://www.cnblogs.com/TechSnail/p/7690829.html    &&   https://blog.csdn.net/qq_3129357 ...

随机推荐

  1. 关于elementUI如何在表格循环列表里分别新增Tag的设计使用

    话不多说,直接上代码.想要实现的目的是这样的,想要在表格里单独添加每一个tag 那么,需要解决的问题就是如何定义这每一个插槽里的输入框,把每个输入框以及里面插入的数据区分开. 研究了很久,最后选择了对 ...

  2. 视觉SLAM十四讲:从理论到实践 两版 PDF和源码

    视觉SLAM十四讲:从理论到实践 第一版电子版PDF 链接:https://pan.baidu.com/s/1SuuSpavo_fj7xqTYtgHBfw提取码:lr4t 源码github链接:htt ...

  3. hanoi(汉诺塔)递归实现

    汉诺塔:汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具.大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘.大梵天命令婆罗门把圆盘从下面开始按大小顺序 ...

  4. GoF设计模式-23大设计模式(表格)-程序员必备+必背

    在GoF经典著作<设计模式:可复用面向对象软件的基础>中一共描述了23种设计模式. <Design Patterns:Elements of Reusable Object-Orie ...

  5. C++:Abstract class : invalid abstract return type for member function ‘virtual...’

    #include <iostream> #include <cmath> #include <sstream> using namespace std; class ...

  6. 'utf-8' codec can't decode byte 0x8b in position 1: invalid start byte

    问题描述:在使用python爬取斗鱼直播的数据时,使用str(读取到的字节,编码格式)进行解码时报错:'utf-8' codec can't decode byte 0x8b in position ...

  7. 用 JS(JavaScript )实现多选、全选、反选

    JS小例题 学习内容: 需求 总结: 学习内容: 需求 用 JavaScript 实现全选.反选.多选 实现代码 <!DOCTYPE html PUBLIC "-//W3C//DTD ...

  8. 《头号玩家》AI电影调研报告(五)

    4.VR自由行走跑步机 电影中,它可以让玩家朝任意方向无限奔跑并保持在平台最中央,还可以模拟上台阶和走斜坡的情况.而下面这件VR跑步装备,可以让你在游戏世界穿行自如. 奥地利创意公司Cyberith公 ...

  9. 轻量化安装 TKEStack:让已有 K8s 集群拥有企业级容器云平台的能力

    关于我们 更多关于云原生的案例和知识,可关注同名[腾讯云原生]公众号~ 福利: ①公众号后台回复[手册],可获得<腾讯云原生路线图手册>&<腾讯云原生最佳实践>~ ②公 ...

  10. pycharm的安装指导教程以及破解

    第一步:下载 下载网址:https://www.jetbrains.com/pycharm/download/#section=windows 根据自己的操作系统选择,然后点击download就开始下 ...