<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>Lee's Blog</title>
    <description></description>
    <link>http://lee5593.javaeye.com</link>
    <language>UTF-8</language>
    <copyright>Copyright 2003-2008, JavaEye.com</copyright>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <generator>JavaEye - 做最棒的软件开发交流社区</generator>
      <item>
        <title>毕业设计项目开发体会</title>
        <author>lee5593</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lee5593.javaeye.com">lee5593</a>&nbsp;
          链接：<a href="http://lee5593.javaeye.com/blog/119482" style="color:red;">http://lee5593.javaeye.com/blog/119482</a>&nbsp;
          发表时间: 2007年09月02日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <font size="4"><font size="2"><em>整理资料时无意中发现以前写下的一些文字，现辑录下来，算是对以前生活点滴的一种记念吧！</em></font><br />
&nbsp;<font size="2"> <br />
</font><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 首先，这次的项目设计能够获得优秀毕业设计是对我们全体项目小组成员一个半月努力付出的肯定，在此我要感谢为我们提供需求分析的袁经理以及在项目的开发过程中给予我们技术帮助的指导老师们。本人有幸担任这次项目设计的组长，在项目开发的过程中也经历了一般软件项目过程中遇到的难题和挑战，现在回过头来想起开发过程中的点点滴滴，虽然这个项目算不上一次成功的开发过程，但确实让人体会深刻、收获颇丰，愿写出来与大家共同分享：<br />
<br />
<strong>交流方式<br />
<br />
</strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 很多人都知道交流在项目开发中的重要性，却往往不知道什么样的交流才是适合的有效的方式。在项目一开始我们就通过定期讨论、各种工作文档进行有效的交流，后面发现执行效果还是不尽人意，因为发现有些组员不善于口头表达自己的想法，于是又组建了QQ群组进行即时沟通。我们利用面对面的讨论，解决很多细小方面的误解；有效地使用QQ群组，来弥补一些在讨论中无法取得的效果；而对系统的全面的理解则通过各种系统文档。三种方式交错进行来确保每个组员对系统认识上的一致性。<br />
<br />
<strong>完美与放弃<br />
<br />
</strong>　　在《人月神化》中有一名为&rdquo;The Tar Pit&rdquo;的章节，翻译过来的意思是&ldquo;焦油坑&rdquo;，这是一个很形象的比喻，在这一章中Brooks大师用简短的篇幅，描绘出整个程序世界的苦与乐。在这次项目开发中，有两个苦恼体现的比较明显。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 首先，必须追求完美。&ldquo;因为计算机是以这样的方式来变戏法的：如果咒语中的一个字符、一个停顿，没有与正确的形式一致，魔术就不会出现（现实中，很少的人类活动要求完美，所以人类对它本来就不习惯）。实际上，我认为，学习编程最困难的部分，是将做事的方式向追求完美的方向调整。&rdquo;很幸运，我是个力求完美的人，而且我也一直认为程序员应该具有这种本性。在编写程序的时候，甚至对一个变量名我都要反复斟酌，直到选择一个我认为可以精确表达这个变量意思为止。我并不认为这是在浪费时间：一是有助于对程序的理解和维护，好的程序本身就是注释；二是减少错误发生的可能。这次开发因为时间短，我尝试采用设计-&gt;编码-&gt;编译的方式来写程序，经常把一个代码模块写完之后才开始调试。效果不错，因为对设计考虑的比较充分，基本上都是一些拼写上的错误。然而，这种追求完美的思想放到项目开发中却有可能导致项目的失败，在系统功能和及时交付之间我们必须面临痛苦的抉择，于是苦恼接踵而至：项目开始的时候，我们把系统定位在智能排课上，于是没日没夜地查资料，各种实现途径遗传算法、退火算法、专家系统甚至神经网络都找来囫囵吞枣地消化了一遍，后面才痛苦的发现那些算法根本无法实现系统那些毫无规律可循的需求，折腾了一周，头脑中最后只剩下两个字：&ldquo;放弃&rdquo;。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 其次，是来自他人的设定目标、供给资源、提供信息。<br />
<br />
&nbsp;&nbsp; &nbsp; &nbsp;&nbsp; 对于程序员而言，对其他人的依赖是一件非常痛苦的事情。在一个项目中，每个项目成员必须依靠其他成员的程序，而往往在自己看来这些代码设计得并不合理，实现拙劣且不完整，或者文档记录得很糟。所以，有些时候不得不花费时间去研究别人的代码，而它们在理想情况下本应该是可靠完整的。追求完美的心态再次让我们陷入无尽的苦恼之中，这时候你会怎么选择，重写一遍别人的代码吗？答案是 &ldquo;NO&rdquo;，我们得学会向他人妥协，整个项目才能按照既定进度不偏不倚地进行下去。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 程序员要学会放弃一部分乐趣，整个项目也一样，这是我完成这个项目后感触最深的一点。<br />
<br />
<strong>负起你的责任<br />
<br />
</strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 软件项目的完成，需要团队的齐心协力，相信这是大家都有共识的。我想说的是在我们这样一个项目团队中，每个人都是潜在的项目负责人，为什么要树立这种意识呢？原因是我们是一个学生团队，不具备严格的工作规范和约束力，我们不能确保团队中的每一个成员都负起了他应有的责任，这其中包括与他人协作、规范化编写代码和文档以及测试代码的习惯。有些成员的想法只局限于自身负责的系统模块，只顾一味发挥自己的创造性埋头写代码，结果就可能象上面提到的那样，自己认为很得意的程序在其它人的眼里却成了一堆意大利面条，理不清、看不懂。在项目中我们难免会遇上这种情况，我的做法是尽量引导成员从项目的角度来观察系统，因为只有把自己摆在项目负责人的位置，你才有可能从系统整体甚至无关于系统本身的角度去思考这个模块应该怎么编码才会与其它的模块无缝地结合，给他人提供便利。这一点非常重要，想象一下我们以后投入到实际的项目开发中去，我们还能象现在做学生项目这样率意而为吗？所以越早树立这种意识，就能越早适应以后的工作，并让自己极具竞争力。（借以自勉）<br />
<br />
<strong>不要让你的团队出现不同的声音<br />
<br />
</strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 严格来说，这是这次项目的教训而不是经验，作为一个需求不很详尽的系统，我们所能做的就是边做边摸索，尽可能地进行重复迭代来减少风险和完善系统，这时问题出现了：很多成员适应了传统瀑布式的软件开发流程，认为需求的变动会导致重复无用的工作，分歧的出现要引起高度的重视，因为一个团队中出现两种不同的声音是一种很危险的标志，我们这时要做的是通过各种方式尽量消除不同的声音，让团队保持高度一致，这样项目才能顺利地开展下去。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 另外在这次的项目开发过程中还有一个小插曲，我们组唯一一个女生在做窗体的时候总是喜欢在控件的边框加上与众不同的边框颜色，各位认为这是个小问题吗？可能有些人不以为意，外观不一致又不影响软件的功能。的确，外观确实不影响功能的实现。那么我请问，如果你作为一位软件用户，天天看着这些外观不统一，风格不协调的软件界面，你作何感想。总之，尽量让你的团队保持一种声音，一致的发力方向，这是确保项目按期完工的保证。<br />
&nbsp;<br />
<strong>保留激情<br />
<br />
</strong>　　从上面的分析可以看到我们存在很多问题，但尽管有很多不如人意的地方，我们还是把项目开发完成了。因为我们有一个法宝&mdash;&mdash;激情，激情可以战胜任何困难。<br />
&nbsp;<br />
&ldquo;我们来自五湖四海，各自为了心中的梦想在软件的世界里寻找自己的坐标。也许是缘分，也许是偶然，也许是心中共同的信念和梦想，让我们走到一起；共同努力，相互帮助，默默奉献着自己的力量，在技术的天地中贪婪地汲取养分，渴望成长，渴望强大。&rdquo;&ldquo;感谢上帝让我成为了为数不多的那些开开心心地做着自己喜欢的工作的人之一&rdquo;。<br />
&nbsp;<br />
回想这一个半月里的日日夜夜，是一种骄傲与自豪。有人问我这么辛苦是为了什么？我也常常问自己，为谁？为钱？都不是。因为我年轻，因为我有激情，因为我从不后悔。在网上曾看到一段话，值得回味：<br />
&nbsp;<br />
&nbsp; 无情的岁月让我们一秒秒地老去<br />
<br />
&nbsp; 慢慢地封存在发黄的照片里&hellip;&hellip;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在回首过去的时候&hellip;&hellip;<br />
<br />
&nbsp; 在那渐渐被遗忘的岁月中<br />
<br />
&nbsp; 我们应该要为自己的人生留下感动的回忆和汗水&hellip;&hellip;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 最后，要对我们全体项目组成员说声谢谢，正因为有了大家的共同努力，才会有今天这一小小的成绩，这一荣誉属于我们其中任何一个人，我爱你们！</font><br />
</font>
          <br/>
          <span style="color:red;">
            <a href="http://lee5593.javaeye.com/blog/119482#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 02 Sep 2007 13:04:20 +0800</pubDate>
        <link>http://lee5593.javaeye.com/blog/119482</link>
        <guid>http://lee5593.javaeye.com/blog/119482</guid>
      </item>
      <item>
        <title>IE7下不同用户会共享同一个session会话的问题</title>
        <author>lee5593</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lee5593.javaeye.com">lee5593</a>&nbsp;
          链接：<a href="http://lee5593.javaeye.com/blog/92409" style="color:red;">http://lee5593.javaeye.com/blog/92409</a>&nbsp;
          发表时间: 2007年06月20日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          问题描述：IE7不同选项卡选择不同的用户对同一个Web应用进行登录，服务器跟踪堆栈时发现两个用户所用的session会话都是一样的。<br /><br />初步诊断：初步判断为IE7不同选项卡属于同一个进程，由于默认开启了cookie来跟踪会话，服务器端会默认收到客户端http请求中传过来的cookie中的session id,并为这些不同的用户都分配同一个session会话。由于该Web应用中没有使用URL重写，在tomcat下禁用cookie会影响正常功能。请问各位有没有遇到过类似的问题，有什么好的解决方案吗？谢谢！
          <br/>
          <span style="color:red;">
            <a href="http://lee5593.javaeye.com/blog/92409#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 20 Jun 2007 14:21:27 +0800</pubDate>
        <link>http://lee5593.javaeye.com/blog/92409</link>
        <guid>http://lee5593.javaeye.com/blog/92409</guid>
      </item>
      <item>
        <title>Magic AOP：面向切面的业务日志框架设计,第二部分</title>
        <author>lee5593</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lee5593.javaeye.com">lee5593</a>&nbsp;
          链接：<a href="http://lee5593.javaeye.com/blog/88169" style="color:red;">http://lee5593.javaeye.com/blog/88169</a>&nbsp;
          发表时间: 2007年06月08日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p style="MARGIN-LEFT: 1cm; TEXT-INDENT: -1cm; mso-list: l0 level2 lfo1; tab-stops: list 1.0cm"><span lang="EN-US" style="mso-fareast-font-family: 'Times New Roman'"><span style="mso-list: Ignore"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">本文是<font face="Arial">Magic AOP：面向切面的业务日志框架设计的第二部分，第一部分请见<font face="Arial"><a href="http://lee5593.javaeye.com/admin/show/88163">http://lee5593.javaeye.com/admin/show/88163</a></font></font></span></span></span></p>
<h3 style="MARGIN-LEFT: 1cm; TEXT-INDENT: -1cm; mso-list: l0 level2 lfo1; tab-stops: list 1.0cm"><span lang="EN-US" style="mso-fareast-font-family: 'Times New Roman'"><span style="mso-list: Ignore">3.1.<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp; </span></span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">业务日志记录组件设计</span></h3>
<p class="MsoNormal" style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">业务日志记录组件的设计思路是通过事先定义好的业务类型和操作类型对业务方法进行两个维度的分类，利用</span><span lang="EN-US">BusinessLog</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">注解对需要记录业务日志的业务方法进行声明，然后用</span><span lang="EN-US">AOP</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">对声明了</span><span lang="EN-US">BusinessLog</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">注解的业务方法进行拦截，取到注解中的参数组装业务日志消息对象，调用业务日志输出组件进行输出。</span></p>
<p class="MsoNormal" style="MARGIN-LEFT: 21pt"><span lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="MARGIN-LEFT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">对一个业务方法进行业务方法进行声明的代码看起来象这样：</span></p>
<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">
<div class="code_title">java 代码</div>
</span>
<div class="dp-highlighter">
<div class="bar"></div>
<ol class="dp-j">
    <li class="alt"><span><span class="annotation">@BusinessLog</span><span>(info=</span><span class="string">&quot;info&nbsp;message&quot;</span><span>) &nbsp;&nbsp;</span></span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;anService(){&hellip;} &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;</span><span class="annotation">@BusinessLog</span><span>(success=</span><span class="string">&quot;success&nbsp;message&quot;</span><span>,failture=</span><span class="string">&quot;failture&nbsp;message&quot;</span><span>,state=State.VALID) &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;anotherService(){&hellip;}&nbsp;&nbsp;</span> </li>
</ol>
</div>
<p class="MsoNormal" style="MARGIN-LEFT: 21pt">&nbsp;<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">对于业务日志信息中的会话信息（如用户标识、客户端机器标识），采用了</span><span lang="EN-US">ThreadLocal</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">通过</span><span lang="EN-US">Filter</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">获取后，直接在业务日志消息对象构造方法中进行赋值，以避免客户端开发人员手动编码。</span> </p>
<p class="MsoNormal" style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">我们推荐使用上述的方式来记录业务日志，当然你也可以将</span><span lang="EN-US">BnLog</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">对象直接注入到你的业务对象中通过显式方法调用来记录业务日志，甚至可以直接拿到</span><span lang="EN-US">BnLogConfiguration</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">对象来按需生成</span><span lang="EN-US">BnLog</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">对象，一切取决于你的喜好，这里只是演示了一种</span><span lang="EN-US">Best Practice</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">。</span></p>
<p class="MsoNormal" style="MARGIN-LEFT: 21pt"><span lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="MARGIN-LEFT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">业务日志记录组件中的主要接口和类清单如下：</span></p>
<p class="MsoNormal"><strong style="mso-bidi-font-weight: normal"><span lang="EN-US" style="FONT-SIZE: 14pt">BnLog<o:p></o:p></span></strong></p>
<p class="MsoNormal"><strong style="mso-bidi-font-weight: normal"><span lang="EN-US"><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp; </span></span></strong><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">业务日志记录接口，包含了多个</span><span lang="EN-US">log</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法</span></p>
<p class="MsoNormal"><strong style="mso-bidi-font-weight: normal"><span lang="EN-US" style="FONT-SIZE: 14pt; COLOR: black; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">BnLogItem<o:p></o:p></span></strong></p>
<p class="MsoNormal" style="MARGIN: 2.8pt 0cm 5.65pt"><strong style="mso-bidi-font-weight: normal"><span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt"><span style="mso-tab-count: 1">&nbsp;&nbsp; </span></span></strong><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">业务日志对象，使用</span><span lang="EN-US">JPA</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">进行数据库表映射，数据库相应的表名需要与对象类名相同。主要属性有业务类型、事件类型、详细信息、记录时间、用户标识、客户端机器标识、是否成功标识。如果扩展该业务日志对象，用</span><span lang="EN-US">JPA</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">对扩展属性进行配置即可，表名需要与扩展对象类名相同。</span></p>
<p class="MsoNormal"><strong style="mso-bidi-font-weight: normal"><span lang="EN-US" style="FONT-SIZE: 14pt; COLOR: black; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">BnLogConfiguration<o:p></o:p></span></strong></p>
<p class="MsoNormal" align="left" style="TEXT-ALIGN: left; mso-layout-grid-align: none"><span lang="EN-US"><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">业务日志配置类</span><span lang="EN-US">,</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">主要负责初始化业务类型、事件类型和维护业务日志实例缓存池。初始化业务日志框架时，该类从外部的属性文件</span><span lang="EN-US">bnlog.properties</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">中读取定义好的参数，然后分别对业务类型、事件类型以及业务日志消息对象进行初始化，</span><span lang="EN-US">bnlog.properties</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的格式定义如下：</span></p>
<p class="MsoNormal" align="left" style="TEXT-ALIGN: left; mso-layout-grid-align: none"><span lang="EN-US"></span></p>
<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">
<div class="code_title">java 代码</div>
</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">
<div class="dp-highlighter">
<div class="bar"></div>
<ol class="dp-j">
    <li class="alt"><span><span>#----------------------定制业务类型---------------------------------- &nbsp;&nbsp;</span></span> </li>
    <li class=""><span>#在这里定制业务类型，每个业务类型标识字符串必须是唯一的，且不区分大小写，不能超过</span><span class="number">50</span><span>个字符，多个业务类型之间请用,进行分隔。 &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>#默认内置general类型 &nbsp;&nbsp;</span> </li>
    <li class=""><span>bnlog.businessTypes=general &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span>#----------------------定制事件类型-------------------------- &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>#在这里定制事件类型，每个事件类型标识字符串必须是唯一的，且不区分大小写，不能超过</span><span class="number">50</span><span>个字符，多个事件类型之间请用,进行分隔。 &nbsp;&nbsp;</span> </li>
    <li class=""><span>#默认内置general类型 &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>bnlog.eventTypes=general &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>#-----------------------定制业务日志领域对象---------------------- &nbsp;&nbsp;</span> </li>
    <li class=""><span>#在这里定制自己扩展的业务日志领域对象，扩展的业务日志领域对象必须继承基类BnLogItem，并自行实现扩展属性的annotations。 &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>#如果自行扩展业务日志领域对象，需要修改关系表结构脚本，使之与扩展的业务日志领域对象一致。 &nbsp;&nbsp;</span> </li>
    <li class=""><span>#默认为基类BnLogItem &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>bnlog.entityClass=com.relax.component.bnlog.BnLogItem&nbsp;&nbsp;</span> </li>
</ol>
</div>
<p class="MsoNormal" align="left" style="TEXT-ALIGN: left; mso-layout-grid-align: none">主要的方法如下：</p>
<p class="MsoNormal" align="left" style="TEXT-ALIGN: left; mso-layout-grid-align: none"><strong><span lang="EN-US" style="FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt">void</span></strong><strong style="mso-bidi-font-weight: normal"><span lang="EN-US" style="FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt"> init()<o:p></o:p></span></strong></p>
<p class="MsoNormal" align="left" style="TEXT-ALIGN: left; mso-layout-grid-align: none"><strong style="mso-bidi-font-weight: normal"><span lang="EN-US" style="FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt"><span style="mso-tab-count: 1">&nbsp;&nbsp; </span></span></strong><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 'Courier New'">初始化方法</span><span lang="EN-US" style="FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt"><o:p></o:p></span></p>
<p class="MsoNormal" align="left" style="TEXT-ALIGN: left; mso-layout-grid-align: none"><strong><span lang="EN-US" style="FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt"><o:p></o:p></span></strong></p>
<p class="MsoNormal" align="left" style="TEXT-ALIGN: left; mso-layout-grid-align: none"><strong><span lang="EN-US" style="FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt">void</span></strong><strong style="mso-bidi-font-weight: normal"><span lang="EN-US" style="FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt"> destory()<o:p></o:p></span></strong></p>
<p class="MsoNormal" align="left" style="TEXT-ALIGN: left; mso-layout-grid-align: none"><strong style="mso-bidi-font-weight: normal"><span lang="EN-US" style="FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt"><span style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp; </span></span></strong><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 'Courier New'">销毁方法</span><strong style="mso-bidi-font-weight: normal"><span lang="EN-US" style="FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt"><o:p></o:p></span></strong></p>
<p class="MsoNormal" align="left" style="TEXT-ALIGN: left; mso-layout-grid-align: none"><strong><span lang="EN-US" style="FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt"><o:p></o:p></span></strong></p>
<p class="MsoNormal" align="left" style="TEXT-ALIGN: left; mso-layout-grid-align: none"><strong><span lang="EN-US" style="FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt">void</span></strong><strong style="mso-bidi-font-weight: normal"><span lang="EN-US" style="FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt"> setBusinessTypes(String businessTypes)<o:p></o:p></span></strong></p>
<p class="MsoNormal" align="left" style="TEXT-ALIGN: left; mso-layout-grid-align: none"><strong style="mso-bidi-font-weight: normal"><span lang="EN-US" style="FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt"><span style="mso-tab-count: 1">&nbsp;&nbsp; </span></span></strong><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 'Courier New'">设置业务类型</span><strong style="mso-bidi-font-weight: normal"><span lang="EN-US" style="FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt"><span style="mso-tab-count: 1">&nbsp; </span><o:p></o:p></span></strong></p>
<p class="MsoNormal" align="left" style="TEXT-ALIGN: left; mso-layout-grid-align: none"><strong style="mso-bidi-font-weight: normal"><span lang="EN-US" style="FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt"><o:p></o:p></span></strong></p>
<p class="MsoNormal" align="left" style="TEXT-ALIGN: left; mso-layout-grid-align: none"><strong><span lang="EN-US" style="FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt">void</span></strong><strong style="mso-bidi-font-weight: normal"><span lang="EN-US" style="FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt"> setEventTypes(String eventTypes)<o:p></o:p></span></strong></p>
<p class="MsoNormal" align="left" style="TEXT-ALIGN: left; mso-layout-grid-align: none"><strong style="mso-bidi-font-weight: normal"><span lang="EN-US" style="FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt"><span style="mso-tab-count: 1">&nbsp;&nbsp; </span></span></strong><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 'Courier New'">设置事件类型</span><strong style="mso-bidi-font-weight: normal"><span lang="EN-US" style="FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt"><o:p></o:p></span></strong></p>
<p class="MsoNormal" align="left" style="TEXT-ALIGN: left; mso-layout-grid-align: none"><strong style="mso-bidi-font-weight: normal"><span lang="EN-US" style="FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt"><o:p></o:p></span></strong></p>
<p class="MsoNormal" align="left" style="TEXT-ALIGN: left; mso-layout-grid-align: none"><strong style="mso-bidi-font-weight: normal"><span lang="EN-US" style="FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt">BnLog getBnLog(String name)<o:p></o:p></span></strong></p>
<p class="MsoNormal" align="left" style="TEXT-ALIGN: left; mso-layout-grid-align: none"><strong style="mso-bidi-font-weight: normal"><span lang="EN-US" style="FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt"><span style="mso-tab-count: 1">&nbsp;&nbsp; </span></span></strong><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 'Courier New'">获取</span><span lang="EN-US" style="FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt">BnLog</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 'Courier New'">实例，所有的</span><span lang="EN-US" style="FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt">BnLog</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 'Courier New'">实例都从这里获取</span><strong style="mso-bidi-font-weight: normal"><span lang="EN-US" style="FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt"><o:p></o:p></span></strong></p>
<p class="MsoNormal" align="left" style="TEXT-ALIGN: left; mso-layout-grid-align: none"><strong style="mso-bidi-font-weight: normal"><span lang="EN-US" style="FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt"><o:p></o:p></span></strong></p>
<p class="MsoNormal" align="left" style="TEXT-ALIGN: left; mso-layout-grid-align: none"><strong><span lang="EN-US" style="FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt">static</span></strong><strong style="mso-bidi-font-weight: normal"><span lang="EN-US" style="FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt"> <span style="mso-bidi-font-weight: bold">boolean</span> validateBusinessType(String businessType)<o:p></o:p></span></strong></p>
<p class="MsoNormal" align="left" style="TEXT-INDENT: 21pt; TEXT-ALIGN: left; mso-layout-grid-align: none"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 'Courier New'">验证业务类型</span><strong style="mso-bidi-font-weight: normal"><span lang="EN-US" style="FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt"><o:p></o:p></span></strong></p>
<p class="MsoNormal" align="left" style="TEXT-ALIGN: left; mso-layout-grid-align: none"><strong><span lang="EN-US" style="FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt"><o:p></o:p></span></strong></p>
<p class="MsoNormal" align="left" style="TEXT-ALIGN: left; mso-layout-grid-align: none"><strong><span lang="EN-US" style="FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt">static</span></strong><strong style="mso-bidi-font-weight: normal"><span lang="EN-US" style="FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt"> <span style="mso-bidi-font-weight: bold">boolean</span> validateEventType(String eventType)<o:p></o:p></span></strong></p>
<p class="MsoNormal" align="left" style="TEXT-INDENT: 21pt; TEXT-ALIGN: left; mso-layout-grid-align: none"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 'Courier New'">验证事件类型</span><span lang="EN-US" style="FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal"><strong style="mso-bidi-font-weight: normal"><span lang="EN-US" style="FONT-SIZE: 14pt; COLOR: black; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">BusinessLog<o:p></o:p></span></strong></p>
<p class="MsoNormal" align="left" style="TEXT-ALIGN: left; mso-layout-grid-align: none"><span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt"><span style="mso-tab-count: 1">&nbsp;&nbsp; </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 'Courier New'">业务日志注解</span><span lang="EN-US" style="FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt">,</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 'Courier New'">用于提供方法级别的声明</span><span lang="EN-US" style="FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt">,</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 'Courier New'">配合</span><span lang="EN-US" style="FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt">AOP</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 'Courier New'">进行切面业务日志记录。</span><span lang="EN-US" style="FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt"><o:p></o:p></span></p>
<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt"><o:p>
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<div class="bar"></div>
<ol class="dp-j">
    <li class="alt"><span><span class="annotation">@Retention</span><span>(RetentionPolicy.RUNTIME) &nbsp;&nbsp;</span></span> </li>
    <li class=""><span></span><span class="annotation">@Target</span><span>(ElementType.METHOD) &nbsp;&nbsp;</span> </li>
    <li class="alt"><span></span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">@interface</span><span>&nbsp;BusinessLog&nbsp;{ &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">/** </span>&nbsp; </li>
    <li class="alt"><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;业务类型,默认为内置general类型 </span>&nbsp;</span> </li>
    <li class=""><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;general业务类型 </span>&nbsp;</span> </li>
    <li class="alt"><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span><span>&nbsp;&nbsp;</span></span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;businessType()&nbsp;</span><span class="keyword">default</span><span>&nbsp;BusinessType.GENERAL; &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">/** </span>&nbsp; </li>
    <li class=""><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;事件类型,默认为内置general类型 </span>&nbsp;</span> </li>
    <li class="alt"><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;general事件类型 </span>&nbsp;</span> </li>
    <li class=""><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span><span>&nbsp;&nbsp;</span></span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;eventType()&nbsp;</span><span class="keyword">default</span><span>&nbsp;EventType.GENERAL; &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">/** </span>&nbsp; </li>
    <li class="alt"><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;当state状态为无效时的日志信息 </span>&nbsp;</span> </li>
    <li class=""><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;日志信息 </span>&nbsp;</span> </li>
    <li class="alt"><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span><span>&nbsp;&nbsp;</span></span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;info()&nbsp;</span><span class="keyword">default</span><span>&nbsp;</span><span class="string">&quot;&quot;</span><span>; &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">/** </span>&nbsp; </li>
    <li class=""><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;当业务操作成功时的日志信息 </span>&nbsp;</span> </li>
    <li class="alt"><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;记录成功业务操作的日志信息 </span>&nbsp;</span> </li>
    <li class=""><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span><span>&nbsp;&nbsp;</span></span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;success()&nbsp;</span><span class="keyword">default</span><span>&nbsp;</span><span class="string">&quot;&quot;</span><span>; &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">/** </span>&nbsp; </li>
    <li class="alt"><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;当业务操作失败时的日志信息 </span>&nbsp;</span> </li>
    <li class=""><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;记录失败业务操作的日志信息 </span>&nbsp;</span> </li>
    <li class="alt"><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span><span>&nbsp;&nbsp;</span></span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;failture()&nbsp;</span><span class="keyword">default</span><span>&nbsp;</span><span class="string">&quot;&quot;</span><span>; &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">/** </span>&nbsp; </li>
    <li class=""><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;业务操作状态,有两种选项INVALID,VALID.<br />
    </span>&nbsp;</span> </li>
    <li class="alt"><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;默认为INVALID </span>&nbsp;</span> </li>
    <li class=""><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;业务操作状态 </span>&nbsp;</span> </li>
    <li class="alt"><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span><span>&nbsp;&nbsp;</span></span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;State&nbsp;state()&nbsp;</span><span class="keyword">default</span><span>&nbsp;State.INVALID; &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>}&nbsp;&nbsp;</span> </li>
</ol>
</div>
<p class="MsoNormal">&nbsp;</p>
<p class="MsoNormal"><strong style="mso-bidi-font-weight: normal"><span lang="EN-US" style="FONT-SIZE: 14pt; COLOR: black; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">State<o:p></o:p></span></strong></p>
<p class="MsoNormal" align="left" style="TEXT-ALIGN: left; mso-layout-grid-align: none"><span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt"><span style="mso-tab-count: 1">&nbsp;&nbsp; </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 'Courier New'">业务操作状态枚举</span><span lang="EN-US" style="FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt">,</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 'Courier New'">配合</span><span lang="EN-US" style="FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt">BusinessLog</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 'Courier New'">注解协同工作。</span></p>
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<div class="bar"></div>
<ol class="dp-j">
    <li class="alt"><span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">enum</span><span>&nbsp;State&nbsp;{ &nbsp;&nbsp;</span></span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">/** </span>&nbsp; </li>
    <li class="alt"><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;无效 </span>&nbsp;</span> </li>
    <li class=""><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span><span>&nbsp;&nbsp;</span></span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;INVALID, &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">/** </span>&nbsp; </li>
    <li class="alt"><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;有效 </span>&nbsp;</span> </li>
    <li class=""><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span><span>&nbsp;&nbsp;</span></span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;VALID &nbsp;&nbsp;</span> </li>
    <li class=""><span>}&nbsp;&nbsp;</span> </li>
</ol>
</div>
<p class="MsoNormal" align="left" style="TEXT-ALIGN: left; mso-layout-grid-align: none">&nbsp; </p>
<p class="MsoNormal"><strong style="mso-bidi-font-weight: normal"><span lang="EN-US" style="FONT-SIZE: 14pt; COLOR: black; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">BnLogAspect<o:p></o:p></span></strong></p>
<p class="MsoNormal" align="left" style="TEXT-ALIGN: left; mso-layout-grid-align: none"><span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt"><span style="mso-tab-count: 1">&nbsp;&nbsp; </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 'Courier New'">业务日志通用切面</span><span lang="EN-US" style="FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt">,</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 'Courier New'">采用</span><span lang="EN-US" style="FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt">@AspectJ</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 'Courier New'">风格</span><span lang="EN-US" style="FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt">,Spring</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 'Courier New'">配置文件中需引入下列元素来启用对</span><span lang="EN-US" style="FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt">@AspectJ</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 'Courier New'">的支持。</span><span lang="EN-US" style="FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt"><o:p></o:p></span><span lang="EN-US" style="mso-fareast-font-family: 'Times New Roman'"><span style="mso-list: Ignore"> </span></span></p>
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<div class="bar"></div>
<ol class="dp-j">
    <li class="alt"><span><span class="annotation">@Aspect</span><span>&nbsp;&nbsp;</span></span> </li>
    <li class=""><span></span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;BnLogAspect&nbsp;{ &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">private</span><span>&nbsp;</span><span class="keyword">final</span><span>&nbsp;Logger&nbsp;logger&nbsp;=&nbsp;Logger.getInstance(BnLogAspect.</span><span class="keyword">class</span><span>); &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">private</span><span>&nbsp;BnLog&nbsp;bnLog; &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">/** </span>&nbsp; </li>
    <li class=""><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;业务日志切入点:所有声明@BusinessLog的方法 </span>&nbsp;</span> </li>
    <li class="alt"><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp; </span>&nbsp;</span> </li>
    <li class=""><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span><span>&nbsp;&nbsp;</span></span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="annotation">@Pointcut</span><span>(</span><span class="string">&quot;@annotation(com.relax.component.bnlog.annotation.BusinessLog)&quot;</span><span>) &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">private</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;bnLogAnnotation()&nbsp;{ &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">/** </span>&nbsp; </li>
    <li class=""><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;业务操作正常返回后的业务日志切面 </span>&nbsp;</span> </li>
    <li class="alt"><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp; </span>&nbsp;</span> </li>
    <li class=""><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;businessLog&nbsp;业务日志声明对象 </span>&nbsp;</span> </li>
    <li class="alt"><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span><span>&nbsp;&nbsp;</span></span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="annotation">@AfterReturning</span><span>(</span><span class="string">&quot;bnLogAnnotation()&nbsp;&amp;&amp;&nbsp;@annotation(businessLog)&quot;</span><span>) &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;afterReturning(BusinessLog&nbsp;businessLog)&nbsp;{ &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;FIXME&nbsp;正式系统应该将记录业务日志操作可能抛出的异常捕获进行处理,以避免业务日志出错对正常的业务逻辑造成干扰 </span><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;this.log(businessLog,&nbsp;true); </span><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">try</span><span>&nbsp;{ &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">this</span><span>.log(businessLog,&nbsp;</span><span class="keyword">true</span><span>); &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span class="keyword">catch</span><span>&nbsp;(BnLogException&nbsp;e)&nbsp;{ &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.error(</span><span class="string">&quot;业务日志切面抛出异常&quot;</span><span>,&nbsp;e); &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">/** </span>&nbsp; </li>
    <li class="alt"><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;业务操作抛出异常后的业务日志切面 </span>&nbsp;</span> </li>
    <li class=""><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp; </span>&nbsp;</span> </li>
    <li class="alt"><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;businessLog&nbsp;业务日志声明对象 </span>&nbsp;</span> </li>
    <li class=""><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;e&nbsp;业务方法抛出的异常 </span>&nbsp;</span> </li>
    <li class="alt"><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@throws&nbsp;Exception&nbsp;将业务方法抛出的异常重新进行抛出 </span>&nbsp;</span> </li>
    <li class=""><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span><span>&nbsp;&nbsp;</span></span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="annotation">@AfterThrowing</span><span>(pointcut&nbsp;=&nbsp;</span><span class="string">&quot;bnLogAnnotation()&nbsp;&amp;&amp;&nbsp;@annotation(businessLog)&quot;</span><span>,&nbsp;throwing&nbsp;=&nbsp;</span><span class="string">&quot;e&quot;</span><span>) &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;afterThrowing(BusinessLog&nbsp;businessLog,&nbsp;Exception&nbsp;e) &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">throws</span><span>&nbsp;Exception&nbsp;{ &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;FIXME&nbsp;正式系统应该将记录业务日志操作可能抛出的异常捕获进行处理,以避免业务日志出错对正常的业务逻辑造成干扰 </span><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;this.log(businessLog,&nbsp;false); </span><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">try</span><span>&nbsp;{ &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">this</span><span>.log(businessLog,&nbsp;</span><span class="keyword">false</span><span>); &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span class="keyword">catch</span><span>&nbsp;(BnLogException&nbsp;ex)&nbsp;{ &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.error(</span><span class="string">&quot;业务日志切面抛出异常&quot;</span><span>,&nbsp;ex); &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">/*将异常重新抛出*/</span><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">throw</span><span>&nbsp;e; &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">/** </span>&nbsp; </li>
    <li class="alt"><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;记录业务日志 </span>&nbsp;</span> </li>
    <li class=""><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp; </span>&nbsp;</span> </li>
    <li class="alt"><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;businessLog&nbsp;业务日志声明对象 </span>&nbsp;</span> </li>
    <li class=""><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;state&nbsp;操作状态,<code>true</code>&nbsp;or&nbsp;<code>false</code> </span>&nbsp;</span> </li>
    <li class="alt"><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@throws&nbsp;BnLogException&nbsp;当业务日志记录失败时抛出业务日志异常 </span>&nbsp;</span> </li>
    <li class=""><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span><span>&nbsp;&nbsp;</span></span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">private</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;log(BusinessLog&nbsp;businessLog,&nbsp;</span><span class="keyword">boolean</span><span>&nbsp;state) &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">throws</span><span>&nbsp;BnLogException&nbsp;{ &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BnLogItem&nbsp;bnLogItem; &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bnLogItem&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;BnLogItem(); &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span>&nbsp;(!BnLogConfiguration &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.validateBusinessType(businessLog.businessType()))&nbsp;{ &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">throw</span><span>&nbsp;</span><span class="keyword">new</span><span>&nbsp;BnLogPreparationException(</span><span class="string">&quot;无效的业务类型:&quot;</span><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+&nbsp;businessLog.businessType()); &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bnLogItem.setBusinessType(businessLog.businessType()); &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span>&nbsp;(!BnLogConfiguration.validateEventType(businessLog.eventType()))&nbsp;{ &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">throw</span><span>&nbsp;</span><span class="keyword">new</span><span>&nbsp;BnLogPreparationException(</span><span class="string">&quot;无效的事件类型:&quot;</span><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+&nbsp;businessLog.eventType()); &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bnLogItem.setEventType(businessLog.eventType()); &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span>&nbsp;(State.INVALID&nbsp;==&nbsp;businessLog.state())&nbsp;{ &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span>&nbsp;(businessLog.info().equals(</span><span class="string">&quot;&quot;</span><span>))&nbsp;{ &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">throw</span><span>&nbsp;</span><span class="keyword">new</span><span>&nbsp;BnLogPreparationException( &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="string">&quot;当state设置为INVALID时,info内容不能为空&quot;</span><span>); &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bnLogItem.setMessage(businessLog.info()); &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span class="keyword">else</span><span>&nbsp;{ &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span>&nbsp;(businessLog.success().equals(</span><span class="string">&quot;&quot;</span><span>) &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;||&nbsp;businessLog.failture().equals(</span><span class="string">&quot;&quot;</span><span>))&nbsp;{ &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">throw</span><span>&nbsp;</span><span class="keyword">new</span><span>&nbsp;BnLogPreparationException( &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="string">&quot;当state设置为VALID时,success和failture内容不能为空&quot;</span><span>); &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span>&nbsp;(state)&nbsp;{ &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bnLogItem.setMessage(businessLog.success()); &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span class="keyword">else</span><span>&nbsp;{ &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bnLogItem.setMessage(businessLog.failture()); &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bnLogItem.setState(state); &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bnLog.log(bnLogItem); &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">/** </span>&nbsp; </li>
    <li class=""><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;设置业务日志记录对象 </span>&nbsp;</span> </li>
    <li class="alt"><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;bnLog </span>&nbsp;</span> </li>
    <li class=""><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;业务日志记录对象 </span>&nbsp;</span> </li>
    <li class="alt"><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span><span>&nbsp;&nbsp;</span></span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;setBnLog(BnLog&nbsp;bnLog)&nbsp;{ &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">this</span><span>.bnLog&nbsp;=&nbsp;bnLog; &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span>}&nbsp;&nbsp;</span> </li>
</ol>
</div>
<h3 style="MARGIN-LEFT: 1cm; TEXT-INDENT: -1cm; mso-list: l0 level2 lfo1; tab-stops: list 1.0cm">3.2.<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp; </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">业务日志输出组件</span></h3>
<p class="MsoNormal" style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">相对于业务日志记录组件，业务日志输出组件要简单得多，我们采用了</span><span lang="EN-US">ActiveMq</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">来对业务日志消息对象进行异步处理，以便隔离业务日志输出异常给业务操作带来的影响。你也可以不用异步处理机制，只需要实现</span><span lang="EN-US">Appender</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">接口，重新编写一种实现来替换默认的输出机制。</span><span lang="EN-US">Appender</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">接口非常简洁，其中只定义了一个</span><span lang="EN-US">doAppend()</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法。</span></p>
<p class="MsoNormal" style="MARGIN-LEFT: 21pt"><span lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">业务日志记录组件中的主要接口和类清单如下：</span></p>
<p class="MsoNormal"><strong style="mso-bidi-font-weight: normal"><span lang="EN-US" style="FONT-SIZE: 14pt">Appender<o:p></o:p></span></strong></p>
<p class="MsoNormal"><span lang="EN-US"><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">业务日志输出接口，定义了一个</span><span lang="EN-US">doAppend(BnLogItem bnLogItem)</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法，实现类需实现该方法对业务日志消息对象进行输出</span></p>
<p class="MsoNormal"><strong style="mso-bidi-font-weight: normal"><span lang="EN-US" style="FONT-SIZE: 14pt">DefaultAppenderImpl<o:p></o:p></span></strong></p>
<p class="MsoNormal"><span lang="EN-US"><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">默认的业务日志输出类，实现了</span><span lang="EN-US">Appender</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">接口，将业务日志持久化到数据库</span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal"><strong style="mso-bidi-font-weight: normal"><span lang="EN-US" style="FONT-SIZE: 14pt">BnLogMessageProducer<o:p></o:p></span></strong></p>
<p class="MsoNormal"><span lang="EN-US"><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">业务日志</span><span lang="EN-US">JMS</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">消息生产者，实现了</span><span lang="EN-US">Appender</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">接口</span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal"><strong style="mso-bidi-font-weight: normal"><span lang="EN-US" style="FONT-SIZE: 14pt">BnLogMessageConverter<o:p></o:p></span></strong></p>
<p class="MsoNormal"><span lang="EN-US"><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">业务日志消息转换类</span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal"><strong style="mso-bidi-font-weight: normal"><span lang="EN-US" style="FONT-SIZE: 14pt">BnLogMessageConsumer<o:p></o:p></span></strong></p>
<p class="MsoNormal"><span lang="EN-US"><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">业务日志消息消费者，接受注入的</span><span lang="EN-US">Appender</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">对象对业务日志消息进行真正地输出</span></p>
<h3 style="MARGIN-LEFT: 1cm; TEXT-INDENT: -1cm; mso-list: l0 level2 lfo1; tab-stops: list 1.0cm"><span lang="EN-US" style="mso-fareast-font-family: 'Times New Roman'"><span style="mso-list: Ignore">3.3.<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp; </span></span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">业务日志查询组件</span></h3>
<p class="MsoNormal" style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">业务日志查询组件定义了一个</span><span lang="EN-US">BnLogQuery</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">接口，包含了多个查询方法，接口定义如下：</span></p>
<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<div class="bar"></div>
<ol class="dp-j">
    <li class="alt"><span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">interface</span><span>&nbsp;BnLogQuery&nbsp;{ &nbsp;&nbsp;</span></span> </li>
    <li class=""><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;List<bnlogitem></bnlogitem>&nbsp;listAll(); &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;List<bnlogitem></bnlogitem>&nbsp;list(String&nbsp;businessType,&nbsp;String&nbsp;eventType); &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;List<bnlogitem></bnlogitem>&nbsp;list(String&nbsp;businessType,&nbsp;String&nbsp;eventType, &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Boolean&nbsp;state); &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;List<bnlogitem></bnlogitem>&nbsp;list(String&nbsp;businessType,&nbsp;String&nbsp;eventType, &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Boolean&nbsp;state,&nbsp;Date&nbsp;beginTime,&nbsp;Date&nbsp;endTime); &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;List<bnlogitem></bnlogitem>&nbsp;list(String&nbsp;hql,&nbsp;Object...&nbsp;values); &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;List<bnlogitem></bnlogitem>&nbsp;pageList(String&nbsp;hql,&nbsp;</span><span class="keyword">int</span><span>&nbsp;pageNo,&nbsp;</span><span class="keyword">int</span><span>&nbsp;pageSize, &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Object...&nbsp;values); &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span>}&nbsp;&nbsp;</span> </li>
</ol>
</div>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 该查询组件相对来说没有什么难度，本文不再予以详细描述。</p>
<h3 style="MARGIN-LEFT: 1cm; TEXT-INDENT: -1cm; mso-list: l0 level2 lfo1; tab-stops: list 1.0cm"><span lang="EN-US" style="mso-fareast-font-family: 'Times New Roman'"><span style="mso-list: Ignore">4.<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp; </span></span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">总结</span></h3>
<p><span style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">&nbsp;&nbsp;&nbsp;&nbsp;本文</span><span style="FONT-SIZE: 10.5pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-font-kerning: 1.0pt; mso-bidi-font-family: Arial; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">通过我们在实际企业级项目中应用</span><span lang="EN-US" style="FONT-SIZE: 10.5pt; COLOR: black; FONT-FAMILY: Arial; mso-fareast-font-family: 宋体; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">AOP</span><span style="FONT-SIZE: 10.5pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-font-kerning: 1.0pt; mso-bidi-font-family: Arial; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">的实际经验，总结了通过</span><span lang="EN-US" style="FONT-SIZE: 10.5pt; COLOR: black; FONT-FAMILY: Arial; mso-fareast-font-family: 宋体; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">AOP</span><span style="FONT-SIZE: 10.5pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-font-kerning: 1.0pt; mso-bidi-font-family: Arial; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">来进行业务日志框架设计的一些经验供大家参考，并希望借此起到抛砖引玉的效果，寻求更加优秀的</span><span lang="EN-US" style="FONT-SIZE: 10.5pt; COLOR: black; FONT-FAMILY: Arial; mso-fareast-font-family: 宋体; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">AOP</span><span style="FONT-SIZE: 10.5pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-font-kerning: 1.0pt; mso-bidi-font-family: Arial; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">设计方案，使面向方面软件设计</span><span lang="EN-US" style="FONT-SIZE: 10.5pt; COLOR: black; FONT-FAMILY: Arial; mso-fareast-font-family: 宋体; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">(AOSD)</span><span style="FONT-SIZE: 10.5pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-font-kerning: 1.0pt; mso-bidi-font-family: Arial; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">深入人心，来改善目前面向对象设计在某些特定问题领域的不足之处，让我们试目以待。</span></p>
</span></o:p></span></span>
          <br/>
          <span style="color:red;">
            <a href="http://lee5593.javaeye.com/blog/88169#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 08 Jun 2007 16:06:00 +0800</pubDate>
        <link>http://lee5593.javaeye.com/blog/88169</link>
        <guid>http://lee5593.javaeye.com/blog/88169</guid>
      </item>
      <item>
        <title>Magic AOP：面向切面的业务日志框架设计，第一部分</title>
        <author>lee5593</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lee5593.javaeye.com">lee5593</a>&nbsp;
          链接：<a href="http://lee5593.javaeye.com/blog/88163" style="color:red;">http://lee5593.javaeye.com/blog/88163</a>&nbsp;
          发表时间: 2007年06月08日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <em style="mso-bidi-font-style: normal"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">本文的设计方案来源于一个真实的软件开发项目，并经过了该项目的初步验证，现记录下来供大家讨论，并试图引发关于面向方面软件设计（</span><span lang="EN-US">AOSD</span></em><em style="mso-bidi-font-style: normal"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">）的一些更深层次的思考，以期集思广益并获得更加完美的解决方案。</span><span lang="EN-US"><o:p></o:p></span></em>
<h3 style="MARGIN-LEFT: 21.25pt; TEXT-INDENT: -21.25pt; mso-list: l2 level1 lfo1; tab-stops: list 21.25pt"><span lang="EN-US" style="mso-fareast-font-family: 'Times New Roman'"><span style="mso-list: Ignore">1.<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">简介</span></h3>
<p class="MsoNormal" style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">业务日志在企业级的软件系统中是不可或缺的功能，它的关注点与我们日常熟悉的系统日志有着一些本质的区别：</span></p>
<p class="MsoNormal" style="TEXT-INDENT: 21pt"><span lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: 6pt; mso-list: l1 level1 lfo2; tab-stops: list 21.0pt"><span lang="EN-US" style="mso-fareast-font-family: 'Times New Roman'"><span style="mso-list: Ignore">1.<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">系统日志主要关注应用程序自身的运行状态，通常用于应用程序的调测跟踪和崩溃恢复，其分类也按照这种理念</span><span lang="EN-US">(TRACE</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">、</span><span lang="EN-US">DEBUG</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">、</span><span lang="EN-US">INFO</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">、</span><span lang="EN-US">WARN</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">、</span><span lang="EN-US">ERROR</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">、</span><span lang="EN-US">FATAL)</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">来划分，而业务日志主要关注业务本身的执行状态，通常用于业务的执行状态记录、分类检索、崩溃恢复以及业务安全；</span></p>
<p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: 6pt; mso-list: l1 level1 lfo2; tab-stops: list 21.0pt"><span lang="EN-US" style="mso-fareast-font-family: 'Times New Roman'"><span style="mso-list: Ignore">2.<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">系统日志一般没有分类查询的需求，其记录介质可以是任何一种可存储的媒介，如文件、数据库、电子邮件等，目前常用的一些日志组件也没有内建对日志进行查询的功能支持；</span></p>
<p class="MsoNormal" style="MARGIN-LEFT: 21pt"><span lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">一般的介绍</span><span lang="EN-US">AOP</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的技术文章都喜欢把系统日志记录作为</span><span lang="EN-US">AOP</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的一个经典示例，但这只是一个美好的愿望，以</span><span lang="EN-US">&quot;</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">系统日志</span><span lang="EN-US">&quot;</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">作为一个方面来切入粒度似乎太大了，系统日志的细粒度和无规律性决定了其切入点难以描述，关注点难以定位，唯一的方式是将&ldquo;系统日志&rdquo;关注点进一步拆解，一直拆解到可以接受的程度，如果我们的项目足够小，这种做法或许可行。但很不幸，我们的项目很大，要经过相当多的分解才能最终找到日志的规律性。我们还是可能需要成百上千条语句来指定切入点的位置，最终的结果将很难维护，这样的做法对于一个企业级的系统而言是脆弱乃至于不可接受的。况且，像</span><span lang="EN-US">Debug</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">这样的</span><span lang="EN-US">Log</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">级别，无论你怎样拆解，都不可能找到完美的规律。通常，任何一个系统中的</span><span lang="EN-US">Log</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">都会保持逻辑的一致性，如果经过了这样的层层分解，</span><span lang="EN-US">Log</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">作为一个逻辑主体的完整性被完全破坏了。这是一种为了</span><span lang="EN-US">AOP</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">而</span><span lang="EN-US">AOP</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的做法，非但工作量没有减轻，还带来了无穷的后患。</span></p>
<p class="MsoNormal" style="TEXT-INDENT: 21pt"><span lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">现在我们再来关注业务日志，我们在上面比较系统日志和业务日志的区别时提到过业务日志的关注点和系统日志有本质区别，业务日志关注于业务，而业务在面向对象的编程体系中往往表现为一个粗粒度的业务方法，正因为业务日志和系统日志的关注点的粒度不同，从而使</span><span lang="EN-US">AOP</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">设计成为一种可能。</span> </p>
<h3 style="MARGIN-LEFT: 21.25pt; TEXT-INDENT: -21.25pt; mso-list: l2 level1 lfo1; tab-stops: list 21.25pt"><span lang="EN-US" style="mso-fareast-font-family: 'Times New Roman'"><span style="mso-list: Ignore">2.<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">业务日志框架的基本特性</span></h3>
<p class="MsoNormal" style="MARGIN-LEFT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">一个完备的业务日志框架应该具备如下基本特性：</span></p>
<p class="MsoNormal" style="MARGIN-LEFT: 21pt"><span lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: 6pt; mso-list: l0 level1 lfo3; tab-stops: list 21.0pt"><span lang="EN-US" style="mso-fareast-font-family: 'Times New Roman'"><span style="mso-list: Ignore">1.<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">业务日志记录、输出和查询</span><span lang="EN-US">(</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">这是最基本的功能需求</span><span lang="EN-US">);</span></p>
<p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: 6pt; mso-list: l0 level1 lfo3; tab-stops: list 21.0pt"><span lang="EN-US" style="mso-fareast-font-family: 'Times New Roman'"><span style="mso-list: Ignore">2.<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">所输出的业务日志应该从业务和操作两个维度进行分类，以支持更加灵活的日志分类检索；</span></p>
<p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: 6pt; mso-list: l0 level1 lfo3; tab-stops: list 21.0pt"><span lang="EN-US" style="mso-fareast-font-family: 'Times New Roman'"><span style="mso-list: Ignore">3.<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">支持多线程：业务日志组件会在多线程环境中使用，需要确保线程安全性</span><span lang="EN-US">;</span></p>
<p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: 6pt; mso-list: l0 level1 lfo3; tab-stops: list 21.0pt"><span lang="EN-US" style="mso-fareast-font-family: 'Times New Roman'"><span style="mso-list: Ignore">4.<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">稳定性：业务日志组件必须保持高度的稳定性，不能因为组件内部错误导致业务代码的崩溃；</span></p>
<p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: 6pt; mso-list: l0 level1 lfo3; tab-stops: list 21.0pt"><span lang="EN-US" style="mso-fareast-font-family: 'Times New Roman'"><span style="mso-list: Ignore">5.<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">高性能：业务日志组件需要提供高速的日志记录功能以应对大请求流量下业务系统的正常运转；</span></p>
<p class="MsoNormal" style="MARGIN-LEFT: 21pt"><span lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="MARGIN-LEFT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">以上的基本特性给框架的设计上也带来了一些约束和挑战：</span></p>
<p class="MsoNormal" style="MARGIN-LEFT: 21pt"><span lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: 6pt; mso-list: l4 level1 lfo4; tab-stops: list 21.0pt"><span lang="EN-US" style="mso-fareast-font-family: 'Times New Roman'"><span style="mso-list: Ignore">1.<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方便检索的业务需求限制了日志输出介质必须为数据库或是某种支持快速检索的存储媒介；</span></p>
<p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: 6pt; mso-list: l4 level1 lfo4; tab-stops: list 21.0pt"><span lang="EN-US" style="mso-fareast-font-family: 'Times New Roman'"><span style="mso-list: Ignore">2.<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">为了满足稳定性和高性能的需求，可以采用异步消息来处理日志信息的输出，同时也会带来一系列的设计上的挑战；</span></p>
<p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: 6pt; mso-list: l4 level1 lfo4; tab-stops: list 21.0pt"><span lang="EN-US" style="mso-fareast-font-family: 'Times New Roman'"><span style="mso-list: Ignore">3.<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span lang="EN-US">AOP</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">要求框架的设计必须严格遵循</span><span lang="EN-US">OO</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的设计原则，以便于清晰地识别关注点和切入点；</span></p>
<p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: 6pt; mso-list: l4 level1 lfo4; tab-stops: list 21.0pt"><span lang="EN-US" style="mso-fareast-font-family: 'Times New Roman'"><span style="mso-list: Ignore">4.<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">业务日志信息的复杂性增加了客户端调用代码的复杂程度，设计应尽可能封装复杂度，提供简单的外部接口，另外业务日志的记录被抽象到通用的日志记录切面，对于业务日志信息中的会话信息（如用户标识、客户端机器标识），需要用一种优雅的设计方法来避免客户端开发人员的手动编码获取；</span></p>
<h3 style="MARGIN-LEFT: 21.25pt; TEXT-INDENT: -21.25pt; mso-list: l2 level1 lfo1; tab-stops: list 21.25pt"><span lang="EN-US" style="mso-fareast-font-family: 'Times New Roman'"><span style="mso-list: Ignore">3.<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">框架设计</span></h3>
<p class="MsoNormal" style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">业务日志框架可以分为业务日志记录组件、业务日志输出组件和业务日志查询组件三大块，业务日志记录组件负责管理业务日志记录器</span><span lang="EN-US">(Bnlog)</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">和业务日志框架的初始化配置，</span> <span lang="EN-US">Bnlog</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">对象负责按照不同的业务类型</span><span lang="EN-US">(BusinessType)</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">和操作类型</span><span lang="EN-US">(EventType)</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">接收各种记录了业务日志信息的业务日志对象（</span><span lang="EN-US">BnlogItem</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">），</span><span lang="EN-US">Bnlog</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">对象获取需要记录的业务日志，然后将日志对象委托给业务日志输出组件进行处理；业务日志输出组件则负责管理业务日志输出器</span><span lang="EN-US">(Appender)</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，并使用</span><span lang="EN-US">JMS</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">对业务日志进行异步处理，将其输出到支持快速查询的存储介质；业务日志查询组件相对简单地负责从存储介质中查询业务日志。整个业务日志框架搭建在</span><span lang="EN-US">IOC</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">容器之上，所有的对象都由</span><span lang="EN-US">IOC</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">容器统一进行管理，系统结构如下图所示：</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'"><img src="http://lee5593.javaeye.com/topics/download/4e0110db-4c69-40df-a9ed-797a4ae4014b" height="398" align="middle" alt="业务日志框架结构图" width="680" /></span></p>
<p class="MsoNormal" align="center" style="TEXT-ALIGN: center"><span lang="EN-US"><v:shapetype o:spt="75" coordsize="21600,21600" filled="f" stroked="f" id="_x0000_t75" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t"><v:stroke joinstyle="miter"></v:stroke><v:formulas><v:f eqn="if lineDrawn pixelLineWidth 0"></v:f><v:f eqn="sum @0 1 0"></v:f><v:f eqn="sum 0 0 @1"></v:f><v:f eqn="prod @2 1 2"></v:f><v:f eqn="prod @3 21600 pixelWidth"></v:f><v:f eqn="prod @3 21600 pixelHeight"></v:f><v:f eqn="sum @0 0 1"></v:f><v:f eqn="prod @6 1 2"></v:f><v:f eqn="prod @7 21600 pixelWidth"></v:f><v:f eqn="sum @8 21600 0"></v:f><v:f eqn="prod @7 21600 pixelHeight"></v:f><v:f eqn="sum @10 21600 0"></v:f></v:formulas><v:path o:extrusionok="f" o:connecttype="rect" gradientshapeok="t"></v:path><o:lock v:ext="edit" aspectratio="t"></o:lock></v:shapetype></span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">整个框架架构的主要职责类和接口的</span><span lang="EN-US">UML</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">类图如下</span><span lang="EN-US">(UML</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">不支持</span><span lang="EN-US">Annaotation</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，故省略了一个主要的</span><span lang="EN-US">Annaotation BusinessLog</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，后面会详细介绍</span><span lang="EN-US">)</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">：</span></p>
<p class="MsoNormal" align="center" style="TEXT-ALIGN: center"><span lang="EN-US"><img src="http://lee5593.javaeye.com/topics/download/c46dad14-87af-4d56-a33a-b29e7fc14010" height="831" align="middle" alt="业务日志框架UML类图" width="680" /></span></p>
<p class="MsoNormal" align="left" style="TEXT-ALIGN: center"><span lang="EN-US"><o:p>&nbsp;</o:p></span></p>
</font>&nbsp;
<p class="MsoNormal" style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">从上面的</span><span lang="EN-US">UML</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">类图中可以看出，每个组件都包含一个接口，这些接口定义了每个组件的协作通信方式，而将其实现隐藏起来，由</span><span lang="EN-US">IOC</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">容器配置指定具体实现类，这样可以无需更改代码就可以达到改变系统行为的目的。第二部分将对每个组件的详细设计进行阐述。</span></p>
          <br/>
          <span style="color:red;">
            <a href="http://lee5593.javaeye.com/blog/88163#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 08 Jun 2007 16:05:00 +0800</pubDate>
        <link>http://lee5593.javaeye.com/blog/88163</link>
        <guid>http://lee5593.javaeye.com/blog/88163</guid>
      </item>
      <item>
        <title>[转贴]Java NIO API详解</title>
        <author>lee5593</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lee5593.javaeye.com">lee5593</a>&nbsp;
          链接：<a href="http://lee5593.javaeye.com/blog/87687" style="color:red;">http://lee5593.javaeye.com/blog/87687</a>&nbsp;
          发表时间: 2007年06月07日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          原文出处：<a href="http://blog.csdn.net/daijialin/archive/2004/12/27/231384.aspx" target="_blank">http://blog.csdn.net/daijialin/archive/2004/12/27/231384.aspx</a><br />作者：DaiJiaLin                        <br /><a href="mailto:woodydai@gmail.com" target="_blank">mailto:woodydai@gmail.com</a><br /><a href="http://blog.csdn.net/DaiJiaLin" target="_blank">http://blog.csdn.net/DaiJiaLin</a><br />--------------------------------------------<br /><br />在JDK 1.4以前，Java的IO操作集中在java.io这个包中，是基于流的阻塞（blocking）API。对于大多数应用来说，这样的API使用很方便，然而，一些对性能要求较高的应用，尤其是服务端应用，往往需要一个更为有效的方式来处理IO。从JDK 1.4起，NIO API作为一个基于缓冲区，并能提供非阻塞(non-blocking)IO操作的API被引入。本文对其进行深入的介绍。<br /><br />NIO API主要集中在java.nio和它的subpackages中：<br /><br />java.nio<br /><br />定义了Buffer及其数据类型相关的子类。其中被java.nio.channels中的类用来进行IO操作的ByteBuffer的作用非常重要。<br /><br />java.nio.channels<br /><br />定义了一系列处理IO的Channel接口以及这些接口在文件系统和网络通讯上的实现。通过Selector这个类，还提供了进行非阻塞IO操作的办法。这个包可以说是NIO API的核心。<br /><br />java.nio.channels.spi<br /><br />定义了可用来实现channel和selector API的抽象类。<br /><br />java.nio.charset<br /><br />       定义了处理字符编码和解码的类。<br /><br />java.nio.charset.spi<br /><br />       定义了可用来实现charset API的抽象类。<br /><br />java.nio.channels.spi和java.nio.charset.spi这两个包主要被用来对现有NIO API进行扩展，在实际的使用中，我们一般只和另外的3个包打交道。下面将对这3个包一一介绍。<br /><br />Package java.nio<br /><br />这个包主要定义了Buffer及其子类。Buffer定义了一个线性存放primitive type数据的容器接口。对于除boolean以外的其他primitive type，都有一个相应的Buffer子类，ByteBuffer是其中最重要的一个子类。<br /><br />下面这张UML类图描述了java.nio中的类的关系：<br /><br /><img src="http://blog.csdn.net/images/blog_csdn_net/daijialin/56921/o_buffer.gif" /><br /><br /><br />Buffer<br /><br />定义了一个可以线性存放primitive type数据的容器接口。Buffer主要包含了与类型（byte, char…）无关的功能。值得注意的是Buffer及其子类都不是线程安全的。<br /><br />每个Buffer都有以下的属性：<br /><br />capacity<br />	这个Buffer最多能放多少数据。capacity一般在buffer被创建的时候指定。<br /><br />limit<br />	在Buffer上进行的读写操作都不能越过这个下标。当写数据到buffer中时，limit一般和capacity相等，当读数据时，limit代表buffer中有效数据的长度。<br /><br />position<br />	读/写操作的当前下标。当使用buffer的相对位置进行读/写操作时，读/写会从这个下标进行，并在操作完成后，buffer会更新下标的值。<br /><br />mark<br />	一个临时存放的位置下标。调用mark()会将mark设为当前的position的值，以后调用reset()会将position属性设置为mark的值。mark的值总是小于等于position的值，如果将position的值设的比mark小，当前的mark值会被抛弃掉。<br /><br /> <br />这些属性总是满足以下条件：<br /><br />0 &lt;= mark &lt;= position &lt;= limit &lt;= capacity<br /><br /><br />limit和position的值除了通过limit()和position()函数来设置，也可以通过下面这些函数来改变：<br /><br /><br />Buffer clear()<br />	把position设为0，把limit设为capacity，一般在把数据写入Buffer前调用。<br /><br />Buffer flip()<br />	把limit设为当前position，把position设为0，一般在从Buffer读出数据前调用。<br /><br />Buffer rewind()<br />	把position设为0，limit不变，一般在把数据重写入Buffer前调用。<br /><br /> <br />Buffer对象有可能是只读的，这时，任何对该对象的写操作都会触发一个ReadOnlyBufferException。isReadOnly()方法可以用来判断一个Buffer是否只读。<br /><br /><br />ByteBuffer<br /><br />在Buffer的子类中，ByteBuffer是一个地位较为特殊的类，因为在java.io.channels中定义的各种channel的IO操作基本上都是围绕ByteBuffer展开的。<br /><br /><br />ByteBuffer定义了4个static方法来做创建工作：<br /><br /><br />ByteBuffer allocate(int capacity)<br /><br />创建一个指定capacity的ByteBuffer。<br /><br />ByteBuffer allocateDirect(int capacity)<br /><br />创建一个direct的ByteBuffer，这样的ByteBuffer在参与IO操作时性能会更好（很有可能是在底层的实现使用了DMA技术），相应的，创建和回收direct的ByteBuffer的代价也会高一些。isDirect()方法可以检查一个buffer是否是direct的。<br /><br />ByteBuffer wrap(byte [] array)<br /><br />ByteBuffer wrap(byte [] array, int offset, int length)<br /><br />把一个byte数组或byte数组的一部分包装成ByteBuffer。<br /><br /><br />ByteBuffer定义了一系列get和put操作来从中读写byte数据，如下面几个：<br /><br />byte get()<br /><br />ByteBuffer get(byte [] dst)<br /><br />byte get(int index)<br /><br />ByteBuffer put(byte b)<br /><br />ByteBuffer put(byte [] src)<br /><br />ByteBuffer put(int index, byte b)<br /><br /><br />这些操作可分为绝对定位和相对定为两种，相对定位的读写操作依靠position来定位Buffer中的位置，并在操作完成后会更新position的值。<br /><br />在其它类型的buffer中，也定义了相同的函数来读写数据，唯一不同的就是一些参数和返回值的类型。<br /><br /><br />除了读写byte类型数据的函数，ByteBuffer的一个特别之处是它还定义了读写其它primitive数据的方法，如：<br /><br /><br />int getInt()<br /><br />       从ByteBuffer中读出一个int值。<br /><br />ByteBuffer putInt(int value)<br /><br />       写入一个int值到ByteBuffer中。<br /><br /><br />读写其它类型的数据牵涉到字节序问题，ByteBuffer会按其字节序（大字节序或小字节序）写入或读出一个其它类型的数据（int,long…）。字节序可以用order方法来取得和设置：<br /><br /> <br /><br />ByteOrder order()<br />       返回ByteBuffer的字节序。<br /><br />ByteBuffer order(ByteOrder bo)<br />       设置ByteBuffer的字节序。<br /><br /> <br /><br />ByteBuffer另一个特别的地方是可以在它的基础上得到其它类型的buffer。如：<br /> <br /><br />CharBuffer asCharBuffer()<br /><br />为当前的ByteBuffer创建一个CharBuffer的视图。在该视图buffer中的读写操作会按照ByteBuffer的字节序作用到ByteBuffer中的数据上。<br /><br /><br />用这类方法创建出来的buffer会从ByteBuffer的position位置开始到limit位置结束，可以看作是这段数据的视图。视图buffer的readOnly属性和direct属性与ByteBuffer的一致，而且也只有通过这种方法，才可以得到其他数据类型的direct buffer。<br /><br /><br />ByteOrder<br /><br />用来表示ByteBuffer字节序的类，可将其看成java中的enum类型。主要定义了下面几个static方法和属性：<br /><br /><br />ByteOrder BIG_ENDIAN<br />       代表大字节序的ByteOrder。<br /><br />ByteOrder LITTLE_ENDIAN<br />       代表小字节序的ByteOrder。<br /><br />ByteOrder nativeOrder()<br />       返回当前硬件平台的字节序。<br /><br /><br />MappedByteBuffer<br />	ByteBuffer的子类，是文件内容在内存中的映射。这个类的实例需要通过FileChannel的map()方法来创建。<br /><br /> <br /><br />接下来看看一个使用ByteBuffer的例子，这个例子从标准输入不停地读入字符，当读满一行后，将收集的字符写到标准输出：<br /><pre name="code" class="java">
    public static void main(String [] args) 
       throws IOException
    {
       // 创建一个capacity为256的ByteBuffer
       ByteBuffer buf = ByteBuffer.allocate(256);
       while (true) {
           // 从标准输入流读入一个字符
           int c = System.in.read();
           // 当读到输入流结束时，退出循环
           if (c == -1)
              break;
           // 把读入的字符写入ByteBuffer中
           buf.put((byte) c);
           // 当读完一行时，输出收集的字符
           if (c == '\n') {
              // 调用flip()使limit变为当前的position的值,position变为0,
              // 为接下来从ByteBuffer读取做准备
              buf.flip();
              // 构建一个byte数组
              byte [] content = new byte[buf.limit()];
              // 从ByteBuffer中读取数据到byte数组中
              buf.get(content);
               // 把byte数组的内容写到标准输出
              System.out.print(new String(content));
             // 调用clear()使position变为0,limit变为capacity的值，
              // 为接下来写入数据到ByteBuffer中做准备
              buf.clear();
           }
       }
    }
</pre><br /><br />Package java.nio.channels<br />	这个包定义了Channel的概念，Channel表现了一个可以进行IO操作的通道（比如，通过FileChannel，我们可以对文件进行读写操作）。java.nio.channels包含了文件系统和网络通讯相关的channel类。这个包通过Selector和SelectableChannel这两个类，还定义了一个进行非阻塞（non-blocking）IO操作的API，这对需要高性能IO的应用非常重要。<br /> <br /><br />下面这张UML类图描述了java.nio.channels中interface的关系：<br /><img src="http://blog.csdn.net/images/blog_csdn_net/daijialin/56921/o_channel.gif" /><br /><br /><br />Channel<br />	Channel表现了一个可以进行IO操作的通道，该interface定义了以下方法：<br /><br />boolean isOpen()<br />	该Channel是否是打开的。<br /><br />void close()<br />	关闭这个Channel，相关的资源会被释放。<br /><br />ReadableByteChannel<br />	定义了一个可从中读取byte数据的channel interface。<br /><br />int read(ByteBuffer dst)<br />	从channel中读取byte数据并写到ByteBuffer中。返回读取的byte数。<br /><br />WritableByteChannel<br />	定义了一个可向其写byte数据的channel interface。<br /><br />int write(ByteBuffer src)<br />	从ByteBuffer中读取byte数据并写到channel中。返回写出的byte数。<br /><br /> <br /><br />ByteChannel<br />	ByteChannel并没有定义新的方法，它的作用只是把ReadableByteChannel和WritableByteChannel合并在一起。<br /><br />ScatteringByteChannel<br />	继承了ReadableByteChannel并提供了同时往几个ByteBuffer中写数据的能力。<br /><br />GatheringByteChannel<br />	继承了WritableByteChannel并提供了同时从几个ByteBuffer中读数据的能力。<br /><br />InterruptibleChannel<br />	用来表现一个可以被异步关闭的Channel。这表现在两方面：<br /><br />1．当一个InterruptibleChannel的close()方法被调用时，其它block在这个InterruptibleChannel的IO操作上的线程会接收到一个AsynchronousCloseException。<br />2．当一个线程block在InterruptibleChannel的IO操作上时，另一个线程调用该线程的interrupt()方法会导致channel被关闭，该线程收到一个ClosedByInterruptException，同时线程的interrupt状态会被设置。<br /><br /><br />接下来的这张UML类图描述了java.nio.channels中类的关系：<br /><br /><br /><br /><br />非阻塞IO<br /><br />非阻塞IO的支持可以算是NIO API中最重要的功能，非阻塞IO允许应用程序同时监控多个channel以提高性能，这一功能是通过Selector，SelectableChannel和SelectionKey这3个类来实现的。<br /><br />SelectableChannel代表了可以支持非阻塞IO操作的channel，可以将其注册在Selector上，这种注册的关系由SelectionKey这个类来表现（见UML图）。Selector这个类通过select()函数，给应用程序提供了一个可以同时监控多个IO channel的方法：<br /><br />应用程序通过调用select()函数，让Selector监控注册在其上的多个SelectableChannel，当有channel的IO操作可以进行时，select()方法就会返回以让应用程序检查channel的状态，并作相应的处理。<br /><br /><br />下面是JDK 1.4中非阻塞IO的一个例子，这段code使用了非阻塞IO实现了一个time server：<br /><pre name="code" class="java">
    private static void acceptConnections(int port) throws Exception {
       // 打开一个Selector
       Selector acceptSelector = 
           SelectorProvider.provider().openSelector();
       // 创建一个ServerSocketChannel，这是一个SelectableChannel的子类
       ServerSocketChannel ssc = ServerSocketChannel.open();
       // 将其设为non-blocking状态，这样才能进行非阻塞IO操作
       ssc.configureBlocking(false);
       // 给ServerSocketChannel对应的socket绑定IP和端口
       InetAddress lh = InetAddress.getLocalHost();
       InetSocketAddress isa = new InetSocketAddress(lh, port);
       ssc.socket().bind(isa);
       // 将ServerSocketChannel注册到Selector上，返回对应的SelectionKey
       SelectionKey acceptKey = 
           ssc.register(acceptSelector, SelectionKey.OP_ACCEPT);
       int keysAdded = 0;
       // 用select()函数来监控注册在Selector上的SelectableChannel
       // 返回值代表了有多少channel可以进行IO操作 (ready for IO)
       while ((keysAdded = acceptSelector.select()) > 0) {
           // selectedKeys()返回一个SelectionKey的集合，
           // 其中每个SelectionKey代表了一个可以进行IO操作的channel。
           // 一个ServerSocketChannel可以进行IO操作意味着有新的TCP连接连入了
           Set readyKeys = acceptSelector.selectedKeys();
           Iterator i = readyKeys.iterator();
           while (i.hasNext()) {
              SelectionKey sk = (SelectionKey) i.next();
              // 需要将处理过的key从selectedKeys这个集合中删除
              i.remove();
              // 从SelectionKey得到对应的channel
              ServerSocketChannel nextReady = 
                  (ServerSocketChannel) sk.channel();
              // 接受新的TCP连接
              Socket s = nextReady.accept().socket();
              // 把当前的时间写到这个新的TCP连接中
              PrintWriter out = 
                  new PrintWriter(s.getOutputStream(), true);
              Date now = new Date();
              out.println(now);
              // 关闭连接
              out.close();
           }
       }
    }
</pre><br /><br />这是个纯粹用于演示的例子，因为只有一个ServerSocketChannel需要监控，所以其实并不真的需要使用到非阻塞IO。不过正因为它的简单，可以很容易地看清楚非阻塞IO是如何工作的。<br /><br /><br />SelectableChannel<br />	这个抽象类是所有支持非阻塞IO操作的channel（如DatagramChannel、SocketChannel）的父类。SelectableChannel可以注册到一个或多个Selector上以进行非阻塞IO操作。<br />	SelectableChannel可以是blocking和non-blocking模式（所有channel创建的时候都是blocking模式），只有non-blocking的SelectableChannel才可以参与非阻塞IO操作。<br /><br /><br />SelectableChannel configureBlocking(boolean block)<br />	设置blocking模式。<br /><br />boolean isBlocking()<br />	返回blocking模式。<br /><br />通过register()方法，SelectableChannel可以注册到Selector上。<br /><br />int validOps()<br />	返回一个bit mask，表示这个channel上支持的IO操作。当前在SelectionKey中，用静态常量定义了4种IO操作的bit值：OP_ACCEPT，OP_CONNECT，OP_READ和OP_WRITE。<br /><br />SelectionKey register(Selector sel, int ops)<br />	将当前channel注册到一个Selector上并返回对应的SelectionKey。在这以后，通过调用Selector的select()函数就可以监控这个channel。ops这个参数是一个bit mask，代表了需要监控的IO操作。<br /><br />SelectionKey register(Selector sel, int ops, Object att)<br />	这个函数和上一个的意义一样，多出来的att参数会作为attachment被存放在返回的SelectionKey中，这在需要存放一些session state的时候非常有用。<br /><br />boolean isRegistered()<br />	该channel是否已注册在一个或多个Selector上。<br /><br />SelectableChannel还提供了得到对应SelectionKey的方法：<br /><br />SelectionKey keyFor(Selector sel)<br />	返回该channe在Selector上的注册关系所对应的SelectionKey。若无注册关系，返回null。<br /><br />Selector<br />	Selector可以同时监控多个SelectableChannel的IO状况，是非阻塞IO的核心。<br /><br /> <br /><br />Selector open()<br />	Selector的一个静态方法，用于创建实例。<br /><br />在一个Selector中，有3个SelectionKey的集合：<br /><br />1．key set代表了所有注册在这个Selector上的channel，这个集合可以通过keys()方法拿到。<br /><br />2．Selected-key set代表了所有通过select()方法监测到可以进行IO操作的channel，这个集合可以通过selectedKeys()拿到。<br /><br />3．Cancelled-key set代表了已经cancel了注册关系的channel，在下一个select()操作中，这些channel对应的SelectionKey会从key set和cancelled-key set中移走。这个集合无法直接访问。<br /><br /><br />以下是select()相关方法的说明：<br /><br />int select()<br />	监控所有注册的channel，当其中有注册的IO操作可以进行时，该函数返回，并将对应的SelectionKey加入selected-key set。<br /><br />int select(long timeout)<br />	可以设置超时的select()操作。<br /><br />int selectNow()<br />	进行一个立即返回的select()操作。<br /><br />Selector wakeup()<br />	使一个还未返回的select()操作立刻返回。<br /><br />SelectionKey<br />	代表了Selector和SelectableChannel的注册关系。<br /><br /><br />Selector定义了4个静态常量来表示4种IO操作，这些常量可以进行位操作组合成一个bit mask。<br /><br />int OP_ACCEPT<br />	有新的网络连接可以accept，ServerSocketChannel支持这一非阻塞IO。<br /><br />int OP_CONNECT<br />	代表连接已经建立（或出错），SocketChannel支持这一非阻塞IO。<br /><br />int OP_READ<br /><br />int OP_WRITE<br />	代表了读、写操作。<br /><br /><br />以下是其主要方法：<br /><br />Object attachment()<br />	返回SelectionKey的attachment，attachment可以在注册channel的时候指定。<br /><br />Object attach(Object ob)<br />	设置SelectionKey的attachment。<br /><br />SelectableChannel channel()<br />	返回该SelectionKey对应的channel。<br /><br />Selector selector()<br />	返回该SelectionKey对应的Selector。<br /><br />void cancel()<br />	cancel这个SelectionKey所对应的注册关系。<br /><br />int interestOps()<br />	返回代表需要Selector监控的IO操作的bit mask。<br /><br />SelectionKey interestOps(int ops)<br />	设置interestOps。<br /><br />int readyOps()<br />	返回一个bit mask，代表在相应channel上可以进行的IO操作。<br /><br />ServerSocketChannel<br />	支持非阻塞操作，对应于java.net.ServerSocket这个类，提供了TCP协议IO接口，支持OP_ACCEPT操作。<br /><br />ServerSocket socket()<br />	返回对应的ServerSocket对象。<br /><br />SocketChannel accept()<br />	接受一个连接，返回代表这个连接的SocketChannel对象。<br /><br />SocketChannel<br />	支持非阻塞操作，对应于java.net.Socket这个类，提供了TCP协议IO接口，支持OP_CONNECT，OP_READ和OP_WRITE操作。这个类还实现了ByteChannel，ScatteringByteChannel和GatheringByteChannel接口。<br />DatagramChannel和这个类比较相似，其对应于java.net.DatagramSocket，提供了UDP协议IO接口。<br /><br />Socket socket()<br />	返回对应的Socket对象。<br /><br />boolean connect(SocketAddress remote)<br /><br />boolean finishConnect()<br /><br />connect()进行一个连接操作。如果当前SocketChannel是blocking模式，这个函数会等到连接操作完成或错误发生才返回。如果当前SocketChannel是non-blocking模式，函数在连接能立刻被建立时返回true，否则函数返回false，应用程序需要在以后用finishConnect()方法来完成连接操作。<br /><br /><br />Pipe<br />	包含了一个读和一个写的channel(Pipe.SourceChannel和Pipe.SinkChannel)，这对channel可以用于进程中的通讯。<br /><br /><br />FileChannel<br />	用于对文件的读、写、映射、锁定等操作。和映射操作相关的类有FileChannel.MapMode，和锁定操作相关的类有FileLock。值得注意的是FileChannel并不支持非阻塞操作。<br /><br /><br />Channels<br />	这个类提供了一系列static方法来支持stream类和channel类之间的互操作。这些方法可以将channel类包装为stream类，比如，将ReadableByteChannel包装为InputStream或Reader；也可以将stream类包装为channel类，比如，将OutputStream包装为WritableByteChannel。<br /><br /><br />Package java.nio.charset<br />	这个包定义了Charset及相应的encoder和decoder。下面这张UML类图描述了这个包中类的关系，可以将其中Charset，CharsetDecoder和CharsetEncoder理解成一个Abstract Factory模式的实现：<br /><img src="http://blog.csdn.net/images/blog_csdn_net/daijialin/56921/o_charset.gif" /><br /><br /><br />Charset<br />	代表了一个字符集，同时提供了factory method来构建相应的CharsetDecoder和CharsetEncoder。<br /><br /><br />Charset提供了以下static的方法：<br /><br />SortedMap availableCharsets()<br />	返回当前系统支持的所有Charset对象，用charset的名字作为set的key。<br /><br />boolean isSupported(String charsetName)<br />	判断该名字对应的字符集是否被当前系统支持。<br /><br />Charset forName(String charsetName)<br />	返回该名字对应的Charset对象。<br /><br /><br />Charset中比较重要的方法有：<br /><br />String name()<br />	返回该字符集的规范名。<br /><br />Set aliases()<br />	返回该字符集的所有别名。<br /><br />CharsetDecoder newDecoder()<br />	创建一个对应于这个Charset的decoder。<br /><br />CharsetEncoder newEncoder()<br />	创建一个对应于这个Charset的encoder。<br /><br /> <br />CharsetDecoder<br />	将按某种字符集编码的字节流解码为unicode字符数据的引擎。<br /><br />CharsetDecoder的输入是ByteBuffer，输出是CharBuffer。进行decode操作时一般按如下步骤进行：<br /><br />1．调用CharsetDecoder的reset()方法。（第一次使用时可不调用）<br />2．调用decode()方法0到n次，将endOfInput参数设为false，告诉decoder有可能还有新的数据送入。<br />3．调用decode()方法最后一次，将endOfInput参数设为true，告诉decoder所有数据都已经送入。<br />4．调用decoder的flush()方法。让decoder有机会把一些内部状态写到输出的CharBuffer中。<br /><br /><br />CharsetDecoder reset()<br />	重置decoder，并清除decoder中的一些内部状态。<br /><br />CoderResult decode(ByteBuffer in, CharBuffer out, boolean endOfInput)<br />	从ByteBuffer类型的输入中decode尽可能多的字节，并将结果写到CharBuffer类型的输出中。根据decode的结果，可能返回3种CoderResult：CoderResult.UNDERFLOW表示已经没有输入可以decode；CoderResult.OVERFLOW表示输出已满；其它的CoderResult表示decode过程中有错误发生。根据返回的结果，应用程序可以采取相应的措施，比如，增加输入，清除输出等等，然后再次调用decode()方法。<br /><br />CoderResult flush(CharBuffer out)<br />	有些decoder会在decode的过程中保留一些内部状态，调用这个方法让这些decoder有机会将这些内部状态写到输出的CharBuffer中。调用成功返回CoderResult.UNDERFLOW。如果输出的空间不够，该函数返回CoderResult.OVERFLOW，这时应用程序应该扩大输出CharBuffer的空间，然后再次调用该方法。<br /><br />CharBuffer decode(ByteBuffer in)<br />	一个便捷的方法把ByteBuffer中的内容decode到一个新创建的CharBuffer中。在这个方法中包括了前面提到的4个步骤，所以不能和前3个函数一起使用。<br /><br />decode过程中的错误有两种：malformed-input CoderResult表示输入中数据有误；unmappable-character CoderResult表示输入中有数据无法被解码成unicode的字符。如何处理decode过程中的错误取决于decoder的设置。对于这两种错误，decoder可以通过CodingErrorAction设置成：<br /><br />1．忽略错误<br />2．报告错误。（这会导致错误发生时，decode()方法返回一个表示该错误的CoderResult。）<br />3．替换错误，用decoder中的替换字串替换掉有错误的部分。<br /><br />CodingErrorAction malformedInputAction()<br />	返回malformed-input的出错处理。<br /><br />CharsetDecoder onMalformedInput(CodingErrorAction newAction)<br />	设置malformed-input的出错处理。<br /><br />CodingErrorAction unmappableCharacterAction()<br />	返回unmappable-character的出错处理。<br /><br />CharsetDecoder onUnmappableCharacter(CodingErrorAction newAction)<br />	设置unmappable-character的出错处理。<br /><br />String replacement()<br />	返回decoder的替换字串。<br /><br />CharsetDecoder replaceWith(String newReplacement)<br />	设置decoder的替换字串。<br /><br /><br />CharsetEncoder<br />	将unicode字符数据编码为特定字符集的字节流的引擎。其接口和CharsetDecoder相类似。<br /><br />CoderResult<br />	描述encode/decode操作结果的类。<br /><br />CodeResult包含两个static成员：<br /><br />CoderResult OVERFLOW<br />	表示输出已满<br /><br />CoderResult UNDERFLOW<br />	表示输入已无数据可用。<br /><br />其主要的成员函数有：<br /><br />boolean isError()<br /><br />boolean isMalformed()<br /><br />boolean isUnmappable()<br /><br />boolean isOverflow()<br /><br />boolean isUnderflow()<br />	用于判断该CoderResult描述的错误。<br /><br />int length()<br />	返回错误的长度，比如，无法被转换成unicode的字节长度。<br /><br />void throwException()<br />	抛出一个和这个CoderResult相对应的exception。<br /><br />CodingErrorAction<br />	表示encoder/decoder中错误处理方法的类。可将其看成一个enum类型。有以下static属性：<br /><br />CodingErrorAction IGNORE<br />	忽略错误。<br /><br />CodingErrorAction REPLACE<br />	用替换字串替换有错误的部分。<br /><br />CodingErrorAction REPORT<br />	报告错误，对于不同的函数，有可能是返回一个和错误有关的CoderResult，也有可能是抛出一个CharacterCodingException。
          <br/>
          <span style="color:red;">
            <a href="http://lee5593.javaeye.com/blog/87687#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 07 Jun 2007 16:45:19 +0800</pubDate>
        <link>http://lee5593.javaeye.com/blog/87687</link>
        <guid>http://lee5593.javaeye.com/blog/87687</guid>
      </item>
      <item>
        <title>大家一起来谈谈Maven吧</title>
        <author>lee5593</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lee5593.javaeye.com">lee5593</a>&nbsp;
          链接