(转)mybatis热部署加载*Mapper.xml文件,手动刷新*Mapper.xml文件
生活随笔
收集整理的這篇文章主要介紹了
(转)mybatis热部署加载*Mapper.xml文件,手动刷新*Mapper.xml文件
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
轉自: https://blog.csdn.net/LOVELONG8808/article/details/78738086?
由于項目已經發布到線上,要是修改一個Mapper.xml文件的話,需要重啟整個服務,這個是很耗時間的,而且在一段時間內導致服務不可用,嚴重影響用戶的體驗度。所以希望可以有一個機制可以,當修改某個mapper.xml的時候,只要重新加載這個mapper.xml就好了,參考網上的一些資料和demo,加上一些自己的總結,下面的代碼是通過測試的,可以供你們參考和使用。
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 org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.ibatis.builder.xml.XMLMapperBuilder; import org.apache.ibatis.session.Configuration; import org.apache.ibatis.session.SqlSessionFactory; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; public class RefreshMapperCache { private Log log = LogFactory.getLog(RefreshMapperCache.class); private SqlSessionFactory sqlSessionFactory; private Resource[] mapperLocations; private String packageSearchPath; private HashMap<String, Long> fileMapping = new HashMap<String, Long>();// 記錄文件是否變化 //記錄發生改變的xml文件名稱private List<String> changeResourceNameList = new ArrayList<>();public void refreshMapper() { try { Configuration configuration = this.sqlSessionFactory.getConfiguration(); // step.1 掃描文件 try { this.scanMapperXml(); } catch (IOException e) { log.error("packageSearchPath掃描包路徑配置錯誤"); return; } // System.out.println("==============刷新前mapper中的內容 start==============="); // //獲取xml中的每個語句的名稱即 id = "findUserById"; // for (String name : configuration.getMappedStatementNames()) { // System.out.println(name); // } // System.out.println("==============刷新前mapper中的內容 end==============="); //清空被修改過后的文件名稱,確保該集合是空的changeResourceNameList.clear();// step.2 判斷是否有文件發生了變化 if (this.isChanged()) { // step.2.1 清理 this.removeConfig(configuration); // step.2.2 重新加載 for (Resource configLocation : mapperLocations) { try { //匹配被修改過的mapper文件,如果存在,則重新加載//如果想要重新加載全部mapper,可以不匹配if(changeResourceNameList.contains(configLocation.getFilename())){XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(configLocation.getInputStream(), configuration, configLocation.toString(), configuration.getSqlFragments()); xmlMapperBuilder.parse(); System.out.println("mapper文件[" + configLocation.getFilename() + "]緩存加載成功"); }} catch (IOException e) { System.out.println("mapper文件[" + configLocation.getFilename() + "]不存在或內容格式不對"); continue; } }//清空被修改過后的文件名稱changeResourceNameList.clear();} // System.out.println("--------------------------刷新后mapper中的內容 start--------------------------"); // for (String name : configuration.getMappedStatementNames()) { // System.out.println(name); // } // System.out.println("--------------------------刷新后mapper中的內容 end--------------------------"); } catch (Exception e) { System.out.println("****************刷新緩存異常: "+e.getMessage());} } 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(); } /** * 判斷文件是否發生了變化 * @param resource * @return * @throws IOException */ private boolean isChanged() throws IOException { boolean flag = false; System.out.println("***************************獲取文件名 開始************************************");for (Resource resource : mapperLocations) { String resourceName = resource.getFilename(); System.out.println("resourceName == " + resourceName+", path = "+resource.getURL().getPath());boolean addFlag = !fileMapping.containsKey(resourceName);// 此為新增標識 // 修改文件:判斷文件內容是否有變化 Long compareFrame = fileMapping.get(resourceName); long lastFrame = resource.contentLength() + resource.lastModified(); boolean modifyFlag = null != compareFrame && compareFrame.longValue() != lastFrame;// 此為修改標識 if(addFlag){System.out.println(" 新增了:==="+ resourceName);}if(modifyFlag){System.out.println(" 修改了:==="+ resourceName);}// 新增或是修改時,存儲文件 if(addFlag || modifyFlag) { fileMapping.put(resourceName, Long.valueOf(lastFrame));// 文件內容幀值 flag = true; changeResourceNameList.add(resourceName);} } System.out.println("***************************獲取文件名 結束************************************");return flag; } }寫一個實體類,然后在spring中配置改實體類的bean即可
?
由于我們公司使用的是多數據源,所以在配置bean的時候,要給每個數據源配置一個bean,注意點就是在配置bean的時候
1. 如果是多數據源的情況 ,? 掃描mapper.xml文件的時候,只能掃該數據源下的mapper.xml文件
2. 多數據源情況想,設置sqlSessionFactory 的時候,要設置為對應的數據源
3. 如果是但數據源的情況,那么就簡單了,只需要配置當前數據源及對應的mapper.xml文件即可
?
總結
以上是生活随笔為你收集整理的(转)mybatis热部署加载*Mapper.xml文件,手动刷新*Mapper.xml文件的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: (转)linux上nginx源码编译安装
- 下一篇: 联想最新款手机(联想最新款手机2018)