每次修改mybatis的sql腳本後,都要重啓,因爲mybatis的mapper文件默認只在啓動時加載到緩存,改動後不會自動加載,於是研究了下mybatis配置文件的加載,分享如下: 實現思路:使用定時器定時掃描mapper文件的改動,如果有改動則調用mapper文件的加載方法XMLMapperBuilder.parse()。 一.寫一個重新加載mapper文件的java類 首先需要構建一個sqlSessionFactory對象,並指定mybatis的Configuration.xml配置文件路徑,之後定時掃描並判斷mapper文件是否有改動,如果有改動則重新加載, 代碼如下: package zttc.itat.user.utils; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Field; import java.util.HashMap; 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.io.Resources; import org.apache.ibatis.session.Configuration; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.apache.log4j.Logger; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; /** * mybatis的mapper文件有改動時,進行重新加載 * @author ycblus * */ public class SqlSessionCache { private Logger log = Logger.getLogger(SqlSessionCache.class); private Resource[] mapperLocations; private String packageSearchPath = "classpath*:zttc/itat/user/mapper/*.xml"; SqlSessionFactory sqlSessionFactory; Configuration configuration; private HashMap<String, Long> fileMapping = new HashMap<String, Long>();// 記錄文件是否變化 { String resource = "Configuration.xml"; InputStream inputStream; try { inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream) ; configuration = this.sqlSessionFactory.getConfiguration(); //掃描文件 } catch (IOException e) { e.printStackTrace(); } } public void refreshMapper() throws Exception{ try { try { this.scanMapperXml(); } catch (IOException e) { log.error("packageSearchPath掃描包路徑配置錯誤"); return; } Runnable runnable = new Runnable() { public void run() { // task to run goes here try { // 判斷是否有文件發生了變化 if (isChanged()) { // 清理 this.removeConfig(configuration); // 重新加載 for (Resource configLocation : mapperLocations) { try { XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(configLocation.getInputStream(), configuration, configLocation.toString(), configuration.getSqlFragments()); xmlMapperBuilder.parse(); log.info("mapper文件[" + configLocation.getFilename() + "]加載成功"); } catch (IOException e) { log.error("mapper文件[" + configLocation.getFilename() + "]不存在或內容格式不對"); continue; } } } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 清空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"); } /** * 判斷文件是否發生了變化 * @param resource * @return * @throws IOException */ 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.longValue() != lastFrame;// 此爲修改標識 fileMapping.put(resourceName, Long.valueOf(lastFrame));// 文件內容幀值 // 新增或是修改時,存儲文件 if(addFlag || modifyFlag) { flag = true; } } return flag; } }; ScheduledExecutorService service = Executors .newSingleThreadScheduledExecutor(); // 第二個參數爲首次執行的延時時間,第三個參數爲定時執行的間隔時間 service.scheduleAtFixedRate(runnable, 1, 10, TimeUnit.SECONDS); } catch (Exception e) { e.printStackTrace(); } } public void setPackageSearchPath(String packageSearchPath) { this.packageSearchPath = packageSearchPath; } public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) { this.sqlSessionFactory = sqlSessionFactory; } /** * 掃描xml文件所在的路徑 * @throws IOException */ private void scanMapperXml() throws IOException { this.mapperLocations = new PathMatchingResourcePatternResolver().getResources(packageSearchPath); } /** * 清空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(); } public static void main(String[] args) { HashMap<String, Long> fileMapping = new HashMap<String, Long>(); boolean f = !fileMapping.isEmpty() && !fileMapping.containsKey("Hello.xml"); System.out.println(f); } } 二.Configuration.xml配置文件 這個配置文件在這裏只作爲掃描配置使用,可以看到其他配置都沒有,因爲我是在spring裏面統一配置了 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <mappers> <mapper resource="zttc/itat/user/mapper/TUserMapper.xml"/> <mapper resource="zttc/itat/user/mapper/TStoreMapper.xml"/> </mappers> </configuration> 三.寫一個Servlet,在服務器啓動時調用前面寫好的定時加載類。 代碼如下: package zttc.itat.user.servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import org.apache.log4j.Logger; import zttc.itat.user.utils.SqlSessionCache; /** * Servlet implementation class MapperReloadServlet * * when mybatis files changed,reload them */ public class MapperReloadServlet extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#HttpServlet() */ public MapperReloadServlet() { super(); // TODO Auto-generated constructor stub } public void init()throws ServletException { Logger logger = Logger.getLogger(this.getClass()); logger.info("The mapper reload timer starting... "); try { new SqlSessionCache().refreshMapper(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } 此外,需在web.xml中加入這個servlet類,添加代碼如下: <servlet> <servlet-name>MapperReloadServlet</servlet-name> <servlet-class>zttc.itat.user.servlet.MapperReloadServlet</servlet-class> <load-on-startup>7</load-on-startup> </servlet> 這樣每次當mapper文件有改動時,就會重新加載。不過會把所有的mapper文件重新加載一遍,如果需要對指定文件進行加載也是可以的,需要修改下重新加載的類。
mybatis實現mapper文件熱部署
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.