当前位置:   article > 正文

springboot+mybatis热启动_springboot mybatis 开机预热

springboot mybatis 开机预热

參考:https://blog.csdn.net/angry_mills/article/details/80565863

 springboot     2.0.0.RELEASE    

 mybatis    3.4.5

mybatis-spring-boot-starter    1.3.0

MapperRefresh 类有点小改动:

  1. package cn.com.do1.component.build.sz.util;
  2. import java.io.File;
  3. import java.io.FileInputStream;
  4. import java.io.FileNotFoundException;
  5. import java.io.IOException;
  6. import java.io.InputStream;
  7. import java.lang.reflect.Field;
  8. import java.net.URL;
  9. import java.util.*;
  10. import org.apache.commons.lang.StringUtils;
  11. import org.apache.ibatis.builder.xml.XMLMapperBuilder;
  12. import org.apache.ibatis.executor.ErrorContext;
  13. import org.apache.ibatis.session.Configuration;
  14. import org.slf4j.Logger;
  15. import org.slf4j.LoggerFactory;
  16. import org.springframework.core.NestedIOException;
  17. import org.springframework.core.io.Resource;
  18. import com.google.common.collect.Sets;
  19. /**
  20. * 刷新MyBatis Mapper XML 线程
  21. * @author juane
  22. * @version 2019-3-03
  23. */
  24. public class MapperRefresh implements java.lang.Runnable {
  25. public static Logger log = LoggerFactory.getLogger(MapperRefresh.class);
  26. private static String filename = "mybatis-refresh.properties";
  27. private static Properties prop = new Properties();
  28. private static boolean enabled; // 是否启用Mapper刷新线程功能
  29. private static boolean refresh; // 刷新启用后,是否启动了刷新线程
  30. private Set<String> location; // Mapper实际资源路径
  31. private Resource[] mapperLocations; // Mapper资源路径
  32. private Configuration configuration; // MyBatis配置对象
  33. private Long beforeTime = 0L; // 上一次刷新时间
  34. private static int delaySeconds; // 延迟刷新秒数
  35. private static int sleepSeconds; // 休眠时间
  36. private static String mappingPath; // xml文件夹匹配字符串,需要根据需要修改
  37. static {
  38. // try {
  39. // prop.load(MapperRefresh.class.getResourceAsStream(filename));
  40. // } catch (Exception e) {
  41. // e.printStackTrace();
  42. // System.out.println("Load mybatis-refresh “"+filename+"” file error.");
  43. // }
  44. URL url = MapperRefresh.class.getClassLoader().getResource(filename);
  45. InputStream is;
  46. try {
  47. is = url.openStream();
  48. if (is == null) {
  49. log.warn("applicationConfig.properties not found.");
  50. } else {
  51. prop.load(is);
  52. }
  53. } catch (IOException e) {
  54. e.printStackTrace();
  55. }
  56. String value = getPropString("enabled");
  57. System.out.println(value);
  58. enabled = "true".equalsIgnoreCase(value);
  59. delaySeconds = getPropInt("delaySeconds");
  60. sleepSeconds = getPropInt("sleepSeconds");
  61. mappingPath = getPropString("mappingPath");
  62. delaySeconds = delaySeconds == 0 ? 50 : delaySeconds;
  63. sleepSeconds = sleepSeconds == 0 ? 3 : sleepSeconds;
  64. mappingPath = StringUtils.isBlank(mappingPath) ? "mappings" : mappingPath;
  65. log.debug("[enabled] " + enabled);
  66. log.debug("[delaySeconds] " + delaySeconds);
  67. log.debug("[sleepSeconds] " + sleepSeconds);
  68. log.debug("[mappingPath] " + mappingPath);
  69. }
  70. public static boolean isRefresh() {
  71. return refresh;
  72. }
  73. public MapperRefresh(Resource[] mapperLocations, Configuration configuration) {
  74. this.mapperLocations = mapperLocations;
  75. this.configuration = configuration;
  76. }
  77. @Override
  78. public void run() {
  79. beforeTime = System.currentTimeMillis();
  80. log.debug("[location] " + location);
  81. log.debug("[configuration] " + configuration);
  82. if (enabled) {
  83. // 启动刷新线程
  84. final MapperRefresh runnable = this;
  85. new Thread(new java.lang.Runnable() {
  86. @Override
  87. public void run() {
  88. if (location == null){
  89. location = Sets.newHashSet();
  90. log.debug("MapperLocation's length:" + mapperLocations.length);
  91. for (Resource mapperLocation : mapperLocations) {
  92. String s = mapperLocation.toString().replaceAll("\\\\", "/");
  93. s = s.substring("file [".length(), s.lastIndexOf(mappingPath) + mappingPath.length());
  94. if (!location.contains(s)) {
  95. location.add(s);
  96. log.debug("Location:" + s);
  97. }
  98. }
  99. log.debug("Locarion's size:" + location.size());
  100. }
  101. try {
  102. Thread.sleep(delaySeconds * 1000);
  103. } catch (InterruptedException e2) {
  104. e2.printStackTrace();
  105. }
  106. refresh = true;
  107. System.out.println("========= Enabled refresh mybatis mapper =========");
  108. while (true) {
  109. try {
  110. for (String s : location) {
  111. runnable.refresh(s, beforeTime);
  112. }
  113. } catch (Exception e1) {
  114. e1.printStackTrace();
  115. }
  116. try {
  117. Thread.sleep(sleepSeconds * 1000);
  118. } catch (InterruptedException e) {
  119. e.printStackTrace();
  120. }
  121. }
  122. }
  123. }, "MyBatis-Mapper-Refresh").start();
  124. }
  125. }
  126. /**
  127. * 执行刷新
  128. * @param filePath 刷新目录
  129. * @param beforeTime 上次刷新时间
  130. * @throws NestedIOException 解析异常
  131. * @throws FileNotFoundException 文件未找到
  132. * @author ThinkGem
  133. */
  134. @SuppressWarnings({ "rawtypes", "unchecked" })
  135. private void refresh(String filePath, Long beforeTime) throws Exception {
  136. // 本次刷新时间
  137. Long refrehTime = System.currentTimeMillis();
  138. // 获取需要刷新的Mapper文件列表
  139. List<File> fileList = this.getRefreshFile(new File(filePath), beforeTime);
  140. if (fileList.size() > 0) {
  141. log.debug("Refresh file: " + fileList.size());
  142. }
  143. for (int i = 0; i < fileList.size(); i++) {
  144. InputStream inputStream = new FileInputStream(fileList.get(i));
  145. String resource = fileList.get(i).getAbsolutePath();
  146. try {
  147. // 清理原有资源,更新为自己的StrictMap方便,增量重新加载
  148. String[] mapFieldNames = new String[]{
  149. "mappedStatements", "caches",
  150. "resultMaps", "parameterMaps",
  151. "keyGenerators", "sqlFragments"
  152. };
  153. Map<String,Field> fieldMap = new HashMap<>() ;
  154. Class tempClass2 = configuration.getClass();
  155. while (tempClass2 != null) {//当父类为null的时候说明到达了最上层的父类(Object类).
  156. for(Field f : Arrays.asList(tempClass2 .getDeclaredFields())) {
  157. fieldMap.put(f.getName(),f);
  158. }
  159. tempClass2 = tempClass2.getSuperclass(); //得到父类,然后赋给自己
  160. }
  161. Class tempClass = configuration.getClass().getSuperclass();
  162. for (String fieldName : mapFieldNames){
  163. Field field = tempClass.getDeclaredField(fieldName);
  164. field.setAccessible(true);
  165. Map map = ((Map)field.get(configuration));
  166. if (!(map instanceof StrictMap)){
  167. Map newMap = new StrictMap(StringUtils.capitalize(fieldName) + "collection");
  168. for (Object key : map.keySet()){
  169. try {
  170. newMap.put(key, map.get(key));
  171. }catch(IllegalArgumentException ex){
  172. newMap.put(key, ex.getMessage());
  173. }
  174. }
  175. field.set(configuration, newMap);
  176. }
  177. }
  178. // 清理已加载的资源标识,方便让它重新加载。
  179. Field loadedResourcesField = tempClass.getDeclaredField("loadedResources");
  180. loadedResourcesField.setAccessible(true);
  181. Set loadedResourcesSet = ((Set)loadedResourcesField.get(configuration));
  182. loadedResourcesSet.remove(resource);
  183. //重新编译加载资源文件。
  184. XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(inputStream, configuration,
  185. resource, configuration.getSqlFragments());
  186. xmlMapperBuilder.parse();
  187. } catch (Exception e) {
  188. throw new NestedIOException("Failed to parse mapping resource: '" + resource + "'", e);
  189. } finally {
  190. ErrorContext.instance().reset();
  191. }
  192. // System.out.println("Refresh file: " + mappingPath + StringUtils.substringAfterLast(fileList.get(i).getAbsolutePath(), mappingPath));
  193. if (log.isDebugEnabled()) {
  194. log.debug("Refresh file: " + fileList.get(i).getAbsolutePath());
  195. log.debug("Refresh filename: " + fileList.get(i).getName());
  196. }
  197. }
  198. // 如果刷新了文件,则修改刷新时间,否则不修改
  199. if (fileList.size() > 0) {
  200. this.beforeTime = refrehTime;
  201. }
  202. }
  203. /**
  204. * 获取需要刷新的文件列表
  205. * @param dir 目录
  206. * @param beforeTime 上次刷新时间
  207. * @return 刷新文件列表
  208. */
  209. private List<File> getRefreshFile(File dir, Long beforeTime) {
  210. List<File> fileList = new ArrayList<File>();
  211. File[] files = dir.listFiles();
  212. if (files != null) {
  213. for (int i = 0; i < files.length; i++) {
  214. File file = files[i];
  215. if (file.isDirectory()) {
  216. fileList.addAll(this.getRefreshFile(file, beforeTime));
  217. } else if (file.isFile()) {
  218. if (this.checkFile(file, beforeTime)) {
  219. fileList.add(file);
  220. }
  221. } else {
  222. System.out.println("Error file." + file.getName());
  223. }
  224. }
  225. }
  226. return fileList;
  227. }
  228. /**
  229. * 判断文件是否需要刷新
  230. * @param file 文件
  231. * @param beforeTime 上次刷新时间
  232. * @return 需要刷新返回true,否则返回false
  233. */
  234. private boolean checkFile(File file, Long beforeTime) {
  235. if (file.lastModified() > beforeTime) {
  236. return true;
  237. }
  238. return false;
  239. }
  240. /**
  241. * 获取整数属性
  242. * @param key
  243. * @return
  244. */
  245. private static int getPropInt(String key) {
  246. int i = 0;
  247. try {
  248. i = Integer.parseInt(getPropString(key));
  249. } catch (Exception e) {
  250. }
  251. return i;
  252. }
  253. /**
  254. * 获取字符串属性
  255. * @param key
  256. * @return
  257. */
  258. private static String getPropString(String key) {
  259. return prop == null ? null : prop.getProperty(key).trim();
  260. }
  261. /**
  262. * 重写 org.apache.ibatis.session.Configuration.StrictMap 类
  263. * 来自 MyBatis3.4.0版本,修改 put 方法,允许反复 put更新。
  264. */
  265. public static class StrictMap<V> extends HashMap<String, V> {
  266. private static final long serialVersionUID = -4950446264854982944L;
  267. private String name;
  268. public StrictMap(String name, int initialCapacity, float loadFactor) {
  269. super(initialCapacity, loadFactor);
  270. this.name = name;
  271. }
  272. public StrictMap(String name, int initialCapacity) {
  273. super(initialCapacity);
  274. this.name = name;
  275. }
  276. public StrictMap(String name) {
  277. super();
  278. this.name = name;
  279. }
  280. public StrictMap(String name, Map<String, ? extends V> m) {
  281. super(m);
  282. this.name = name;
  283. }
  284. @SuppressWarnings("unchecked")
  285. public V put(String key, V value) {
  286. // ThinkGem 如果现在状态为刷新,则刷新(先删除后添加)
  287. if (MapperRefresh.isRefresh()) {
  288. remove(key);
  289. // MapperRefresh.log.debug("refresh key:" + key.substring(key.lastIndexOf(".") + 1));
  290. }
  291. // ThinkGem end
  292. if (containsKey(key)) {
  293. throw new IllegalArgumentException(name + " already contains value for " + key);
  294. }
  295. if (key.contains(".")) {
  296. final String shortKey = getShortName(key);
  297. if (super.get(shortKey) == null) {
  298. super.put(shortKey, value);
  299. } else {
  300. super.put(shortKey, (V) new Ambiguity(shortKey));
  301. }
  302. }
  303. return super.put(key, value);
  304. }
  305. public V get(Object key) {
  306. V value = super.get(key);
  307. if (value == null) {
  308. throw new IllegalArgumentException(name + " does not contain value for " + key);
  309. }
  310. if (value instanceof Ambiguity) {
  311. throw new IllegalArgumentException(((Ambiguity) value).getSubject() + " is ambiguous in " + name
  312. + " (try using the full name including the namespace, or rename one of the entries)");
  313. }
  314. return value;
  315. }
  316. private String getShortName(String key) {
  317. final String[] keyparts = key.split("\\.");
  318. return keyparts[keyparts.length - 1];
  319. }
  320. protected static class Ambiguity {
  321. private String subject;
  322. public Ambiguity(String subject) {
  323. this.subject = subject;
  324. }
  325. public String getSubject() {
  326. return subject;
  327. }
  328. }
  329. }
  330. }

启动类:

  1. @Autowired
  2. private SqlSession sqlSession;
  3. @PostConstruct
  4. public void postConstruct() throws IOException {
  5. //Constant.threadPool = Executors.newFixedThreadPool(20);
  6. Resource[] resources = new PathMatchingResourcePatternResolver().getResources("classpath*:**/mapper/*/*Dao.xml");
  7. org.apache.ibatis.session.Configuration configuration = (org.apache.ibatis.session.Configuration)sqlSession.getConfiguration();
  8. new MapperRefresh(resources, configuration).run();
  9. }

改了XML之后,build一下。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/191604
推荐阅读
相关标签
  

闽ICP备14008679号