MyBatis SQL 热替换
-----------------------
package cn.bisoft.ibatis;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.apache.ibatis.binding.MapperProxyFactory;
import org.apache.ibatis.binding.MapperRegistry;
import org.apache.ibatis.builder.annotation.MapperAnnotationBuilder;
import org.apache.ibatis.cache.Cache;
import org.apache.ibatis.executor.keygen.KeyGenerator;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMap;
import org.apache.ibatis.mapping.ResultMap;
import org.apache.ibatis.parsing.XNode;
import org.apache.ibatis.session.Configuration;
import cn.bisoft.util.CollectionUtil;
import cn.bisoft.util.ReflectUtil;
public final class ConfigurationRefactor {
private static final String FIELD_LOADED_RESOURCES = "loadedResources";
private static final String FIELD_MAPPER_REGISTRY = "mapperRegistry";
private static final String FIELD_KNOW_MAPPERS = "knownMappers";
private static final String FIELD_MAPPED_STATEMENTS = "mappedStatements";
private static final String FIELD_CACHES = "caches";
private static final String FIELD_RESULT_MAPS = "resultMaps";
private static final String FIELD_PARAMETER_MAPS = "parameterMaps";
private static final String FIELD_KEY_GENERATORS = "keyGenerators";
private static final String FIELD_SQL_FRAGMENTS = "sqlFragments";
/**
* 热替换MyBatis的SQL.新增加Mapper暂时不适用.
*
* @param conf Configuration
* @param name Mapper 完全限定类名
* @throws Exception
*/
public void replaceMapper(Configuration conf, String name) throws Exception {
Class<?> type = conf.getClass().getClassLoader().loadClass(name);
if (null != type) {
// 1. lock configuration
synchronized (conf.getClass()) {
// 2. 清除配置的Mapper资源标志
String resource = type.toString();
if (conf.isResourceLoaded(resource)) {
// 利用反射修改
Set<String> loadedResources = (Set<String>) ReflectUtil
.get(conf, FIELD_LOADED_RESOURCES);
loadedResources.remove(resource);
} else {
// PASS
}
// 3. 清除Mapper资源
if (conf.hasMapper(type)) {
MapperRegistry mapperRegistry = (MapperRegistry) ReflectUtil
.get(conf, FIELD_MAPPER_REGISTRY);
Map<Class<?>, MapperProxyFactory<?>> knownMappers = (Map<Class<?>, MapperProxyFactory<?>>) ReflectUtil
.get(conf, FIELD_KNOW_MAPPERS);
knownMappers.put(type, new MapperProxyFactory(type));
}
// 4. 清除语句
Map<String, MappedStatement> mappedStatements = (Map<String, MappedStatement>) ReflectUtil
.get(conf, FIELD_MAPPED_STATEMENTS);
Map<String, MappedStatement> mappedStatementsDup = CollectionUtil
.cloneMap(mappedStatements);
ReflectUtil.set(conf, FIELD_MAPPED_STATEMENTS,
mappedStatementsDup, true);
// 5. 清除缓存
Map<String, Cache> caches = (Map<String, Cache>) ReflectUtil
.get(conf, FIELD_CACHES);
Map<String, Cache> cachesDup = CollectionUtil.cloneMap(caches);
ReflectUtil.set(conf, FIELD_CACHES, new HashMap<String, Cache>(), true);
// 6. 清除结果
Map<String, ResultMap> resultMaps = (Map<String, ResultMap>) ReflectUtil
.get(conf, FIELD_RESULT_MAPS);
Map<String, ResultMap> resultMapsDup = CollectionUtil
.cloneMap(resultMaps);
ReflectUtil.set(conf, FIELD_RESULT_MAPS, resultMapsDup, true);
// 7. 清除参数
Map<String, ParameterMap> parameterMaps = (Map<String, ParameterMap>) ReflectUtil
.get(conf, FIELD_PARAMETER_MAPS);
Map<String, ParameterMap> parameterMapsDup = CollectionUtil
.cloneMap(parameterMaps);
ReflectUtil
.set(conf, FIELD_PARAMETER_MAPS, resultMapsDup, true);
// 8. 清除主键
Map<String, KeyGenerator> keyGenerators = (Map<String, KeyGenerator>) ReflectUtil
.get(conf, FIELD_KEY_GENERATORS);
Map<String, KeyGenerator> keyGeneratorsDup = CollectionUtil
.cloneMap(keyGenerators);
ReflectUtil
.set(conf, FIELD_KEY_GENERATORS, resultMapsDup, true);
// 9. 清除SQL
Map<String, XNode> sqlFragments = (Map<String, XNode>) ReflectUtil
.get(conf, FIELD_SQL_FRAGMENTS);
Map<String, XNode> sqlFragmentsDup = CollectionUtil
.cloneMap(sqlFragments);
ReflectUtil.set(conf, FIELD_SQL_FRAGMENTS, resultMapsDup, true);
// 10. 重新加载配置
MapperAnnotationBuilder parser = new MapperAnnotationBuilder(
conf, type);
parser.parse();
}
}
}
}