mybatis热部署加载*Mapper.xml文件,手动刷新*Mapper.xml文件

由于项目已经发布到线上,要是修改一个Mapper.xml文件的话,需要重启整个服务,这个是很耗时间的,而且在一段时间内导致服务不可用,严重影响用户

的体验度。所以希望可以有一个机制可以,当修改某个mapper.xml的时候,只要重新加载这个mapper.xml就好了,参考网上的一些资料和demo,加上一些

自己的总结,下面的代码是通过测试的,可以供你们参考和使用。

[java]  view plain  copy
  1. import java.io.IOException;    
  2. import java.lang.reflect.Field;    
  3. import java.util.ArrayList;  
  4. import java.util.HashMap;    
  5. import java.util.List;  
  6. import java.util.Map;    
  7. import java.util.Set;    
  8.     
  9. import org.apache.commons.logging.Log;    
  10. import org.apache.commons.logging.LogFactory;    
  11. import org.apache.ibatis.builder.xml.XMLMapperBuilder;    
  12. import org.apache.ibatis.session.Configuration;    
  13. import org.apache.ibatis.session.SqlSessionFactory;    
  14. import org.springframework.core.io.Resource;    
  15. import org.springframework.core.io.support.PathMatchingResourcePatternResolver;    
  16.     
  17. public class RefreshMapperCache {    
  18.     private Log log  = LogFactory.getLog(RefreshMapperCache.class);    
  19.       
  20.     private SqlSessionFactory sqlSessionFactory;    
  21.     private Resource[] mapperLocations;    
  22.     private String packageSearchPath;    
  23.     private HashMap<String, Long> fileMapping = new HashMap<String, Long>();// 记录文件是否变化    
  24.       
  25.     //记录发生改变的xml文件名称  
  26.     private List<String> changeResourceNameList = new ArrayList<>();  
  27.         
  28.     public void refreshMapper() {    
  29.         try {    
  30.             Configuration configuration = this.sqlSessionFactory.getConfiguration();    
  31.                 
  32.             // step.1 扫描文件    
  33.             try {    
  34.                 this.scanMapperXml();    
  35.             } catch (IOException e) {    
  36.                 log.error("packageSearchPath扫描包路径配置错误");    
  37.                 return;    
  38.             }    
  39.                 
  40. //            System.out.println("==============刷新前mapper中的内容 start===============");    
  41. //            //获取xml中的每个语句的名称即 id = "findUserById";  
  42. //            for (String name : configuration.getMappedStatementNames()) {    
  43. //                System.out.println(name);    
  44. //            }    
  45. //            System.out.println("==============刷新前mapper中的内容   end===============");    
  46.               
  47.             //清空被修改过后的文件名称,确保该集合是空的  
  48.             changeResourceNameList.clear();  
  49.             // step.2 判断是否有文件发生了变化    
  50.             if (this.isChanged()) {    
  51.                 // step.2.1 清理    
  52.                 this.removeConfig(configuration);    
  53.     
  54.                 // step.2.2 重新加载    
  55.                 for (Resource configLocation : mapperLocations) {    
  56.                     try {   
  57.                         //匹配被修改过的mapper文件,如果存在,则重新加载  
  58.                         //如果想要重新加载全部mapper,可以不匹配  
  59.                         if(changeResourceNameList.contains(configLocation.getFilename())){  
  60.                              XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(configLocation.getInputStream(), configuration, configLocation.toString(), configuration.getSqlFragments());    
  61.                              xmlMapperBuilder.parse();    
  62.                              System.out.println("mapper文件[" + configLocation.getFilename() + "]缓存加载成功");    
  63.                         }  
  64.                     } catch (IOException e) {    
  65.                         System.out.println("mapper文件[" + configLocation.getFilename() + "]不存在或内容格式不对");    
  66.                         continue;    
  67.                     }    
  68.                 }  
  69.                 //清空被修改过后的文件名称  
  70.                 changeResourceNameList.clear();  
  71.             }    
  72.                 
  73. //            System.out.println("--------------------------刷新后mapper中的内容 start--------------------------");    
  74. //            for (String name : configuration.getMappedStatementNames()) {    
  75. //                System.out.println(name);    
  76. //            }  
  77. //            System.out.println("--------------------------刷新后mapper中的内容  end--------------------------");     
  78.         } catch (Exception e) {    
  79.            System.out.println("****************刷新缓存异常: "+e.getMessage());  
  80.         }    
  81.     }    
  82.         
  83.     public void setPackageSearchPath(String packageSearchPath) {    
  84.         this.packageSearchPath = packageSearchPath;    
  85.     }    
  86.         
  87.     public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {    
  88.         this.sqlSessionFactory = sqlSessionFactory;    
  89.     }    
  90.     
  91.     /**  
  92.      * 扫描xml文件所在的路径  
  93.      * @throws IOException   
  94.      */    
  95.     private void scanMapperXml() throws IOException {    
  96.         this.mapperLocations = new PathMatchingResourcePatternResolver().getResources(packageSearchPath);    
  97.     }    
  98.     
  99.     /**  
  100.      * 清空Configuration中几个重要的缓存  
  101.      * @param configuration  
  102.      * @throws Exception  
  103.      */    
  104.     private void removeConfig(Configuration configuration) throws Exception {    
  105.         Class<?> classConfig = configuration.getClass();    
  106.         clearMap(classConfig, configuration, "mappedStatements");    
  107.         clearMap(classConfig, configuration, "caches");    
  108.         clearMap(classConfig, configuration, "resultMaps");    
  109.         clearMap(classConfig, configuration, "parameterMaps");    
  110.         clearMap(classConfig, configuration, "keyGenerators");    
  111.         clearMap(classConfig, configuration, "sqlFragments");    
  112.     
  113.         clearSet(classConfig, configuration, "loadedResources");    
  114.     
  115.     }    
  116.     
  117.     @SuppressWarnings("rawtypes")    
  118.     private void clearMap(Class<?> classConfig, Configuration configuration, String fieldName) throws Exception {    
  119.         Field field = classConfig.getDeclaredField(fieldName);    
  120.         field.setAccessible(true);    
  121.         Map mapConfig = (Map) field.get(configuration);    
  122.         mapConfig.clear();    
  123.     }    
  124.     
  125.     @SuppressWarnings("rawtypes")    
  126.     private void clearSet(Class<?> classConfig, Configuration configuration, String fieldName) throws Exception {    
  127.         Field field = classConfig.getDeclaredField(fieldName);    
  128.         field.setAccessible(true);    
  129.         Set setConfig = (Set) field.get(configuration);    
  130.         setConfig.clear();    
  131.     }    
  132.         
  133.     /**  
  134.      * 判断文件是否发生了变化  
  135.      * @param resource  
  136.      * @return  
  137.      * @throws IOException  
  138.      */    
  139.     private boolean isChanged() throws IOException {    
  140.         boolean flag = false;    
  141.         System.out.println("***************************获取文件名   开始************************************");  
  142.         for (Resource resource : mapperLocations) {    
  143.             String resourceName = resource.getFilename();    
  144.               
  145.             System.out.println("resourceName == " + resourceName+",  path = "+resource.getURL().getPath());  
  146.               
  147.             boolean addFlag = !fileMapping.containsKey(resourceName);// 此为新增标识    
  148.                 
  149.             // 修改文件:判断文件内容是否有变化    
  150.             Long compareFrame = fileMapping.get(resourceName);    
  151.             long lastFrame = resource.contentLength() + resource.lastModified();    
  152.             boolean modifyFlag = null != compareFrame && compareFrame.longValue() != lastFrame;// 此为修改标识    
  153.               
  154.             if(addFlag){  
  155.                 System.out.println("            新增了:==="+ resourceName);  
  156.             }  
  157.             if(modifyFlag){  
  158.                 System.out.println("            修改了:==="+ resourceName);  
  159.             }  
  160.               
  161.             // 新增或是修改时,存储文件    
  162.             if(addFlag || modifyFlag) {    
  163.                 fileMapping.put(resourceName, Long.valueOf(lastFrame));// 文件内容帧值    
  164.                 flag = true;    
  165.                 changeResourceNameList.add(resourceName);  
  166.             }    
  167.         }   
  168.         System.out.println("***************************获取文件名   结束************************************");  
  169.         return flag;    
  170.     }    
  171. }    

写一个实体类,然后在spring中配置改实体类的bean即可

[html]  view plain  copy
  1. <bean id="refreshMapperCache" class="com.company.project.util.RefreshMapperCache" >    
  2.     <!-- 扫描的映射mapper.xml的文件路径   
  3.            这个地方要注意mapper的文件,多数据源情况下,只能扫描自己数据源下的mapper,否则会报异常          -->  
  4.       <property name="packageSearchPath" value="classpath*:mapper/trade/**/*.xml"></property>   
  5.       <!-- 配置自己的数据源 -->   
  6.       <property name="sqlSessionFactory" ref="sqlSessionFactoryPay"></property>    
  7. </bean>    


由于我们公司使用的是多数据源,所以在配置bean的时候,要给每个数据源配置一个bean,注意点就是在配置bean的时候

1. 如果是多数据源的情况 ,  扫描mapper.xml文件的时候,只能扫该数据源下的mapper.xml文件

2. 多数据源情况想,设置sqlSessionFactory 的时候,要设置为对应的数据源

3. 如果是但数据源的情况,那么就简单了,只需要配置当前数据源及对应的mapper.xml文件即可

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值