我使用绑定有两个原因:
- 使用“全局”的资源,例如数据库连接或消息中介通道运行重写常量或其他符号的其它值测试
testing
我工作在一个分布式系统上有几个组件通过消息交换发送消息进行通信。这些交换机具有全局名称,这是我喜欢这样的定义:
(ns const)
(def JOB-EXCHANGE "my.job.xchg")
(def CRUNCH-EXCHANGE "my.crunch.xchg")
;; ... more constants
这些常量在许多地方被用来将消息发送到正确的地方。为了测试我的代码,我的测试套件的一部分运行使用实际消息交换的代码。但是,我不希望我的测试干扰实际系统。
为了解决这个问题,我总结我的测试代码的binding
呼叫覆盖这些常量:
;; in my testing code:
(binding [const/CRUNCH-EXCHANGE (str const/CRUNCH-EXCHANGE (gensym "-TEST-"))
const/CRUNCH-TASK-QUEUE (str const/CRUNCH-TASK-QUEUE (gensym "-TEST-"))]
;; tests here
)
这里面binding
功能,我可以调用使用常数的任何代码,它会使用重写的值。
使用全球资源
另一种方式我使用绑定是“修复”特定范围内的全球或单资源的价值。这里有一个RabbitMQ的库我写的,我在那里一个RabbitMQ的Connection
的值绑定到符号*amqp-connection*
的例子让我的代码可以使用它:
(with-connection (make-connection opts)
;; code that uses a RabbitMQ connection
)
的with-connection
实现相当简单:
(def ^{:dynamic true} *amqp-connection* nil)
(defmacro with-connection
"Binds connection to a value you can retrieve
with (current-connection) within body."
[conn & body]
`(binding [*amqp-connection* ~conn]
[email protected]))
我的RabbitMQ库中的任何代码都可以使用*amqp-connection*
中的连接,并假定它是有效的,打开Connection
。或者使用(current-connection)
功能,它抛出,当你忘记在with-connection
来包装你的RabbitMQ调用一个描述异常:
(defn current-connection
"If used within (with-connection conn ...),
returns the currently bound connection."
[]
(if (current-connection?)
*amqp-connection*
(throw (RuntimeException.
"No current connection. Use (with-connection conn ...) to bind a connection."))))
给大家,到目前为止都是很好的答案。如果有其他人想要刺伤,我会在选择一个答案之前多留几天。 – bmillare