SlideShare a Scribd company logo
Java DSL 与动态代码生成技术的应用
( 上集 :DSL 部分 )
—— by 温悦
2014 05
什么是 DSL ?
个例子?举
内容提要
●
(上集)
●
DSL 概念
●
DSL 的实现
●
DSL 的测试
●
实现思路和工具推介
●
(下集)
●
动态代码生成
●
动态编译
●
源码增强
●
媲美手写的生成代码
DSL 概念
●
领域特定语言
●
相对于 java, prolog, scala 等“通用编程语言”而言
●
面向某一特定“领域”
regex
sql
html
DSL 概念 —— 为什么需要?
●
试想:如何通过纯 java 编程识别出“ a*b+c”( 正
则 ) ?
s
1
a
b
2
b
c
start
a*b+c v.s 一堆 java if-else
•
便于阅读
•
便于存储
•
便于 化优
•
仍然是 javaregex 是 DSL ,而 java 是“宿主 言”语
转换DSL 宿主 言语 行执
DSL 的实现
●
内部 DSL
– Fluent Interface
– 由大到小 , 从“通用编程语言”裁剪而来
●
外部 DSL
– 从无到有,从头定义、实现词法、语法
从
头
建
设
逐
步
雕
刻
内部 DSL—— 由通用编程语言裁剪
●
实际需求:开放平台的 api 对应多个底层 service
时,需要对多个 service 进行编排调用
●
编排逻辑需要支持 if-else, 循环 , 变量 ...... 基本上
就跟一个“过程式编程语言”差不多
API 排编 逻辑
service1
service2
service3
用调
返回 果结
用户
需求很类似一个
“ 程式的通用 言”过 语example & test
内部 DSL—— 由通用编程语言裁剪 , 开放平台 api 服务编排需求
●
由于需求非常类似过程式语言,所以直接选取
java 语言作为“宿主语言”
●
进行“裁剪”—— 禁止 assert 语句,禁止 goto( 带
label 的 continue) ,禁止内部类 ... whatever...
src javac
A
S
T
字 生成节码 .class
A
S
T
和改检查 动
动态编译 .class
JDK1.6
内部 DSL—— 开放平台需求 :Java 实现细节
● Annotation Processor + Compiler Tree API
●
遍历 AST ,做限制、改动
●
Java的AST节点类型(hyper link)
●
实现技术详细介绍(hyper link)
● Demo & Code
Groovy? Ruby?
Python?
And more...
ForbiddenStructuresChecker &
LoopLimitEnhancer
内部 DSL :用于词法 & 语法描述
●
BNF 描述语法规则
●
四则运算表达式:
calc ::= expr $
expr ::= addend (('+'|'-') addend)*
addend ::= factor (('*'|'/') factor)*
factor ::= '(' expr ')'
| 'd+(.d+)?'
Pure Java Fluent Interface
内部 DSL :用于词法 & 语法描述—— Fluent Interface
calc ::= expr $
calc.defineGrule(expr, CC.EOF)
expr ::= addend (('+'|'-') addend)*
expr.define(addend, CC.ks(a.or("-"), addend))
addend ::= factor (('*'|'/') factor)*
addend.define(factor, CC.ks(m.or("/"), factor))
内部 DSL :用于词法 & 语法描述—— Fluent Interface
factor ::= '(' expr ')'
| 'd+(.d+)?'
factor.define("(", expr, ")")
.alt("d+(.d+)?")
●
逐行翻译
●
串接 api
●
“ 模 ”拟
Code & demo
内部 DSL 总结 : 优点与缺点
●
天生的宿主语言编译器、编辑器支持
●
无需为语法正确性做专门测试
●
各种成本通常较低
点优
●
方式受制于宿主 言的“元 程”能力实现 语 编
●
通常要求 DSL 与宿主 言的 法 接近语 语 较为
缺点
外部 DSL :参数映射表达式
●
需求:调用方传给 api 的参数,需要被映射到一
个或多个对应的底层 service 上
示例
●
需要支持数组 filter 、无穷层次的属性访问
●
继续使用手写解析工具将变得非常复杂
的实现 问题
外部 DSL :参数映射表达式——实现方案
s ::= e $
e ::= ('#' ID)+ filter ?
| dto
filter ::= '[' ID ':' e (',' ID ':' e)* ']'
dto :: = '{' ID :e ( ',' ID ':' e)* '}'
定 法义语
使用工具解析 法语
添加业务
“ 作”动
MappingSyntaxParser.java
约 100 行 java 代码 Code & demo
外部 DSL :参数映射表达式——实现效果
{"array":[
{"key":"test",
"key2":{"key3":"test3",
"key4":"test4"},
"key5":"test5"}]}
$namespace:serviceName#array[key:#key, key2:{key3:#key2#key3}]
{"array":[{"key":"test","key2":{"key3":"test3"}}]}
外部 DSL :布尔逻辑表达式——需求与问题
●
需求:风控部门的规则引擎,根据事实对象的数
据做逻辑匹配,对事件作出相应处罚;老系统采
用 drools5 规则引擎,但其规则文本难以维护
老系 drools 示例统 规则
Java 夹杂 drools, 困维护 难
新增、修改 ,上 周期规则 线 约 3 人日
新增 ,上 周期业务 线 5 人日以上
外部 DSL :布尔逻辑表达式—解决方案
●
自定义一套布尔逻辑表达式 (RDL) ,包含大于、
小于 ... 与、或、非等逻辑,代替 drools 语法
●
表达式需要支持“操作符扩展”,用于支持需要在
drools 文件中做 java 编程的情况
●
定期 (30s) 将表达式编译为 drools 文件,加载到内
存,用于规则匹配
RDL drools 匹配规则
外部 DSL :布尔逻辑表达式—解决方案
RDL 范规
数据库
存储规则
DSL后的编译
rete 网络
控事件风
消息
匹配
果结
定时
任务 更 、 取检查 细 读
生编译产
操作符 展扩
外部 DSL :布尔逻辑表达式——实现技术
RDL AST
法解析语
各 化种优
visitor
新
AST
代 生成码
visitor
Drools
代码 加载
外部 DSL :布尔逻辑表达式——最终效果
●
规则修改 5 分钟响应 ( 相对于纯 drools 系统 3 人
日 )
●
规则更加结构化,实现了非技术人员界面配置
●
新增业务 1 人日 ( 相对于纯 drools 系统 5 人日 )
($offerEntity.offerCategory = 'jaysn' ||
$offerEntity.offerCategory = ' 数 、码 电脑 / 数 品码产 /MP4') ||
$memberInfo.memberName = 'jaysn_004' ||
$memberInfo.memberId inBlackList 'jaysn_004'
rule "19405"
when
mf0:OfferEntity((offerCategory == "jaysn" || offerCategory
== " 数 、码 电脑 / 数 品码产 /MP4")) or
mf1:MemberInfo(memberName == "jaysn_004") or
mf1:MemberInfo(customOpInvoker.ivk("inBlackList",
memberId, "jaysn_004"))
then
end
Code demo: BoolExprTest.java
外部 DSL :布尔逻辑表达式——如何测试
如此“ magical” 的 、 化 程,编译 优 过
如何保 正 性?证 确
每一个操作符
都需要被测试
每 操作符、种
数据类型的
与或非 合情形组 ...
由此衍生出的 2 次、
3 次 合情形;组
再加上括号 ...
我 在 一 “ 言”,们 测试 门 语
意味着“ 用例”是这 测试
无 无尽穷 的
外部 DSL :布尔逻辑表达式——测试方案
基 正 性 : 法础 确 测试 归纳 测试
仍然不足以这
保 怕 法的证哪 语
正 性确 ...
基本 n n + 1
用例无 多,不可能一次 完,测试 穷 测
能否每次 build 一部分?且随机覆盖?测
日 一日、年 一年复 复 ...
外部 DSL 正确性最强力保证——随机测试
随机代码
生成 visitor
Maven
build
合法代码
期预
果结
被 系测 统
( 品产 )
实际
果结
比较 N
随机测试效果
●
“ 布尔逻辑表达式”——每次 build 跑 1000 次随机测
试
●
正式上线前通过了 100w 次随机测试考验
●
测出许多人工测试几乎无法抵达的场景
●
修复或绕过的bug举例
●
“ 语法功能正确”可被最大限度地近似保证 ( 可以
认为是一定的 )
●
日处理量千万的系统,从未因语法正确性出问题Code & demo
外部 DSL 思考:优点与缺点
最大化 法自由度语
不受任何 言、平台限制语
点优
缺点
程有 高 成本实现过 较 测试
几乎无法利用 有 器、现 编辑
器支持,一切都需从 始编译 头开
抉择:内部 or 外部?
成本需求
宿主 言语器编辑
常见实现思路与工具概览
内部
DSL
外部
DSL
Fluent Interface
言特性语 : methodMissing,
特殊 定约 , 特殊符号 先优 级
行期运 AST 更改
Macro
“ 元 程”能力编
antlr
javacc
dropincc.java
dropincc.java
●
LL(*) 算法 , 解析能力与 antlr3 一致
●
纯 java ,因此无需学习额外语法
●
动态编译,无需手工管理复杂的生成源码
●
多个千万级以上日处理量的系统实际应用 ( 规则
引擎,黑名单服务, ocean)
●
项目地址: https://github.com/pfmiles/dropincc.java
●
文档 ( 含 PDF 中文教程 ) :
https://github.com/pfmiles/dropincc.java/wiki
关于外部 DSL 工具—— A little bit theory...
●
为什么需要语法解析工具?正则表达式能做么?
●
什么情况可以用正则,什么情况必须用语法解析
工具?
●
正则和语法解析工具有什么共同点和不同点?
: 接连 + 选择 +
不能做
什么?克林 包闭正则
括号“ 仗”对
问题
递归
Insight: 正 其 是则 实
法解析工具的一 特例语 种
( 上集完 )
Thank You
下集 告:预
探 如何在讨 2 秒 写完钟
2w 行精美代码 , 可用、完美格式化,
且包含丰富的、 范的注 ?规 释

More Related Content

What's hot (20)

PPTX
MongoDBの監視
Tetsutaro Watanabe
 
PDF
S10_Microsoft 365 E5 Compliance で実現する機密情報の検出・分類・保護 - Microsoft Information P...
日本マイクロソフト株式会社
 
PDF
[AWSマイスターシリーズ] AWS Elastic Beanstalk -Python編-
Amazon Web Services Japan
 
PDF
【Zabbix2.0】snmpttによるトラップメッセージの編集 #Zabbix #自宅ラック勉強会
真乙 九龍
 
PDF
Amazon DynamoDB(初心者向け 超速マスター編)JAWSUG大阪
崇之 清水
 
PDF
HTTP/2の現状とこれから
shigeki_ohtsu
 
PPTX
Edge Computing と k8s でなんか話すよ
VirtualTech Japan Inc.
 
PDF
それでも環境依存は残っている~起きたり起きなかったりする問題のお話~
Hiroki Tateno
 
PDF
自動テストの誤解とアンチパターン in 楽天 Tech Talk
kyon mm
 
PPTX
Ch6 대용량서비스레퍼런스아키텍처 part.1
Minchul Jung
 
PDF
NTTデータ流 Hadoop活用のすすめ ~インフラ構築・運用の勘所~
NTT DATA OSS Professional Services
 
PDF
ドメイン駆動設計 モデリング_実装入門勉強会_2020.3.8
Koichiro Matsuoka
 
PDF
MySQLとPostgreSQLと日本語全文検索 - Azure DatabaseでMroonga・PGroongaを使いたいですよね!?
Kouhei Sutou
 
PDF
忙しい人の5分で分かるDocker 2017年春Ver
Masahito Zembutsu
 
PPTX
AKS と ACI を組み合わせて使ってみた
Hideaki Aoyagi
 
PDF
十二項架構設計原則
Philip Zheng
 
PDF
20221021_JP5.0.2-Webinar-JP_Final.pdf
NVIDIA Japan
 
PDF
1から学ぶスクラム
Keisuke Izumiya
 
PDF
Test Yourself - テストを書くと何がどう変わるか
Takuto Wada
 
PDF
性能問題を起こしにくい 強いDBシステムの作り方(Ver. 2018.9)
Tomoyuki Oota
 
MongoDBの監視
Tetsutaro Watanabe
 
S10_Microsoft 365 E5 Compliance で実現する機密情報の検出・分類・保護 - Microsoft Information P...
日本マイクロソフト株式会社
 
[AWSマイスターシリーズ] AWS Elastic Beanstalk -Python編-
Amazon Web Services Japan
 
【Zabbix2.0】snmpttによるトラップメッセージの編集 #Zabbix #自宅ラック勉強会
真乙 九龍
 
Amazon DynamoDB(初心者向け 超速マスター編)JAWSUG大阪
崇之 清水
 
HTTP/2の現状とこれから
shigeki_ohtsu
 
Edge Computing と k8s でなんか話すよ
VirtualTech Japan Inc.
 
それでも環境依存は残っている~起きたり起きなかったりする問題のお話~
Hiroki Tateno
 
自動テストの誤解とアンチパターン in 楽天 Tech Talk
kyon mm
 
Ch6 대용량서비스레퍼런스아키텍처 part.1
Minchul Jung
 
NTTデータ流 Hadoop活用のすすめ ~インフラ構築・運用の勘所~
NTT DATA OSS Professional Services
 
ドメイン駆動設計 モデリング_実装入門勉強会_2020.3.8
Koichiro Matsuoka
 
MySQLとPostgreSQLと日本語全文検索 - Azure DatabaseでMroonga・PGroongaを使いたいですよね!?
Kouhei Sutou
 
忙しい人の5分で分かるDocker 2017年春Ver
Masahito Zembutsu
 
AKS と ACI を組み合わせて使ってみた
Hideaki Aoyagi
 
十二項架構設計原則
Philip Zheng
 
20221021_JP5.0.2-Webinar-JP_Final.pdf
NVIDIA Japan
 
1から学ぶスクラム
Keisuke Izumiya
 
Test Yourself - テストを書くと何がどう変わるか
Takuto Wada
 
性能問題を起こしにくい 強いDBシステムの作り方(Ver. 2018.9)
Tomoyuki Oota
 

Java DSL与动态代码生成技术的应用 (上集:DSL部分)

  • 1. Java DSL 与动态代码生成技术的应用 ( 上集 :DSL 部分 ) —— by 温悦 2014 05 什么是 DSL ? 个例子?举
  • 2. 内容提要 ● (上集) ● DSL 概念 ● DSL 的实现 ● DSL 的测试 ● 实现思路和工具推介 ● (下集) ● 动态代码生成 ● 动态编译 ● 源码增强 ● 媲美手写的生成代码
  • 3. DSL 概念 ● 领域特定语言 ● 相对于 java, prolog, scala 等“通用编程语言”而言 ● 面向某一特定“领域” regex sql html
  • 4. DSL 概念 —— 为什么需要? ● 试想:如何通过纯 java 编程识别出“ a*b+c”( 正 则 ) ? s 1 a b 2 b c start a*b+c v.s 一堆 java if-else • 便于阅读 • 便于存储 • 便于 化优 • 仍然是 javaregex 是 DSL ,而 java 是“宿主 言”语 转换DSL 宿主 言语 行执
  • 5. DSL 的实现 ● 内部 DSL – Fluent Interface – 由大到小 , 从“通用编程语言”裁剪而来 ● 外部 DSL – 从无到有,从头定义、实现词法、语法 从 头 建 设 逐 步 雕 刻
  • 6. 内部 DSL—— 由通用编程语言裁剪 ● 实际需求:开放平台的 api 对应多个底层 service 时,需要对多个 service 进行编排调用 ● 编排逻辑需要支持 if-else, 循环 , 变量 ...... 基本上 就跟一个“过程式编程语言”差不多 API 排编 逻辑 service1 service2 service3 用调 返回 果结 用户 需求很类似一个 “ 程式的通用 言”过 语example & test
  • 7. 内部 DSL—— 由通用编程语言裁剪 , 开放平台 api 服务编排需求 ● 由于需求非常类似过程式语言,所以直接选取 java 语言作为“宿主语言” ● 进行“裁剪”—— 禁止 assert 语句,禁止 goto( 带 label 的 continue) ,禁止内部类 ... whatever... src javac A S T 字 生成节码 .class A S T 和改检查 动 动态编译 .class JDK1.6
  • 8. 内部 DSL—— 开放平台需求 :Java 实现细节 ● Annotation Processor + Compiler Tree API ● 遍历 AST ,做限制、改动 ● Java的AST节点类型(hyper link) ● 实现技术详细介绍(hyper link) ● Demo & Code Groovy? Ruby? Python? And more... ForbiddenStructuresChecker & LoopLimitEnhancer
  • 9. 内部 DSL :用于词法 & 语法描述 ● BNF 描述语法规则 ● 四则运算表达式: calc ::= expr $ expr ::= addend (('+'|'-') addend)* addend ::= factor (('*'|'/') factor)* factor ::= '(' expr ')' | 'd+(.d+)?' Pure Java Fluent Interface
  • 10. 内部 DSL :用于词法 & 语法描述—— Fluent Interface calc ::= expr $ calc.defineGrule(expr, CC.EOF) expr ::= addend (('+'|'-') addend)* expr.define(addend, CC.ks(a.or("-"), addend)) addend ::= factor (('*'|'/') factor)* addend.define(factor, CC.ks(m.or("/"), factor))
  • 11. 内部 DSL :用于词法 & 语法描述—— Fluent Interface factor ::= '(' expr ')' | 'd+(.d+)?' factor.define("(", expr, ")") .alt("d+(.d+)?") ● 逐行翻译 ● 串接 api ● “ 模 ”拟 Code & demo
  • 12. 内部 DSL 总结 : 优点与缺点 ● 天生的宿主语言编译器、编辑器支持 ● 无需为语法正确性做专门测试 ● 各种成本通常较低 点优 ● 方式受制于宿主 言的“元 程”能力实现 语 编 ● 通常要求 DSL 与宿主 言的 法 接近语 语 较为 缺点
  • 13. 外部 DSL :参数映射表达式 ● 需求:调用方传给 api 的参数,需要被映射到一 个或多个对应的底层 service 上 示例 ● 需要支持数组 filter 、无穷层次的属性访问 ● 继续使用手写解析工具将变得非常复杂 的实现 问题
  • 14. 外部 DSL :参数映射表达式——实现方案 s ::= e $ e ::= ('#' ID)+ filter ? | dto filter ::= '[' ID ':' e (',' ID ':' e)* ']' dto :: = '{' ID :e ( ',' ID ':' e)* '}' 定 法义语 使用工具解析 法语 添加业务 “ 作”动 MappingSyntaxParser.java 约 100 行 java 代码 Code & demo
  • 16. 外部 DSL :布尔逻辑表达式——需求与问题 ● 需求:风控部门的规则引擎,根据事实对象的数 据做逻辑匹配,对事件作出相应处罚;老系统采 用 drools5 规则引擎,但其规则文本难以维护 老系 drools 示例统 规则 Java 夹杂 drools, 困维护 难 新增、修改 ,上 周期规则 线 约 3 人日 新增 ,上 周期业务 线 5 人日以上
  • 17. 外部 DSL :布尔逻辑表达式—解决方案 ● 自定义一套布尔逻辑表达式 (RDL) ,包含大于、 小于 ... 与、或、非等逻辑,代替 drools 语法 ● 表达式需要支持“操作符扩展”,用于支持需要在 drools 文件中做 java 编程的情况 ● 定期 (30s) 将表达式编译为 drools 文件,加载到内 存,用于规则匹配 RDL drools 匹配规则
  • 18. 外部 DSL :布尔逻辑表达式—解决方案 RDL 范规 数据库 存储规则 DSL后的编译 rete 网络 控事件风 消息 匹配 果结 定时 任务 更 、 取检查 细 读 生编译产 操作符 展扩
  • 19. 外部 DSL :布尔逻辑表达式——实现技术 RDL AST 法解析语 各 化种优 visitor 新 AST 代 生成码 visitor Drools 代码 加载
  • 20. 外部 DSL :布尔逻辑表达式——最终效果 ● 规则修改 5 分钟响应 ( 相对于纯 drools 系统 3 人 日 ) ● 规则更加结构化,实现了非技术人员界面配置 ● 新增业务 1 人日 ( 相对于纯 drools 系统 5 人日 ) ($offerEntity.offerCategory = 'jaysn' || $offerEntity.offerCategory = ' 数 、码 电脑 / 数 品码产 /MP4') || $memberInfo.memberName = 'jaysn_004' || $memberInfo.memberId inBlackList 'jaysn_004' rule "19405" when mf0:OfferEntity((offerCategory == "jaysn" || offerCategory == " 数 、码 电脑 / 数 品码产 /MP4")) or mf1:MemberInfo(memberName == "jaysn_004") or mf1:MemberInfo(customOpInvoker.ivk("inBlackList", memberId, "jaysn_004")) then end Code demo: BoolExprTest.java
  • 21. 外部 DSL :布尔逻辑表达式——如何测试 如此“ magical” 的 、 化 程,编译 优 过 如何保 正 性?证 确 每一个操作符 都需要被测试 每 操作符、种 数据类型的 与或非 合情形组 ... 由此衍生出的 2 次、 3 次 合情形;组 再加上括号 ... 我 在 一 “ 言”,们 测试 门 语 意味着“ 用例”是这 测试 无 无尽穷 的
  • 22. 外部 DSL :布尔逻辑表达式——测试方案 基 正 性 : 法础 确 测试 归纳 测试 仍然不足以这 保 怕 法的证哪 语 正 性确 ... 基本 n n + 1 用例无 多,不可能一次 完,测试 穷 测 能否每次 build 一部分?且随机覆盖?测 日 一日、年 一年复 复 ...
  • 23. 外部 DSL 正确性最强力保证——随机测试 随机代码 生成 visitor Maven build 合法代码 期预 果结 被 系测 统 ( 品产 ) 实际 果结 比较 N
  • 24. 随机测试效果 ● “ 布尔逻辑表达式”——每次 build 跑 1000 次随机测 试 ● 正式上线前通过了 100w 次随机测试考验 ● 测出许多人工测试几乎无法抵达的场景 ● 修复或绕过的bug举例 ● “ 语法功能正确”可被最大限度地近似保证 ( 可以 认为是一定的 ) ● 日处理量千万的系统,从未因语法正确性出问题Code & demo
  • 25. 外部 DSL 思考:优点与缺点 最大化 法自由度语 不受任何 言、平台限制语 点优 缺点 程有 高 成本实现过 较 测试 几乎无法利用 有 器、现 编辑 器支持,一切都需从 始编译 头开
  • 27. 常见实现思路与工具概览 内部 DSL 外部 DSL Fluent Interface 言特性语 : methodMissing, 特殊 定约 , 特殊符号 先优 级 行期运 AST 更改 Macro “ 元 程”能力编 antlr javacc dropincc.java
  • 28. dropincc.java ● LL(*) 算法 , 解析能力与 antlr3 一致 ● 纯 java ,因此无需学习额外语法 ● 动态编译,无需手工管理复杂的生成源码 ● 多个千万级以上日处理量的系统实际应用 ( 规则 引擎,黑名单服务, ocean) ● 项目地址: https://github.com/pfmiles/dropincc.java ● 文档 ( 含 PDF 中文教程 ) : https://github.com/pfmiles/dropincc.java/wiki
  • 29. 关于外部 DSL 工具—— A little bit theory... ● 为什么需要语法解析工具?正则表达式能做么? ● 什么情况可以用正则,什么情况必须用语法解析 工具? ● 正则和语法解析工具有什么共同点和不同点? : 接连 + 选择 + 不能做 什么?克林 包闭正则 括号“ 仗”对 问题 递归 Insight: 正 其 是则 实 法解析工具的一 特例语 种
  • 30. ( 上集完 ) Thank You 下集 告:预 探 如何在讨 2 秒 写完钟 2w 行精美代码 , 可用、完美格式化, 且包含丰富的、 范的注 ?规 释