自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

從零搭建開發(fā)腳手架Spring Boot 集成Groovy實現(xiàn)動態(tài)加載業(yè)務(wù)規(guī)則

開發(fā) 前端
前段時間體驗了Zuul的groovy Filter,其實現(xiàn)了動態(tài)熱加載Filter,可以在不重啟應(yīng)用的情況下新增、修改自己的業(yè)務(wù)規(guī)則,現(xiàn)在我也來仿照Zuul來山寨一個,用于我們?nèi)粘6嘧兊臉I(yè)務(wù)規(guī)則中。

[[420920]]

本文轉(zhuǎn)載自微信公眾號「Java大廠面試官」,作者laker。轉(zhuǎn)載本文請聯(lián)系Java大廠面試官公眾號。

背景

前段時間體驗了Zuul的groovy Filter,其實現(xiàn)了動態(tài)熱加載Filter,可以在不重啟應(yīng)用的情況下新增、修改自己的業(yè)務(wù)規(guī)則,現(xiàn)在我也來仿照Zuul來山寨一個,用于我們?nèi)粘6嘧兊臉I(yè)務(wù)規(guī)則中。

需要依賴groovy-all

  1. <dependency> 
  2.      <groupId>org.codehaus.groovy</groupId> 
  3.      <artifactId>groovy-all</artifactId> 
  4.      <version>2.4.12</version> 版本自己去適配哈 
  5.  </dependency> 

什么是 Groovy?

類似于Python,perl等靈活動態(tài)語言,不過它是運行在java平臺上,也就是Groovy最后代碼會被編譯成class字節(jié)碼文件,集成到web應(yīng)用或者java應(yīng)用中,groovy編寫的程序其實就是特殊點的Java程序,而且java類庫可以在groovy中直接使用。

Groovy 的另一個好處是,它的語法與 Java 語言的語法很相似。

使用體驗

先來體驗下實現(xiàn)后的成果

1、利用Spring Boot的CommandLineRunner注冊SpringBean、GroovyBean

  • 初始化加載項目中RuleFilter的Spring Bean
    • 直接使用@Autowired注解配合List即可獲取所有RuleFilter的子類
  • 初始化Groovy動態(tài)掃描的監(jiān)控間隔,目錄配置
    • 這里配置的是每5秒檢查D:\\laker\\lakernote\\groovy目錄下,新增或者修改的文件用于編譯加載
    • 初始化也會加載D:\\laker\\lakernote\\groovy目錄下文件。
  1. @Component 
  2. public class GroovyRunner implements CommandLineRunner { 
  3.     @Autowired 
  4.     List<RuleFilter> ruleFilterList; 
  5.     @Override 
  6.     public void run(String... args) throws Exception { 
  7.         // 初始化加載項目中RuleFilter的Springbean 
  8.         RuleFilterLoader.getInstance().initSpringRuleFilter(ruleFilterList); 
  9.         try { 
  10.             // 每隔多少秒,掃描目錄下的groovy文件 
  11.             RuleFilterFileManager.init(5, "D:\\laker\\lakernote\\groovy"); 
  12.         } catch (Exception e) { 
  13.             e.printStackTrace(); 
  14.             throw new RuntimeException(); 
  15.         } 
  16.     } 

2、項目內(nèi)不變的規(guī)則以Java實現(xiàn)繼承RuleFilter

這個就是普通的Java類,我們把不變的規(guī)則以這種方式實現(xiàn)。

  1. @Component 
  2. public class JavaRule extends RuleFilter { 
  3.     /** 
  4.      * 具體規(guī)則執(zhí)行 
  5.      * @param msg 
  6.      */ 
  7.     @Override 
  8.     public void run(String msg) { 
  9.         System.out.println(" === Java 實現(xiàn)的業(yè)務(wù)規(guī)則 order = 1 , msg = " + msg + " === "); 
  10.     } 
  11.     /** 
  12.      * 該規(guī)則是否被執(zhí)行 
  13.      * @return 
  14.      */ 
  15.     @Override 
  16.     public boolean shouldRun() { 
  17.         return true
  18.     } 
  19.  
  20.     /** 
  21.      * 該規(guī)則執(zhí)行的順序 
  22.      * @return 
  23.      */ 
  24.     @Override 
  25.     public int runOrder() { 
  26.         return 1; 
  27.     } 

3、項目內(nèi)經(jīng)常變動的以Groovy來實現(xiàn)

groovy兼容Java語法,可以直接用java語法來寫。

  1. public class GroovyRule extends RuleFilter { 
  2.     @Override 
  3.     public void run(String msg) { 
  4.  
  5.         System.out.println(" === Groovy 實現(xiàn)的業(yè)務(wù)規(guī)則 order = " + runOrder() + ", msg = " + msg + " === "); 
  6.     } 
  7.     @Override 
  8.     public boolean shouldRun() { 
  9.         return true
  10.     } 
  11.     @Override 
  12.     public int runOrder() { 
  13.         return 2; 
  14.     } 

“然后把這個xxx.java文件丟到我們監(jiān)控的文件夾即可

4、在合適的位置使用RuleFilterProcessor

這里我寫了個Controller用來測試動態(tài)加載規(guī)則。

  1. @RestController 
  2. @RequestMapping("/groovy"
  3. public class GroovyController { 
  4.     @Autowired 
  5.     private RuleFilterProcessor ruleFilterProcessor; 
  6.  
  7.     @GetMapping() 
  8.     @ApiOperation("測試groovy的動態(tài)加載"
  9.     public void transaction(@RequestParam String msg) { 
  10.         ruleFilterProcessor.runRuleFilters(msg); 
  11.     } 

5、啟動并驗證

我分了幾個場景驗證如下:

1). 啟動程序

瀏覽器訪問:http://localhost:8080/groovy?msg=laker%20666

結(jié)果如下:

  1. === Java 實現(xiàn)的業(yè)務(wù)規(guī)則 order = 1 , msg = laker 666 ===  
  2. === Groovy 實現(xiàn)的業(yè)務(wù)規(guī)則 order = 2 , msg = laker 666 ===  

2.) 我修改GroovyRule中的runOrder(),把它改為0

“不用重啟服務(wù)

瀏覽器訪問:http://localhost:8080/groovy?msg=laker%20666

結(jié)果如下:

  1. === Groovy 實現(xiàn)的業(yè)務(wù)規(guī)則 order = 0 , msg = laker 666 ===  
  2. === Java 實現(xiàn)的業(yè)務(wù)規(guī)則 order = 1 , msg = laker 666 ===  

3). 我新增一個Groovy2Rule然后丟進上面指定的監(jiān)控文件夾

  1. public class Groovy2Rule extends RuleFilter { 
  2.     @Override 
  3.     public void run(String msg) { 
  4.         System.out.println(" === Groovy 實現(xiàn)的業(yè)務(wù)規(guī)則 order = " + runOrder() + ", msg = " + msg + " === "); 
  5.         List<RuleFilter> ruleFilters = RuleFilterLoader.getInstance().getFilters(); 
  6.         for (RuleFilter ruleFilter : ruleFilters) { 
  7.             System.out.println(ruleFilter.getClass().getName()); 
  8.         } 
  9.     } 
  10.     @Override 
  11.     public boolean shouldRun() { 
  12.         return true
  13.     } 
  14.  
  15.     @Override 
  16.     public int runOrder() { 
  17.         return 3; 
  18.     } 

不用重啟服務(wù)

瀏覽器訪問:http://localhost:8080/groovy?msg=laker%20666

結(jié)果如下:

  1.  === Groovy 實現(xiàn)的業(yè)務(wù)規(guī)則 order = 0 , msg = laker 666 ===  
  2.  === Java 實現(xiàn)的業(yè)務(wù)規(guī)則 order = 1 , msg = laker 666 ===  
  3.  === Groovy 實現(xiàn)的業(yè)務(wù)規(guī)則 order = 3, msg = laker 666 ===  
  4. com.laker.map.moudle.groovy.javarule.GroovyRule 
  5. com.laker.map.moudle.groovy.javarule.JavaRule 
  6. com.laker.map.moudle.groovy.Groovy2Rule 

“這里如果想調(diào)用Spring環(huán)境中的bean可以借助SpringContextUtil

實現(xiàn)

核心的模塊如下

  • RuleFilter :規(guī)則過濾器抽象類,用于擴展實現(xiàn)業(yè)務(wù)規(guī)則,供Java和Groovy繼承。
  • RuleFilterLoader :規(guī)則過濾器加載器,用于加載基于Spring的RuleFilter實現(xiàn)類和動態(tài)編譯指定文件基于Groovy的RuleFilter實現(xiàn)類。

存儲所有的規(guī)則過濾器并能動態(tài)加載改變的和新增的規(guī)則。

  • RuleFilterFileManager : 一個獨立線程輪詢監(jiān)聽指定目錄文件的變化配合RuleFilterLoader ( 規(guī)則過濾器加載器)使用。
  • RuleFilterProcessor: 業(yè)務(wù)規(guī)則處理器核心入口

“這四個核心模塊都是盜版Zuul的實現(xiàn)。

貼上部分核心代碼如下:

RuleFilter.java

  1. public abstract class RuleFilter implements IRule, Comparable<RuleFilter> { 
  2.  
  3.     abstract public int runOrder(); 
  4.  
  5.     @Override 
  6.     public int compareTo(RuleFilter ruleFilter) { 
  7.         return Integer.compare(this.runOrder(), ruleFilter.runOrder()); 
  8.     } 
  9.     ... 

RuleFilterLoader.java

  1. public class RuleFilterLoader { 
  2.     public boolean putFilter(File file) throws Exception { 
  3.         String sName = file.getAbsolutePath() + file.getName(); 
  4.         if (filterClassLastModified.get(sName) != null && (file.lastModified() != filterClassLastModified.get(sName))) { 
  5.             LOG.debug("reloading filter " + sName); 
  6.             filterRegistry.remove(sName); 
  7.         } 
  8.         RuleFilter filter = filterRegistry.get(sName); 
  9.         if (filter == null) { 
  10.             Class clazz = compile(file); 
  11.             if (!Modifier.isAbstract(clazz.getModifiers())) { 
  12.                 filter = (RuleFilter) clazz.newInstance(); 
  13.                 filterRegistry.put(file.getAbsolutePath() + file.getName(), filter); 
  14.                 ruleFilters.clear(); 
  15.                 filterClassLastModified.put(sName, file.lastModified()); 
  16.                 return true
  17.             } 
  18.         } 
  19.         return false
  20.     } 
  21.     public List<RuleFilter> getFilters() { 
  22.         if (CollUtil.isNotEmpty(ruleFilters)) { 
  23.             return ruleFilters; 
  24.         } 
  25.         ruleFilters.addAll(springRuleFilterList); 
  26.         ruleFilters.addAll(this.filterRegistry.values()); 
  27.         Collections.sort(ruleFilters); 
  28.         return ruleFilters; 
  29.     } 
  30.     private Class compile(File file) throws IOException { 
  31.         GroovyClassLoader loader = getGroovyClassLoader(); 
  32.         Class groovyClass = loader.parseClass(file); 
  33.         return groovyClass; 
  34.     } 
  35.     GroovyClassLoader getGroovyClassLoader() { 
  36.         return new GroovyClassLoader(); 
  37.     } 
  38.     ... 

RuleFilterFileManager.java

  1. public class RuleFilterFileManager { 
  2.     public static void init(int pollingIntervalSeconds, String... directories)  { 
  3.         if (INSTANCE == null) INSTANCE = new RuleFilterFileManager(); 
  4.  
  5.         INSTANCE.aDirectories = directories; 
  6.         INSTANCE.pollingIntervalSeconds = pollingIntervalSeconds; 
  7.         INSTANCE.manageFiles(); 
  8.         INSTANCE.startPoller(); 
  9.     } 
  10.     void startPoller() { 
  11.         poller = new Thread("GroovyRuleFilterFileManagerPoller") { 
  12.             @Override 
  13.             public void run() { 
  14.                 while (bRunning) { 
  15.                     try { 
  16.                         sleep(pollingIntervalSeconds * 1000); 
  17.                         manageFiles(); 
  18.                     } catch (Exception e) { 
  19.                         e.printStackTrace(); 
  20.                     } 
  21.                 } 
  22.             } 
  23.         }; 
  24.         poller.setDaemon(true); 
  25.         poller.start(); 
  26.     } 
  27.    void processGroovyFiles(List<File> aFiles) throws Exception, InstantiationException, IllegalAccessException { 
  28.  
  29.         for (File file : aFiles) { 
  30.             RuleFilterLoader.getInstance().putFilter(file); 
  31.         } 
  32.     } 
  33.     void manageFiles() throws Exception, IllegalAccessException, InstantiationException { 
  34.         List<File> aFiles = getFiles(); 
  35.         processGroovyFiles(aFiles); 
  36.     } 
  37.     ... 

RuleFilterProcessor.java

  1. @Component 
  2. public class RuleFilterProcessor { 
  3.     public void runRuleFilters(String msg) { 
  4.         List<RuleFilter> list = RuleFilterLoader.getInstance().getFilters(); 
  5.         if (list != null) { 
  6.             list.forEach(ruleFilter -> { 
  7.                 if (ruleFilter.shouldRun()) { 
  8.                     ruleFilter.run(msg); 
  9.                 } 
  10.             }); 
  11.         } 
  12.     } 

總結(jié)

可以看到使用起來是相當(dāng)?shù)姆奖悖瑑H依賴groovy-all,整體代碼結(jié)構(gòu)簡單。

性能和穩(wěn)定性未測試,但是這基本就是翻版的Zuul,Zuul都在使用了,應(yīng)該沒什么問題。

參考:

參考了Zuul源碼,比較簡單,建議大家都去看看。

 

責(zé)任編輯:武曉燕 來源: Java大廠面試官
相關(guān)推薦

2021-04-28 16:10:48

開發(fā)腳手架 Spring

2021-03-09 17:11:09

數(shù)據(jù)庫腳手架開發(fā)

2021-07-13 18:42:38

Spring Boot腳手架開發(fā)

2020-08-19 08:55:47

Redis緩存數(shù)據(jù)庫

2021-04-13 14:47:53

認證授權(quán)Java

2021-05-13 17:02:38

MDC腳手架日志

2021-03-11 14:16:47

Spring Boo開發(fā)腳手架

2021-07-29 18:49:49

Spring開發(fā)腳手架

2021-04-20 19:24:16

腳手架 Java微信

2021-06-02 17:58:49

腳手架 冪等性前端

2021-02-19 22:43:50

開發(fā)腳手架Controller

2020-06-29 11:35:02

Spring BootJava腳手架

2016-08-10 14:59:41

前端Javascript工具

2022-04-24 11:33:47

代碼管理工程

2023-11-21 17:36:04

OpenFeignSentinel

2014-08-15 09:36:06

2021-01-07 05:34:07

腳手架JDK緩存

2021-05-21 05:22:52

腳手架工具項目

2018-08-30 16:08:37

Node.js腳手架工具

2018-06-11 14:39:57

前端腳手架工具node.js
點贊
收藏

51CTO技術(shù)棧公眾號