成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

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

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

[[420920]]

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

背景

前段時(shí)間體驗(yàn)了Zuul的groovy Filter,其實(shí)現(xiàn)了動(dòng)態(tài)熱加載Filter,可以在不重啟應(yīng)用的情況下新增、修改自己的業(yè)務(wù)規(guī)則,現(xiàn)在我也來(lái)仿照Z(yǔ)uul來(lái)山寨一個(gè),用于我們?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?

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

Groovy 的另一個(gè)好處是,它的語(yǔ)法與 Java 語(yǔ)言的語(yǔ)法很相似。

使用體驗(yàn)

先來(lái)體驗(yàn)下實(shí)現(xiàn)后的成果

1、利用Spring Boot的CommandLineRunner注冊(cè)SpringBean、GroovyBean

  • 初始化加載項(xiàng)目中RuleFilter的Spring Bean
    • 直接使用@Autowired注解配合List即可獲取所有RuleFilter的子類(lèi)
  • 初始化Groovy動(dòng)態(tài)掃描的監(jiān)控間隔,目錄配置
    • 這里配置的是每5秒檢查D:\\laker\\lakernote\\groovy目錄下,新增或者修改的文件用于編譯加載
    • 初始化也會(huì)加載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.         // 初始化加載項(xiàng)目中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、項(xiàng)目?jī)?nèi)不變的規(guī)則以Java實(shí)現(xiàn)繼承RuleFilter

這個(gè)就是普通的Java類(lèi),我們把不變的規(guī)則以這種方式實(shí)現(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 實(shí)現(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、項(xiàng)目?jī)?nèi)經(jīng)常變動(dòng)的以Groovy來(lái)實(shí)現(xiàn)

groovy兼容Java語(yǔ)法,可以直接用java語(yǔ)法來(lái)寫(xiě)。

  1. public class GroovyRule extends RuleFilter { 
  2.     @Override 
  3.     public void run(String msg) { 
  4.  
  5.         System.out.println(" === Groovy 實(shí)現(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.     } 

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

4、在合適的位置使用RuleFilterProcessor

這里我寫(xiě)了個(gè)Controller用來(lái)測(cè)試動(dòng)態(tài)加載規(guī)則。

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

5、啟動(dòng)并驗(yàn)證

我分了幾個(gè)場(chǎng)景驗(yàn)證如下:

1). 啟動(dòng)程序

瀏覽器訪問(wèn):http://localhost:8080/groovy?msg=laker%20666

結(jié)果如下:

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

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

“不用重啟服務(wù)

瀏覽器訪問(wèn):http://localhost:8080/groovy?msg=laker%20666

結(jié)果如下:

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

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

  1. public class Groovy2Rule extends RuleFilter { 
  2.     @Override 
  3.     public void run(String msg) { 
  4.         System.out.println(" === Groovy 實(shí)現(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ù)

瀏覽器訪問(wèn):http://localhost:8080/groovy?msg=laker%20666

結(jié)果如下:

  1.  === Groovy 實(shí)現(xiàn)的業(yè)務(wù)規(guī)則 order = 0 , msg = laker 666 ===  
  2.  === Java 實(shí)現(xiàn)的業(yè)務(wù)規(guī)則 order = 1 , msg = laker 666 ===  
  3.  === Groovy 實(shí)現(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

實(shí)現(xiàn)

核心的模塊如下

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

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

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

“這四個(gè)核心模塊都是盜版Zuul的實(shí)現(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é)

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

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

參考:

參考了Zuul源碼,比較簡(jiǎn)單,建議大家都去看看。

 

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

2021-04-28 16:10:48

開(kāi)發(fā)腳手架 Spring

2021-03-09 17:11:09

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

2020-08-19 08:55:47

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

2021-07-13 18:42:38

Spring Boot腳手架開(kāi)發(fā)

2021-04-13 14:47:53

認(rèn)證授權(quán)Java

2021-05-13 17:02:38

MDC腳手架日志

2021-03-11 14:16:47

Spring Boo開(kāi)發(fā)腳手架

2021-07-29 18:49:49

Spring開(kāi)發(fā)腳手架

2021-04-20 19:24:16

腳手架 Java微信

2025-05-16 07:24:41

Springkafka腳手架

2021-06-02 17:58:49

腳手架 冪等性前端

2021-02-19 22:43:50

開(kāi)發(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緩存

2018-06-11 14:39:57

前端腳手架工具node.js

2018-08-30 16:08:37

Node.js腳手架工具
點(diǎn)贊
收藏

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

主站蜘蛛池模板: 美女一区 | 久久久成人一区二区免费影院 | 国产午夜精品一区二区三区四区 | 美女午夜影院 | 九九热在线免费观看 | 超碰超碰 | 欧美日韩亚洲系列 | 国产一区视频在线 | 91av免费版 | 98久久| 欧美13videosex性极品 | 日本不卡在线视频 | 狠狠操天天干 | 日韩视频在线免费观看 | 涩涩鲁亚洲精品一区二区 | 亚洲欧美在线视频 | 国产不卡视频在线 | 欧美日韩亚 | 午夜精品一区 | 久久精品av麻豆的观看方式 | 欧美国产精品 | 国产精品一区二区久久 | 日韩第一区 | 亚洲一区二区在线视频 | 一级全黄少妇性色生活免费看 | 日日夜夜91 | 久久av综合 | 99re视频在线 | 在线视频91 | 男女羞羞视频网站 | 国产乱码精品1区2区3区 | 色免费视频 | 一区二区三区视频在线免费观看 | 欧美视频在线播放 | 成人在线免费观看视频 | 国产精品成人免费 | 一级毛片视频 | 亚洲一区在线免费观看 | 在线观看中文字幕dvd播放 | 成人h动漫亚洲一区二区 | 视频一区在线 |