application.properties 中添加配置mybatis.mapper.reload=true。如果不想让热部署生效mybatis.mapper.reload=false 注意:修改一个mapper.xml后,会把所有mapper.xml重新加载一遍。
@Component public class MapperHotDeployPlugin { protected final Log log = LogFactory.getLog(getClass()); @Value("${mybatis.mapper-locations}") private String packageSerchPath; @Autowired private SqlSessionFactory sqlSessionFactory; private Resource[] mapperLocations; private Configuration configuration; private HashMap<String, Long> fileMapping = new HashMap<String, Long>();// 记录文件是否变化 @Value("${mybatis.mapper.reload}") private String reloadFlag; @PostConstruct public void init() { try { if(prepareEnv()) return; Runnable runnable = new Runnable() { public void run() { changeCompare(); } }; ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor(); // 第二个参数为首次执行的延时时间,第三个参数为定时执行的间隔时间 service.scheduleAtFixedRate(runnable, 1, 10, TimeUnit.SECONDS); log.info("============mapper热部署已生效============="); } catch (Exception e) { log.error("packageSearchPath扫描包路径配置错误"); return; } } /** * 功能描述: 准备赋值环境变量 * @param: * @return: * @auther: zenglingsheng * @date: 2020/10/21 8:43 */ public boolean prepareEnv() throws Exception{ boolean flag=true; this.configuration = sqlSessionFactory.getConfiguration(); this.mapperLocations = new PathMatchingResourcePatternResolver().getResources(packageSerchPath); for (Resource resource : mapperLocations) { String resourceName = resource.getFilename(); long lastFrame = resource.contentLength() + resource.lastModified(); fileMapping.put(resourceName, Long.valueOf(lastFrame));// 文件内容帧值 } if("true".equals(reloadFlag)) flag= false; return flag; } /** * 功能描述:判断xml文件是否修改方法 * @param: * @return: * @auther: zenglingsheng * @date: 2020/10/21 8:35 */ public void changeCompare(){ // task to run goes here try { // 判断是否有文件发生了变化 if (isChanged()) { // 清理 removeConfig(configuration); // 重新加载 for (Resource configLocation : mapperLocations) { try { XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(configLocation.getInputStream(), configuration, configLocation.toString(), configuration.getSqlFragments()); xmlMapperBuilder.parse(); } catch (IOException e) { log.error("mapper文件[" + configLocation.getFilename() + "]不存在或内容格式不对"); continue; } } log.info("-------mapper文件已全部更新-------"); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 判断文件是否发生了变化 */ boolean isChanged() throws IOException { boolean flag = false; for (Resource resource : mapperLocations) { String resourceName = resource.getFilename(); boolean addFlag = !fileMapping.isEmpty() && !fileMapping.containsKey(resourceName);// 此为新增标识 // 修改文件:判断文件内容是否有变化 Long compareFrame = fileMapping.get(resourceName); long lastFrame = resource.contentLength() + resource.lastModified(); boolean modifyFlag = null != compareFrame && compareFrame != lastFrame;// 此为修改标识 fileMapping.put(resourceName, Long.valueOf(lastFrame));// 文件内容帧值 // 新增或是修改时,存储文件 if (addFlag || modifyFlag) { flag = true; log.info("-------" + resourceName + "文件 已修改-------"); } } return flag; } /** * 清空Configuration中几个重要的缓存 * @param configuration * @throws Exception */ 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 mapConfig = (Map) field.get(configuration); mapConfig.clear(); } @SuppressWarnings("rawtypes") private void clearSet(Class<?> classConfig, Configuration configuration, String fieldName) throws Exception { Field field = classConfig.getDeclaredField(fieldName); field.setAccessible(true); Set setConfig = (Set) field.get(configuration); setConfig.clear(); } }