🥃 动态变量绑定
在大部分情况下,变量引用 + 配置文件
的方式都可以满足要求,比如:不同环境下配置不同的变量。但如果我想在每次引用变量的时候,都根据某种条件动态获取变量值就办不到了
因此,Forest 在 1.5.3
版本开始,提供了一种动态绑定变量名的技术
# 静态变量绑定
在了解什么是 动态变量绑定
之前,先来了解一下什么是 静态变量绑定
ForestConfiguration
对象提供了setVariableValue
方法可以动态设置静态绑定的全局变量值
但该方法设置的值为静态的值,即设置完之后该变量就不会再改变了,所有再次调用 setVariableValue
方法覆盖原来的变量值,所以称为变量的 静态绑定
。
setVariableValue(String name, Object value) 设置全局变量所对应的值
- 参数
name
: 变量名- 参数
name
: 变量值
// 获取 Forest 全局配置对象
ForestConfiguration configuration = Forest.config();
// 设置全局变量: name -> Peter
configuration.setVariableValue("name", "Peter");
// 设置全局变量: baseUrl -> http://abc.com
configuration.setVariableValue("baseUrl", "http://abc.com");
2
3
4
5
6
此时就能引用到刚才设置的全局变量名了
@Get("${baseUrl}/data?n={name}")
String getData();
// 调用该方法所产生的URL为
// http://abc.com/data?n=Peter
2
3
4
5
# 动态变量绑定
动态变量绑定
的概念是相对静态变量绑定
而来的,静态绑定的变量是一个固定值,即一旦设置完之后,就不会再做改变,每次引用到同一个变量名的值都是相同的,除非将变量名重新设值,覆盖掉原来的值。
而动态绑定的变量尤其说是变量,其实更接近于函数或者方法,即每次引用一个变量名的时候都会重新计算其变量值,相当于调用一次方法,而它的返回值即为变量名所对应的值。
上面介绍过的ForestConfiguration
对象的setVariableValue
方法的兄弟方法(重载方法)可以动态设置动态绑定的全局变量值
setVariableValue(String name, ForestVariableValue value)
- 参数
name
: 变量名- 参数
value
: 变量值,ForestVariableValue
接口的实现类
欸,我们发现,这里的value
是一个接口类的实例对象,这个接口本质上可以看成一个Lambda
// 获取 Forest 全局配置对象
ForestConfiguration configuration = Forest.config();
// 定义一个原子整数对象
AtomicInteger count = new AtomicInteger(0);
// 设置全局动态变量: num -> 从0开始记,每次引用加一的值
configuration.setVariableValue("num", (method) -> count.getAndIncrement());
2
3
4
5
6
此时就能引用到刚才设置的全局动态变量名了
@Get("/data?num={num}")
String getData();
2
然后,多次调用该方法,所产生的结果都是不同的 (每次都累加一)
myClient.getData(); // 第一次调用,URL: http://localhost/data?num=0
myClient.getData(); // 第二次调用,URL: http://localhost/data?num=1
myClient.getData(); // 第三次调用,URL: http://localhost/data?num=2
2
3
ForestVariableValue
接口的 Lambda 带有一个参数 method
, 它是 ForestMethod
类型的对象,即 Forest 接口方法对象
ForestConfiguration configuration = Forest.config();
// 设置全局动态变量: baseUrl -> 根据条件产生不同的IP地址
configuration.setVariableValue("num", (method) -> {
// method: Forest 接口方法对象,即对请求所对应的方法的封装对象
// method.getMethodName() 获得请求所对应的方法的方法名
String methodName = method.getMethodName();
if (methodName.equals("getData")) {
// 若调用的是 getData 方法,则返回 192.168.0.2
return "192.168.0.2";
}
// 默认返回 192.168.0.1
return "192.168.0.1";
});
2
3
4
5
6
7
8
9
10
11
12
13
引用该 baseUrl 变量
@Get("{baseUrl}/data")
String getData();
@Get("{baseUrl}/user")
String getUser();
2
3
4
5
调用不同方法产生的结果
myClient.getData(); // 调用getData,URL: http://192.168.0.2/data
myClient.getUser(); // 调用getUser,URL: http://192.168.0.1/user
2
# @BindingVar注解
还有一种更方便的声明式动态绑定变量的办法,就是在 Spring 环境下利用 @BindingVar
注解修饰某个在 Spring 上下文的 Bean 的方法
@Service("myService")
public class MyService {
// 定义一个原子整数对象
private AtomicInteger count = new AtomicInteger(0);
/**
* 使用 @BindingVar 注解
* 将变量名 num 和一段方法代码绑定
* 方法的参数可以忽略不定义
* 每次引用 num 变量,都会调用该方法重算出该值
*/
@BindingVar("num")
public int getNum() {
// 返回原子整数的值,每次调用加一
return count.getAndIncrement();
}
/**
* 使用 @BindingVar 注解
* 将变量名 baseUrl 和一段方法代码绑定
* 该方法可以有一个 ForestMethod 类型的参数
*/
@BindingVar("baseUrl")
public String getBaseUrl(ForestMethod method) {
// method: Forest 接口方法对象,即对请求所对应的方法的封装对象
// method.getMethodName() 获得请求所对应的方法的方法名
String methodName = method.getMethodName();
if (methodName.equals("getData")) {
// 若调用的是 getData 方法,则返回 192.168.0.2
return "192.168.0.2";
}
// 默认返回 192.168.0.1
return "192.168.0.1";
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
此时就能引用到刚才设置的全局动态变量名了
@Get("{baseUrl}/data?num={num}")
String getData();
@Get("{baseUrl}/user?num={num}")
String getUser();
2
3
4
5
然后,多次调用该方法,所产生的结果都是不同的 (每次都累加一)
myClient.getData(); // 第一次调用,URL: http://192.168.0.2/data?num=0
myClient.getData(); // 第二次调用,URL: http://192.168.0.2/data?num=1
myClient.getData(); // 第三次调用,URL: http://192.168.0.2/data?num=2
myClient.getUser(); // 调用另一个方法,URL: http://192.168.0.1/data?num=3
2
3
4
5