初学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的方法,如果真没有官方现成的,那么上面的做法无疑是一条可行的解决方案。