MyBatis SQL 热替换

shouwangV 2016-02-11

MyBatisSQL热替换

-----------------------

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();

			}

		}

	}

}

相关推荐

lionelf / 0评论 2020-07-28