首页 > 代码库 > 即時更新程式設定
即時更新程式設定
有一些交易程式,在營業時間並不容許隨易的停止服務,如果遇到很小的 bug 或問題,最好是以不停止服務,僅更改設定的方式來解決,這裡提供一個小小的程式,可以不停止服務的情況下,更新程式的設定。
1 package idv.steven.annotation; 2 3 import java.lang.annotation.ElementType; 4 import java.lang.annotation.Retention; 5 import java.lang.annotation.RetentionPolicy; 6 import java.lang.annotation.Target; 7 8 @Retention(RetentionPolicy.RUNTIME) 9 @Target(ElementType.FIELD)10 public @interface AutoUpdate {11 public String key();12 }
首先定義一個 annotation,這個 annotation 是用在標注要更新的欄位,所以第 9 行設定僅能用在欄位上。第 8 行也要特別注意,RetentionPolicy 有三個值,如下:
- SOURCE: Annotations 只存於程式碼檔,編譯器產生二進位表時捨棄之。
- CLASS: Annotations 保留於 class 二進位表內,但於執行期無法取用。
- RUNTIME: Annotations 保留於 class 二進位表內,且執行期可經由 reflection 機制取用。
RetentionPolicy 的預設值是 CLASS。
1 package idv.steven.annotation;2 3 import java.util.Map;4 5 public interface WatchedObject {6 public void onUpdating(Map<String, String> map);7 }
要被即時更新的類別必須實作這個介面,之後會以 Observer pattern 的方式更新物件的值。
1 package idv.steven.annotation; 2 3 import java.io.FileInputStream; 4 import java.io.FileNotFoundException; 5 import java.io.IOException; 6 import java.lang.reflect.Field; 7 import java.nio.file.FileSystems; 8 import java.nio.file.Path; 9 import java.nio.file.Paths; 10 import java.nio.file.StandardWatchEventKinds; 11 import java.nio.file.WatchEvent; 12 import java.nio.file.WatchKey; 13 import java.nio.file.WatchService; 14 import java.util.ArrayList; 15 import java.util.Map; 16 import java.util.Properties; 17 import java.util.TreeMap; 18 19 public class WatchProperties implements Runnable { 20 private ArrayList<WatchedObject> watchedObj = new ArrayList<WatchedObject>(); 21 private boolean isContinue = true; 22 23 private String fullFilename; 24 private String pathname = ""; 25 private String filename = ""; 26 27 public WatchProperties(String fullFilename) throws FileNotFoundException { 28 this.fullFilename = fullFilename; 29 splitPathAndFile(fullFilename); 30 } 31 32 public void run() { 33 final Path path = Paths.get(pathname); 34 WatchService watchService; 35 try { 36 watchService = FileSystems.getDefault().newWatchService(); 37 38 path.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY); 39 40 while (isContinue) { 41 final WatchKey key = watchService.take(); 42 43 for (WatchEvent<?> watchEvent : key.pollEvents()) { 44 final WatchEvent<Path> watchEventPath = (WatchEvent<Path>) watchEvent; 45 final Path currentFilename = watchEventPath.context(); 46 47 if (currentFilename.toString().equalsIgnoreCase(filename)) { 48 triggerUpdating(); 49 break; 50 } 51 } 52 53 boolean valid = key.reset(); 54 if (!valid) { 55 System.out.println("reset fail"); 56 break; 57 } 58 else { 59 System.out.println("reset success"); 60 } 61 } 62 63 watchService.close(); 64 } catch (IOException | InterruptedException e) { 65 e.printStackTrace(); 66 } 67 } 68 69 private void splitPathAndFile(String fullFilename) throws FileNotFoundException { 70 fullFilename.replace(‘\\‘, ‘/‘); 71 String[] tokens = fullFilename.split("/"); 72 if (tokens != null) { 73 for(int i=0; i<tokens.length-2; i++) { 74 pathname = pathname + tokens[i] + "/"; 75 } 76 pathname = pathname + tokens[tokens.length-2]; 77 filename = tokens[tokens.length-1]; 78 } 79 else { 80 throw new FileNotFoundException(); 81 } 82 } 83 84 private void triggerUpdating() { 85 Properties properties = new Properties(); 86 87 try { 88 properties.load(new FileInputStream(fullFilename)); 89 90 for(WatchedObject obj:watchedObj) { 91 Map<String, String> map = new TreeMap<String, String>(); 92 93 Class<? extends WatchedObject> aClass = obj.getClass().asSubclass(WatchedObject.class); 94 Field[] fields = aClass.getDeclaredFields(); 95 for(Field field:fields) { 96 AutoUpdate autoUpdate = field.getAnnotation(AutoUpdate.class); 97 if (autoUpdate != null) { 98 String key = autoUpdate.key(); 99 if (properties.getProperty(key) != null) {100 map.put(key, properties.getProperty(key));101 }102 }103 }104 105 if (map.size() > 0) {106 obj.onUpdating(map);107 }108 }109 } catch (FileNotFoundException ex) {110 ex.printStackTrace();111 return;112 } catch (IOException ex) {113 ex.printStackTrace();114 return;115 }116 }117 118 public void register(WatchedObject obj) {119 watchedObj.add(obj);120 }121 122 public void unregister(WatchedObject obj) {123 watchedObj.remove(obj);124 }125 }
這個類別使用 Watch Service API 監看設定檔,當設定檔改變,透過 Observer pattern 的方式,通知相關物件。這裡就程式簡略的說明:
- Line 94: 一定要呼叫 getDeclaredFields() 才能取得所有的 field,如果呼叫 getFields() 僅能取得 public 的 field。
- register(): 要被即時更新的物件透過這個 method 註冊。
- Line 96: 我們僅在意有 @AutoUpdate 這個 annotation 的欄位。
1 package idv.steven.annotation; 2 3 import java.io.FileNotFoundException; 4 import java.util.Map; 5 import java.util.Set; 6 7 public class Main implements WatchedObject { 8 @AutoUpdate(key="bufLen") 9 private Integer bufLen;10 @AutoUpdate(key="msgCode")11 private String msgCode;12 13 private void run() {14 try {15 WatchProperties watchProperties = new WatchProperties("D:/temp/main.properties");16 watchProperties.register(this);17 Thread watchThread = new Thread(watchProperties);18 watchThread.start();19 20 } catch (FileNotFoundException e) {21 e.printStackTrace();22 }23 }24 25 @Override26 public void onUpdating(Map<String, String> map) {27 Set<String> keys = map.keySet();28 for(String key:keys) {29 if (key.equals("bufLen")) {30 bufLen = Integer.parseInt(map.get(key).toString());31 System.out.println("bufLen = " + bufLen);32 }33 else if (key.equals("msgCode")) {34 msgCode = map.get(key).toString();35 System.out.println("msgCode = " + msgCode);36 }37 }38 }39 40 public static void main(String[] args) {41 new Main().run();42 }43 }
Main 是要被即時更新的類別,所以要實作 WatchedObject 這個介面,並在 16 行將自己註冊到監看的程式上。當設定檔有異動,會有事件透過 onUpdating() 傳過來,這時候即可更新相關欄位的值。
bufLen=1024
msgCode=MSG001
Organization=OTC
設定檔的內容如上,當然會用到的只有上面兩行,這是個 property 檔,key 的值要和 Main 類別程式中的 annotation 標示的 key 值一樣。
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。