Refactoring Zhaunzhuan App Backend Routing with the Aviator Expression Engine
The article describes how the Zhaunzhuan app backend team replaced a hard‑coded Map‑based routing configuration with a rule‑driven Aviator expression engine, detailing the problem analysis, engine selection, architectural redesign, code changes, a deployment incident, and the resulting improvements in flexibility, maintainability, and performance.
The author, responsible for the Zhaunzhuan app backend, explains that the detail page module must route users to different business‑specific M‑pages based on product attributes, and the original implementation used a static Map where keys were concatenated strings.
Before refactoring, the configuration looked like a JSON map with keys such as "label_红布林标签ID" and values containing URL, name, and other fields. This approach suffered from poor extensibility, bloated configuration, and high maintenance cost because every new dimension required code changes and hard‑coded priority logic.
{
"label_红布林标签ID": {
"url": "红布林落地页地址",
"name": "红布林配置",
"其他字段": "省略表示"
},
"uid_帮卖用户ID_searchType_2": {
"url": "转转帮卖暗拍落地页地址",
"name": "转转帮卖暗拍配置"
},
"uid_帮卖用户ID": {
"url": "转转帮卖落地页地址",
"name": "转转帮卖配置"
},
"cateId_图书社会科学分类ID": {
"url": "图书科学类落地页地址",
"name": "图书科学类配置"
},
"cateId_图书自然科学分类ID": {
"url": "图书科学类落地页地址",
"name": "图书科学类配置"
}
}To solve these issues, the team evaluated three expression engines—SpringEL, Aviator, and MVEL—comparing their advantages, disadvantages, and extensibility. Aviator was chosen for its lightweight nature, high performance, and support for custom functions and lambda expressions.
The refactoring introduced a wrapper component that provides standardized rule storage, engine extensibility, and a developer‑friendly API. Rules are now expressed as JSON objects containing a ruleEl field that holds an Aviator expression, a URL, a name, priority, and other optional fields.
[
{
"url": "红布林落地页地址",
"name": "红布林配置",
"ruleEl": "list.contains(labelList, 红布林标签ID)",
"priority": 20,
"其他字段": "省略表示"
},
{
"url": "转转帮卖暗拍落地页地址",
"name": "转转帮卖暗拍配置",
"ruleEl": "帮卖用户ID == product.userId && 2 == product.product.searchType",
"priority": 20
},
{
"url": "转转帮卖落地页地址",
"name": "转转帮卖配置",
"ruleEl": "帮卖用户ID == product.userId",
"priority": 20
},
{
"url": "游戏代练陪玩落地页地址",
"name": "游戏代练陪玩配置",
"ruleEl": "代练分类ID == product.cateId || 陪玩分类ID == product.cateId",
"priority": 20
}
]During the first rollout, the new engine caused detail‑page timeouts due to massive class loading and Full GC. Investigation revealed that Aviator recompiles expressions on every call because caching was disabled, leading to continuous generation of ASM classes such as Script_1645773082560_152 . Enabling the cache eliminated the class‑loading burst and stabilized the service.
public Object execute(final String expression, final Map
env, final boolean cached) {
// 1. compile expression
Expression compiledExpression = compile(expression, cached);
if (compiledExpression != null) {
return compiledExpression.execute(env);
} else {
throw new ExpressionNotFoundException("Null compiled expression for " + expression);
}
} public Expression compile(final String expression, final boolean cached) {
if (expression == null || expression.trim().length() == 0) {
throw new CompileExpressionErrorException("Blank expression");
}
if (cached) {
// cache logic
} else {
// real‑time compile
return innerCompile(expression, cached);
}
}After a period of iteration, the rule‑driven configuration proved more flexible, readable, and extensible. It reduced the need for code changes during promotions (e.g., 618, Double‑11), avoided duplicated development through reusable functions, and allowed many configuration changes without redeploying.
In conclusion, the case study demonstrates how analyzing legacy logic, selecting an appropriate expression engine, and refactoring to a configuration‑centric design can deliver significant productivity and performance gains for backend services.
About the author : Zhao Tianming, backend lead of the Zhaunzhuan app.
Zhuanzhuan Tech
A platform for Zhuanzhuan R&D and industry peers to learn and exchange technology, regularly sharing frontline experience and cutting‑edge topics. We welcome practical discussions and sharing; contact waterystone with any questions.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.