有一些交易程式,在營業時間並不容許隨易的停止服務,如果遇到很小的 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 @Override 26 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 值一樣。
【日劇 - Miss PILOT】
2013/10/15 開播的日劇,堀北真希主演,是一個不小心被錄取為儲備機師後努力取得機師資格的人,當然這是勵志片。戲的重點是什麼呢? 美女吧?! 主角手塚晴 (堀北真希) 不用說是個大美女。
劇中另一個儲備女機師小田千里 (相武紗季) 外表比較不亮眼,所以讓大家看一下非本劇的另一張照片。
第三位阿倍野鈴 (櫻庭奈奈美) 是地勤,是一個缺乏安全感的機師女友,因為她只是戲份不多的配角,很難找到她在 Miss PILOT 中的獨照,就姑且看一下底下這張照片吧!
鈴木倫子 (菜菜緒) 是地勤,自認是教官國木田孝之助 (齋藤工) 的女友,才色兼具。
不知道為什麼,航空公司裡,連廚師都很漂亮,三枝佳乃子 (藤澤惠麻) 是飛行員宿舍的管理員兼主廚,戲份也不多,很難找到劇中的獨照 …