🥃 动态变量绑定
在大部分情况下,变量引用 + 配置文件的方式都可以满足要求,比如:不同环境下配置不同的变量。但如果我想在每次引用变量的时候,都根据某种条件动态获取变量值就办不到了
因此,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