前几天在琢磨mybatis xml热加载的问题,原理还是通过定时扫描xml文件去跟新,但放到项目上就各种问题,由于用了mybatisplus死活不生效。本着”即插即用”的原则,狠心把其中的代码优化了一遍,能够兼容mybatisplus,还加入了一些日志,直接上代码
package com.bzd.core.mybatis;import java.io.file;import java.io.filenotfoundexception;import java.io.ioexception;import java.io.inputstream;import java.lang.reflect.field;import java.net.url;import java.util.arraylist;import java.util.hashmap;import java.util.list;import java.util.map;import java.util.properties;import java.util.t;import lombok.sneakythrows;import org.apache.commons.lang3.stringutils;import org.apache.ibatis.builder.xml.xmlmapperbuilder;import org.apache.ibatis.executor.errorcontext;import org.apache.ibatis.ssion.configuration;import org.slf4j.logger;import org.slf4j.loggerfactory;import org.springframework.core.nestedioexception;import org.springframework.core.io.resource;import com.google.common.collect.ts;/*** 刷新mybatis mapper xml 线程* @author thinkgem* @version 2016-5-29*/public class mapperrefresh implements java.lang.runnable {public static logger log = loggerfactory.getlogger(mapperrefresh.class);private static string filename = "mybatis-refresh.properties";private static properties prop = new properties();private static boolean enabled; // 是否启用mapper刷新线程功能private static boolean refresh; // 刷新启用后,是否启动了刷新线程private t<string> location; // mapper实际资源路径private resource[] mapperlocations; // mapper资源路径private configuration configuration; // mybatis配置对象private long beforetime = 0l; // 上一次刷新时间private static int delayconds; // 延迟刷新秒数private static int sleepconds; // 休眠时间private static string mappingpath; // xml文件夹匹配字符串,需要根据需要修改static {// try {// prop.load(mapperrefresh.class.getresourceasstream(filename));// } catch (exception e) {// e.printstacktrace();// system.out.println("load mybatis-refresh “"+filename+"” file error.");// }url url = mapperrefresh.class.getclassloader().getresource(filename);inputstream is;try {is = url.openstream();if (is == null) {log.warn("applicationconfig.properties not found.");} el {prop.load(is);}} catch (ioexception e) {e.printstacktrace();}string value = getpropstring("enabled");system.out.println(value);enabled = "true".equalsignoreca(value);delayconds = getpropint("delayconds");sleepconds = getpropint("sleepconds");//mappingpath = getpropstring("mappingpath");delayconds = delayconds == 0 ? 50 : delayconds;sleepconds = sleepconds == 0 ? 3 : sleepconds;mappingpath = stringutils.isblank(mappingpath) ? "mappings" : mappingpath;log.debug("[enabled] " + enabled);log.debug("[delayconds] " + delayconds);log.debug("[sleepconds] " + sleepconds);log.debug("[mappingpath] " + mappingpath);}public static boolean isrefresh() {return refresh;}public mapperrefresh(resource[] mapperlocations, configuration configuration) {this.mapperlocations = mapperlocations;this.configuration = configuration;}@overridepublic void run() {beforetime = system.currenttimemillis();log.debug("[location] " + location);log.debug("[configuration] " + configuration);if (enabled) {// 启动刷新线程final mapperrefresh runnable = this;new thread(new java.lang.runnable() {@sneakythrows@overridepublic void run() {/*if (location == null){location = ts.newhasht();log.debug("mapperlocation's length:" + mapperlocations.length);for (resource mapperlocation : mapperlocations) {string s = mapperlocation.tostring().replaceall("\\\\", "/");s = s.substring("file [".length(), s.lastindexof(mappingpath) + mappingpath.length());s = mapperlocation.getfile().getparent();if (!location.contains(s)) {location.add(s);log.debug("location:" + s);}}log.debug("locarion's size:" + location.size());}*/try {thread.sleep(delayconds * 1000);} catch (interruptedexception e2) {e2.printstacktrace();}refresh = true;system.out.println("========= enabled refresh mybatis mapper =========");while (true) {try {log.info("start refresh");list<教师个人简介100字;resource> res = getmodifyresource(mapperlocations,beforetime);if(res.size()>0)runnable.refresh(res);// 如果刷新了文件,则修改刷新时间,否则不修改beforetime = system.currenttimemillis();log.info("end refresh("+res.size()+")");} catch (exception e1) {e1.printstacktrace();}try {thread.sleep(sleepconds * 1000);} catch (interruptedexception e) {e.printstacktrace();}}}}, "mybatis-mapper-refresh").start();}}private list<resource> getmodifyresource(resource[] mapperlocations,long time){list<resource> resources = new arraylist<>();for (int i = 0; i < mapperlocations.length; i++) {try {if(ismodify(mapperlocations[i],time))resources.add(mapperlocations[i]);} catch (ioexception e) {throw new runtimeexception("读取mapper文件异常",e);}}return resources;}private boolean ismodify(resource resource,long time) throws ioexception {if (resource.lastmodified() > time) {return true;}return fal;}/*** 执行刷新* @param filepath 刷新目录* @param beforetime 上次刷新时间* @throws nestedioexception 解析异常* @throws filenotfoundexception 文件未找到* @author thinkgem*/@suppresswarnings({ "rawtypes", "unchecked" })private void refresh(list<resource> mapperlocations) throws exception {// 获取需要刷新的mapper文件列表/*list<file> filelist = this.getrefreshfile(new file(filepath), beforetime);if (filelist.size蛋糕盒图片() > 0) {log.debug("refresh file: " + filelist.size());}*/for (int i = 0; i < mapperlocations.size(); i++) {resource resource = mapperlocations.get(i);inputstream inputstream = resource.getinputstream();system.out.println("refreshed : "+resource.getdescription());//这个是mybatis 加载的资源标识,没有绝对标准string resourcepath = resource.getdescription();try {clearmybatis(resourcepath);//重新编译加载资源文件。xmlmapperbuilder xmlmapperbuilder = new xmlmapperbuilder(inputstream, configuration,resourcepath, configuration.getsqlfragments());xmlmapperbuilder.par();} catch (exception e) {throw new nestedioexception("failed to par mapping resource: '" + resourcepath + "'", e);} finally {errorcontext.instance().ret();}// system.out.println("refresh file: " + mappingpath + stringutils.substringafterlast(filelist.get(i).getabsolutepath(), mappingpath));/*if (log.isdebugenabled()) {log.debug("refresh file: " + filelist.get(i).getabsolutepath());log.debug("refresh filename: " + filelist.get(i).getname());}*/}}private void clearmybatis(string resource) throws nosuchfieldexception, illegala斜率是什么意思ccesxception {// 清理原有资源,更新为自己的strictmap方便,增量重新加载string[] mapfieldnames = new string[]{"mappedstatements", "caches","resultmaps", "parametermaps","keygenerators", "sqlfragments"};for (string fieldname : mapfieldnames){field field = configuration.getclass().getdeclaredfield(fieldname);field.taccessible(true);map map = ((map)field.get(configuration));if (!(map instanceof strictmap)){map newmap = new strictmap(stringutils.capitalize(fieldname) + "collection");for (object key : map.keyt()){try {newmap.put(key, map.get(key));}catch(illegalargumentexception ex){newmap.put(key, ex.getmessage());}}field.t(configuration, newmap);}}// 清理已加载的资源标识,方便让它重新加载。field loadedresourcesfield = configuration.getclass().getdeclaredfield("loadedresources");loadedresourcesfield.taccessible(true);t loadedresourcest = ((t)loadedresourcesfield.get(configuration));loadedresourcest.remove(resource);}/*** 获取需要刷新的文件列表* @param dir 目录* @param beforetime 上次刷新时间* @return 刷新文件列表*/private list<file> getrefreshfile(file dir, long beforetime) {list<file> filelist = new arraylist<file>();file[] files = dir.listfiles();if (files != null) {for (int i = 0; i < files.length; i++) {file file = files[i];if (file.isdirectory()) {filelist.addall(this.getrefreshfile(file, beforetime));} el if (file.isfile()) {if (this.checkfile(file, beforetime)) {filelist.add(file);}} el {system.out.println("error file." + file.getname());}}}return filelist;}/*** 判断文件是否需要刷新* @param file 文件* @param beforetime 上次刷新时间* @return 需要刷新返回true,否则返回fal*/private boolean checkfile(file file, long beforetime) {if (file.lastmodified() > beforetime) {return true;}return fal;}/*** 获取整数属性* @param key* @return*/private static int getpropint(string key) {int i = 0;try {i = integer.parint(getpropstring(key));} catch (exception e) {}return i;}/*** 获取字符串属性* @param key* @return*/private static string getpropstring(string key) {return prop == null ? null : prop.getproperty(key).trim();}/*** 重写 org.apache.ibatis.ssion.configuration.strictmap 类* 来自 mybatis3.4.0版本,修改 put 方法,允许反复 put更新。*/public static class strictmap<v> extends hashmap<string, v> {private static final long rialversionuid = -4950446264854982944l;private string name;public strictmap(string name, int initialcapacity, float loadfactor) {super(initialcapacity, loadfactor);this.name = name;}public strictmap(string name, int initialcapacity) {super(initialcapacity);this.name = name;}public strictmap(string name) {super();this.name = name;}public strictmap(string name, map<string, ? extends v> m) {super(m);this.name = name;}@suppresswarnings("unchecked")public v put(string key, v value) {// thinkgem 如果现在状态为刷新,则刷新(先删除后添加)if (mapperrefresh.isrefresh()) {remove(key);// mapperrefresh.log.debug("refresh key:" + key.substring(key.lastindexof(".") + 1));}// thinkgem endif (containskey(key)) {throw new illegalargumentexception(name + " already contains value for " + key);}if (key.contains(".")) {final string shortkey = getshortname(key);if (super.get(shortkey) == null) {super.put(shortkey, value);} el {super.put(shortkey, (v) new ambiguity(shortkey));}}return super.put(key, value);}public v get(object key) {v value = super.get(key);if (value == null) {throw new illegalargumentexception(name + " does not contain value for " + key);}if (value instanceof ambiguity) {throw new illegalargumentexception(((ambiguity) value).getsubject() + " is ambiguous in " + name+ " (try using the full name including the namespace, or rename one of the entries)");}return value;}private string getshortname(string key) {final string[] keyparts = key.split("\\.");return keyparts[keyparts.length - 1];}protected static class ambiguity {private string subject;public ambiguity(string subject) {this.subject = subject;}public string getsubject() {return subject;}}}}
这里提供两种配置方式一种是springboot,一种就是普通的spring项目
1.springboot 方式 就是
package com优秀简历.bzd.bootadmin.conf;import com.bzd.core.mybatis.mapperrefresh;import org.apache.ibatis.ssion.sqlssionfactory;import org.mybatis.spring.annotation.mapperscan;import org.mybatis.spring.boot.autoconfigure.mybatisproperties;import org.springframework.beans.factory.annotation.autowired;import org.springframework.context.annotation.configuration;import org.springframework.core.io.resource;import javax.annotation.postconstruct;/**** @author created by bzd on 2020/12/28/15:10**/@configuration@mapperscan(value = {"com.bzd.bootadmin.modular.index.mapper"})public class mybatisconfig {@autowiredsqlssionfactory factory;@autowiredmybatisproperties properties;@postconstructpublic void postconstruct() {resource[] resources = this.properties.resolvemapperlocations();new mapperrefresh(resources, factory.getconfiguration()).run();}}
2:普通spring项目
import org.apache.ibatis.ssion.configuration;import org.apache.ibatis.ssion.sqlssionfactory;import org.springframework.core.io.resource;import javax.annotation.postconstruct;import java.io.ioexception;import java.lang.reflect.invocationtargetexception;import java.lang.reflect.method;/*** created by lxr on 2020/5/3**/public class refreshstarter {sqlssionfactory factory;resource[] mapperlocations;@postconstructpublic void postconstruct() throws ioexception {resource[] resources = mapperlocations;enablemybatisplusrefresh(factory.getconfiguration());new mapperrefresh(resources, factory.getconfiguration()).run();}/*** 反射配置开启 mybatisplus 的 refresh,不使用mybatisplus也不会有影响* @param configuration*/public void enablemybatisplusrefresh(configuration configuration){try {method method = class.forname("com.baomidou.mybatisplus.toolkit.globalconfigutils").getmethod("getglobalconfig", configuration.class);object globalconfiguration = method.invoke(null, configuration);method = class.forname("com.baomidou.mybatisplus.entity.globalconfiguration").getmethod("trefresh", boolean.class);method.invoke(globalconfiguration, true);} catch (classnotfoundexception e) {} catch (nosuchmethodexception e) {e.printstacktrace();} catch (illegalaccesxception e) {e.printstacktrace();} catch (invocationtargetexception e) {e.printstacktrace();}}public sqlssionfactory getfactory() {return factory;}public void tfactory(sqlssionfactory factory) {this.factory = factory;}public resource[] getmapperlocations() {return mapperlocations;}public void tmapperlocations(resource[] mapperlocations) {this.mapperlocations = mapperlocations;}}
在xml中配置
<bean class="com.foxtail.core.mybatis.refreshstarter"><prope学生营养早餐食谱rty name="mapperlocations"><array><value>classpath:com/foxtail/mapping/*/*.xml</value><value>classpath:com/foxtail/mapping/*.xml</value></array></property><property name="factory" ref="sqlssionfactory" /></bean>
最后在resources中加入mybatis-refresh.properties
#是否开启刷新线程 enabled=true #延迟启动刷新程序的秒数 delayconds=5 #刷新扫描间隔的时长秒数 sleepconds=3
到这里就大功告成了,最后加到代码里面有没有生效呢,改完sql之后总会想到底是更新了还是没更新,又看不到,这是程序员最头疼的。因为加了日志都不用担心啦
到此这篇关于关于mybatis中mapper xml热加载优化的文章就介绍到这了,更多相关mybatis mapper xml热加载内容请搜索www.887551.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持www.887551.com!
本文发布于:2023-04-04 17:10:24,感谢您对本站的认可!
本文链接:https://www.wtabcd.cn/fanwen/zuowen/a069a386a3f22d2966f4f956de163d1c.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文word下载地址:关于MyBatis中Mapper XML热加载优化.doc
本文 PDF 下载地址:关于MyBatis中Mapper XML热加载优化.pdf
留言与评论(共有 0 条评论) |