mybatis 的mapper.xml修改后无需重启 热部署

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();
    }
}
  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值