Java模板引擎 httl
openkk
13年前
<p><span style="line-height:25px;font-family:Helvetica, Tahoma, Arial, sans-serif;font-size:14px;" class="Apple-style-span">在07的时候,写过一个模板引擎,当时叫CommonTemplate,后来功能越来越多,性能却越来越差,在金大为发给我<a style="color:#006699;text-decoration:underline;" href="/misc/goto?guid=4959498282789623071" target="_blank">性能对比结果</a>后,看到惨不忍睹的差距,就打算抛弃原设计进行重写,但因工作忙,就搁置了,最近看温少发了几个EL和JSON的解析器,有点手痒,就抽了个周未,拿出来再改了改,主要将模板改成了字节码编译,并简化了语法及缩小使用范围,只针对HTML场景使用,并将名称改成了HTTL,名字含义是把HTML中的 M(Marker)改成了T(Template),放在GoogleCode上:<a style="color:#006699;text-decoration:underline;" href="/misc/goto?guid=4959498309224620266" target="_blank">http://code.google.com/p/httl</a>,性能和Java硬编码输出模板内容差不多,比Velocity/FreeMarker等快10倍左右。 </span></p> <p><span style="line-height:25px;font-family:Helvetica, Tahoma, Arial, sans-serif;font-size:14px;" class="Apple-style-span"><strong style="font-weight:bold;">语法方面的区别:</strong> <br /> 发现基于文本指令的,基于HTML标签的,基于HTML注释的,都有不少模板引擎实现, <br /> 为了标新立异以及使用的直观性,HTTL采用基于HTML属性的指令,如: <br /> </span></p> <div style="padding-bottom:1px;overflow-x:auto;overflow-y:auto;background-color:transparent;padding-left:1px;width:766px;padding-right:1px;font-family:Monaco, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', Consolas, 'Courier New', monospace;word-wrap:break-word;margin-left:9px;font-size:12px;word-break:break-all;padding-top:1px;" class="dp-highlighter"> <ol style="border-bottom:#d1d7dc 1px solid;border-left:#d1d7dc 1px solid;padding-bottom:2px;line-height:1.4em;background-color:#ffffff;list-style-type:decimal;margin:0px 0px 1px;padding-left:0px;padding-right:0px;color:#2b91af;font-size:1em;border-top:#d1d7dc 1px solid;border-right:#d1d7dc 1px solid;padding-top:2px;" class="dp-xml"> <li style="border-left:#d1d7dc 1px solid;padding-bottom:0px;line-height:18px;background-color:#fafafa;margin:0px 0px 0px 38px;padding-left:10px;padding-right:0px;font-size:1em;padding-top:0px;"><span style="color:black;"><span style="color:#006699;font-weight:bold;" class="tag"><</span><span style="color:#006699;font-weight:bold;" class="tag-name">table</span><span style="color:black;"> </span><span style="color:red;" class="attribute">if</span><span style="color:black;">=</span><span style="color:blue;" class="attribute-value">"user.role == 'admin'"</span><span style="color:#006699;font-weight:bold;" class="tag">></span><span style="color:black;"> </span></span></li> <li style="border-left:#d1d7dc 1px solid;padding-bottom:0px;line-height:18px;background-color:#fafafa;margin:0px 0px 0px 38px;padding-left:10px;padding-right:0px;font-size:1em;padding-top:0px;"><span style="color:black;"> <span style="color:#006699;font-weight:bold;" class="tag"><</span><span style="color:#006699;font-weight:bold;" class="tag-name">tr</span><span style="color:black;"> </span><span style="color:red;" class="attribute">foreach</span><span style="color:black;">=</span><span style="color:blue;" class="attribute-value">"book in books"</span><span style="color:#006699;font-weight:bold;" class="tag">></span><span style="color:black;"> </span></span></li> <li style="border-left:#d1d7dc 1px solid;padding-bottom:0px;line-height:18px;background-color:#fafafa;margin:0px 0px 0px 38px;padding-left:10px;padding-right:0px;font-size:1em;padding-top:0px;"><span style="color:black;"> ... </span></li> <li style="border-left:#d1d7dc 1px solid;padding-bottom:0px;line-height:18px;background-color:#fafafa;margin:0px 0px 0px 38px;padding-left:10px;padding-right:0px;font-size:1em;padding-top:0px;"><span style="color:black;"> <span style="color:#006699;font-weight:bold;" class="tag"> <span style="color:#006699;font-weight:bold;" class="tag-name">tr</span><span style="color:#006699;font-weight:bold;" class="tag">></span><span style="color:black;"> </span></span></span></li> <li style="border-left:#d1d7dc 1px solid;padding-bottom:0px;line-height:18px;background-color:#fafafa;margin:0px 0px 0px 38px;padding-left:10px;padding-right:0px;font-size:1em;padding-top:0px;"><span style="color:black;"><span style="color:#006699;font-weight:bold;" class="tag"><span style="color:#006699;font-weight:bold;" class="tag-name">table</span><span style="color:#006699;font-weight:bold;" class="tag">></span><span style="color:black;"> </span></span></span></li> </ol> </div> <p><br /> <br /> <strong style="font-weight:bold;">选型方面的区别:</strong></p> <ul> <li>Velocity采用JavaCC编译成AST树,解释执行。</li> <li>FreeMarker类似,只是采用FreeCC。</li> <li>Smarty4j采用ASM生成字节码。</li> <li>HTTL采用先将模板转译成Java代码,再由JDK或Javassist编译成字节码。</li> </ul> <p><br /> <strong style="font-weight:bold;">性能测试:</strong></p> <ul> <li>模板内循环显示100行数据。</li> <li>每模板各运行一万次。</li> <li>模板大小约800字符。</li> <li>模板每次运行输出内容约27K字符。</li> </ul> <p><br /> <strong style="font-weight:bold;">测试结果:</strong> </p> <table style="border-bottom:#cccccc 1px solid;border-left:#cccccc 1px solid;border-top:#cccccc 1px solid;border-right:#cccccc 1px solid;" class="bbcode ke-zeroborder"> <tbody> <tr> <td style="border-bottom:#cccccc 1px solid;border-left:#cccccc 1px solid;padding-bottom:5px;padding-left:5px;padding-right:5px;font-size:1em;border-top:#cccccc 1px solid;border-right:#cccccc 1px solid;padding-top:5px;">Engine</td> <td style="border-bottom:#cccccc 1px solid;border-left:#cccccc 1px solid;padding-bottom:5px;padding-left:5px;padding-right:5px;font-size:1em;border-top:#cccccc 1px solid;border-right:#cccccc 1px solid;padding-top:5px;">Compile</td> <td style="border-bottom:#cccccc 1px solid;border-left:#cccccc 1px solid;padding-bottom:5px;padding-left:5px;padding-right:5px;font-size:1em;border-top:#cccccc 1px solid;border-right:#cccccc 1px solid;padding-top:5px;">Run</td> <td style="border-bottom:#cccccc 1px solid;border-left:#cccccc 1px solid;padding-bottom:5px;padding-left:5px;padding-right:5px;font-size:1em;border-top:#cccccc 1px solid;border-right:#cccccc 1px solid;padding-top:5px;">TPS</td> </tr> <tr> <td style="border-bottom:#cccccc 1px solid;border-left:#cccccc 1px solid;padding-bottom:5px;padding-left:5px;padding-right:5px;font-size:1em;border-top:#cccccc 1px solid;border-right:#cccccc 1px solid;padding-top:5px;">Freemarker</td> <td style="border-bottom:#cccccc 1px solid;border-left:#cccccc 1px solid;padding-bottom:5px;padding-left:5px;padding-right:5px;font-size:1em;border-top:#cccccc 1px solid;border-right:#cccccc 1px solid;padding-top:5px;">125ms</td> <td style="border-bottom:#cccccc 1px solid;border-left:#cccccc 1px solid;padding-bottom:5px;padding-left:5px;padding-right:5px;font-size:1em;border-top:#cccccc 1px solid;border-right:#cccccc 1px solid;padding-top:5px;">16,934ms</td> <td style="border-bottom:#cccccc 1px solid;border-left:#cccccc 1px solid;padding-bottom:5px;padding-left:5px;padding-right:5px;font-size:1em;border-top:#cccccc 1px solid;border-right:#cccccc 1px solid;padding-top:5px;">590t/s</td> </tr> <tr> <td style="border-bottom:#cccccc 1px solid;border-left:#cccccc 1px solid;padding-bottom:5px;padding-left:5px;padding-right:5px;font-size:1em;border-top:#cccccc 1px solid;border-right:#cccccc 1px solid;padding-top:5px;">Velocity</td> <td style="border-bottom:#cccccc 1px solid;border-left:#cccccc 1px solid;padding-bottom:5px;padding-left:5px;padding-right:5px;font-size:1em;border-top:#cccccc 1px solid;border-right:#cccccc 1px solid;padding-top:5px;">110ms</td> <td style="border-bottom:#cccccc 1px solid;border-left:#cccccc 1px solid;padding-bottom:5px;padding-left:5px;padding-right:5px;font-size:1em;border-top:#cccccc 1px solid;border-right:#cccccc 1px solid;padding-top:5px;">19,278ms</td> <td style="border-bottom:#cccccc 1px solid;border-left:#cccccc 1px solid;padding-bottom:5px;padding-left:5px;padding-right:5px;font-size:1em;border-top:#cccccc 1px solid;border-right:#cccccc 1px solid;padding-top:5px;">518t/s</td> </tr> <tr> <td style="border-bottom:#cccccc 1px solid;border-left:#cccccc 1px solid;padding-bottom:5px;padding-left:5px;padding-right:5px;font-size:1em;border-top:#cccccc 1px solid;border-right:#cccccc 1px solid;padding-top:5px;">Smarty4j</td> <td style="border-bottom:#cccccc 1px solid;border-left:#cccccc 1px solid;padding-bottom:5px;padding-left:5px;padding-right:5px;font-size:1em;border-top:#cccccc 1px solid;border-right:#cccccc 1px solid;padding-top:5px;">78ms</td> <td style="border-bottom:#cccccc 1px solid;border-left:#cccccc 1px solid;padding-bottom:5px;padding-left:5px;padding-right:5px;font-size:1em;border-top:#cccccc 1px solid;border-right:#cccccc 1px solid;padding-top:5px;">21,653ms</td> <td style="border-bottom:#cccccc 1px solid;border-left:#cccccc 1px solid;padding-bottom:5px;padding-left:5px;padding-right:5px;font-size:1em;border-top:#cccccc 1px solid;border-right:#cccccc 1px solid;padding-top:5px;">461t/s</td> </tr> <tr> <td style="border-bottom:#cccccc 1px solid;border-left:#cccccc 1px solid;padding-bottom:5px;padding-left:5px;padding-right:5px;font-size:1em;border-top:#cccccc 1px solid;border-right:#cccccc 1px solid;padding-top:5px;">Httl</td> <td style="border-bottom:#cccccc 1px solid;border-left:#cccccc 1px solid;padding-bottom:5px;padding-left:5px;padding-right:5px;font-size:1em;border-top:#cccccc 1px solid;border-right:#cccccc 1px solid;padding-top:5px;">547ms</td> <td style="border-bottom:#cccccc 1px solid;border-left:#cccccc 1px solid;padding-bottom:5px;padding-left:5px;padding-right:5px;font-size:1em;border-top:#cccccc 1px solid;border-right:#cccccc 1px solid;padding-top:5px;">2,077ms</td> <td style="border-bottom:#cccccc 1px solid;border-left:#cccccc 1px solid;padding-bottom:5px;padding-left:5px;padding-right:5px;font-size:1em;border-top:#cccccc 1px solid;border-right:#cccccc 1px solid;padding-top:5px;">4,814t/s</td> </tr> <tr> <td style="border-bottom:#cccccc 1px solid;border-left:#cccccc 1px solid;padding-bottom:5px;padding-left:5px;padding-right:5px;font-size:1em;border-top:#cccccc 1px solid;border-right:#cccccc 1px solid;padding-top:5px;">Java</td> <td style="border-bottom:#cccccc 1px solid;border-left:#cccccc 1px solid;padding-bottom:5px;padding-left:5px;padding-right:5px;font-size:1em;border-top:#cccccc 1px solid;border-right:#cccccc 1px solid;padding-top:5px;">0ms</td> <td style="border-bottom:#cccccc 1px solid;border-left:#cccccc 1px solid;padding-bottom:5px;padding-left:5px;padding-right:5px;font-size:1em;border-top:#cccccc 1px solid;border-right:#cccccc 1px solid;padding-top:5px;">2,016ms</td> <td style="border-bottom:#cccccc 1px solid;border-left:#cccccc 1px solid;padding-bottom:5px;padding-left:5px;padding-right:5px;font-size:1em;border-top:#cccccc 1px solid;border-right:#cccccc 1px solid;padding-top:5px;">4,960t/s</td> </tr> </tbody> </table> <p><br /> 更多信息参见: <br /> <a style="color:#006699;text-decoration:underline;" href="/misc/goto?guid=4959498309224620266" target="_blank">http://code.google.com/p/httl</a> <br /> <br /> HTTL缺省使用Jdk的javax,tools编译字节码,需要500ms左右,如果换成Javassist编译,编译时间可以降到200ms左右,但字节码执行效率略差一点,如果想换成Javassist,只需在httl.properties中加入: </p> <div style="padding-bottom:1px;overflow-x:auto;overflow-y:auto;background-color:transparent;padding-left:1px;width:766px;padding-right:1px;font-family:Monaco, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', Consolas, 'Courier New', monospace;word-wrap:break-word;margin-left:9px;font-size:12px;word-break:break-all;padding-top:1px;" class="dp-highlighter"> <ol style="border-bottom:#d1d7dc 1px solid;border-left:#d1d7dc 1px solid;padding-bottom:2px;line-height:1.4em;background-color:#ffffff;list-style-type:decimal;margin:0px 0px 1px;padding-left:0px;padding-right:0px;color:#2b91af;font-size:1em;border-top:#d1d7dc 1px solid;border-right:#d1d7dc 1px solid;padding-top:2px;" class="dp-j"> <li style="border-left:#d1d7dc 1px solid;padding-bottom:0px;line-height:18px;background-color:#fafafa;margin:0px 0px 0px 38px;padding-left:10px;padding-right:0px;font-size:1em;padding-top:0px;"><span style="color:black;"><span style="color:black;">compiler=com.googlecode.httl.support.compilers.JavassistCompiler </span></span></li> <li style="border-left:#d1d7dc 1px solid;padding-bottom:0px;line-height:18px;background-color:#fafafa;margin:0px 0px 0px 38px;padding-left:10px;padding-right:0px;font-size:1em;padding-top:0px;"><span style="color:black;">java.version=<span style="color:#c00000;" class="number">1.4</span><span style="color:black;"> </span></span></li> </ol> </div> <p><br /> 注:Javassist不支持1.5的语法,所以要设置java.version=1.4 </p>