zookeeper作配置中心(存储支付信息)
zookeeper作配置中心(存储敏感信息)
前提:最近在项目中需要用到支付接口,支付宝或者微信支付,根据官方文档,需要配置一些诸如notify-url
或者app-private-key
等信息,这些信息比较敏感,且是协同开发,为了避免发生一些不安全的事情,于是决定将这些信息存放在zookeeper中,这是主要原因,另一个原因是一旦配置需要改变,直接在zookeeper中改变即可,不需要重启后端服务,这里涉及到了zookeeper的NIO以及长连接等相关的底层网络编程,这里不再赘述。
1、首先在服务器端安装zookeeper,默认端口是2181,安装教程不讲解
2、在本机(Window 10)安装ZKUI(ZK可视化客户端),方便管理zookeeper
3、安装zookeeper的java客户端(curator)
4、读取配置信息并设置监听器
@Configuration
class PaymentConfig {
@Value("\${custom-config.zookeeper.url}")
lateinit var zkUrl: String
@Value("\${custom-config.zookeeper.zfb-nodename}")
lateinit var zfbNodeName: String
@Value("\${custom-config.zookeeper.wx-nodename}")
lateinit var wxNodeName: String
val remoteProperties: Properties = Properties()
companion object {
/**
* zookeeper节点映射在本地的键值
*/
private const val ALI_APP_ID = "/pay-server-config/pay.alipay/app-id"
private const val ALI_APP_PRIVATE_KEY = "/pay-server-config/pay.alipay/app-private-key"
private const val ALI_NOTIFY_URL = "/pay-server-config/pay.alipay/notify-url"
private const val ALI_PUBLIC_KEY = "/pay-server-config/pay.alipay/public-key"
private const val WX_NOTIFY_URL = "/pay-server-config/pay.wxpay/notify-url"
private const val WX_APP_ID = "/pay-server-config/pay.wxpay/app-id"
private const val WX_APP_PRIVATE_KEY = "/pay-server-config/pay.wxpay/app-private-key"
private const val WX_MCH_ID = "/pay-server-config/pay.wxpay/mch-id"
}
@PostConstruct
fun init(){
setPaymentConfigFromZk(remoteProperties)
}
fun setPaymentConfigFromZk(remoteProperties: Properties){
val zkClient: CuratorFramework = CuratorFrameworkFactory.newClient(zkUrl, RetryOneTime(1000))
zkClient.start()
try {
val zfbConfigNames = zkClient.children.forPath("/$zfbNodeName")
val wxConfigNames = zkClient.children.forPath("/$wxNodeName")
for (configName in zfbConfigNames) {
val value = String(zkClient.data.forPath("/$zfbNodeName/$configName"))
remoteProperties["/$zfbNodeName/$configName"] = value
}
for (configName in wxConfigNames) {
val value = String(zkClient.data.forPath("/$wxNodeName/$configName"))
remoteProperties["/$wxNodeName/$configName"] = value
}
setListener(zkClient, zfbNodeName, remoteProperties)
setListener(zkClient, wxNodeName, remoteProperties)
} catch (e: Exception) {
e.printStackTrace()
}
}
fun setListener(zkClient: CuratorFramework, uri: String, remoteProperties: Properties){
val treeCache = TreeCache(zkClient, "/$uri")
treeCache.start()
treeCache.listenable.addListener(TreeCacheListener(
fun(client: CuratorFramework, event: TreeCacheEvent) {
when (event.type) {
TreeCacheEvent.Type.NODE_UPDATED -> {
val value = String(event.data.data)
remoteProperties[event.data.path] = value
println("Payment URL has changed, the changed is ${String(event.data.data)}")
println("Payment URL has changed, the path is ${event.data.path}")
}
else -> {
print("Now, get the config from zookeeper ${event.data}")
}
}
}
)
)
}
}
以上代码大意为:在初始化的时候读取zookeeper中的值,并赋值到本地的Properties,key为zookeeper节点的全路径,值为叶子节点的Value,之后使用TreeCache监听客户端的变化,当某个叶子节点的值发生改变后,改变原有的properties,替换为新值。