这个是在@歇蹩虎子 (http://www.oschina.net/code/snippet_1018034_26472)提供的自动加载的基础上改进的;
主要是添加了注解方式的自动加载
import java.io.File; import java.io.IOException; import java.lang.reflect.Field; import java.net.URL; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; 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.binding.MapperRegistry; 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.apache.log4j.Logger; import org.mybatis.spring.SqlSessionFactoryBean; 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; /** * * <p> * </p> * * @author 吕兵峰 2014-2-19 上午11:56:47 * @version V1.0 * @modificationHistory 如有逻辑或功能性重大变更记录,请修改一下以下内容 * @modify by user: {修改人} 2014-2-19 * @modify by reason:{方法名}:{原因} */ public class MyMapperLoader implements DisposableBean, InitializingBean, ApplicationContextAware { private Logger logger = Logger.getLogger(MyMapperLoader.class); private ConfigurableApplicationContext context = null; private HashMap<String, String> fileMapping = new HashMap<String, String>(); private Scanner scanner = null; private ScheduledExecutorService service = null; private Resource[] resources = null; private File[] mapperFiles; private Collection<Class<?>> mappers; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.context = (ConfigurableApplicationContext) applicationContext; } @Override public void afterPropertiesSet() throws Exception { try { service = Executors.newScheduledThreadPool(1); // 获取xml SqlSessionFactoryBean sessionFactoryBean = context .getBean(SqlSessionFactoryBean.class); Field field = sessionFactoryBean.getClass().getDeclaredField( "mapperLocations"); field.setAccessible(true); resources = (Resource[]) field.get(sessionFactoryBean); //获取mapper的class SqlSessionFactory factory = context .getBean(SqlSessionFactory.class); Configuration configuration = factory.getConfiguration(); mappers = configuration.getMapperRegistry().getMappers(); mapperFiles = new File[mappers.size()]; Iterator<Class<?>> iterator = mappers.iterator(); int i = 0; while (iterator.hasNext()) { Class<?> class1 = (Class<?>) iterator.next(); URL url = new URL(class1.getResource("") + class1.getSimpleName() + ".class"); mapperFiles[i++] = new File(url.getFile()); } // 触发文件监听事件 scanner = new Scanner(); scanner.scan(); service.scheduleAtFixedRate(new Task(), 5, 5, TimeUnit.SECONDS); } catch (Exception e1) { e1.printStackTrace(); } } class Task implements Runnable { @Override public void run() { try { if (scanner.isChanged()) { logger.debug("文件改变,重新加载."); System.out.println(""); scanner.reload(); logger.debug("加载完毕."); } } catch (Exception e) { e.printStackTrace(); } } } @SuppressWarnings({ "rawtypes" }) class Scanner { public void reload() throws Exception { SqlSessionFactory factory = context .getBean(SqlSessionFactory.class); Configuration configuration = factory.getConfiguration(); // 移除加载项 removeConfig(configuration); // 重新扫描加载xml if (resources != null) { for (int i = 0; i < resources.length; i++) { if (resources[i] == null) { continue; } try { XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder( resources[i].getInputStream(), configuration, resources[i].toString(), configuration.getSqlFragments()); xmlMapperBuilder.parse(); } catch (Exception e) { throw new NestedIOException( "Failed to parse mapping resource: '" + resources[i] + "'", e); } finally { ErrorContext.instance().reset(); } } } // 重新扫描加载class Field f = Configuration.class.getDeclaredField("mapperRegistry"); f.setAccessible(true); f.set(configuration, new MapperRegistry(configuration)); Iterator<Class<?>> iterator = mappers.iterator(); while (iterator.hasNext()) { Class<?> class1 = (Class<?>) iterator.next(); configuration.addMapper(class1); } } 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"); } 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(); } 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(); } public void scan() throws IOException { if (!fileMapping.isEmpty()) { return; } if (resources != null) { for (int i = 0; i < resources.length; i++) { String multi_key = getValue(resources[i]); fileMapping.put(resources[i].getFilename(), multi_key); } } if (mapperFiles != null) { for (int i = 0; i < mapperFiles.length; i++) { fileMapping.put(mapperFiles[i].getAbsolutePath(), mapperFiles[i].lastModified() + ""); } } } 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 boolean isChanged() throws IOException { boolean isChanged = false; 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)) { isChanged = true; fileMapping.put(name, multi_key); } } } if (mapperFiles != null) { for (int i = 0; i < mapperFiles.length; i++) { String name = mapperFiles[i].getAbsolutePath(); String preValue = fileMapping.get(name); String curValue = mapperFiles[i].lastModified() + ""; if (!curValue.equals(preValue)) { isChanged = true; fileMapping.put(name, curValue); } } } return isChanged; } } @Override public void destroy() throws Exception { if (service != null) { service.shutdownNow(); } } }