﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>语源科技BlogJava-庄周梦蝶</title><link>http://www.blogjava.net/killme2008/</link><description>生活、程序、未来</description><language>zh-cn</language><lastBuildDate>Thu, 23 Apr 2026 03:19:49 GMT</lastBuildDate><pubDate>Thu, 23 Apr 2026 03:19:49 GMT</pubDate><ttl>60</ttl><item><title>博客搬迁</title><link>http://www.blogjava.net/killme2008/archive/2012/12/10/392701.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Sun, 09 Dec 2012 17:24:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2012/12/10/392701.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/392701.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2012/12/10/392701.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/392701.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/392701.html</trackback:ping><description><![CDATA[<br />很久没有更新博客，没想到更新是搬迁公告。这个博客累计的访问量突破百万，是我建立的时候完全没有想过的事情。博客对我来说更多是记录、记忆的地方，我时常因为想不起某个东西，来翻自己的博客，查找旧知，发现新知。阅读很多人的博客，也是我跟踪、学习新知的主要方式。虽然微博兴起，不过博客作为更系统性的记录的地方，不会过时。<br /><br />非常感谢blogjava提供这么优秀的平台。只是我今年给自己的一个目标是建立自己的博客，因此现在要搬迁，加上其实现在也写的少，其实搬迁不搬迁，意义也不大了。算是一个通告，有兴趣的可以订阅我的新博客，没兴趣的请自行略过，谢谢大家。<br /><br />新博客地址：<a href="http://blog.fnil.net/">http://blog.fnil.net/</a><br />RSS地址：<a href="http://blog.fnil.net/index.php/feed">http://blog.fnil.net/index.php/feed</a><br /><br />新博客的第一篇记忆是《<a href="http://blog.fnil.net/index.php/archives/14">Leiningen教程中文版</a>》，从现在开始，这个博客将不再发布任何新的文章，已有的也不会删除，部分可能会导到我的知识库上去。<br /><br />最后，祝福blogjava越办越好。<br /><img src ="http://www.blogjava.net/killme2008/aggbug/392701.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2012-12-10 01:24 <a href="http://www.blogjava.net/killme2008/archive/2012/12/10/392701.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Another URL Shortener using NodeJS</title><link>http://www.blogjava.net/killme2008/archive/2012/11/25/391936.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Sun, 25 Nov 2012 12:31:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2012/11/25/391936.html</guid><description><![CDATA[It's my weekend project&#8212;&#8212;node-shorten: URL Shortener just like t.cn,goo.gl etc.<br />
<br />
Is is written in&nbsp;<a href="http://nodejs.org/">NodeJS</a>,using <a href="http://expressjs.com/">express.js</a> for MVC framework,and using MySQL for storage and Redis for caching.<br />
<br />
A demo online: <a href="http://fnil.me/">http://fnil.me/</a><br />
<br />
The project is at <a href="https://github.com/killme2008/node-shorten">https://github.com/killme2008/node-shorten</a><br />
<br />
Feel free to modify and use it.Have fun.<img src ="http://www.blogjava.net/killme2008/aggbug/391936.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2012-11-25 20:31 <a href="http://www.blogjava.net/killme2008/archive/2012/11/25/391936.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Clojure中文专业技术社区</title><link>http://www.blogjava.net/killme2008/archive/2012/09/25/388498.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Tue, 25 Sep 2012 04:51:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2012/09/25/388498.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/388498.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2012/09/25/388498.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/388498.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/388498.html</trackback:ping><description><![CDATA[很久没写博客，一是工作忙，二是没有太多的事情可说。<br /><br />最近在公司大佬的支持下，建立了一个Clojure语言中文方面的博客和问答网站，欢迎任何对Clojure这门基于JVM之上的函数式语言感兴趣的童鞋贡献原创文章或者资料，申请帐号请看<a href="http://blog.clojure.cn/?page_id=8">这里</a>。<br /><br />博客地址： &nbsp;<a href="http://blog.clojure.cn/">http://blog.clojure.cn/</a><br />问答网站： &nbsp;<a href="http://ask.clojure.cn/" title="http://ask.clojure.cn/">http://ask.clojure.cn/</a><br /><br />欢迎转发和注册使用，谢谢。<br /><br />邮件列表仍然使用google group：<a href="https://groups.google.com/group/cn-clojure/">https://groups.google.com/group/cn-clojure/</a><img src ="http://www.blogjava.net/killme2008/aggbug/388498.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2012-09-25 12:51 <a href="http://www.blogjava.net/killme2008/archive/2012/09/25/388498.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Ring.velocity:render velocity templates for ring in clojure</title><link>http://www.blogjava.net/killme2008/archive/2012/07/18/383354.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Tue, 17 Jul 2012 16:07:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2012/07/18/383354.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/383354.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2012/07/18/383354.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/383354.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/383354.html</trackback:ping><description><![CDATA[<h1></h1><span style="color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; line-height: 22px; ">Home:&nbsp;</span><a href="https://github.com/killme2008/ring.velocity" style="font-family: Helvetica, arial, freesans, clean, sans-serif; line-height: 22px; ">https://github.com/killme2008/ring.velocity<br /></a><br /><p style="margin: 0px 0px 15px; padding: 0px; border: 0px; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; line-height: 22px; ">A Clojure library designed to render velocity template for ring in clojure.<br /></p><h2><a name="usage" href="https://github.com/killme2008/ring.velocity#usage" style="margin: 0px 0px 0px -30px; padding: 0px 0px 0px 30px; border: 0px; color: rgb(65, 131, 196); text-decoration: none; display: block; cursor: pointer; position: absolute; top: 0px; left: 0px; bottom: 0px; "></a>Usage</h2><p style="margin: 0px 0px 15px; padding: 0px; border: 0px; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; line-height: 22px; ">Adds dependency in leiningen project.clj:</p><pre style="margin-top: 15px; margin-bottom: 15px; padding: 6px 10px; border: 1px solid #cccccc; font-size: 13px; font-family: Consolas, 'Liberation Mono', Courier, monospace; background-color: #f8f8f8; line-height: 19px; overflow: auto; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; color: #333333; "><code style="margin: 0px; padding: 0px; border: none; font-size: 12px; font-family: Consolas, 'Liberation Mono', Courier, monospace; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; ">  [ring.velocity "0.1.0-SNAPSHOT"] </code></pre><p style="margin: 15px 0px; padding: 0px; border: 0px; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; line-height: 22px; ">Create a directory named&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; border: 1px solid #eaeaea; font-size: 12px; font-family: Consolas, 'Liberation Mono', Courier, monospace; white-space: nowrap; background-color: #f8f8f8; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; ">templates</code>&nbsp;in your project directory to keep all velocity templates.</p><p style="margin: 15px 0px; padding: 0px; border: 0px; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; line-height: 22px; ">Create a template&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; border: 1px solid #eaeaea; font-size: 12px; font-family: Consolas, 'Liberation Mono', Courier, monospace; white-space: nowrap; background-color: #f8f8f8; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; ">templates/test.vm</code>:</p><pre style="margin-top: 15px; margin-bottom: 15px; padding: 6px 10px; border: 1px solid #cccccc; font-size: 13px; font-family: Consolas, 'Liberation Mono', Courier, monospace; background-color: #f8f8f8; line-height: 19px; overflow: auto; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; color: #333333; "><code style="margin: 0px; padding: 0px; border: none; font-size: 12px; font-family: Consolas, 'Liberation Mono', Courier, monospace; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; ">  hello,$name,your age is $age. </code></pre><p style="margin: 15px 0px; padding: 0px; border: 0px; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; line-height: 22px; ">Use ring.velocity in your namespace:</p><pre style="margin-top: 15px; margin-bottom: 15px; padding: 6px 10px; border: 1px solid #cccccc; font-size: 13px; font-family: Consolas, 'Liberation Mono', Courier, monospace; background-color: #f8f8f8; line-height: 19px; overflow: auto; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; color: #333333; "><code style="margin: 0px; padding: 0px; border: none; font-size: 12px; font-family: Consolas, 'Liberation Mono', Courier, monospace; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; ">  (use '[ring.velocity.core :only [render]]) </code></pre><p style="margin: 15px 0px; padding: 0px; border: 0px; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; line-height: 22px; ">Use&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; border: 1px solid #eaeaea; font-size: 12px; font-family: Consolas, 'Liberation Mono', Courier, monospace; white-space: nowrap; background-color: #f8f8f8; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; ">render</code>&nbsp;function to render template with vars:</p><pre style="margin-top: 15px; margin-bottom: 15px; padding: 6px 10px; border: 1px solid #cccccc; font-size: 13px; font-family: Consolas, 'Liberation Mono', Courier, monospace; background-color: #f8f8f8; line-height: 19px; overflow: auto; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; color: #333333; "><code style="margin: 0px; padding: 0px; border: none; font-size: 12px; font-family: Consolas, 'Liberation Mono', Courier, monospace; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; ">  (render "test.vm" :name "dennis" :age 29) </code></pre><p style="margin: 15px 0px; padding: 0px; border: 0px; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; line-height: 22px; ">The&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; border: 1px solid #eaeaea; font-size: 12px; font-family: Consolas, 'Liberation Mono', Courier, monospace; white-space: nowrap; background-color: #f8f8f8; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; ">test.vm</code>&nbsp;will be interpreted equals to:</p><pre style="margin-top: 15px; margin-bottom: 15px; padding: 6px 10px; border: 1px solid #cccccc; font-size: 13px; font-family: Consolas, 'Liberation Mono', Courier, monospace; background-color: #f8f8f8; line-height: 19px; overflow: auto; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; color: #333333; "><code style="margin: 0px; padding: 0px; border: none; font-size: 12px; font-family: Consolas, 'Liberation Mono', Courier, monospace; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; ">  hello,dennis,your age is 29. </code></pre><p style="margin: 15px 0px; padding: 0px; border: 0px; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; line-height: 22px; ">Use ring.velocity in <a href="https://github.com/weavejester/compojure/">compojure</a>:</p><pre style="margin-top: 15px; margin-bottom: 15px; padding: 6px 10px; border: 1px solid #cccccc; font-size: 13px; font-family: Consolas, 'Liberation Mono', Courier, monospace; background-color: #f8f8f8; line-height: 19px; overflow: auto; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; color: #333333; "><code style="margin: 0px; padding: 0px; border: none; font-size: 12px; font-family: Consolas, 'Liberation Mono', Courier, monospace; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; ">  (defroutes app-routes      <br />    (GET "/" [] (render "test.vm" :name "dennis" :age 29))   <br />    (route/not-found "Not Found")) </code></pre><p style="margin: 15px 0px; padding: 0px; border: 0px; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; line-height: 22px; ">Use ring.velocity in <a href="https://github.com/ring-clojure/ring">ring</a>:</p><pre style="margin-top: 15px; margin-bottom: 15px; padding: 6px 10px; border: 1px solid #cccccc; font-size: 13px; font-family: Consolas, 'Liberation Mono', Courier, monospace; background-color: #f8f8f8; line-height: 19px; overflow: auto; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; color: #333333; "><code style="margin: 0px; padding: 0px; border: none; font-size: 12px; font-family: Consolas, 'Liberation Mono', Courier, monospace; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; ">  (use '[ring.util.response])   <br />  (response (render "test.vm" :name "dennis" :age 29)) </code></pre><p style="margin: 15px 0px; padding: 0px; border: 0px; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; line-height: 22px; ">Custom velocity properties,just put a file named&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; border: 1px solid #eaeaea; font-size: 12px; font-family: Consolas, 'Liberation Mono', Courier, monospace; white-space: nowrap; background-color: #f8f8f8; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; ">ring-velocity.properties</code>&nbsp;to your classpath or resource paths.The default velocity properties is in&nbsp;<a href="https://github.com/killme2008/ring.velocity/blob/master/src/default/velocity.properties" style="margin: 0px; padding: 0px; border: 0px; color: #4183c4; text-decoration: none; ">src/default/velocity.properties</a>.</p><h2><a name="license" href="https://github.com/killme2008/ring.velocity#license" style="margin: 0px 0px 0px -30px; padding: 0px 0px 0px 30px; border: 0px; color: rgb(65, 131, 196); text-decoration: none; display: block; cursor: pointer; position: absolute; top: 0px; left: 0px; bottom: 0px; "></a>License</h2><p style="margin: 0px 0px 15px; padding: 0px; border: 0px; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; line-height: 22px; ">Copyright &#169; 2012 dennis zhuang[killme2008@gmail.com]</p><p style="margin-top: 15px; margin-right: 0px; margin-bottom: 0px !important; margin-left: 0px; padding: 0px; border: 0px; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; line-height: 22px; ">Distributed under the Eclipse Public License, the same as Clojure.<br /><br />Home:&nbsp;<a href="https://github.com/killme2008/ring.velocity">https://github.com/killme2008/ring.velocity</a></p><img src ="http://www.blogjava.net/killme2008/aggbug/383354.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2012-07-18 00:07 <a href="http://www.blogjava.net/killme2008/archive/2012/07/18/383354.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Clojure笔记：用好type hint</title><link>http://www.blogjava.net/killme2008/archive/2012/07/10/382738.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Tue, 10 Jul 2012 12:37:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2012/07/10/382738.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/382738.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2012/07/10/382738.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/382738.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/382738.html</trackback:ping><description><![CDATA[<br />
&nbsp; &nbsp; Clojure的一大优点就是跟Java语言的完美配合，Clojure和Java之间可以相互调用，Clojure可以天然地使用Java平台上的丰富资源。在Clojure里调用一个类的方法很简单，利用dot操作符：<br />
<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->user=&gt;&nbsp;(.substring&nbsp;"hello"&nbsp;3)<br />
"lo"<br />
user=&gt;&nbsp;(.substring&nbsp;"hello"&nbsp;0&nbsp;3)<br />
"hel"</div>
<br />
&nbsp; &nbsp; 上面的例子是在clojure里调用String的substring方法做字符串截取。Clojure虽然是一门弱类型的语言，但是它的Lisp Reader还是能识别大多数常见的类型，比如这里hello是一个字符串就可以识别出来,3是一个整数也可以，通过这些类型信息可以找到最匹配的substring方法，在生成字节码的时候避免使用反射，而是直接调用substring方法（INVOKEVIRTUAL指令）。<br />
<br />
&nbsp; &nbsp; 但是当你在函数里调用类方法的时候，情况就变了，例如，定义substr函数：<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->(defn&nbsp;substr&nbsp;[s&nbsp;begin&nbsp;end]&nbsp;(.substring&nbsp;s&nbsp;begin&nbsp;end))</div>
<br />
&nbsp; &nbsp; 我们打开*warn-on-reflection*选项，当有反射的时候告警：<br />
<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->user=&gt;&nbsp;(set!&nbsp;*warn-on-reflection*&nbsp;<span style="color: #0000FF; ">true</span>)<br />
<span style="color: #0000FF; ">true</span><br />
user=&gt;&nbsp;(defn&nbsp;substr&nbsp;[s&nbsp;begin&nbsp;end]&nbsp;(.substring&nbsp;s&nbsp;begin&nbsp;end))<br />
<strong>Reflection&nbsp;warning,&nbsp;NO_SOURCE_PATH:22&nbsp;-&nbsp;call&nbsp;to&nbsp;substring&nbsp;can't&nbsp;be&nbsp;resolved.</strong><br />
#'user/substr</div>
&nbsp; &nbsp; <br />
&nbsp; &nbsp; 问题出现了，由于函数substr里没有任何关于参数s的类型信息，为了调用s的substring方法，必须使用反射来调用，clojure编译器也警告我们调用substring没办法解析，只能通过反射调用。众所周知，反射调用是个相对昂贵的操作（对比于普通的方法调用有）。这一切都是因为clojure本身是弱类型的语言，对参数或者返回值你不需要声明类型而直接使用,Clojure会自动处理类型的转换和调用。ps.在<a href="https://github.com/technomancy/leiningen">leiningen</a>里启用反射警告很简单，在project.clj里设置：<br /><br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->;;&nbsp;Emit&nbsp;warnings&nbsp;on&nbsp;all&nbsp;reflection&nbsp;calls.<br />&nbsp;&nbsp;:warn-on-reflection&nbsp;<span style="color: #0000FF; ">true</span></div>
&nbsp; &nbsp; <br />过多的反射调用会影响效率，有没有办法避免这种情况呢？有的，Clojure提供了type hint机制，允许我们帮助编译器来生成更高效的字节码。所谓type hint就是给参数或者返回值添加一个提示：hi,clojure编译器，这是xxx类型，我想调用它的yyy方法，请生成最高效的调用代码，谢谢合作：<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->user=&gt;&nbsp;(defn&nbsp;substr&nbsp;[<strong>^String</strong>&nbsp;s&nbsp;begin&nbsp;end]&nbsp;(.substring&nbsp;s&nbsp;begin&nbsp;end))<br />
#'user/substr</div>
&nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; 这次没有警告，^String就是参数s的type hint，提示clojure编译器说s的类型是字符串，那么clojure编译器会从java.lang.String类里查找<strong>名称为substring并且接收两个参数的方法</strong>，并利用invokevirtual指令直接调用此方法，避免了反射调用。除了target对象（这里的s)可以添加type hint，方法参数和返回值也可以添加type hint：<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->user=&gt;&nbsp;(defn&nbsp;<strong>^{:tag&nbsp;String}</strong>&nbsp;substr&nbsp;[<strong>^String</strong>&nbsp;s&nbsp;<strong>^Integer</strong>&nbsp;begin<strong>&nbsp;^Integer</strong>&nbsp;end]&nbsp;(.substring&nbsp;s&nbsp;begin&nbsp;end))<br />
#'user/substr</div>
&nbsp; &nbsp;&nbsp;<br />
&nbsp; &nbsp; 返回值添加type hint是利用tag元数据，提示substr的返回类型是String，其他函数在使用substr的时候可以利用这个类型信息来避免反射；而参数的type hint跟target object的type hint一样以^开头加上类型，例如这里begin和end都提示说是Integer类型。<br />
<br />
&nbsp; &nbsp; <strong>问题1，什么时候应该为参数添加type hint呢？我的观点是，在任何为target object添加type hint的地方，都应该相应地为参数添加type hint，除非你事先不知道参数的类型。</strong>为什么呢？因为clojure查找类方法的顺序是这样：<br />
<br />
1.从String类里查找出所有参数个数为2并且名称为substring方法<br />
2.遍历第一步里查找出来的Method，如果你有设置参数的type hint,则
<div style="display: inline-block; "></div>
查找最匹配参数类型的Method；否则，如果第一步查找出来的Method就一个，直接使用这个Method，相反就认为没有找到对应的Method。<br />
3.如果第二步没有找到Method，使用反射调用；否则根据该Method元信息生成调用字节码。<br />
<br />
&nbsp; &nbsp;因此，如果substring方法的两个参数版本刚好就一个，方法参数有没有type hint都没有关系（有了错误的type hint反而促使反射的发生），我们都会找到这个唯一的方法；但是如果目标方法的有多个重载方法并且参数相同，而只是参数类型不同（Java里是允许方法的参数类型重载的，Clojure只允许函数的参数个数重载），那么如果没有方法参数的type hint，Clojure编译器仍然无法找到合适的调用方法，而只能通过反射。<br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;看一个例子,定义get-bytes方法调用String.getBytes：<br />
<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->user=&gt;&nbsp;(defn&nbsp;get-bytes&nbsp;[s&nbsp;charset]&nbsp;(.getBytes&nbsp;s&nbsp;charset))<br />
<strong>Reflection&nbsp;warning,&nbsp;NO_SOURCE_PATH:26&nbsp;-&nbsp;call&nbsp;to&nbsp;getBytes&nbsp;can't&nbsp;be&nbsp;resolved</strong>.<br />
#'user/get-bytes<br />
user=&gt;&nbsp;(defn&nbsp;get-bytes&nbsp;[<strong>^String</strong>&nbsp;s&nbsp;charset]&nbsp;(.getBytes&nbsp;s&nbsp;charset))<br />
<strong>Reflection&nbsp;warning,&nbsp;NO_SOURCE_PATH:27&nbsp;-&nbsp;call&nbsp;to&nbsp;getBytes&nbsp;can't&nbsp;be&nbsp;resolved.</strong><br />
#'user/get-bytes</div>
<br />
&nbsp; &nbsp; 第一次定义，s和charset都没有设置type hint，有反射警告；第二次，s设置了type hint，但是还是有反射警告。原因就在于String.getBytes有两个重载方法，参数个数都是一个，但是接收不同的参数类型，一个是String的charset名称，一个Charset对象。如果我们明确地知道这里charset是字符串，那么还可以为charset添加type hint:<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->user=&gt;&nbsp;(defn&nbsp;get-bytes&nbsp;[<strong>^String</strong>&nbsp;s&nbsp;<strong>^String</strong>&nbsp;charset]&nbsp;(.getBytes&nbsp;s&nbsp;charset))<br />
#'user/get-bytes</div>
&nbsp; &nbsp;<br />
&nbsp; &nbsp; 这次才真正的没有警告了。总结：在设置type hint的时候，不要只考虑被调用的target object，也要考虑调用的方法参数。<br />
<br />
&nbsp; &nbsp; 问题2：什么时候应该添加tag元数据呢？理论上，在任何你明确知道返回类型的地方都应该添加tag，但是这不是教条，如果一个偶尔被调用的方法是无需这样做的。这一点只对写库的童鞋要特别注意。<br />
<br />
&nbsp; &nbsp; Type hint的原理在上文已经大概描述了下，具体到clojure源码级别，请参考clojure.lang.Compiler.InstanceMethodExpr类的构造函数和emit方法。最后，附送是否使用type hint生成substr函数的字节码之间的差异对比：<br />
<table border="1" cellspacing="2" cellpadding="2" width="500">
     <tbody>
         <tr>
             <td>未使用type hint</td>
             <td>使用type hint</td>
         </tr>
         <tr>
             <td>
             <p>&nbsp; // access flags 1</p>
             <p>&nbsp; public invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;</p>
             <p>&nbsp;&nbsp; L0</p>
             <p>&nbsp; &nbsp; LINENUMBER 14 L0</p>
             <p>&nbsp;&nbsp; L1</p>
             <p>&nbsp; &nbsp; LINENUMBER 14 L1</p>
             <p>&nbsp; &nbsp; ALOAD 1</p>
             <p>&nbsp; &nbsp; ACONST_NULL</p>
             <p>&nbsp; &nbsp; ASTORE 1</p>
             <p>&nbsp; &nbsp; LDC "substring"</p>
             <p>&nbsp; &nbsp; ICONST_2</p>
             <p>&nbsp; &nbsp; ANEWARRAY java/lang/Object</p>
             <p>&nbsp; &nbsp; DUP</p>
             <p>&nbsp; &nbsp; ICONST_0</p>
             <p>&nbsp; &nbsp; ALOAD 2</p>
             <p>&nbsp; &nbsp; ACONST_NULL</p>
             <p>&nbsp; &nbsp; ASTORE 2</p>
             <p>&nbsp; &nbsp; AASTORE</p>
             <p>&nbsp; &nbsp; DUP</p>
             <p>&nbsp; &nbsp; ICONST_1</p>
             <p>&nbsp; &nbsp; ALOAD 3</p>
             <p>&nbsp; &nbsp; ACONST_NULL</p>
             <p>&nbsp; &nbsp; ASTORE 3</p>
             <p>&nbsp; &nbsp; AASTORE</p>
             <p>&nbsp; &nbsp; <strong>INVOKESTATIC clojure/lang/Reflector.invokeInstanceMethod (Ljava/lang/Object;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/Object;</strong></p>
             <p>&nbsp;&nbsp; L2</p>
             <p>&nbsp; &nbsp; LOCALVARIABLE this Ljava/lang/Object; L0 L2 0</p>
             <p>&nbsp; &nbsp; LOCALVARIABLE s Ljava/lang/Object; L0 L2 1</p>
             <p>&nbsp; &nbsp; LOCALVARIABLE begin Ljava/lang/Object; L0 L2 2</p>
             <p>&nbsp; &nbsp; LOCALVARIABLE end Ljava/lang/Object; L0 L2 3</p>
             <p>&nbsp; &nbsp; ARETURN</p>
             <p>&nbsp; &nbsp; MAXSTACK = 0</p>
             <p>&nbsp; &nbsp; MAXLOCALS = 0</p>
             </td>
             <td>
             <p>public invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;</p>
             <p>&nbsp;&nbsp; L0</p>
             <p>&nbsp; &nbsp; LINENUMBER 15 L0</p>
             <p>&nbsp;&nbsp; L1</p>
             <p>&nbsp; &nbsp; LINENUMBER 15 L1</p>
             <p>&nbsp; &nbsp; ALOAD 1</p>
             <p>&nbsp; &nbsp; ACONST_NULL</p>
             <p>&nbsp; &nbsp; ASTORE 1</p>
             <p>&nbsp; &nbsp; CHECKCAST java/lang/String</p>
             <p>&nbsp; &nbsp; ALOAD 2</p>
             <p>&nbsp; &nbsp; ACONST_NULL</p>
             <p>&nbsp; &nbsp; ASTORE 2</p>
             <p>&nbsp; &nbsp; CHECKCAST java/lang/Number</p>
             <p>&nbsp; &nbsp; INVOKESTATIC clojure/lang/RT.intCast (Ljava/lang/Object;)I</p>
             <p>&nbsp; &nbsp; ALOAD 3</p>
             <p>&nbsp; &nbsp; ACONST_NULL</p>
             <p>&nbsp; &nbsp; ASTORE 3</p>
             <p>&nbsp; &nbsp; CHECKCAST java/lang/Number</p>
             <p>&nbsp; &nbsp; INVOKESTATIC clojure/lang/RT.intCast (Ljava/lang/Object;)I</p>
             <p>&nbsp; &nbsp; <strong>INVOKEVIRTUAL java/lang/String.substring (II)Ljava/lang/String;</strong></p>
             <p>&nbsp;&nbsp; L2</p>
             <p>&nbsp; &nbsp; LOCALVARIABLE this Ljava/lang/Object; L0 L2 0</p>
             <p>&nbsp; &nbsp; LOCALVARIABLE s Ljava/lang/Object; L0 L2 1</p>
             <p>&nbsp; &nbsp; LOCALVARIABLE begin Ljava/lang/Object; L0 L2 2</p>
             <p>&nbsp; &nbsp; LOCALVARIABLE end Ljava/lang/Object; L0 L2 3</p>
             <p>&nbsp; &nbsp; ARETURN</p>
             <p>&nbsp; &nbsp; MAXSTACK = 0</p>
             <p>&nbsp; &nbsp; MAXLOCALS = 0</p>
             </td>
         </tr>
     </tbody>
</table>
<br />
&nbsp; &nbsp;&nbsp;<br />
&nbsp; &nbsp; 对比很明显，没有使用type hint，调用clojure.lang.Reflector的invokeInstanceMethod方法，使用反射调用（具体见clojure.lang.Reflector.java)，而使用了type hint之后，则直接使用invokevirtual指令（其他方法可能是invokestatic或者invokeinterface等指令）调用该方法，避免了反射。<br />
&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;<br />
<br />
&nbsp; &nbsp; 参考：<br />
<ul>
<li><a href="http://clojure.org/java_interop#Java%20Interop-Type%20Hints">Type hint官方指南</a></li>
<li><a href="http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.10.1.4.5.invokevirtual">invokevirtual指令</a></li>
<li><a href="https://github.com/clojure/clojure">Clojure源码</a></li>
</ul><img src ="http://www.blogjava.net/killme2008/aggbug/382738.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2012-07-10 20:37 <a href="http://www.blogjava.net/killme2008/archive/2012/07/10/382738.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Clojure世界：利用HouseMD诊断clojure</title><link>http://www.blogjava.net/killme2008/archive/2012/06/15/380822.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Thu, 14 Jun 2012 18:52:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2012/06/15/380822.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/380822.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2012/06/15/380822.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/380822.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/380822.html</trackback:ping><description><![CDATA[<br />
&nbsp; &nbsp; <a href="https://github.com/zhongl/HouseMD">HouseMD</a>是淘宝的聚石写的一个非常优秀的Java进程运行时诊断和调试工具，如果你接触过btrace，那么HouseMD也许你应该尝试下，它比btrace更易用，不需要写脚本，类似strace的方式attach到jvm进程做跟踪调试。<br />
<br />
&nbsp; &nbsp; 基本的安装和使用请看这篇文档《<a href="https://github.com/zhongl/HouseMD/wiki/UserGuideCN">UserGuide</a>》，恕不重复。以下内容都假设你正确安装了housemd。<br />
<br />
&nbsp; &nbsp; 本文主要介绍下怎么用housemd诊断跟踪clojure进程。Clojure的java实现也是跑在JVM里，当然也可以用housemd。<br /><br />
&nbsp; &nbsp; 我们以一个简单的例子开始，假设我们有如下clojure代码：<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->(loop&nbsp;[x&nbsp;1]<br />
&nbsp;&nbsp;(Thread/sleep&nbsp;1000)<br />
&nbsp;&nbsp;(prn&nbsp;x)<br />
&nbsp;&nbsp;(recur (inc x)))</div>
<br />
&nbsp; &nbsp; 这段很简单，只是间隔一秒不断地打印递增的数字x。我们准备用housemd跟踪这个程序的运行，首先运行这个程序，你可以用lein，也可以直接java命令运行：<br />
<div style="font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%; word-break: break-all; background-color: #eeeeee; "><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
-->java&nbsp;-cp&nbsp;clojure.jar&nbsp;clojure.main&nbsp;test.clj</div>
<br />
&nbsp; &nbsp; 运行时不断地在控制台打印数字，通过jps或者ps查询到该进程的id，假设为pid，使用housemd连接到该进程：<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
-->housemd&nbsp;&lt;pid&gt;</div>
&nbsp; &nbsp; 顺利进入housemd的交互控制台，通过help命令可以查询支持的命令：<br />
<br />
<div style="font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%; word-break: break-all; background-color: #eeeeee; "><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->housemd&gt;&nbsp;help<br />
<br />
quit&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;terminate&nbsp;the&nbsp;process.<br />
help&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;display&nbsp;<span style="color: #0000FF; ">this</span>&nbsp;infomation.<br />
trace&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;display&nbsp;or&nbsp;output&nbsp;infomation&nbsp;of&nbsp;method&nbsp;invocaton.<br />
loaded&nbsp;&nbsp;&nbsp;&nbsp;display&nbsp;loaded&nbsp;classes&nbsp;information.</div>
<br />
&nbsp; &nbsp; 要用housemd调试clojure，你需要对clojure的实现有一点点了解，有兴趣可以看过去的一篇blog《<a href="http://www.blogjava.net/killme2008/archive/2010/07/11/325775.html">clojure hacking guide</a>》，简单来说，clojure的编译器会将clojure代码编译成java类并运行。对于JVM来说，clojure生成的类，跟java编译器生成类没有什么不同。<br />
&nbsp; &nbsp; 具体到上面的clojure代码，会生成一个名为<strong>user$eval1</strong>的类，user是默认的namespace，而eval1是clojure编译器自动生成的一个标示类名，通过<strong>loaded</strong>命令查询类的加载情况：<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->housemd&gt;&nbsp;loaded&nbsp;user$eval1&nbsp;-h<br />
user$eval1&nbsp;-&gt;&nbsp;<span style="color: #0000FF; ">null</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;clojure.lang.DynamicClassLoader@1d25d06e<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;clojure.lang.DynamicClassLoader@1d96f4b5<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;sun.misc.Launcher$AppClassLoader@a6eb38a<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;sun.misc.Launcher$ExtClassLoader@69cd2e5f</div>
<br />
&nbsp; &nbsp; 通过-h选项打印了加载user$eval1的类加载器的层次关系，因为user$eval1是动态生成的（clojure启动过程中），因此它不在任何一个class或者jar文件中。除了查询user namespace的类之外，你还可以查询clojure.core,clojure.lang,clojure.java等任何被加载进来的类，例如查询clojure.core.prn的类,在clojure里这是一个函数，在jvm看来这只是一个类：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->housemd&gt;&nbsp;loaded&nbsp;-h&nbsp;core$prn<br />clojure.core$prn&nbsp;-&gt;&nbsp;/Volumes/HDD/Users/apple/clojure/clojure.jar<br />&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;sun.misc.Launcher$AppClassLoader@a6eb38a<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;sun.misc.Launcher$ExtClassLoader@69cd2e5f</div>&nbsp; &nbsp;注意，不需要完整的namespace&#8212;&#8212;clojure.core，直接core$prn即可。其他也是类似。<strong>小技巧：如果你实在不知道clojure编译器生成的类名，你可以利用jvm自带的jmap命令来查询。</strong><br /><br />&nbsp; &nbsp;接下来，我们尝试用trace命令跟踪方法的运行，例如例子中的clojure代码用到了loop和recur两个sepcial form，我们跟踪下loop:<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->housemd&gt;&nbsp;trace&nbsp;-t&nbsp;5&nbsp;core$loop<br />INFO&nbsp;:&nbsp;probe&nbsp;<span style="color: #0000FF; ">class</span>&nbsp;clojure.core$loop<br />core$loop.doInvoke(Object,&nbsp;Object,&nbsp;Object,&nbsp;Object)&nbsp;&nbsp;&nbsp;&nbsp;sun.misc.Launcher$AppClassLoader@a6eb38a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-ms&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">null</span><br />core$loop.getRequiredArity()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sun.misc.Launcher$AppClassLoader@a6eb38a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-ms&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">null</span><br /><br />core$loop.doInvoke(Object,&nbsp;Object,&nbsp;Object,&nbsp;Object)&nbsp;&nbsp;&nbsp;&nbsp;sun.misc.Launcher$AppClassLoader@a6eb38a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-ms&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">null</span><br />core$loop.getRequiredArity()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sun.misc.Launcher$AppClassLoader@a6eb38a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-ms&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">null</span><br /><br />core$loop.doInvoke(Object,&nbsp;Object,&nbsp;Object,&nbsp;Object)&nbsp;&nbsp;&nbsp;&nbsp;sun.misc.Launcher$AppClassLoader@a6eb38a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-ms&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">null</span><br />core$loop.getRequiredArity()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sun.misc.Launcher$AppClassLoader@a6eb38a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-ms&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">null</span><br /><br />core$loop.doInvoke(Object,&nbsp;Object,&nbsp;Object,&nbsp;Object)&nbsp;&nbsp;&nbsp;&nbsp;sun.misc.Launcher$AppClassLoader@a6eb38a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-ms&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">null</span><br />core$loop.getRequiredArity()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sun.misc.Launcher$AppClassLoader@a6eb38a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-ms&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">null</span><br /><br />core$loop.doInvoke(Object,&nbsp;Object,&nbsp;Object,&nbsp;Object)&nbsp;&nbsp;&nbsp;&nbsp;sun.misc.Launcher$AppClassLoader@a6eb38a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-ms&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">null</span><br />core$loop.getRequiredArity()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sun.misc.Launcher$AppClassLoader@a6eb38a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-ms&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">null</span><br /><br />INFO&nbsp;:&nbsp;Ended&nbsp;by&nbsp;timeout<br />INFO&nbsp;:&nbsp;reset&nbsp;<span style="color: #0000FF; ">class</span>&nbsp;clojure.core$loop</div><br />&nbsp; &nbsp; 在5秒内，clojure.core$loop类有两个方法各被调用了5次，doInvoke是实际的调用，而getRequiredArity用来查询loop所需要的参数个数。trace还可以跟踪到具体的方法，例如我们跟踪prn函数的调用情况：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->housemd&gt;&nbsp;trace&nbsp;-t&nbsp;5&nbsp;core$prn.<strong>doInvoke</strong><br />INFO&nbsp;:&nbsp;probe&nbsp;<span style="color: #0000FF; ">class</span>&nbsp;clojure.core$prn<br />core$prn.doInvoke(Object)&nbsp;&nbsp;&nbsp;&nbsp;sun.misc.Launcher$AppClassLoader@a6eb38a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1ms&nbsp;&nbsp;&nbsp;&nbsp;clojure.core$prn@3e4ac866<br /><br />core$prn.doInvoke(Object)&nbsp;&nbsp;&nbsp;&nbsp;sun.misc.Launcher$AppClassLoader@a6eb38a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;1ms&nbsp;&nbsp;&nbsp;&nbsp;clojure.core$prn@3e4ac866<br /><br />core$prn.doInvoke(Object)&nbsp;&nbsp;&nbsp;&nbsp;sun.misc.Launcher$AppClassLoader@a6eb38a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;1ms&nbsp;&nbsp;&nbsp;&nbsp;clojure.core$prn@3e4ac866<br /><br />core$prn.doInvoke(Object)&nbsp;&nbsp;&nbsp;&nbsp;sun.misc.Launcher$AppClassLoader@a6eb38a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;1ms&nbsp;&nbsp;&nbsp;&nbsp;clojure.core$prn@3e4ac866<br /><br />core$prn.doInvoke(Object)&nbsp;&nbsp;&nbsp;&nbsp;sun.misc.Launcher$AppClassLoader@a6eb38a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;1ms&nbsp;&nbsp;&nbsp;&nbsp;clojure.core$prn@3e4ac866<br /><br />INFO&nbsp;:&nbsp;Ended&nbsp;by&nbsp;timeout<br />INFO&nbsp;:&nbsp;reset&nbsp;<span style="color: #0000FF; ">class</span>&nbsp;clojure.core$prn</div>&nbsp;&nbsp;<br />&nbsp; &nbsp;trace打印了方法的调用次数（5秒内）和每次调用的时间（毫秒级别），以及调用的target object<strong>。小技巧：没有可变参数的函数生成类最终调用的是invoke方法（参数个数可能重载），有可变参数的函数调用的是doInvoke方法。<br /><br /></strong>&nbsp; &nbsp;trace命令还支持打印调用堆栈到文件，例如：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->trace&nbsp;-t&nbsp;5&nbsp;-d&nbsp;-s&nbsp;&nbsp;core$prn.doInvoke</div><br />&nbsp; &nbsp;利用-s和-d命令会将详细的调用信息输出到临时目录，临时目录的路径可以通过trace help命令查询到，在我的机器上是/tmp/trace/&lt;pid&gt;@host目录下。调用堆栈的输出类似：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->example$square.invoke(Long)&nbsp;call&nbsp;by&nbsp;thread&nbsp;[main]<br />&nbsp;&nbsp;&nbsp;&nbsp;example$eval9.invoke(test.clj:11)<br />&nbsp;&nbsp;&nbsp;&nbsp;clojure.lang.Compiler.eval(Compiler.java:6465)<br />&nbsp;&nbsp;&nbsp;&nbsp;clojure.lang.Compiler.load(Compiler.java:6902)<br />&nbsp;&nbsp;&nbsp;&nbsp;clojure.lang.Compiler.loadFile(Compiler.java:6863)<br />&nbsp;&nbsp;&nbsp;&nbsp;clojure.main$load_script.invoke(main.clj:282)<br />&nbsp;&nbsp;&nbsp;&nbsp;clojure.main$script_opt.invoke(main.clj:342)<br />&nbsp;&nbsp;&nbsp;&nbsp;clojure.main$main.doInvoke(main.clj:426)<br />&nbsp;&nbsp;&nbsp;&nbsp;clojure.lang.RestFn.invoke(RestFn.java:421)<br />&nbsp;&nbsp;&nbsp;&nbsp;clojure.lang.Var.invoke(Var.java:405)<br />&nbsp;&nbsp;&nbsp;&nbsp;clojure.lang.AFn.applyToHelper(AFn.java:163)<br />&nbsp;&nbsp;&nbsp;&nbsp;clojure.lang.Var.applyTo(Var.java:518)<br />&nbsp;&nbsp;&nbsp;&nbsp;clojure.main.main(main.java:37)</div><br />&nbsp; &nbsp;上面这个简单的例子展示了使用housemd跟踪诊断clojure进程的方法。<br /><br />&nbsp; &nbsp;自定义ns和函数的调试与此类似，假设我们有下面的clojure代码：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->(ns&nbsp;example)<br />(defn&nbsp;square&nbsp;[x]<br />&nbsp;&nbsp;(*&nbsp;x&nbsp;x))<br /><br />(loop&nbsp;[x&nbsp;1]<br />&nbsp;&nbsp;(Thread/sleep&nbsp;1000)<br />&nbsp;&nbsp;(square&nbsp;x)<br />&nbsp;&nbsp;(recur&nbsp;(inc&nbsp;x)))</div>&nbsp;<br />&nbsp; &nbsp;ns为example，自定义函数square并定期循环调用。使用housemd诊断这段代码：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->loaded&nbsp;-h&nbsp;example$square&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#查询square的加载情况<br />trace&nbsp;-t&nbsp;10 -d -s example$square.invoke&nbsp;&nbsp;#跟踪10秒内square的调用情况</div><img src ="http://www.blogjava.net/killme2008/aggbug/380822.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2012-06-15 02:52 <a href="http://www.blogjava.net/killme2008/archive/2012/06/15/380822.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>分布式消息中间件Metaq发布1.4.3</title><link>http://www.blogjava.net/killme2008/archive/2012/06/04/379895.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Mon, 04 Jun 2012 02:03:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2012/06/04/379895.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/379895.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2012/06/04/379895.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/379895.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/379895.html</trackback:ping><description><![CDATA[<p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #f7f7f7; ">我们在维护的淘宝开源消息中间件的<a href="http://metaq.taobao.org/" style="color: #006699; ">metaq</a>的<a href="https://github.com/killme2008/Metamorphosis" style="color: #006699; ">github分支</a>，今天发布了1.4.2版本，主要做了如下改进：<br /><br />1.支持发送和订阅分离，可以细粒度地控制Broker或者某个Topic是否接收消息和接受订阅。服务端添加新选项acceptPublish和acceptSubscribe。<br /><br />2.更友好地关闭Broker，梳理关闭流程并通过JMX调用方法关闭替代原来简单的kill。<br /><br />3.更新<a href="https://github.com/killme2008/Metamorphosis/tree/master/contrib/python/meta-python" style="color: #006699; ">python客户端</a>到0.2版本，可以通过pip安装: &nbsp;pip install metaq<br /><br />4.发布ruby语言客户端<a href="https://github.com/killme2008/Metamorphosis/tree/master/contrib/ruby/meta-ruby" style="color: #006699; ">meta-ruby</a>&nbsp;0.1版本。<br /><br />5.其他小改进：升级gecko到1.1.1版本，升级quartz到2.1.4版本，添加集成测试工程和内部重构等。<br /><br />6.新文档<a href="https://github.com/killme2008/Metamorphosis/wiki/%E4%BD%BF%E7%94%A8Log4j%E6%89%A9%E5%B1%95%E5%8F%91%E9%80%81%E6%B6%88%E6%81%AF">《使用log4j扩展发送消息》</a><br /><br />简介：<a href="https://github.com/killme2008/Metamorphosis/wiki/%E4%BB%8B%E7%BB%8D" style="color: #006699; ">https://github.com/killme2008/Metamorphosis/wiki/介绍</a><br />下载：<a href="https://github.com/killme2008/Metamorphosis/downloads" style="color: #006699; ">https://github.com/killme2008/Metamorphosis/downloads</a></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #f7f7f7; ">文档：<a href="https://github.com/killme2008/Metamorphosis/wiki" style="color: #006699; ">https://github.com/killme2008/Metamorphosis/wiki</a></p><img src ="http://www.blogjava.net/killme2008/aggbug/379895.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2012-06-04 10:03 <a href="http://www.blogjava.net/killme2008/archive/2012/06/04/379895.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何熟悉一个开源项目？</title><link>http://www.blogjava.net/killme2008/archive/2012/05/22/378885.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Tue, 22 May 2012 15:12:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2012/05/22/378885.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/378885.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2012/05/22/378885.html#Feedback</comments><slash:comments>9</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/378885.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/378885.html</trackback:ping><description><![CDATA[<br />&nbsp; &nbsp; 你有个任务，需要用到某个开源项目;或者老大交代你一个事情，让你去了解某个东西。怎么下手呢？如何开始呢？我的习惯是这样：<br /><br />1.首先，查找和阅读该项目的博客和资料，通过google你能找到某个项目大体介绍的博客，快速阅读一下就能对项目的目的、功能、基本使用有个大概的了解。<br /><br />2.阅读项目的文档，重点关注类似<strong>Getting started、Example</strong>之类的文档，从中学习如何下载、安装、甚至基本使用该项目所需要的知识。<br /><br />3.如果该项目有提供现成的example工程，首先尝试按照开始文档的介绍运行example，如果运行顺利，那么恭喜你顺利开了个好头;如果遇到问题，首先尝试在项目的<strong>FAQ</strong>等文档里查找答案，再次，可以将问题（例如异常信息）当成关键词去搜索，查找相关的解决办法，你遇到了，别人一般也会遇到，热心的朋友会记录下解决的过程;最后，可以将问题提交到项目的邮件列表，请大家帮你看看。<strong>在没有成功运行example之前，不要尝试修改example。<br /><br /></strong>4.运行了第一个example之后，尝试根据你的理解和需要修改example，测试高级功能等。<br /><br />5.在了解基本使用后，需要开始深入的了解该项目。例如项目的配置管理、高级功能以及最佳实践。通常一个运作良好的项目会提供一份从浅到深的用户指南，你并不需要从头到尾阅读这份指南，根据时间和兴趣，特别是你自己任务的需要，重点阅读部分章节并做笔记（推荐evernote）。<br /><br />6.如果时间允许，尝试从源码构建该项目。通常开源项目都会提供一份构建指南，指导你如何搭建一个用于开发、调试和构建的环境。尝试构建一个版本。<br /><br />7.如果时间允许并且有兴趣，可以尝试阅读源码：<br />（1）阅读源码之前，查看该项目是否提供架构和设计文档，阅读这些文档可以了解该项目的大体设计和结构，读源码的时候不会无从下手。<br />（2）阅读源码之前，一定要能构建并运行该项目，有个直观感受。<br />（3）阅读源码的第一步是抓主干，尝试理清一次正常运行的代码调用路径，这可以通过debug来观察运行时的变量和行为。修改源码加入日志和打印可以帮助你更好的理解源码。<br />（4）适当画图来帮助你理解源码，在理清主干后，可以将整个流程画成一张流程图或者标准的UML图，帮助记忆和下一步的阅读。<br />（5）挑选感兴趣的&#8220;枝干&#8221;代码来阅读，比如你对网络通讯感兴趣，就阅读网络层的代码，深入到实现细节，如它用了什么库，采用了什么设计模式，为什么这样做等。如果可以，debug细节代码。<br />（6）阅读源码的时候，重视单元测试，尝试去运行单元测试，基本上一个好的单元测试会将该代码的功能和边界描述清楚。<br />（7）在熟悉源码后，发现有可以改进的地方，有精力、有意愿可以向该项目的开发者提出改进的意见或者issue，甚至帮他修复和实现，参与该项目的发展。<br /><br />8.通常在阅读文档和源码之后，你能对该项目有比较深入的了解了，但是该项目所在领域，你可能还想搜索相关的项目和资料，看看有没有其他的更好的项目或者解决方案。在广度和深度之间权衡。<br /><br />&nbsp; &nbsp; 以上是我个人的一些习惯，我自己也并没有完全按照这个来，但是按照这个顺序，基本上能让你比较高效地学习和使用某个开源项目。<img src ="http://www.blogjava.net/killme2008/aggbug/378885.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2012-05-22 23:12 <a href="http://www.blogjava.net/killme2008/archive/2012/05/22/378885.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Emacs + Clojure配置的几个Tip</title><link>http://www.blogjava.net/killme2008/archive/2012/05/19/378535.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Fri, 18 May 2012 16:57:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2012/05/19/378535.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/378535.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2012/05/19/378535.html#Feedback</comments><slash:comments>11</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/378535.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/378535.html</trackback:ping><description><![CDATA[<br />
&nbsp; &nbsp; 很久没更新博客了，在北京工作，忙碌并且充实。目前来说，Clojure最好的开发编辑器应该是Emacs + <a href="http://common-lisp.net/project/slime/doc/html/">Slime</a>的组合，利用<a href="https://github.com/technomancy/swank-clojure">swank-clojure</a>这个项目，加上clojure-mode，可以完美地运行slime。编译、运行、跳转、文档和引用查看甚至<a href="http://georgejahad.com/clojure/swank-cdt.html">debug</a>都可以搞定。具体配置恕不重复，看swank-clojure的文档即可自己安装起来，或者这篇<a href="http://sunng.info/blog/2011/09/beginning-emacs-for-clojure/">中文博客</a>，<a href="http://www.cnblogs.com/darkluck99/archive/2012/02/20/2360216.html">windows上配置</a>。<br />
<br />
&nbsp; &nbsp; 分享几个Tip，也期待大家分享你们的使用心得。<br />
<br />
&nbsp; &nbsp; 首先是自动在打开clj后缀文件的时候启动执行clojure-jack-in与slime连接，可以在emacs配置里加上个callback：<br />
<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->(eval-after-load&nbsp;"clojure-mode"<br />&nbsp;&nbsp;'(progn<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(require&nbsp;'slime)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(require&nbsp;'clojure-mode)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(unless&nbsp;(slime-connected-p)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(save-excursion&nbsp;(clojure-jack-in)))))</div>
&nbsp; &nbsp; 这样在打开clj为后缀的文件的时候，将自动启动clojure-mode执行clojure-jack-in函数并且连接slime。<br /><br />&nbsp; &nbsp; 将clj后缀的文件自动关联到clojure-mode:<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->(setq&nbsp;auto-mode-alist&nbsp;(cons&nbsp;'("\\.clj$"&nbsp;.&nbsp;clojure-mode)&nbsp;auto-mode-alist))</div>
&nbsp; &nbsp; 通常来说如果你是利用<a href="http://marmalade-repo.org/">marmalade</a>安装的，会自动关联的。<br /><br />&nbsp; &nbsp; 另外，启动自动匹配括号、字符串引号等的paredit模式一定要启动：<br /><div style="font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%; word-break: break-all; background-color: #eeeeee; "><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->(defun&nbsp;paredit-mode-enable&nbsp;()&nbsp;(paredit-mode&nbsp;1))<br />(add-hook&nbsp;'clojure-mode-hook&nbsp;'paredit-mode-enable)<br />(add-hook&nbsp;'clojure-test-mode-hook&nbsp;'paredit-mode-enable)</div><br />
&nbsp; &nbsp;在使用clojure-mode或者clojure-test-mode的时候自动启用paredit模式，括号再也不是问题。括号匹配提示一般是开启的，如果没有，强制开启：<br /><br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->;;&nbsp;&nbsp;&nbsp;&nbsp;显示括号匹配<br />(show-paren-mode&nbsp;t)<br />(setq&nbsp;show-paren-style&nbsp;'parentheses)</div><br />&nbsp; &nbsp; slime更多配置，启用IO重定向（多线程IO输出都定向到SLIME repl）以及设置通讯字符编码等：<br /><br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->(eval-after-load&nbsp;"slime"<br />&nbsp;&nbsp;'(progn<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(slime-setup&nbsp;'(slime-repl&nbsp;slime-fuzzy))<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;(setq&nbsp;slime-truncate-lines&nbsp;t)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(setq&nbsp;&nbsp;swank:*globally-redirect-io*&nbsp;&nbsp;t)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;(setq&nbsp;slime-complete-symbol-function&nbsp;'&nbsp;slime-fuzzy-complete-symbol)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(setq&nbsp;slime-net-coding-system&nbsp;'utf-8-unix)))</div><br />&nbsp; &nbsp; 细心的朋友可能注意到我注释了slime-fuzzy-complete的配置，这是一个支持更好的自动补全功能的SLIME插件（可以用缩写来自动补全），可惜在我机器上没有尝试配置成功，有兴趣你可以尝试下。<br /><br />&nbsp; &nbsp; 在REPL里支持语法高亮，一定要配置上：<br /><br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->(add-hook&nbsp;'slime-repl-mode-hook<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(defun&nbsp;clojure-mode-slime-font-lock&nbsp;()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(require&nbsp;'clojure-mode)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;(font-lock-mode)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(clojure-mode-font-lock-setup))))</div><br />&nbsp; &nbsp; 单独在clojure-mode（在其他mode里这些快捷键不会起作用）里配置快捷键可以这样:<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->(eval-after-load&nbsp;"clojure-mode"<br />&nbsp;&nbsp;'(progn<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(require&nbsp;'slime)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(require&nbsp;'clojure-mode)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(define-key&nbsp;clojure-mode-map&nbsp;(kbd&nbsp;"M-/")&nbsp;&nbsp;(quote&nbsp;slime-complete-symbol))<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(define-key&nbsp;clojure-mode-map&nbsp;(kbd&nbsp;"C-c&nbsp;s")&nbsp;&nbsp;(quote&nbsp;slime-selector)))</div><br />&nbsp; &nbsp;例如我这里将M-/作为自动补全的快捷键，因为meta键在我的Mac机器上设置为command键，因此自动补全的操作习惯就跟Eclipse类似。而<strong>slime-selector</strong>是一个非常有用的函数，用来跳转到slime的一系列buffer，因此我绑定了C-c s快捷键。<br /><br />&nbsp; &nbsp; 额外一提，在Mac osx下，将command作为meta键:<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all">;;;&nbsp;I&nbsp;prefer&nbsp;cmd&nbsp;key&nbsp;<span style="color: #0000FF; ">for</span>&nbsp;meta<br />(setq&nbsp;mac-option-key-is-meta&nbsp;nil<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mac-command-key-is-meta&nbsp;t<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mac-command-modifier&nbsp;'meta<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mac-option-modifier&nbsp;'none)</div><br />&nbsp; &nbsp; 最后，期待大家不吝分享你的心得。<br />&nbsp; &nbsp;&nbsp;<img src ="http://www.blogjava.net/killme2008/aggbug/378535.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2012-05-19 00:57 <a href="http://www.blogjava.net/killme2008/archive/2012/05/19/378535.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>clj.monitor : monitoring applications in clojure based on SSH</title><link>http://www.blogjava.net/killme2008/archive/2012/05/12/378018.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Sat, 12 May 2012 14:38:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2012/05/12/378018.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/378018.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2012/05/12/378018.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/378018.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/378018.html</trackback:ping><description><![CDATA[<div><br />&nbsp; &nbsp; My weekend project clj.monitor is beta release,it's a clojure DSL for monitoring system and applications based on SSH.<br />
<br />
Home:<a href="https://github.com/killme2008/clj.monitor">https://github.com/killme2008/clj.monitor
<br /></a><br />
An example:<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->(ns&nbsp;clj.monitor.example<br />
&nbsp;&nbsp;(:use&nbsp;[clj.monitor.core]<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[control.core]<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[clj.monitor.tasks]))<br />
<br />
;;define&nbsp;a&nbsp;mysql&nbsp;cluster<br />
(defcluster&nbsp;mysql<br />
&nbsp;&nbsp;:clients&nbsp;[{:user&nbsp;"deploy"&nbsp;:host&nbsp;"mysql.app.com"}])<br />
<br />
;;define&nbsp;a&nbsp;monitor&nbsp;for&nbsp;mysql&nbsp;cluster<br />
(defmonitor&nbsp;mysql-monitor<br />
&nbsp;&nbsp;:tasks&nbsp;[(ping-mysql&nbsp;"root"&nbsp;"password")<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (system-load&nbsp;:5&nbsp;3)]<br />
&nbsp;&nbsp;:clusters&nbsp;[:mysql])<br />
<br />
;;start&nbsp;monitors<br />
(start-monitors<br />
&nbsp;:cron&nbsp;"*&nbsp;0/5&nbsp;*&nbsp;*&nbsp;*&nbsp;?"<br />
&nbsp;:alerts&nbsp;[(mail&nbsp;:from&nbsp;"alert@app.com"&nbsp;:to&nbsp;"yourname@app.com")]<br />
&nbsp;:monitors&nbsp;[mysql-monitor])</div>
<br />
API document:<a href="http://fnil.net/clj.monitor">&nbsp;http://fnil.net/clj.monitor
</a>
<br />
<br />It is just a beta release,if you have any questions or find issues ,please let me know,thanks.
</div><img src ="http://www.blogjava.net/killme2008/aggbug/378018.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2012-05-12 22:38 <a href="http://www.blogjava.net/killme2008/archive/2012/05/12/378018.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>