让Ioc容器帮你规划配置文件
配置文件的痛苦
一个 Java 项目,无论大小,多半是有那么几个配置文件的,比如:
- 数据库连接啦
- 关键的文件路径啦
- 一些曝露给运维人员的配置项啦
如果我们采用了 Ioc 方式组织我们的程序,我们(程序员)会理直气壮的对运维人员 说:“你去改xxxx Ioc 文件去。”
老实说,运维人员会恨死你,我列一个很简单的 JSON 配置文件:
var ioc = { // 数据源 dataSource : { type :"org.apache.commons.dbcp.BasicDataSource", events : { depose :"close" }, fields : { driverClassName : "com.mysql.jdbc.Driver", url : "jdbc:mysql://127.0.0.1:3306/mydb", username : "root", password : "123456", initialSize : 10, maxActive : 100, testOnReturn : true, //validationQueryTimeout : 5, validationQuery : "select 1" } }, // Dao dao : { type :'org.nutz.dao.impl.NutDao', args : [ {refer :"dataSource"}] } };
这个配置文件就是简单的配置了以下数据源,以及一个 Dao 对象。一个运维人员打开这个文件,首先映入 眼帘的就是"org.apache.commons.dbcp.BasicDataSource" 以及 depose :"close" 他会吓的够呛,心里嘀咕:"这TM是神马东西!"
运维人员希望看到什么呢? 他希望看到这个:
db-driver=com.mysql.jdbc.Driver db-url=jdbc:mysql://127.0.0.1:3306/mydb db-username=root db-password=123456
这样格式的文件,傻子也知道怎么维护。
当然,很多小JIAN人喜欢XML,这样的文件
<db> <driver>com.mysql.jdbc.Driver</driver> <url>jdbc:mysql://127.0.0.1:3306/mydb</url> <username>root</username> <password>123456</password> </db>
TA 看到会欢喜的不得了。
总之,有没有什么办法,能够让运维人员之看到他们喜欢看到的文件,而程序员则继续维护自己的 Ioc 文件呢? 怎么把 这两种文件连接起来呢?
有,实际上,从很早以前,Nutz 就很好的支持了这样的做法,不过这次,郑重写个文档出来,也是为了避免有人再有 这个问题
答案是:采用 java 型注入值
用 Properties 举个例子
就用上面的例子,如果我们需要暴露给运维人员一个 properties 文件任其修改:
-----------------------------------------------------[下面是 myapp.properties 文件的内容]--- db-driver=com.mysql.jdbc.Driver db-url=jdbc:mysql://127.0.0.1:3306/mydb db-username=root db-password=123456
那么我们的 Ioc 文件就改成这样:
var ioc = { // 读取配置文件 conf : { type : "org.nutz.ioc.impl.PropertiesProxy", fields : { paths : ["myapp.properties"] } }, // 数据源 dataSource : { type :"org.apache.commons.dbcp.BasicDataSource", events : { depose :"close" }, fields : { driverClassName : {java :"$conf.get('db-driver')"}, url : {java :"$conf.get('db-url')"}, username : {java :"$conf.get('db-username')"}, password : {java :"$conf.get('db-password')"}, initialSize : 10, maxActive : 100, testOnReturn : true, //validationQueryTimeout : 5, validationQuery : "select 1" } }, // Dao dao : { type :'org.nutz.dao.impl.NutDao', args : [ {refer :"dataSource"}] } };
这里有几个重点
- Nutz 提供了一个类 org.nutz.ioc.impl.PropertiesProxy,他能读取并解析一个 properties 文件
- 在 Ioc 容器中,我们创建一个这样的单例对象,随便起个名字,比如叫 "config"
- 那么根据配置 "myapp.properties" 会被 PropertiesProxy 类加载
- 通过 java 调用,你可以直接调用 "config" 对象的 get 方法
- 这样,你就能将分散在各个 Ioc 文件中的值集中到一个 properties 文件里了
使用PropertiesProxy实现更简洁的构造方式
dao.js
var ioc = { // 读取配置文件 conf : { type : "org.nutz.ioc.impl.PropertiesProxy", fields : { paths : ["custom/"] } }, // 数据源 dataSource : { factory : "$conf#make", args : ["com.alibaba.druid.pool.DruidDataSource", "db."], type : "com.alibaba.druid.pool.DruidDataSource", events : { create : "init", depose : 'close' } }, // Dao dao : { type :'org.nutz.dao.impl.NutDao', args : [ {refer :"dataSource"}] } };
custom/db.properties文件
db.url=jdbc:mysql://127.0.0.1:3306/nutzbook db.username=root db.password=root db.validationQuery=select 1 db.maxActive=50 db.testWhileIdle=true db.filters=mergeStat db.connectionProperties=druid.stat.slowSqlMillis=2000 db.defaultAutoCommit=true
重点是 factory配置, 使用$conf的make方法,可以根据一个类和指定前缀,生成一个对象
关于XML
如果你打算给你的运维人员看 XML 怎么办呢?抱歉,Nutz 木有给出内部支持,但是简单的要命,你需要:
- 提供一个 XML 配置解析类,从xml读取内容,然后,提供 get 方法
- 在 Ioc 配置的任何地方,你都可以用 java 调用的方式,调用 get 方法
我是用Annotation的Ioc
如果是这样,那么 @Inject 可以这样写:
@Inject("java:$config.get('xxxxx')") private String myXXXX;
关于更多扩展的意淫
现在的云端应用,你不弄七八台机器放在一负载均衡后面,你都不好意思叫它们服务器。并且这些机器基本 都是跑一样的程序,用一样的配置文件,很多运维人员(尤其是不会写脚本的鼠标派运维人员)会很痛苦:
“配置文件同步害死人呀!”
那么,如果你把关键的配置信息放到一张数据表里,然后自己提供一个类 ...
+--------+ +------------+ +----------+ | Ioc | <<< {java:...} <<< | Your Class | <<<<<< | Database | +--------+ +------------+ +----------+
你只需要修改数据表,然后重启各个应用 ......
根据这个思路,你可以将你的关键配置信息汇集在:
- 数据表里
- YAML 或者其它什么运维人员喜欢的格式上
- 电子表格中
写一个解析类动态读取,于是,整个世界就会安静了 ...