HiSEN

BeanUtils 对象拷贝 - 仅拷贝指定属性 - 接口性能优化

零、背景

很多时候我们调用接口并不是需要接口返回的所有信息;
就像查询数据库很少使用 select * from table; 一样;

为了使现有的存储结构以及代码逻辑改动最少
想办法在最外层的接口对返回的对象进行精简

目的使为了提高接口性能:减少 RPC 传输时间、节省网络带宽、节省序列化开销

一、方案

  1. 直接创建一个对象,根据入参传入的所需字段,写一堆 if else 进行 get set;
  2. 使用序列化工具,转为类似 Map 结构,取值拼装;
  3. 使用 BeanWrapper 操作对象;

前面两种比较呆板,属于定制化开发;

二、实践

Spring BeanWrapper 方案处理非集合对象比较完美,输出对象小不少;
基本数据类型有默认值,无法去除,不过这种对大小影响不大;
完整代码:github.com

1
2
3
4
5
6
7
8
9
10
11
12
13
public static void main(String[] args) {
Order order = getOrder();
Order smallerOrder = new Order();
List<String> keepFields = Lists.newArrayList();
keepFields.add("orderId");
keepFields.add("address.province");
// i want get all names, not only index 1, how to do ?
keepFields.add("productInfos[1].name");
copyLimitedProperties(order, smallerOrder, keepFields);
Gson gson = new Gson();
System.out.println("src:" + gson.toJson(order));
System.out.println("des" + gson.toJson(smallerOrder));
}

输出 src:

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
{
"address": {
"province": "B",
"city": "A",
"county": "C"
},
"productInfos": [
{
"productId": 0,
"name": "name0",
"price": 1,
"num": 0,
"imgUrl": "url1"
},
{
"productId": 0,
"name": "name1",
"price": 2,
"num": 0,
"imgUrl": "url1"
},
{
"productId": 0,
"name": "name2",
"price": 3,
"num": 0,
"imgUrl": "url1"
}
]
}

输出dst

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"address": {
"province": "B"
},
"productInfos": [
{
"productId": 0,
"num": 0
},
{
"productId": 0,
"name": "name1",
"num": 0
}
]
}

三、缺点

目前 Spring BeanWrapper 处理集合类型比较费劲,需要告知一个个具体的路径
比如:productInfos[1].name
如果能做到 productInfos[any].name 这种,然后取出所有 index 的属性,就比较完美
(目前解决方法:通过自定义处理,遇到 any 标识,自动补全所有 index 的 key 即可,只是不那么优雅)

缺陷原因:内部逻辑直接用 key 转换为 index ,没有 any 逻辑。

1
2
3
4
5
6
else if (value instanceof List) {
index = Integer.parseInt(key);
List<Object> list = (List)value;
this.growCollectionIfNecessary(list, index, indexedPropertyName, ph, i + 1);
value = list.get(index);
}

代码位置:org.springframework.beans.AbstractNestablePropertyAccessor#getPropertyValue

四、参考

Spring 官方文档:Bean Manipulation and the BeanWrapper