mybatis mapper.xml 文件修改后自动刷新
2018-04-03 11:22
477 查看
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
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.NestedIOException;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.util.StringUtils;
/**
* mapper文件修改时自动刷新
*
* @project : tykj-common
* @createTime : 2018年2月11日 : 下午10:54:25
* @author : lukewei
* @description :
*/
public class XMLMapperLoader implements DisposableBean, InitializingBean, ApplicationContextAware {
}
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
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.NestedIOException;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.util.StringUtils;
/**
* mapper文件修改时自动刷新
*
* @project : tykj-common
* @createTime : 2018年2月11日 : 下午10:54:25
* @author : lukewei
* @description :
*/
public class XMLMapperLoader implements DisposableBean, InitializingBean, ApplicationContextAware {
private Logger logger = LoggerFactory.getLogger(XMLMapperLoader.class); private SqlSessionFactory sqlSession; /** * * *Mapper.xml 文件路径 */ private String basePackage = "classpath*:**/*Mapper.xml"; private HashMap<String, String> fileMapping = new HashMap<String, String>(); private ScheduledExecutorService scheduledThreadPool; public void setBasePackage(String basePackage) { this.basePackage = basePackage; } public void setSqlSession(SqlSessionFactory sqlSession) { this.sqlSession = sqlSession; } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { // this.context = (ConfigurableApplicationContext) applicationContext; } @Override public void afterPropertiesSet() throws Exception { try { ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(1); scheduledThreadPool.scheduleAtFixedRate(new Task(new Scanner()), 5, 15, TimeUnit.SECONDS); } catch (Exception e1) { logger.error("mapper文件修改刷新启动异常 : {}", e1); } } class Task implements Runnable { private Scanner scanner; public Task(Scanner scanner) { this.scanner = scanner; } @Override public void run() { try { List<Resource> resources = scanner.getChangedFiles(); if (resources.size() > 0) { logger.debug("**********Mapper.xml文件改变,重新加载**************"); scanner.reloadXML(resources); logger.debug("*****************加载完毕***********************"); } } catch (Exception e) { logger.error("mapper文件修改重新加载失败: {}", e); } } } class Scanner { private String[] basePackages; public Scanner() { basePackages = StringUtils.tokenizeToStringArray(XMLMapperLoader.this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS); try { scan(); } catch (IOException e) { e.printStackTrace(); } } /** * 获取mapper.xml 资源 * * @param basePackage * @return * @throws IOException */ public Resource[] getResource(String basePackage) throws IOException { return new PathMatchingResourcePatternResolver().getResources(basePackage); } /** * 重新加载xml文件 * * @param resources * @throws Exception */ public void reloadXML(List<Resource> resources) throws Exception { Configuration configuration = sqlSession.getConfiguration(); removeConfig(configuration); for (Resource resource : resources) { try { XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(resource.getInputStream(), configuration, resource.toString(), configuration.getSqlFragments()); xmlMapperBuilder.parse(); } catch (Exception e) { throw new NestedIOException("Failed to parse mapping resource: '" + resource + "'", e); } finally { ErrorContext.instance().reset(); } } } /** * 清除配置 * * @param configuration * @throws Exception */ private void removeConfig(Configuration configuration) throws Exception { clearValues(configuration, "mappedStatements"); clearValues(configuration, "caches"); clearValues(configuration, "resultMaps"); clearValues(configuration, "parameterMaps"); clearValues(configuration, "keyGenerators"); clearValues(configuration, "sqlFragments"); // 清理已加载的资源标识,方便让它重新加载。 Field loadedResourcesField = configuration.getClass().getDeclaredField("loadedResources"); loadedResourcesField.setAccessible(true); ((Set<?>) loadedResourcesField.get(configuration)).clear(); } private void clearValues(Configuration configuration, String fieldName) throws Exception { Field field = configuration.getClass().getDeclaredField(fieldName); field.setAccessible(true); Map<?, ?> map = (Map<?, ?>) field.get(configuration); StrictMap<Object> newMap = new StrictMap<Object>(); for (Object key : map.keySet()) { try { newMap.put((String) key, map.get(key)); } catch (IllegalArgumentException ex) { newMap.put((String) key, ex.getMessage()); } } field.set(configuration, newMap); } public void scan() throws IOException { if (!fileMapping.isEmpty()) { return; } for (String basePackage : basePackages) { Resource[] resources = getResource(basePackage); if (resources != null) { for (Resource resource : resources) { fileMapping.put(resource.getFilename(), getValue(resource)); } } } } private String getValue(Resource resource) throws IOException { String contentLength = String.valueOf(resource.contentLength()); String lastModified = String.valueOf(resource.lastModified()); return new StringBuilder(contentLength).append(lastModified).toString(); } public List<Resource> getChangedFiles() throws IOException { List<Resource> list = new ArrayList<Resource>(); for (String basePackage : basePackages) { logger.debug("开始 刷新mybatis mapper.xml 文件************************"); Resource[] resources = getResource(basePackage); if (resources != null) { for (int i = 0; i < resources.length; i++) { String name = resources[i].getFilename(); String value = fileMapping.get(name); String multi_key = getValue(resources[i]); if (!multi_key.equals(value)) { list.add(resources[i]); fileMapping.put(name, multi_key); logger.debug("{} 文件修改************************", name); } } } } logger.debug("mybatis mapper.xml 文件刷新结束************************"); return list; } } @Override public void destroy() throws Exception { if (scheduledThreadPool != null) { scheduledThreadPool.shutdownNow(); } } /** * 重写 org.apache.ibatis.session.Configuration.StrictMap 类 来自 MyBatis3.4.0版本,修改 * put 方法,允许反复 put更新。 */ public static class StrictMap<V> extends HashMap<String, V> { private static final long serialVersionUID = -4950446264854982944L; @SuppressWarnings("unchecked") public V put(String key, V value) { remove(key); if (key.contains(".")) { final String shortKey = getShortName(key); if (super.get(shortKey) == null) { super.put(shortKey, value); } else { super.put(shortKey, (V) new Ambiguity(shortKey)); } } return super.put(key, 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; } } }
}
相关文章推荐
- 实现MyBatis Mapper XML文件增量动态刷新,自动加载,热加载,热部署
- 实现MyBatis Mapper XML文件增量动态刷新,自动加载,热加载,热部署
- 实现MyBatis Mapper XML文件增量动态刷新,自动加载,热加载,热部署
- 实现MyBatis Mapper XML文件增量动态刷新,自动加载,热加载,热部署
- 实现MyBatis Mapper XML文件增量动态刷新,自动加载,热加载,热部署
- 实现MyBatis Mapper XML文件增量动态刷新,自动加载,热加载,热部署
- 使用Mybatis-Generator自动生成Dao、model和mapper.xml相关文件
- mybatis 自动生成实体类、mapper.xml文件
- mybatis热部署加载*Mapper.xml文件,手动刷新*Mapper.xml文件
- mybatis逆向工程自动生成实体类、接口以及映射Mapper.xml配置文件
- MyBatis之Mapper XML 文件详解(五)-自动映射查询结果
- MyBatis之Mapper XML 文件详解-自动映射查询结果
- 使用mybatis-generator生成自动生成mapper.java和mapper.xml等文件
- Mybatis的xml修改后自动刷新(不改源码)
- 【mybatis】mapper.xml文件自动扫描注入的方法
- mybatis-generatorConfig.xml 文件编写自动生成MAPPER文件
- maven插件mybatis-generator自动生成实体类、mapper.xml、mapper.java文件
- 如何去掉mybatis自动生成的mapper.xml文件背景色
- Spring3 Mybatis3 freemarker 自动生成对应表的model、mapper、service、controller并自动修改mybatis配置文件
- MyBatis之Mapper XML 文件详解(五)-自动映射查询结果