<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>yufeimen</title>
    <description></description>
    <link>http://yufeimen.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>利用JProfiler对应用服务器内存泄漏问题诊断一例（转）</title>
        <author>yufeimen</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://yufeimen.javaeye.com">yufeimen</a>&nbsp;
          链接：<a href="http://yufeimen.javaeye.com/blog/70721" style="color:red;">http://yufeimen.javaeye.com/blog/70721</a>&nbsp;
          发表时间: 2007年04月13日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在中间件应用服务器的整体调优中，有关于等待队列、执行线程，EJB池以及数据库连接池和Statement Cache方面的调优，这些都属于系统参数方面的调优，本文主要从另外一个角度，也就是从应用的角度来解决中间件应用服务器的内存泄露问题，从这个角度来提高系统的稳定性和性能。 </p><p><span><span style="font-size: medium; color: #000000; font-family: Arial">项目背景</span></span> </p><p><span><strong><span style="font-size: small; color: #000000; font-family: Arial">问题描述</span></strong></span> </p><p>某个大型项目（Use Case用例超过300个），在项目上线后，其Web应用服务器经常宕机。表现为： </p><p>1. 应用服务器内存长期不合理占用，内存经常处于高位占用，很难回收到低位； </p><p>2. 应用服务器极为不稳定，几乎每两天重新启动一次，有时甚至每天重新启动一次； </p><p>3. 应用服务器经常做Full GC(Garbage Collection)，而且时间很长，大约需要30-40秒，应用服务器在做Full GC的时候是不响应客户的交易请求的，非常影响系统性能。 </p><p><span><strong><span style="font-size: small; color: #000000; font-family: Arial">Web应用服务器的物理部署</span></strong></span> </p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一台Unix服务器（4CPU，8G Memory）来部署本Web应用程序；Web应用程序部署在中间件应用服务器上；部署了一个节点（Node），只配置一个应用服务器实例（Instance），没有做Cluster部署。 </p><p><span><strong><span style="font-size: small; color: #000000; font-family: Arial">Web应用服务器启动脚本中的内存参数</span></strong></span> <table border="1" width="100%" cellpadding="0"><tbody><tr><td bgcolor="#f4f4f4">MEM_ARGS=&quot;-XX:MaxPermSize=128m -XX:MaxNewSize=512m -Xms3096m <br />-Xmx3096m -XX:+Printetails -Xloggc:./inwebapp1/gc.$$&quot; </td></tr></tbody></table></p><p>可以看出目前生产系统中Web应用服务器的内存分配为3G Memory。 </p><p><span><strong><span style="font-size: small; color: #000000; font-family: Arial">Web应用服务器的重要部署参数</span></strong></span> <table border="1" cellpadding="4"><tbody><tr><td>参数名称 </td><td>参数值 </td><td>参数解释 </td></tr><tr><td>kernel.default(Thread Count) </td><td>120 </td><td>执行线程数目，是并发处理能力的重要参数 </td></tr><tr><td>Session Timeout </td><td>240分钟（4小时） </td><td>HttpSession会话超时</td></tr></tbody></table></p><p>&nbsp;</p><p><span><span style="font-size: medium; color: #000000; font-family: Arial"><strong>分析</strong></span></span> </p><p><span><strong><span style="font-size: small; color: #000000; font-family: Arial">分析方法</span></strong></span> </p><p>内存长期占用并导致系统不稳定一般有两种可能： </p><p>1. 对象被大量创建而且被缓存，在旧的对象释放前又有大量新的对象被创建使得内存长期高位占用。 </p><ul><li>表现为：内存不断被消耗、在高位时也很难回归到低位，有大量的对象在不断的创建，经过很长时间后又被回收。例如：在HttpSession中保存了大量的分页查询数据，而HttpSession的会话超时时间设置过长（例如：1天），那么在旧的对象释放前又有大量新的对象在第二天产生。 </li><li>解决办法：对共享的对象可以采用池机制进行缓存，避免各自创建；缓存的临时对象应该及时释放；另一种办法是扩大系统的内存容量。</li></ul><p>2. 另一种情况就是内存泄漏问题 </p><ul><li>表现为：内存回收低位点不断升高（以每次内存回收的最低点连成一条直线，那么它是一条上升线）；内存回收的频率也越来越高，内存占用也越来越高，最终出现&quot;Out of Memory Exception&quot;的系统异常。 </li><li>解决办法：定位那些有内存泄漏的类或对象并修改完善这些类以避免内存泄漏。方法是：经过一段时间的测试、监控，如果某个类的对象数目屡创新高，即使在JVM Full GC后仍然数目降不下来，这些对象基本上是属于内存泄漏的对象了。</li></ul><p><span><strong><span style="font-size: small; color: #000000; font-family: Arial">问题定位</span></strong></span> </p><p>这里请看5月份 Web应用服务器的内存回收图形： </p><p>《注意：5月18日早上10点重新启动了Web服务器，5月20日早上又重新启动了Web服务器。》 </p><ul><li>在Web应用重要部署参数中，我们知道：Session的超时时间为4个小时，我们在监控平台也观测到：在18日晚上10点左右所有的会话都过期了，从图形一中也能看出18日晚上确实系统的内存有回收到40%（就象股票的高位跳水）； </li><li>从图形一（5月18日）中我们也能看到Full GC回收后的内存占用率走势（红色曲线），上午基本平滑上升到20%（内存占用率），中午开始上升到30%，下午上升到40% </li><li>从图形二（5月19日）中我们也能看到Full GC回收后的内存占用率走势（红色曲线），上午又上升到了60%，到下午上升到了70%。 </li><li>从黄色曲线（GC花费的时间，以秒为单位），Full GC的频率也在增快，时间耗费也越来越长，在图形一中基本高位在20秒左右，到19日基本都是30-40秒之间了。</li></ul><p>&nbsp;<strong><span style="color: #000000">图形一 5月18日</span></strong><br /><img src="http://www-128.ibm.com/developerworks/cn/java/j-performance/images/image002.gif" border="0" height="318" alt="图形一 5月18日" width="554" /><br /><br /><strong><span style="color: #000000">图二</span></strong><br /><img src="http://www-128.ibm.com/developerworks/cn/java/j-performance/images/image004.gif" border="0" height="320" alt="图二" width="554" /></p><p>通过上述分析，我们基本定位到了Web应用服务器的内存在高位长期占用的原因了：是内存泄露！并且正是由于这个原因导致系统不稳定、响应客户请求越来越慢的。 </p><p><span><strong><span style="font-size: small; color: #000000; font-family: Arial">解决方法</span></strong></span> </p><p>方法如下： </p><ul><li>我们从图形二中发现，在8.95(将近9点钟)到9.66（将近9点40）期间有几次Full GC，但是有内存泄漏，从占用率40%上升到50%左右，泄漏了大约10%的内存，约300M； </li><li>我们在自己搭建的Web应用服务器平台（应用软件版本和生产版本一致）做这一阶段相同的查询交易；表明对同一个黑盒（Web应用）施加同样的刺激（相同的操作过程和查询交易）以期重现现象； </li><li>我们使用Jprofiler工具对Web应用服务器的内存进行实时监控； </li><li>做完这些交易后，用户退出系统，并等待Web应用服务器的HttpSession超时（我们这里设置为15分钟）； </li><li>我们对Web应用服务器做了两次强制性的内存回收操作。</li></ul><p>发现如下： </p><p><br /><strong><span style="color: #000000">图三</span></strong><br /><img src="http://www-128.ibm.com/developerworks/cn/java/j-performance/images/image007.gif" border="0" height="392" alt="图三" width="554" /></p><p>如图三所示，内存经过HttpSession超时后，并强制gc后，仍然有大量的对象没有释放。例如：gov.gdlt.taxcore.comm.security.MenuNode，仍然有807个实例没有释放。 </p><p>我们继续追溯发现，这些MenuNode首先存放在一个ArrayList对象中，然后发现这个ArrayList对象又是存放在WHsessionAttrVO对象的Map中，WHsessionAttrVO 对象又是存放在ExternalSessionManager的staic Map中（名称为sessionMap），如图四所示。 </p><p><br /><strong><span style="color: #000000">图四</span></strong><br /><img src="http://www-128.ibm.com/developerworks/cn/java/j-performance/images/image009.gif" border="0" height="260" alt="图四" width="554" /></p><p>我们发现gov.gdlt.taxcore.taxevent.xtgl.comm.WHsessionAttrVO中保存了EJBSessionId信息(登录用户的唯一标志，由用户id+登录时间戳组成，每天都不同)和一个HashMap，这个HashMap中的内容有： </p><ul><li>ArrayList: 内有MenuTreeNodes（菜单树节点） </li><li>HashMap: 内有操作人员代码信息 </li><li>CurrentVersion:当前版本号 </li><li>CurrentTime:当前系统时间</li></ul><p>WHsessionAttrVO这个对象的最终存放在ExternalSessionManager的static Map sessionMap中，由于ExternalSessionManager是一个全局的单实例，不会释放，所以它的成员变量sessionMap中的数据也不会释放，而Map中的Key值为EJBSessionId，每天登录的用户EJBSessionId都不同，就造成了每天的登录信息（包括菜单信息）都保存在sessionMap中不会被释放，最终造成了内存的泄漏。 </p><p><br /><strong><span style="color: #000000">图五</span></strong><br /><img src="http://www-128.ibm.com/developerworks/cn/java/j-performance/images/image011.jpg" border="0" height="151" alt="图五" width="502" /></p><p>如上图所示：WHsessionAttrsVO对象中除了有一个String对象（内容是EJBSessionId），还有一个HashMap对象。 </p><p><br /><strong><span style="color: #000000">图六</span></strong><br /><img src="http://www-128.ibm.com/developerworks/cn/java/j-performance/images/image013.gif" border="0" height="264" alt="图六" width="516" /></p><p>如上图所示，这个HashMap中的内容主要有menuTreeNodes为key，value为ArrayList的对象和以czrydminfo为key，value为HashMap对象的数据。 </p><p><br /><strong><span style="color: #000000">图七</span></strong><br /><img src="http://www-128.ibm.com/developerworks/cn/java/j-performance/images/image015.jpg" border="0" height="299" alt="图七" width="596" /></p><p>如上图所示：menuTreeNodes为key，value为ArrayList对象中包含的对象有许多的MenuNode对象，封装的都是用户的菜单节点。 </p><p><br /><strong><span style="color: #000000">图八</span></strong><br /><img src="http://www-128.ibm.com/developerworks/cn/java/j-performance/images/image017.jpg" border="0" height="116" alt="图八" width="384" /></p><p>如上图所示，最顶层（Root）的初始对象为一个ExternalSessionManager对象，其中的一个成员变量为static (静态的)，名称为：sessionMap，这个对象是singleton方式的，全局只有一个。 </p><p><span><strong><span style="font-size: small; color: #000000; font-family: Arial">初步估量</span></strong></span> </p><p>我们从图形一和图形二中可以看出，每天应用服务器损失大约40%的内存，大约1G左右。 </p><p>从图形四可以看出，当前用户（Id=24400001129）有807个菜单项（每个菜单项为一个MenuNode 对象实例，图形四中的这个实例的size为592 Byte），这些菜单数据和用户基本登录信息（czrydmInfo HashMap）也都存放在WHsessionAttrVO对象中，当前这个WHsessionAttrVO对象的size为457K。 </p><p>我们做如下估算： </p><p>假设平均每天有4千人（估计值，这个数值仅仅是5月19日峰值的1/2左右）登录系统（有重复登录的现象，例如：上午登录一次，中午退出系统，下午登录一次），以平均每人占用200K（估计值，是用户id=24400001129 的Size的1/2左右）来计算，一天泄漏的内存约800M，比较符合目前内存泄漏的情况。当然，这种估计仍然需要经过实践的检验，方法是：当这次发现的内存泄漏问题解决后看系统是否还有其它内存泄漏问题。 </p><p><br /><table cellspacing="0" border="0" width="100%" cellpadding="0"><tbody><tr><td><img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" height="1" alt="" width="100%" /></td></tr></tbody></table><span><span style="font-size: medium; color: #000000; font-family: Arial">方案</span></span> </p><p>ExternalSessionManager类是当初某某软件商设计的用来解决Web服务器负载均衡的模块，这个类主要用来保存客户的基本登录信息（包括会话的EJBSessionId），以维护多个Web服务器之间的会话信息一致。 </p><p>改进方案有两种： </p><ul><li><p>从架构设计方面改进 </p><p>实现Web层的负载均衡有很多标准的实现方式。例如：采用负载均衡设备(硬件或软件)来实现。 </p><p>如果采用新的Web层的负载均衡方式，那么就可以去掉ExternalSessionManager这个类了。 </p></li><li><p>从应用实现方面改进 </p><p>保留当前的Web层的负载均衡设计机制，仅仅从应用实现方面解决内存泄漏问题，首先菜单信息不应该保存在ExternalSessionManager中。其次，增加对ExternalSessionManager类中用户会话登录信息的清除，有几种方式可以选择： </p><ul><li>被动方式，当HttpSession会话超时（或过期）被Web应用服务器回收时清除相应的ExternalSessionManager中的过期会话登录信息。 </li><li>主动方式，可以采用任务定时清理每天的过期会话登录信息或线程轮询清理。 </li><li>采用新的会话登录信息存储方式，ExternalSessionManager的sessionMap中的key值不再以EJBSessionId作为键值，而是以用户id（EJBSessionId的前11位）代替。由于用户id每天都是一样的，所以不会造成内存泄漏。保存得登录信息也不再包含菜单节点信息，而只是登录基本信息。最多也只是保存整个系统所有的用户id及其基本登录信息（大约每个用户的登录信息只有1.5K左右，而目前这个系统的营业网点用户为1万左右，所以大约只占用Web服务器15M内存）。</li></ul></li></ul><p><br /><table cellspacing="0" border="0" width="100%" cellpadding="0"><tbody><tr><td><img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" height="1" alt="" width="100%" /></td></tr></tbody></table><span><span style="font-size: medium; color: #000000; font-family: Arial">实施情况</span></span> </p><p>采用的方案：某某软件商采用了新的会话登录信息存贮方案，即:ExternalSessionManager的成员变量sessionMap中不再保存用户菜单信息，只保存基本的登录信息；存储方式采用用户id（11位）作为键值（key）来保留用户基本登录信息。 </p><p>基本分析：由于基本登录信息只有1K左右，而目前内网登录的用户总数也只有8887个，所以只保存了大约10M-15M的信息在内存，占用量很小，并且不会有内存泄漏。用户菜单信息保存在session中，如果用户退出时点击logout页面，那么应用服务器可以很快地释放这部分内存；如果用户直接关闭窗口，那么保存在session中的菜单信息只有等会话超时后才会由系统清除并回收内存。 </p><p>监控状况： </p><p><br /><strong><span style="color: #000000">图九</span></strong><br /><img src="http://www-128.ibm.com/developerworks/cn/java/j-performance/images/image019.jpg" border="0" height="378" alt="图九" width="622" /></p><p>如图九所示，ExternalSessionManager中只保留了简单的登录信息（Map中保存了WHsessionAttrVO对象），包括：当前版本(currentversion)，操作人员代码基本信息（czrydmInfo），当前时间（currenttime）。 </p><p><br /><strong><span style="color: #000000">图十</span></strong><br /><img src="http://www-128.ibm.com/developerworks/cn/java/j-performance/images/image021.jpg" border="0" height="164" alt="图十" width="553" /></p><p>如图十所示，这个登录用户的基本信息只有1368 bytes，大约1.3K </p><p><br /><strong><span style="color: #000000">图十一</span></strong><br /><img src="http://www-128.ibm.com/developerworks/cn/java/j-performance/images/image023.jpg" border="0" height="281" alt="图十一" width="658" /></p><p>如图十一所示，一共有两个用户（相同的用户id）登录系统，当一个用户使用logout页面退出时，保留在session中的菜单信息(MenuNode)立刻释放了，所以Difference一栏减少了806个菜单项。 </p><p><br /><strong><span style="color: #000000">图十二</span></strong><br /><img src="http://www-128.ibm.com/developerworks/cn/java/j-performance/images/image025.jpg" border="0" height="256" alt="图十二" width="604" /></p><p>如图十二所示，当另外一个会话超时后，应用服务器回收了整个会话的菜单信息（MenuNode），图上已经没有MenuNode对象了。并且由于是同一个用户登录，所以保留在ExternalSessionManager成员变量sessionMap中的对象WHsessionAttrVO只有一个(id=24400001129)，而没有产生多个，没有因为多次登录而产生多个对象的后果，避免了内存泄漏问题的出现，解决了前期定位的内存泄漏问题。 </p><p><br /><strong><span style="color: #000000">图十三</span></strong><br /><img src="http://www-128.ibm.com/developerworks/cn/java/j-performance/images/image027.jpg" border="0" height="335" alt="图十三" width="451" /></p><p>如图十三所示，经过gc内存回收后，发现内存回收比较稳定，基本都回收到了最低点，也证明了内存没有泄露。 </p><p>结论与建议：从测试情况看，解决了前期定位的内存泄漏问题。 </p><p><strong>生产系统实施后的监控与分析</strong> </p><p>经过调优后，我们发现：在2005年6月2日晚9点40左右重新部署、启动了Web应用服务器（采用了新的调优方案）。经过几天的监控运行，发现Web应用服务器目前运行基本稳定，目前没有出现新的内存泄漏问题，下列图示说明了这一点 </p><p><br /><strong><span style="color: #000000">图十四 2005年6月2日</span></strong><br /><img src="http://www-128.ibm.com/developerworks/cn/java/j-performance/images/image029.gif" border="0" height="224" alt="图十四 2005年6月2日" width="554" /></p><p>如图十四所示，6月2日晚21.7（21点42分）重新启动应用服务器，内存占用很少，大约为15%（请看红色曲线），每次GC消耗的时间也很短，大约在5秒以内（请看黄色曲线）。 </p><p><br /><strong><span style="color: #000000">图十五 2005年6月3日周五</span></strong><br /><img src="http://www-128.ibm.com/developerworks/cn/java/j-performance/images/image031.gif" border="0" height="248" alt="图十五 2005年6月3日周五" width="553" /></p><p>如图十五所示，在6月3日周五的整个工作日内，内存的回收基本到位，回收位置控制在20%-30%之间，也就是在600M-900M之间（请看红色曲线的最低点），始终可以回收2G的内存供应用程序使用，每次GC的时间最高不超过20秒，Full GC平均在10秒左右，时间消耗比较短（请看黄色曲线）。 </p><p><br /><strong><span style="color: #000000">图十六2005年6月5日周日</span></strong><br /><img src="http://www-128.ibm.com/developerworks/cn/java/j-performance/images/image033.gif" border="0" height="198" alt="图十六2005年6月5日周日" width="554" /></p><p>如图十六所示，在周日休息日期间，Web应用服务器全天只做了大约4次Full GC（黄色曲线中的小山峰），时间都在10秒以内；大的Full GC后，内存只占用10%，内存回收很彻底。 </p><p><br /><strong><span style="color: #000000">图十七 2005年6月6日周一</span></strong><br /><img src="http://www-128.ibm.com/developerworks/cn/java/j-performance/images/image035.gif" border="0" height="249" alt="图十七 2005年6月6日周一" width="554" /></p><p>如图十七所示，在周一工作日期间，内存回收还是不错的，基本可以回收到30%（见红色曲线的最低点），即：占用900M内存空间，剩余2G的内存空间；Full GC的时间大部分控制在20秒以内，平均15秒（见黄色曲线）。 </p><p><br /><strong><span style="color: #000000">图十八 2005年6月7日周二</span></strong><br /><img src="http://www-128.ibm.com/developerworks/cn/java/j-performance/images/image037.gif" border="0" height="208" alt="图十八 2005年6月7日周二" width="554" /></p><p>如图十八所示，在6月7日周二早上，大约8:30左右，Web应用服务器作了一次Full GC，用了10秒的时间，把内存回收到了10%的位置，为后续的使用腾出了90%的内存空间。内存回收仍然比较彻底，说明基本没有内存泄漏问题。 </p><p>经过这几天的监控分析，我们可以看出： </p><ul><li>Web应用服务器的内存使用已经比较合理，内存在工作日的占用在20%至30%之间，约1G的内存占用，有2G的内存空间富裕；而在空闲时间（周日，每天的凌晨等）内存可以回收到10%，有90%的内存空间富裕； </li><li>Web应用服务器的Full GC的次数明显减少了并且每次Full GC占用的时间也很少，基本控制在10-20秒之间，有的甚至在10秒以内，明显改善了内网应用服务器内存的使用； </li><li>从6月2日重新部署之后，Web应用服务器没有出现宕机重启的现象。</li></ul><p>&nbsp;</p><p><table cellspacing="0" border="0" width="100%" cellpadding="0"><tbody><tr><td><img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" height="1" alt="" width="100%" /></td></tr></tbody></table></p><p><span><span style="font-size: medium; color: #000000; font-family: Arial">总结</span></span></p><p>&nbsp;通过本文，我们可以看到，内存的泄露将会导致服务器的宕机，系统性能就更别说了。对于系统内存泄露问题应该从服务器GC日志方面进行早诊断，使用工具早确认并提出解决方案，排除内存泄露问题，提高系统性能，以规避项目风险。 </p><p>原作者：<a href="http://spaces.msn.com/mmm2005-11-01_10.54/#author"><span style="color: #5c81a7">曾胜财 </span></a>, IBM BCS 部门 I/T架构师</p>
          <br/>
          <span style="color:red;">
            <a href="http://yufeimen.javaeye.com/blog/70721#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, 13 Apr 2007 20:34:33 +0800</pubDate>
        <link>http://yufeimen.javaeye.com/blog/70721</link>
        <guid>http://yufeimen.javaeye.com/blog/70721</guid>
      </item>
      <item>
        <title>JDK6 Web Service开发(转贴)</title>
        <author>yufeimen</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://yufeimen.javaeye.com">yufeimen</a>&nbsp;
          链接：<a href="http://yufeimen.javaeye.com/blog/68192" style="color:red;">http://yufeimen.javaeye.com/blog/68192</a>&nbsp;
          发表时间: 2007年04月05日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>JSR-181的元数据清单<br />下面介绍JSR-181里面各个元数据的相关参数及用途<br />Annotation&nbsp;Retention&nbsp;Target&nbsp;Description&nbsp;<br />&nbsp;WebService&nbsp;&nbsp;Runtime&nbsp;Type&nbsp;<br />&nbsp;标注要暴露为Web&nbsp;Services的类或接口&nbsp;<br />&nbsp;WebParam&nbsp;&nbsp;Runtime&nbsp;Parameter&nbsp;自定义服务方法参数到WSDL的映射&nbsp;<br />&nbsp;WebResult&nbsp;&nbsp;Runtime&nbsp;Method&nbsp;自定义服务方法返回值到WSDL的映射&nbsp;<br />&nbsp;WebMethod&nbsp;&nbsp;Runtime&nbsp;Method&nbsp;自定义单个服务方法到WSDL的映射&nbsp;<br />&nbsp;Oneway&nbsp;&nbsp;Runtime&nbsp;Method&nbsp;必须与@WebMethod连用,表明被标注方法只有输入没有输出,这就要求被标注方法不能有返回值,也不能声明checked&nbsp;exception<br />&nbsp;<br />&nbsp;HandlerChain&nbsp;&nbsp;Runtime&nbsp;Type,Method,Field&nbsp;将Web服务与外部Handler&nbsp;chain关联起来&nbsp;<br />&nbsp;SOAPBinding&nbsp;&nbsp;Runtime&nbsp;Type,Method&nbsp;自定义SOAPBinding&nbsp;<br /><br />JSR-181元数据使用示例<br /><br />package&nbsp;WebServices;<br /><br />import&nbsp;java.io.File;<br />import&nbsp;java.io.IOException;<br />import&nbsp;javax.jws.Oneway;<br />import&nbsp;javax.jws.WebMethod;<br />import&nbsp;javax.jws.WebParam;<br />import&nbsp;javax.jws.WebResult;<br />import&nbsp;javax.jws.WebService;<br />import&nbsp;javax.xml.ws.Endpoint;<br /><br />/**<br />&nbsp;*&nbsp;@author&nbsp;chinajash<br />&nbsp;*/<br />@WebService(targetNamespace=&quot;http://blog.csdn.net/chinajash&quot;,serviceName=&quot;HelloService&quot;)<br />public&nbsp;class&nbsp;WSProvider&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;@WebResult(name=&quot;Greetings&quot;)//自定义该方法返回值在WSDL中相关的描述&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;@WebMethod<br />&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;String&nbsp;sayHi(@WebParam(name=&quot;MyName&quot;)&nbsp;String&nbsp;name){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;&quot;Hi,&quot;+name;&nbsp;//@WebParam是自定义参数name在WSDL中相关的描述<br />&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;@Oneway&nbsp;//表明该服务方法是单向的,既没有返回值,也不应该声明检查异常<br />&nbsp;&nbsp;&nbsp;&nbsp;@WebMethod(action=&quot;printSystemTime&quot;,operationName=&quot;printSystemTime&quot;)//自定义该方法在WSDL中相关的描述<br />&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;printTime(){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(System.currentTimeMillis());<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread&nbsp;wsPublisher&nbsp;=&nbsp;new&nbsp;Thread(new&nbsp;WSPublisher());<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wsPublisher.start();<br />&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;static&nbsp;class&nbsp;WSPublisher&nbsp;implements&nbsp;Runnable{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;run()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//发布WSProvider到http://localhost:8888/chinajash/WSProvider这个地址,之前必须调用wsgen命令<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//生成服务类WSProvider的支持类,命令如下:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//wsgen&nbsp;-cp&nbsp;.&nbsp;WebServices.WSProvider<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Endpoint.publish(&quot;http://localhost:8888/chinajash/WSProvider&quot;,new&nbsp;WSProvider());<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}<br /><br />如果想看到Web&nbsp;Services&nbsp;Engine生成的WSDL文件是否遵守上面的元数据,&nbsp;我们没有必要将上面的WSProvider部署到支持JSR-181的应用服务器或Servlet形式的Web&nbsp;Services&nbsp;Engine,现在JDK6已经提供了一个很简单的机制可以用来测试和发布Web&nbsp;Services,下面讲讲如何在JDK6环境下发布Web&nbsp;Services和查看生成的WSDL<br />1.将/bin加入path环境变量<br />2.在命令行下切换当前目录到WSProvider的class文件所在的目录,运行下面命令<br />wsgen&nbsp;-cp&nbsp;.&nbsp;WebServices.WSProvider<br />在这个例子中会生成以下3个类的源代码文件及class文件<br />SayHi<br />SayHiResponse<br />PrintTime<br />3.执行如下代码发布WSProvider到http://localhost:8888/chinajash/WSProvider,在这里可以执行WSProvider类的main方法就可以<br />Endpoint.publish(&quot;http://localhost:8888/chinajash/WSProvider&quot;,new&nbsp;WSProvider());<br />4.在浏览器输入<a href="http://localhost:8888/chinajash/WSProvider?wsdl">http://localhost:8888/chinajash/WSProvider?wsdl</a>就可以看到生成的WSDL文件</p><p>/**.用wsimport为服务消费者(也就是服务的客户端)生成必要的帮助类,命令如下:<br />wsimport&nbsp;http://localhost:8888/chinajash/WSProvider?wsdl<br />这会在&lt;当前目录&gt;\net\csdn\blog\chinajash下生成客户端的帮助类,在这个例子中会生成7个类<br />HelloService.class<br />ObjectFactory.class<br />package-info.class<br />PrintSystemTime.class<br />SayHi.class<br />SayHiResponse.class<br />WSProvider.class<br />在客户端用下面代码即可调用步骤1定义的Web&nbsp;Service<br />HelloService&nbsp;hs&nbsp;=&nbsp;new&nbsp;HelloService();<br />WSProvider&nbsp;ws&nbsp;=&nbsp;hs.getWSProviderPort();<br />System.out.println(ws.sayHi(&quot;chinajash&quot;));<br />ws.printSystemTime();<br />调用上述代码后客户端控制台输出<br />hi,chinajash<br />服务端控制台输出服务器当前系统时间</p><p>*/</p>
          <br/>
          <span style="color:red;">
            <a href="http://yufeimen.javaeye.com/blog/68192#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>Thu, 05 Apr 2007 01:33:08 +0800</pubDate>
        <link>http://yufeimen.javaeye.com/blog/68192</link>
        <guid>http://yufeimen.javaeye.com/blog/68192</guid>
      </item>
  </channel>
</rss>