初學guice,每每看到guice 綁定常量的用法介紹,總是在想這個功能有什么用處?實在想不出來用它的場合和優點,感覺頗為雞肋。
今天閑坐家中,又無聊翻書打發時間,再次看到這個東東,作者和我似乎有相同的想法,不過他的一句“既然我們可以使用自定義注解,那么這里也可以替換成@Named,這里不再贅述。”,讓我突發奇想,能不能這樣用呢?
插一句題外話,guice入門資料,這里有一份整理好的,非常適合第一次接觸guice的朋友,推薦給大家:
guice入門資料 ,我今天看的就是這個。
首先看思路,@Named是這樣用的:
binder.bindConstant().annotatedWith(named("count")).to(40);
binder.bindConstant().annotatedWith(named("color")).to("red");
似乎還沒有特別感覺是吧?換成這樣呢?
binder.bindConstant().annotatedWith(named("username")).to("root");
binder.bindConstant().annotatedWith(named("password")).to("root");
看到username,password,總該熟悉了吧?配置啊配置,哪有不用配置文件的程序啊。
提到配置文件,第一個想到的,當然就是最原始的properties資源文件,相信類似這樣內容的文件大家都見的多了:
username=root
password=root
ip=192.168.0.1
port=80
聯系一下@Named,有感覺了吧?properties資源文件的name、value對,剛好對應
.annotatedWith(named("color")).to("red");如果能把資源文件讀出來,再按照name、value對用@Named綁定,不就實現了將properties資源文件中的配置信息綁定到運用程序中了嗎?
先給出資源文件server.config.properties,內容簡單點意思一下:
server.ip=192.168.0.1
server.port=90
server.username=root
server.password=root
然后是java實現代碼,同樣簡單意思一下而已:
package test.hw.basic.demo.bindconstant;
import static com.google.inject.name.Names.named;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Enumeration;
import java.util.Properties;
import com.google.inject.Binder;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.name.Named;
public class ConfigMain {
private static class Client {
@Inject
@Named("config.server.ip")
private String IP;
@Inject
@Named("config.server.port")
private int port;
@Inject
@Named("config.server.username")
private String username;
@Inject
@Named("config.server.password")
private String password;
public void work() {
System.out.println("ip=" + IP);
System.out.println("port=" + port);
System.out.println("username=" + username);
System.out.println("password=" + password);
//

}
}
public static void main(String[] args) {
Injector injector = Guice.createInjector(new Module() {
@SuppressWarnings("unchecked")
public void configure(Binder binder) {
Properties p = new Properties();
try {
p.load(new InputStreamReader(this.getClass()
.getResourceAsStream("server.config.properties")));
} catch (IOException e) {
e.printStackTrace();
assert false;
}
Enumeration e = p.keys();
while(e.hasMoreElements()) {
String key = (String)e.nextElement();
String value = (String)p.get(key);
binder.bindConstant().annotatedWith(named("config." + key)).to(value);
}
}
});
Client client = injector.getInstance(Client.class);
client.work();
}
}
run一下,可以看到意料中的輸出:
ip=192.168.0.1
port=90
username=root
password=root
Ok,確認無誤,我的想法得到了驗證,這個思路是可行的。額外注意的是,port是int類型,guice非常機敏的完成了類型轉換,正確的注入了我們期望的int數據。
上面的做法,適合類似用戶名密碼,ip端口這樣的幾乎是必須修改的配置信息,這些信息絕對不可能寫死在代碼里面。傳統的資源文件或者xml配置文件是存放它們最好的地方,而如何將這些配置信息傳入到以ioc,di為核心理念的應用,以spring為例,比如有一個client bean要連接外部服務器需要注入ip,port信息,如果直接在applicationContext.xml文件中配置,毫無疑問不是一個好辦法:太分散了,修改時找到要修改的地方可不容易,尤其對于bean比較多的情況而修改的人可能是客戶,現網施工維護人員,讓他們修改spring配置文件不現實。記得spring就有現成的完成讀取配置文件再注入bean的方案,細節大家可以google一下,比較簡單好用。
guice剛開始學習,似乎沒有找到類似spring的方法,如果真沒有官方現成的,那么上面的做法無疑是一條可行的解決方案。