<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>美丽人生</title>
    <description></description>
    <link>http://fzfx88.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>正确使用 Volatile 变量</title>
        <author>fzfx88</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fzfx88.javaeye.com">fzfx88</a>&nbsp;
          链接：<a href="http://fzfx88.javaeye.com/blog/195163" style="color:red;">http://fzfx88.javaeye.com/blog/195163</a>&nbsp;
          发表时间: 2008年05月21日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>Java&trade; 语言包含两种内在的同步机制：同步块（或方法）和 volatile 变量。这两种机制的提出都是为了实现代码线程的安全性。其中 Volatile 变量的同步性较差（但有时它更简单并且开销更低），而且其使用也更容易出错。在这期的 Java 理论与实践 中，Brian Goetz 将介绍几种正确使用 volatile 变量的模式，并针对其适用性限制提出一些建议。 <br />Java 语言中的 volatile 变量可以被看作是一种 &ldquo;程度较轻的 synchronized&rdquo;；与 synchronized 块相比，volatile 变量所需的编码较少，并且运行时开销也较少，但是它所能实现的功能也仅是 synchronized 的一部分。本文介绍了几种有效使用 volatile 变量的模式，并强调了几种不适合使用 volatile 变量的情形。 </p>
<p>锁提供了两种主要特性：互斥（mutual exclusion） 和可见性（visibility）。互斥即一次只允许一个线程持有某个特定的锁，因此可使用该特性实现对共享数据的协调访问协议，这样，一次就只有一个线程能够使用该共享数据。可见性要更加复杂一些，它必须确保释放锁之前对共享数据做出的更改对于随后获得该锁的另一个线程是可见的 &mdash;&mdash; 如果没有同步机制提供的这种可见性保证，线程看到的共享变量可能是修改前的值或不一致的值，这将引发许多严重问题。 </p>
<p>Volatile 变量</p>
<p>Volatile 变量具有 synchronized 的可见性特性，但是不具备原子特性。这就是说线程能够自动发现 volatile 变量的最新值。Volatile 变量可用于提供线程安全，但是只能应用于非常有限的一组用例：多个变量之间或者某个变量的当前值与修改后值之间没有约束。因此，单独使用 volatile 还不足以实现计数器、互斥锁或任何具有与多个变量相关的不变式（Invariants）的类（例如 &ldquo;start &lt;=end&rdquo;）。 </p>
<p>出于简易性或可伸缩性的考虑，您可能倾向于使用 volatile 变量而不是锁。当使用 volatile 变量而非锁时，某些习惯用法（idiom）更加易于编码和阅读。此外，volatile 变量不会像锁那样造成线程阻塞，因此也很少造成可伸缩性问题。在某些情况下，如果读操作远远大于写操作，volatile 变量还可以提供优于锁的性能优势。 </p>
<p>正确使用 volatile 变量的条件</p>
<p>您只能在有限的一些情形下使用 volatile 变量替代锁。要使 volatile 变量提供理想的线程安全，必须同时满足下面两个条件： </p>
<p>对变量的写操作不依赖于当前值。 <br />该变量没有包含在具有其他变量的不变式中。 </p>
<p>实际上，这些条件表明，可以被写入 volatile 变量的这些有效值独立于任何程序的状态，包括变量的当前状态。 </p>
<p>第一个条件的限制使 volatile 变量不能用作线程安全计数器。虽然增量操作（x++）看上去类似一个单独操作，实际上它是一个由读取－修改－写入操作序列组成的组合操作，必须以原子方式执行，而 volatile 不能提供必须的原子特性。实现正确的操作需要使 x 的值在操作期间保持不变，而 volatile 变量无法实现这点。（然而，如果将值调整为只从单个线程写入，那么可以忽略第一个条件。） </p>
<p>大多数编程情形都会与这两个条件的其中之一冲突，使得 volatile 变量不能像 synchronized 那样普遍适用于实现线程安全。清单 1 显示了一个非线程安全的数值范围类。它包含了一个不变式 &mdash;&mdash; 下界总是小于或等于上界。 </p>
<p><br />清单 1. 非线程安全的数值范围类</p>
<pre name="code" class="java">@NotThreadSafe 
public class NumberRange {
    private int lower, upper;

    public int getLower() { return lower; }
    public int getUpper() { return upper; }

    public void setLower(int value) { 
        if (value &gt; upper) 
            throw new IllegalArgumentException(...);
        lower = value;
    }

    public void setUpper(int value) { 
        if (value &lt; lower) 
            throw new IllegalArgumentException(...);
        upper = value;
    }
}
</pre>
<p>&nbsp;</p>
<p>这种方式限制了范围的状态变量，因此将 lower 和 upper 字段定义为 volatile 类型不能够充分实现类的线程安全；从而仍然需要使用同步。否则，如果凑巧两个线程在同一时间使用不一致的值执行 setLower 和 setUpper 的话，则会使范围处于不一致的状态。例如，如果初始状态是 (0, 5)，同一时间内，线程 A 调用 setLower(4) 并且线程 B 调用 setUpper(3)，显然这两个操作交叉存入的值是不符合条件的，那么两个线程都会通过用于保护不变式的检查，使得最后的范围值是 (4, 3) &mdash;&mdash; 一个无效值。至于针对范围的其他操作，我们需要使 setLower() 和 setUpper() 操作原子化 &mdash;&mdash; 而将字段定义为 volatile 类型是无法实现这一目的的。 </p>
<p>性能考虑</p>
<p>使用 volatile 变量的主要原因是其简易性：在某些情形下，使用 volatile 变量要比使用相应的锁简单得多。使用 volatile 变量次要原因是其性能：某些情况下，volatile 变量同步机制的性能要优于锁。 </p>
<p>很难做出准确、全面的评价，例如 &ldquo;X 总是比 Y 快&rdquo;，尤其是对 JVM 内在的操作而言。（例如，某些情况下 VM 也许能够完全删除锁机制，这使得我们难以抽象地比较 volatile 和 synchronized 的开销。）就是说，在目前大多数的处理器架构上，volatile 读操作开销非常低 &mdash;&mdash; 几乎和非 volatile 读操作一样。而 volatile 写操作的开销要比非 volatile 写操作多很多，因为要保证可见性需要实现内存界定（Memory Fence），即便如此，volatile 的总开销仍然要比锁获取低。 </p>
<p>volatile 操作不会像锁一样造成阻塞，因此，在能够安全使用 volatile 的情况下，volatile 可以提供一些优于锁的可伸缩特性。如果读操作的次数要远远超过写操作，与锁相比，volatile 变量通常能够减少同步的性能开销。 </p>
<p>正确使用 volatile 的模式</p>
<p>很多并发性专家事实上往往引导用户远离 volatile 变量，因为使用它们要比使用锁更加容易出错。然而，如果谨慎地遵循一些良好定义的模式，就能够在很多场合内安全地使用 volatile 变量。要始终牢记使用 volatile 的限制 &mdash;&mdash; 只有在状态真正独立于程序内其他内容时才能使用 volatile &mdash;&mdash; 这条规则能够避免将这些模式扩展到不安全的用例。 </p>
<p>模式 #1：状态标志</p>
<p>也许实现 volatile 变量的规范使用仅仅是使用一个布尔状态标志，用于指示发生了一个重要的一次性事件，例如完成初始化或请求停机。 </p>
<p>很多应用程序包含了一种控制结构，形式为 &ldquo;在还没有准备好停止程序时再执行一些工作&rdquo;，如清单 2 所示： </p>
<p><br />清单 2. 将 volatile 变量作为状态标志使用</p>
<pre name="code" class="java">volatile boolean shutdownRequested;

...

public void shutdown() { shutdownRequested = true; }

public void doWork() { 
    while (!shutdownRequested) { 
        // do stuff
    }
}
</pre>
<p>&nbsp;</p>
<p>很可能会从循环外部调用 shutdown() 方法 &mdash;&mdash; 即在另一个线程中 &mdash;&mdash; 因此，需要执行某种同步来确保正确实现 shutdownRequested 变量的可见性。（可能会从 JMX 侦听程序、GUI 事件线程中的操作侦听程序、通过 RMI 、通过一个 Web 服务等调用）。然而，使用 synchronized 块编写循环要比使用清单 2 所示的 volatile 状态标志编写麻烦很多。由于 volatile 简化了编码，并且状态标志并不依赖于程序内任何其他状态，因此此处非常适合使用 volatile。 </p>
<p>这种类型的状态标记的一个公共特性是：通常只有一种状态转换；shutdownRequested 标志从 false 转换为 true，然后程序停止。这种模式可以扩展到来回转换的状态标志，但是只有在转换周期不被察觉的情况下才能扩展（从 false 到 true，再转换到 false）。此外，还需要某些原子状态转换机制，例如原子变量。 </p>
<p>模式 #2：一次性安全发布（one-time safe publication）</p>
<p>缺乏同步会导致无法实现可见性，这使得确定何时写入对象引用而不是原语值变得更加困难。在缺乏同步的情况下，可能会遇到某个对象引用的更新值（由另一个线程写入）和该对象状态的旧值同时存在。（这就是造成著名的双重检查锁定（double-checked-locking）问题的根源，其中对象引用在没有同步的情况下进行读操作，产生的问题是您可能会看到一个更新的引用，但是仍然会通过该引用看到不完全构造的对象）。 </p>
<p>实现安全发布对象的一种技术就是将对象引用定义为 volatile 类型。清单 3 展示了一个示例，其中后台线程在启动阶段从数据库加载一些数据。其他代码在能够利用这些数据时，在使用之前将检查这些数据是否曾经发布过。 </p>
<p><br />清单 3. 将 volatile 变量用于一次性安全发布</p>
<pre name="code" class="java">public class BackgroundFloobleLoader {
    public volatile Flooble theFlooble;

    public void initInBackground() {
        // do lots of stuff
        theFlooble = new Flooble();  // this is the only write to theFlooble
    }
}

public class SomeOtherClass {
    public void doWork() {
        while (true) { 
            // do some stuff...
            // use the Flooble, but only if it is ready
            if (floobleLoader.theFlooble != null) 
                doSomething(floobleLoader.theFlooble);
        }
    }
}
</pre>
<p>&nbsp;</p>
<p>如果 theFlooble 引用不是 volatile 类型，doWork() 中的代码在解除对 theFlooble 的引用时，将会得到一个不完全构造的 Flooble。 </p>
<p>该模式的一个必要条件是：被发布的对象必须是线程安全的，或者是有效的不可变对象（有效不可变意味着对象的状态在发布之后永远不会被修改）。volatile 类型的引用可以确保对象的发布形式的可见性，但是如果对象的状态在发布后将发生更改，那么就需要额外的同步。 </p>
<p>模式 #3：独立观察（independent observation）</p>
<p>安全使用 volatile 的另一种简单模式是：定期 &ldquo;发布&rdquo; 观察结果供程序内部使用。例如，假设有一种环境传感器能够感觉环境温度。一个后台线程可能会每隔几秒读取一次该传感器，并更新包含当前文档的 volatile 变量。然后，其他线程可以读取这个变量，从而随时能够看到最新的温度值。 </p>
<p>使用该模式的另一种应用程序就是收集程序的统计信息。清单 4 展示了身份验证机制如何记忆最近一次登录的用户的名字。将反复使用 lastUser 引用来发布值，以供程序的其他部分使用。 </p>
<p><br />清单 4. 将 volatile 变量用于多个独立观察结果的发布</p>
<pre name="code" class="java">public class UserManager {
    public volatile String lastUser;

    public boolean authenticate(String user, String password) {
        boolean valid = passwordIsValid(user, password);
        if (valid) {
            User u = new User();
            activeUsers.add(u);
            lastUser = user;
        }
        return valid;
    }
} 
</pre>
<p>&nbsp;</p>
<p>该模式是前面模式的扩展；将某个值发布以在程序内的其他地方使用，但是与一次性事件的发布不同，这是一系列独立事件。这个模式要求被发布的值是有效不可变的 &mdash;&mdash; 即值的状态在发布后不会更改。使用该值的代码需要清楚该值可能随时发生变化。 </p>
<p>模式 #4：&ldquo;volatile bean&rdquo; 模式</p>
<p>volatile bean 模式适用于将 JavaBeans 作为&ldquo;荣誉结构&rdquo;使用的框架。在 volatile bean 模式中，JavaBean 被用作一组具有 getter 和/或 setter 方法 的独立属性的容器。volatile bean 模式的基本原理是：很多框架为易变数据的持有者（例如 HttpSession）提供了容器，但是放入这些容器中的对象必须是线程安全的。 </p>
<p>在 volatile bean 模式中，JavaBean 的所有数据成员都是 volatile 类型的，并且 getter 和 setter 方法必须非常普通 &mdash;&mdash; 除了获取或设置相应的属性外，不能包含任何逻辑。此外，对于对象引用的数据成员，引用的对象必须是有效不可变的。（这将禁止具有数组值的属性，因为当数组引用被声明为 volatile 时，只有引用而不是数组本身具有 volatile 语义）。对于任何 volatile 变量，不变式或约束都不能包含 JavaBean 属性。清单 5 中的示例展示了遵守 volatile bean 模式的 JavaBean： </p>
<p><br />清单 5. 遵守 volatile bean 模式的 Person 对象</p>
<pre name="code" class="java">@ThreadSafe
public class Person {
    private volatile String firstName;
    private volatile String lastName;
    private volatile int age;

    public String getFirstName() { return firstName; }
    public String getLastName() { return lastName; }
    public int getAge() { return age; }

    public void setFirstName(String firstName) { 
        this.firstName = firstName;
    }

    public void setLastName(String lastName) { 
        this.lastName = lastName;
    }

    public void setAge(int age) { 
        this.age = age;
    }
}
</pre>
<p>&nbsp;</p>
<p>volatile 的高级模式</p>
<p>前面几节介绍的模式涵盖了大部分的基本用例，在这些模式中使用 volatile 非常有用并且简单。这一节将介绍一种更加高级的模式，在该模式中，volatile 将提供性能或可伸缩性优势。 </p>
<p>volatile 应用的的高级模式非常脆弱。因此，必须对假设的条件仔细证明，并且这些模式被严格地封装了起来，因为即使非常小的更改也会损坏您的代码！同样，使用更高级的 volatile 用例的原因是它能够提升性能，确保在开始应用高级模式之前，真正确定需要实现这种性能获益。需要对这些模式进行权衡，放弃可读性或可维护性来换取可能的性能收益 &mdash;&mdash; 如果您不需要提升性能（或者不能够通过一个严格的测试程序证明您需要它），那么这很可能是一次糟糕的交易，因为您很可能会得不偿失，换来的东西要比放弃的东西价值更低。 </p>
<p>模式 #5：开销较低的读－写锁策略</p>
<p>目前为止，您应该了解了 volatile 的功能还不足以实现计数器。因为 ++x 实际上是三种操作（读、添加、存储）的简单组合，如果多个线程凑巧试图同时对 volatile 计数器执行增量操作，那么它的更新值有可能会丢失。 </p>
<p>然而，如果读操作远远超过写操作，您可以结合使用内部锁和 volatile 变量来减少公共代码路径的开销。清单 6 中显示的线程安全的计数器使用 synchronized 确保增量操作是原子的，并使用 volatile 保证当前结果的可见性。如果更新不频繁的话，该方法可实现更好的性能，因为读路径的开销仅仅涉及 volatile 读操作，这通常要优于一个无竞争的锁获取的开销。 </p>
<p><br />清单 6. 结合使用 volatile 和 synchronized 实现 &ldquo;开销较低的读－写锁&rdquo; </p>
<pre name="code" class="java">@ThreadSafe
public class CheesyCounter {
    // Employs the cheap read-write lock trick
    // All mutative operations MUST be done with the 'this' lock held
    @GuardedBy("this") private volatile int value;

    public int getValue() { return value; }

    public synchronized int increment() {
        return value++;
    }
}
</pre>
<p>&nbsp;</p>
<p>之所以将这种技术称之为 &ldquo;开销较低的读－写锁&rdquo; 是因为您使用了不同的同步机制进行读写操作。因为本例中的写操作违反了使用 volatile 的第一个条件，因此不能使用 volatile 安全地实现计数器 &mdash;&mdash; 您必须使用锁。然而，您可以在读操作中使用 volatile 确保当前值的可见性，因此可以使用锁进行所有变化的操作，使用 volatile 进行只读操作。其中，锁一次只允许一个线程访问值，volatile 允许多个线程执行读操作，因此当使用 volatile 保证读代码路径时，要比使用锁执行全部代码路径获得更高的共享度 &mdash;&mdash; 就像读－写操作一样。然而，要随时牢记这种模式的弱点：如果超越了该模式的最基本应用，结合这两个竞争的同步机制将变得非常困难。 </p>
<p>结束语</p>
<p>与锁相比，Volatile 变量是一种非常简单但同时又非常脆弱的同步机制，它在某些情况下将提供优于锁的性能和伸缩性。如果严格遵循 volatile 的使用条件 &mdash;&mdash; 即变量真正独立于其他变量和自己以前的值 &mdash;&mdash; 在某些情况下可以使用 volatile 代替 synchronized 来简化代码。然而，使用 volatile 的代码往往比使用锁的代码更加容易出错。本文介绍的模式涵盖了可以使用 volatile 代替 synchronized 的最常见的一些用例。遵循这些模式（注意使用时不要超过各自的限制）可以帮助您安全地实现大多数用例，使用 volatile 变量获得更佳性能。</p>
          <br/>
          <span style="color:red;">
            <a href="http://fzfx88.javaeye.com/blog/195163#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, 21 May 2008 11:30:16 +0800</pubDate>
        <link>http://fzfx88.javaeye.com/blog/195163</link>
        <guid>http://fzfx88.javaeye.com/blog/195163</guid>
      </item>
      <item>
        <title>构建一个更好的 HashMap</title>
        <author>fzfx88</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fzfx88.javaeye.com">fzfx88</a>&nbsp;
          链接：<a href="http://fzfx88.javaeye.com/blog/195140" style="color:red;">http://fzfx88.javaeye.com/blog/195140</a>&nbsp;
          发表时间: 2008年05月21日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>ConcurrentHashMap 是 Doug Lea 的 util.concurrent 包的一部分，它提供比Hashtable 或者 synchronizedMap 更高程度的并发性。而且，对于大多数成功的 get() 操作它会设法避免完全锁定，其结果就是使得并发应用程序有着非常好的吞吐量。这个月，BrianGoetz 仔细分析了 ConcurrentHashMap 的代码，并探讨 Doug Lea 是如何在不损失线程安全的情况下取得这么骄人成绩的。请在 讨论论坛上与作者及其他读者共享您对本文的一些想法（也可以在文章的顶部或底部点击 讨论来访问论坛）。 <br />在7月份的那期 Java理论与实践（&ldquo; Concurrent collections classes&rdquo;）中，我们简单地回顾了可伸缩性的瓶颈，并讨论了怎么用共享数据结构的方法获得更高的并发性和吞吐量。有时候学习的最好方法是分析专家的成果，所以这个月我们将分析 Doug Lea 的 util.concurrent 包中的 ConcurrentHashMap 的实现。JSR 133 将指定 ConcurrentHashMap 的一个版本，该版本针对 Java 内存模型（JMM）作了优化，它将包含在 JDK 1.5 的 java.util.concurrent 包中。 util.concurrent 中的版本在老的和新的内存模型中都已通过线程安全审核。 </p>
<p>针对吞吐量进行优化</p>
<p>ConcurrentHashMap 使用了几个技巧来获得高程度的并发以及避免锁定，包括为不同的 hash bucket（桶）使用多个写锁和使用 JMM 的不确定性来最小化锁被保持的时间――或者根本避免获取锁。对于大多数一般用法来说它是经过优化的，这些用法往往会检索一个很可能在 map 中已经存在的值。事实上，多数成功的 get() 操作根本不需要任何锁定就能运行。（警告：不要自己试图这样做！想比 JMM 聪明不像看上去的那么容易。 util.concurrent 类是由并发专家编写的，并且在 JMM 安全性方面经过了严格的同行评审。） </p>
<p>多个写锁</p>
<p>我们可以回想一下，Hashtable（或者替代方案 Collections.synchronizedMap ）的可伸缩性的主要障碍是它使用了一个 map 范围（map-wide）的锁，为了保证插入、删除或者检索操作的完整性必须保持这样一个锁，而且有时候甚至还要为了保证迭代遍历操作的完整性保持这样一个锁。这样一来，只要锁被保持，就从根本上阻止了其他线程访问 Map，即使处理器有空闲也不能访问，这样大大地限制了并发性。 </p>
<p>ConcurrentHashMap 摒弃了单一的 map 范围的锁，取而代之的是由 32 个锁组成的集合，其中每个锁负责保护 hash bucket 的一个子集。锁主要由变化性操作（ put() 和 remove() ）使用。具有 32 个独立的锁意味着最多可以有 32 个线程可以同时修改 map。这并不一定是说在并发地对 map 进行写操作的线程数少于 32 时，另外的写操作不会被阻塞――32 对于写线程来说是理论上的并发限制数目，但是实际上可能达不到这个值。但是，32 依然比 1 要好得多，而且对于运行于目前这一代的计算机系统上的大多数应用程序来说已经足够了。&amp;#160 </p>
<p>map 范围的操作</p>
<p>有 32 个独立的锁，其中每个锁保护 hash bucket 的一个子集，这样需要独占访问 map 的操作就必须获得所有32个锁。一些 map 范围的操作，比如说 size() 和 isEmpty()， 也许能够不用一次锁整个 map（通过适当地限定这些操作的语义），但是有些操作，比如 map 重排（扩大 hash bucket 的数量，随着 map 的增长重新分布元素），则必须保证独占访问。Java 语言不提供用于获取可变大小的锁集合的简便方法。必须这么做的情况很少见，一旦碰到这种情况，可以用递归方法来实现。 </p>
<p>JMM概述</p>
<p>在进入 put() 、 get() 和 remove() 的实现之前，让我们先简单地看一下 JMM。JMM 掌管着一个线程对内存的动作（读和写）影响其他线程对内存的动作的方式。由于使用处理器寄存器和预处理 cache 来提高内存访问速度带来的性能提升，Java 语言规范（JLS）允许一些内存操作并不对于所有其他线程立即可见。有两种语言机制可用于保证跨线程内存操作的一致性―― synchronized 和 volatile。 </p>
<p>按照 JLS 的说法，&ldquo;在没有显式同步的情况下，一个实现可以自由地更新主存，更新时所采取的顺序可能是出人意料的。&rdquo;其意思是说，如果没有同步的话，在一个给定线程中某种顺序的写操作对于另外一个不同的线程来说可能呈现出不同的顺序， 并且对内存变量的更新从一个线程传播到另外一个线程的时间是不可预测的。 </p>
<p>虽然使用同步最常见的原因是保证对代码关键部分的原子访问，但实际上同步提供三个独立的功能――原子性、可见性和顺序性。原子性非常简单――同步实施一个可重入的（reentrant）互斥，防止多于一个的线程同时执行由一个给定的监视器保护的代码块。不幸的是，多数文章都只关注原子性方面，而忽略了其他方面。但是同步在 JMM 中也扮演着很重要的角色，会引起 JVM 在获得和释放监视器的时候执行内存壁垒（memory barrier）。 </p>
<p>一个线程在获得一个监视器之后，它执行一个 读屏障（read barrier）――使得缓存在线程局部内存（比如说处理器缓存或者处理器寄存器）中的所有变量都失效，这样就会导致处理器重新从主存中读取同步代码块使用的变量。与此类似，在释放监视器时，线程会执行一个 写屏障（write barrier）――将所有修改过的变量写回主存。互斥独占和内存壁垒结合使用意味着只要您在程序设计的时候遵循正确的同步法则（也就是说，每当写一个后面可能被其他线程访问的变量，或者读取一个可能最后被另一个线程修改的变量时，都要使用同步），每个线程都会得到它所使用的共享变量的正确的值。 </p>
<p>如果在访问共享变量的时候没有同步的话，就会发生一些奇怪的事情。一些变化可能会通过线程立即反映出来，而其他的则需要一些时间（这由关联缓存的本质所致）。结果，如果没有同步您就不能保证内存内容必定一致（相关的变量相互间可能会不一致），或者不能得到当前的内存内容（一些值可能是过时的）。避免这种危险情况的常用方法（也是推荐使用的方法）当然是正确地使用同步。然而在有些情况下，比如说在像 ConcurrentHashMap 之类的一些使用非常广泛的库类中，在开发过程当中还需要一些额外的专业技能和努力（可能比一般的开发要多出很多倍）来获得较高的性能。 </p>
<p>ConcurrentHashMap 实现</p>
<p>如前所述， ConcurrentHashMap 使用的数据结构与 Hashtable 或 HashMap 的实现类似，是 hash bucket 的一个可变数组，每个 ConcurrentHashMap 都由一个 Map.Entry 元素链构成，如清单1所示。与 Hashtable 和 HashMap 不同的是， ConcurrentHashMap 没有使用单一的集合锁（collection lock），而是使用了一个固定的锁池，这个锁池形成了bucket 集合的一个分区。 </p>
<p><br />清单1. ConcurrentHashMap 使用的 Map.Entry 元素</p>
<pre name="code" class="java">protected static class Entry implements Map.Entry {
    protected final Object key;
    protected volatile Object value;
    protected final int hash;
    protected final Entry next;
    ...
}
</pre>
<p>&nbsp;</p>
<p>不用锁定遍历数据结构</p>
<p>与 Hashtable 或者典型的锁池 Map 实现不同， ConcurrentHashMap.get() 操作不一定需要获取与相关bucket 相关联的锁。如果不使用锁定，那么实现必须有能力处理它用到的所有变量的过时的或者不一致的值，比如说列表头指针和 Map.Entry 元素的域（包括组成每个 hash bucket 条目的链表的链接指针）。 </p>
<p>大多并发类使用同步来保证独占式访问一个数据结构（以及保持数据结构的一致性）。 ConcurrentHashMap 没有采用独占性和一致性，它使用的链表是经过精心设计的，所以其实现可以 检测 到它的列表是否一致或者已经过时。如果它检测到它的列表出现不一致或者过时，或者干脆就找不到它要找的条目，它就会对适当的bucket 锁进行同步并再次搜索整个链。这样做在一般的情况下可以优化查找，所谓的一般情况是指大多数检索操作是成功的并且检索的次数多于插入和删除的次数。 </p>
<p>使用不变性</p>
<p>不一致性的一个重要来源是可以避免得，其方法是使 Entry 元素接近不变性――除了值字段（它们是易变的）之外，所有字段都是 final 的。这就意味着不能将元素添加到 hash 链的中间或末尾，或者从 hash 链的中间或末尾删除元素――而只能从 hash 链的开头添加元素，并且删除操作包括克隆整个链或链的一部分并更新列表的头指针。所以说只要有对某个 hash 链的一个引用，即使可能不知道有没有对列表头节点的引用，您也可以知道列表的其余部分的结构不会改变。而且，因为值字段是易变的，所以能够立即看到对值字段的更新，从而大大简化了编写能够处理内存潜在过时的 Map 的实现。 </p>
<p>新的 JMM 为 final 型变量提供初始化安全，而老的 JMM 不提供，这意味着另一个线程看到的可能是 final 字段的默认值，而不是对象的构造方法提供的值。实现必须能够同时检测到这一点，这是通过保证 Entry 中每个字段的默认值不是有效值来实现的。这样构造好列表之后，如果任何一个 Entry 字段有其默认值（零或空），搜索就会失败，提示同步 get() 并再次遍历链。 </p>
<p>检索操作</p>
<p>检索操作首先为目标 bucket 查找头指针（是在不锁定的情况下完成的，所以说可能是过时的），然后在不获取 bucket 锁的情况下遍历 bucket 链。如果它不能发现要查找的值，就会同步并试图再次查找条目，如清单2所示： </p>
<p><br />清单2. ConcurrentHashMap.get() 实现</p>
<pre name="code" class="java">  public Object get(Object key) {
    int hash = hash(key);     // throws null pointer exception if key is null
    // Try first without locking...
    Entry[] tab = table;
    int index = hash &amp; (tab.length - 1);
    Entry first = tab[index];
    Entry e;
    for (e = first; e != null; e = e.next) {
      if (e.hash == hash &amp;&amp; eq(key, e.key)) {
        Object value = e.value;
        // null values means that the element has been removed
        if (value != null) 
          return value;
        else
          break;
      }
    }
    // Recheck under synch if key apparently not there or interference
    Segment seg = segments[hash &amp; SEGMENT_MASK];
    synchronized(seg) { 
      tab = table;
      index = hash &amp; (tab.length - 1);
      Entry newFirst = tab[index];
      if (e != null || first != newFirst) {
        for (e = newFirst; e != null; e = e.next) {
          if (e.hash == hash &amp;&amp; eq(key, e.key)) 
            return e.value;
        }
      }
      return null;
    }
  }
</pre>
<p>&nbsp;</p>
<p>删除操作</p>
<p>因为一个线程可能看到 hash 链中链接指针的过时的值，简单地从链中删除一个元素不足以保证其他线程在进行查找的时候不继续看到被删除的值。相反，从清单3我们可以看到，删除操作分两个过程――首先找到适当的 Entry 对象并把其值字段设为 null ，然后对链中从头元素到要删除的元素的部分进行克隆，再连接到要删除的元素之后的部分。因为值字段是易变的，如果另外一个线程正在过时的链中查找那个被删除的元素，它会立即看到一个空值，并知道使用同步重新进行检索。最终，原始 hash 链中被删除的元素将会被垃圾收集。 </p>
<p><br />清单3. ConcurrentHashMap.remove() 实现</p>
<pre name="code" class="java">protected Object remove(Object key, Object value) {
    /*
      Find the entry, then 
        1. Set value field to null, to force get() to retry
        2. Rebuild the list without this entry.
           All entries following removed node can stay in list, but
           all preceding ones need to be cloned.  Traversals rely
           on this strategy to ensure that elements will not be
          repeated during iteration.
    */
    int hash = hash(key);
    Segment seg = segments[hash &amp; SEGMENT_MASK];
    synchronized(seg) {
      Entry[] tab = table;
      int index = hash &amp; (tab.length-1);
      Entry first = tab[index];
      Entry e = first;
      for (;;) {
        if (e == null)
          return null;
        if (e.hash == hash &amp;&amp; eq(key, e.key)) 
          break;
        e = e.next;
      }
      Object oldValue = e.value;
      if (value != null &amp;&amp; !value.equals(oldValue))
        return null;
     
      e.value = null;
      Entry head = e.next;
      for (Entry p = first; p != e; p = p.next) 
        head = new Entry(p.hash, p.key, p.value, head);
      tab[index] = head;
      seg.count--;
      return oldValue;
    }
  }
</pre>
<p>&nbsp;</p>
<p>图1为删除一个元素之前的 hash 链：</p>
<p><br />图1. Hash链<br /><img src="http://www.ibm.com/developerworks/cn/java/j-jtp08223/images/chm-removal-1.jpg" height="80" alt="" width="481" /></p>
<p>图2为删除元素3之后的链：</p>
<p><br />图2. 一个元素的删除过程</p>
<p><img src="http://www.ibm.com/developerworks/cn/java/j-jtp08223/images/chm-removal-2.jpg" alt="" /></p>
<p>插入和更新操作</p>
<p>put() 的实现很简单。像 remove() 一样， put() 会在执行期间保持 bucket 锁，但是由于 put() 并不是都需要获取锁，所以这并不一定会阻塞其他读线程的执行（也不会阻塞其他写线程访问别的 bucket）。它首先会在适当的 hash 链中搜索需要的键值。如果能够找到， value 字段（易变的）就直接被更新。如果没有找到，新会创建一个用于描述新 map 的新 Entry 对象，然后插入到 bucket 列表的头部。 </p>
<p>弱一致的迭代器</p>
<p>由 ConcurrentHashMap 返回的迭代器的语义又不同于 ava.util 集合中的迭代器；而且它又是 弱一致的（weakly consistent）而非 fail-fast 的（所谓 fail-fast 是指，当正在使用一个迭代器的时候，如何底层的集合被修改，就会抛出一个异常）。当一个用户调用 keySet().iterator() 去迭代器中检索一组 hash 键的时候，实现就简单地使用同步来保证每个链的头指针是当前值。 next() 和 hasNext() 操作以一种明显的方式定义，即遍历每个链然后转到下一个链直到所有的链都被遍历。弱一致迭代器可能会也可能不会反映迭代器迭代过程中的插入操作，但是一定会反映迭代器还没有到达的键的更新或删除操作，并且对任何值最多返回一次。 ConcurrentHashMap 返回的迭代器不会抛出 ConcurrentModificationException 异常。 </p>
<p>动态调整大小</p>
<p>随着 map 中元素数目的增长，hash 链将会变长，因此检索时间也会增加。从某种意义上说，增加 bucket 的数目和重排其中的值是非常重要的。在有些像 Hashtable 之类的类中，这很简单，因为保持一个应用到整个 map 的独占锁是可能的。在 ConcurrentHashMap 中，每次一个条目插入的时候，如果链的长度超过了某个阈值，链就被标记为需要调整大小。当有足够多的链被标记为需要调整大小以后， ConcurrentHashMap 就使用递归获取每个 bucket 上的锁并重排每个 bucket 中的元素到一个新的、更大的 hash 表中。多数情况下，这是自动发生的，并且对调用者透明。 </p>
<p>不锁定？</p>
<p>要说不用锁定就可以成功地完成 get() 操作似乎有点言过其实，因为 Entry 的 value 字段是易变的，这是用来检测更新和删除的。在机器级，易变的和同步的内容通常在最后会被翻译成相同的缓存一致原语，所以这里会有 一些 锁定，虽然只是细粒度的并且没有调度，或者没有获取和释放监视器的 JVM 开销。但是，除语义之外，在很多通用的情况下，检索的次数大于插入和删除的次数，所以说由 ConcurrentHashMap 取得的并发性是相当高的。</p>
          <br/>
          <span style="color:red;">
            <a href="http://fzfx88.javaeye.com/blog/195140#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, 21 May 2008 10:47:31 +0800</pubDate>
        <link>http://fzfx88.javaeye.com/blog/195140</link>
        <guid>http://fzfx88.javaeye.com/blog/195140</guid>
      </item>
      <item>
        <title>使用 xfire 开发 web service 应用</title>
        <author>fzfx88</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fzfx88.javaeye.com">fzfx88</a>&nbsp;
          链接：<a href="http://fzfx88.javaeye.com/blog/178467" style="color:red;">http://fzfx88.javaeye.com/blog/178467</a>&nbsp;
          发表时间: 2008年04月01日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p class="MsoNormal" align="left" style="margin: 0cm 0cm 0pt; text-align: left"><span style="font-size: 10pt; font-family: 宋体">转载:<span><a href="http://www.blogjava.net/oksonic/" id="Header1_HeaderTitle">oksonic博客</a></span>&nbsp;</span></p><p><span style="font-size: 10pt; font-family: 宋体">制作工具：<span style="color: blue">Eclipse3.2</span><span>&nbsp;&nbsp; </span><span style="color: blue">MyEclipse5.0m2<span>&nbsp;&nbsp; </span>Tomcat5.5.x</span></span>&nbsp;<span style="font-size: 10pt">&nbsp; </span></p><p><strong><span style="font-size: 10pt; font-family: 宋体">一、一个简单的 <span style="color: blue">web service</span></span> </strong><span style="font-size: 10pt">&nbsp; </span><span style="font-size: 10pt; font-family: 宋体"><span>&nbsp;&nbsp; </span>新建一个 <span style="color: blue">web service </span>工程，名称为 <span style="color: blue">xfire</span></span> <span style="font-size: 10pt; font-family: 宋体">&nbsp; </span><span style="font-size: 10pt; font-family: 宋体"><span>&nbsp;&nbsp; </span>新建一个 <span style="color: blue">java </span>文件，名称为 <span style="color: blue">Hello.java</span>，内容如下：</span> <span style="font-size: 10pt; color: blue; font-family: 宋体">-------------------------------------------------------------------------------------</span> <span style="font-size: 10pt; font-family: 宋体"><pre name="code" class="java">package com.test; 

public class Hello { 

    public String getName(String name){ 

       return &quot;Hello world &quot; + name; 

    } 

} 
</pre></span></p><span style="font-size: 10pt; font-family: 宋体">-------------------------------------------------------------------------------------</span> <span style="font-size: 10pt; font-family: 宋体">&nbsp; </span><span style="font-size: 10pt; font-family: 宋体"><span>&nbsp; </span>修改<span style="color: blue">Web Services</span>目录下的 <span style="color: blue">services.xml </span>文件，内容如下：</span> <span style="font-size: 10pt; font-family: 'Courier New'"><pre name="code" class="xml">&lt; beans xmlns = &quot;http://xfire.codehaus.org/config/1.0&quot; &gt; 

    &lt; service &gt; 

       &lt; name &gt; Hello &lt;/ name &gt; 

       &lt; namespace &gt; http://www.oksonic.cn/xfire &lt;/ namespace &gt; 

       &lt; serviceClass &gt; com.test.Hello &lt;/ serviceClass &gt; 

    &lt;/ service &gt; 

&lt;/ beans &gt; 

&lt; name &gt; Hello &lt;/ name &gt;   服务名称 
  &lt; serviceClass &gt; com.test.Hello &lt;/ serviceClass &gt;   服务类 
</pre><p class="MsoNormal" align="left" style="margin: 0cm 0cm 0pt; text-align: left">&nbsp;&nbsp; </p><p><span style="font-size: 10pt; font-family: ??"><span>&nbsp; </span></span><span style="font-size: 10pt; font-family: 宋体">现在可以部署项目，使用以下链接访问：</span> <span style="font-size: 10pt; font-family: 宋体"><span>&nbsp; </span><span style="color: blue">http://localhost/xfire/services/Hello?wsdl</span>&nbsp;</span><span style="font-size: 10pt; color: blue; font-family: 宋体"><span>&nbsp; </span></span></p></span><p><span style="font-size: 10pt; color: red; font-family: 宋体">注：我的端口已经修改为80，如果没有修改过的话请使用</span><span style="font-size: 10pt; color: blue; font-family: 宋体">&nbsp;&nbsp; <a href="http://localhost:8080/xfire/services/Hello?wsdl">http://localhost:8080/xfire/services/Hello?wsdl</a></span>&nbsp;<span style="font-size: 10pt">&nbsp;&nbsp;</span><span style="font-size: 10pt; font-family: 宋体"><span>&nbsp; </span></span></p><p><span style="font-size: 10pt; font-family: 宋体">网上原有的教程中提到可以使用 <span style="color: blue">http://localhost/xfire/services/ </span>访问，但测试时出现无法连接</span> <span style="font-size: 10pt">&nbsp; </span><span style="font-size: 10pt; font-family: 宋体"><span>&nbsp; </span>页面中出现 <span style="color: blue">xml </span>文件内容表示服务正常</span>&nbsp;<span style="font-size: 10pt">&nbsp;&nbsp;</span><span style="font-size: 10pt">&nbsp; </span></p><p><strong><span style="font-size: 10pt; font-family: 宋体">二、使用 jsr181 风格</span>&nbsp;</strong><strong><span style="font-size: 10pt">&nbsp; </span></strong></p><p><strong><span style="font-size: 10pt; color: blue; font-family: 宋体">---------------------</span> </strong><strong><span style="font-size: 10pt; font-family: 宋体">介绍 摘抄自 XFire 实战<span>&nbsp; </span><span style="color: blue">------------------------</span></span>&nbsp;</strong><span style="font-size: 10pt; font-family: 宋体"><span>&nbsp; </span></span></p><p><span style="font-size: 10pt; font-family: 宋体">JSR 181通过标准化一个易于学习且可以快速开发的Web服务简单编程模型，从而刺激了对Web服务的采用。一直以来，J2EE开发人员要开发和部署Web服务就必须掌握相当多的信息。通过使用J2SE 5.0中的新增注释功能，Java软件源代码可以使用JSR 181注释进行注释，从而声明式地定义所需的Web服务行为。这使开发人员可以将注意力集中在Web服务的应用逻辑上而无需担心复杂的API、协议和部署描述符。 </span><span style="font-size: 10pt; font-family: 宋体">&nbsp; </span><span style="font-size: 10pt; font-family: 宋体">BEA官方网站有一篇</span> <span style="font-size: 10pt; font-family: ??">&ldquo;</span> <span style="font-size: 10pt; font-family: 宋体">web服务元数据简介</span> <span style="font-size: 10pt; font-family: ??">&rdquo;</span> <span style="font-size: 10pt; font-family: 宋体">,对理解JSR 181规范很有帮助。 </span><span style="font-size: 10pt; font-family: 宋体">&nbsp; </span><span style="font-size: 10pt; font-family: 宋体">这一节的例子和上一节的例子很相似，或者通过使用java注释，比上一节的POJO稍微复杂了一点。不是说JSR 181节省了很多的配置信息吗？鄙人认为可以从这个方面来理解，正常情况下，POJO如果配置到其他webservices框架下，比如axis2、Celtix、weblogic等容器中，必然需要编写适合这些容器的配置文件，以便这些容器能够识别这个POJO类是wenservices，并根据配置文件中的比如命名空间、参数类型、web服务的方法等信息提供web服务。而通过jsr 181规范中的定义可以自动识别这些信息，这样这些信息不必在每个容器中所配置，这些容器通过java注释就可以得到这些信息，所以说jsr181在这方面进行了简化。XFire通过services.xml文件得到哪个类被定义为web服务， XFire可以通过java注释来获取web服务的相关信息。 </span></p><p><span style="font-size: 10pt; font-family: 宋体">-------------------------------------------------------------------------------------</span> <span style="font-size: 10pt; font-family: 宋体">&nbsp; </span><span style="font-size: 10pt; font-family: 宋体"><span>&nbsp; </span>修改 <span style="color: blue">Hello.java </span>文件，内容如下：</span> </p><p><span style="font-size: 10pt; color: blue; font-family: 宋体">-------------------------------------------------------------------------------------</span> </p><pre name="code" class="java">package com.test;   
import javax.jws.WebMethod; 
import javax.jws.WebParam; i
mport javax.jws.WebResult; 
import javax.jws.WebService;   
@WebService (name= &quot;Hello&quot; ,serviceName= &quot;Hello&quot; ,        targetNamespace= &quot;http://www.oksonic.cn/xfire&quot; ) 
public class Hello {       
@WebMethod     
@WebResult     
public String getName( @WebParam String name){        return &quot;Hello world &quot; + name;     
} 
}</pre><p>&nbsp;</p><p><span style="font-size: 10pt; font-family: 宋体">-------------------------------------------------------------------------------------</span> <span style="font-size: 10pt; font-family: 宋体">&nbsp; </span><span style="font-size: 10pt; font-family: 宋体"><span>&nbsp; </span>修改 <span style="color: blue">services.xml</span> 文件，内容如下：</span> </p><p><span style="font-size: 10pt; color: blue; font-family: 宋体">-------------------------------------------------------------------------------------</span> </p><pre name="code" class="xml">&lt; beans xmlns = &quot;http://xfire.codehaus.org/config/1.0&quot; &gt;     
&lt; service &gt;        
&lt; serviceClass &gt; com.test.Hello &lt;/ serviceClass &gt;        
&lt; serviceFactory &gt; jsr181 &lt;/ serviceFactory &gt;     
&lt;/ service &gt; 
&lt;/ beans &gt; </pre><p>&nbsp;</p><p><span style="font-size: 10pt; font-family: 宋体">-------------------------------------------------------------------------------------</span> <span style="font-size: 10pt; font-family: 宋体">&nbsp; </span><span style="font-size: 10pt; font-family: 宋体"><span>&nbsp; </span>启动服务，现次测试，没什么变化，服务正常</span>&nbsp;<span style="font-size: 10pt">&nbsp; </span></p><p><strong><span style="font-size: 10pt; font-family: 宋体">三、对 xfire 进行单元测试</span>&nbsp;</strong><strong><span style="font-size: 10pt">&nbsp; </span></strong></p><p><strong><span style="font-size: 10pt; color: blue; font-family: 宋体">---------------------</span> </strong><strong><span style="font-size: 10pt; font-family: 宋体">介绍 摘抄自 XFire 实战<span>&nbsp; </span><span style="color: blue">------------------------</span></span>&nbsp;</strong><span style="font-size: 10pt; font-family: 宋体"><span>&nbsp; </span></span></p><p><span style="font-size: 10pt; font-family: 宋体">你不必发布到 tomcat 等容器中就可以进行测试，常用的测试类常继承 AbstractXFireTest 抽像类。</span> <span style="font-size: 10pt; font-family: 宋体">AbstractXFireSpringTest 类又实现了 AbstractXFireTest 类，AbstractXFireTest 类是 TestCase</span> <span style="font-size: 10pt; font-family: 宋体">的子类，所以你可以使用 junit 进行单元测试。</span></p><p>&nbsp;<span style="font-size: 10pt; font-family: 宋体">------------------------------------------------------------------------------</span>&nbsp;<span style="font-size: 10pt; font-family: 宋体">&nbsp;&nbsp;</span><span style="font-size: 10pt; font-family: 宋体"><span>&nbsp;</span></span></p><p><span style="font-size: 10pt; font-family: 宋体"><span>&nbsp;</span>新建一个 <span style="color: blue">JUnit case</span> ，这是为了让 <span style="color: blue">IDE </span>自动增加 <span style="color: blue">JUnit </span>相关的类库</span> <span style="font-size: 10pt; font-family: 宋体">&nbsp; </span><span style="font-size: 10pt; font-family: 宋体"><span>&nbsp; </span>新建一个 <span style="color: blue">java </span>文件，名称为 <span style="color: blue">HelloTest.java</span>，此类继承 <span style="color: blue">AbstractXFireSpringTest</span>，</span> <span style="font-size: 10pt; font-family: 宋体">实现一个 <span style="color: blue">createContest </span>方法，内容如下：</span></p><p>&nbsp;<span style="font-size: 10pt; color: blue; font-family: 宋体">------------------------------------------------------------------------------</span> </p><pre name="code" class="java">package test.com.test; 

import org.apache.xbean.spring.context.ClassPathXmlApplicationContext; 
import org.codehaus.xfire.spring.AbstractXFireSpringTest; 

import org.jdom.Document; 

import org.springframework.context.ApplicationContext; 

public class HelloTest extends AbstractXFireSpringTest { 

    @Override 

    protected ApplicationContext createContext() { 

       return new ClassPathXmlApplicationContext( new String[] { 

              &quot;/org/codehaus/xfire/spring/xfire.xml&quot; , 

              &quot;/META-INF/xfire/services.xml&quot; }); 

  

    } 

    public void testService() throws Exception { 

        Document wsdl = getWSDLDocument( &quot;Hello&quot; ); 

        printNode(wsdl); 

    } 

} 
</pre><p class="MsoNormal" align="left" style="margin: 0cm 0cm 0pt; text-align: left">&nbsp;</p><p><span style="font-size: 10pt; font-family: 宋体">------------------------------------------------------------------------------</span>&nbsp;<span style="font-size: 10pt; font-family: 宋体"><span>&nbsp; </span></span></p><p><span style="font-size: 10pt; font-family: 宋体">为了让 </span><span style="font-size: 10pt; color: blue; font-family: 'Courier New'">createContext</span> <span style="font-size: 10pt; color: black; font-family: 宋体">方法可以找到 </span><span style="font-size: 10pt; color: blue; font-family: 宋体">services.xml</span> <span style="font-size: 10pt; color: black; font-family: 宋体">文件，需要把 </span><span style="font-size: 10pt; color: blue; font-family: 宋体">Web Services</span> <span style="font-size: 10pt; color: black; font-family: 宋体">目录下的 </span><span style="font-size: 10pt; color: blue; font-family: 宋体">services.xml </span><span style="font-size: 10pt; color: black; font-family: 宋体">拷贝到</span> <span style="font-size: 10pt; color: blue; font-family: 宋体">src/</span> <span style="font-size: 10pt; color: blue; font-family: 'Courier New'">META-INF/xfire</span> <span style="font-size: 10pt; color: black; font-family: 宋体">目录下</span>&nbsp;<span style="font-size: 10pt">&nbsp;&nbsp;</span><span style="font-size: 10pt; font-family: 宋体"><span>&nbsp; </span></span></p><p><span style="font-size: 10pt; font-family: 宋体">不用启动 tomcat 直接在 HelloTest.java 文件上点击鼠标右键 Run as --&gt; Junit ... 进行测试，</span></p><p><span style="font-size: 10pt; font-family: 宋体">结果显示绿色条，通过测试！</span>&nbsp;<span style="font-size: 10pt; font-family: 宋体"><span>&nbsp; </span></span></p><p><span style="font-size: 10pt; font-family: 宋体">关于其它的测试方法请查看《XFire实战.pdf》</span>&nbsp;<span style="font-size: 10pt">&nbsp; </span></p><p><strong><span style="font-size: 10pt; font-family: 宋体">四、和 Spring 集成</span> </strong><strong><span style="font-size: 10pt">&nbsp; </span></strong><span style="font-size: 10pt; font-family: 宋体"><span>&nbsp; </span>新建一个 <span style="color: blue">service </span>层接口 <span style="color: blue">IHelloService</span>，内容如下：</span></p><p>&nbsp;<span style="font-size: 10pt; color: blue; font-family: 宋体">------------------------------------------------------------------------------</span> <strong><span style="font-size: 10pt; color: #7f0055; font-family: 'Courier New'">package</span> </strong><span style="font-size: 10pt; color: black; font-family: 'Courier New'">com.test.services;</span>&nbsp;<span style="font-size: 10pt; font-family: 'Courier New'">&nbsp;</span></p><p><span style="font-size: 10pt; font-family: 'Courier New'">&nbsp;</span><strong><span style="font-size: 10pt; color: #7f0055; font-family: 'Courier New'">public</span> </strong><strong><span style="font-size: 10pt; color: #7f0055; font-family: 'Courier New'">interface</span> </strong><span style="font-size: 10pt; color: black; font-family: 'Courier New'">IHelloService {</span>&nbsp;<span style="font-size: 10pt; font-family: 'Courier New'">&nbsp;&nbsp;</span><span style="font-size: 10pt; color: black; font-family: 'Courier New'"><span>&nbsp;&nbsp;&nbsp; </span></span></p><p><strong><span style="font-size: 10pt; color: #7f0055; font-family: 'Courier New'">public</span> </strong><span style="font-size: 10pt; color: black; font-family: 'Courier New'">String getName(String name);</span>&nbsp;<span style="font-size: 10pt; color: black; font-family: 'Courier New'"><span>&nbsp;&nbsp;&nbsp; </span></span></p><p><span style="font-size: 10pt; color: black; font-family: 'Courier New'">}</span></p><p>&nbsp;<span style="font-size: 10pt; font-family: 宋体">------------------------------------------------------------------------------</span>&nbsp;<span style="font-size: 10pt">&nbsp;&nbsp;</span><span style="font-size: 10pt; font-family: 宋体"><span>&nbsp; </span></span></p><p><span style="font-size: 10pt; font-family: 宋体">创建接口的实现 <span style="color: blue">HelloService</span>,内容如下：</span></p><p><span style="font-size: 10pt; color: blue; font-family: 宋体">------------------------------------------------------------------------------</span> </p><pre name="code" class="java">package com.test.services.impl;   

import com.test.services.IHelloService;   

public class HelloService implements IHelloService {       

        public String getName(String name) {        

                     return &quot;Hello World &quot; + name;     

        }   

}
</pre><p>&nbsp;</p><p>&nbsp;<span style="font-size: 10pt; font-family: 宋体">------------------------------------------------------------------------------</span>&nbsp;<span style="font-size: 10pt; color: black; font-family: 'Courier New'">&nbsp;&nbsp;</span><span style="font-size: 10pt; color: black; font-family: ??"><span>&nbsp;</span></span></p><p><span style="font-size: 10pt; color: black; font-family: ??"><span>&nbsp;</span></span><span style="font-size: 10pt; color: black; font-family: 宋体">添加 </span><span style="font-size: 10pt; color: blue; font-family: 宋体">spirng </span><span style="font-size: 10pt; color: black; font-family: 宋体">框架，设置将 </span><span style="font-size: 10pt; color: blue; font-family: 宋体">applicationContext.xml </span><span style="font-size: 10pt; color: black; font-family: 宋体">文件创建到 WEB-INF 目录下</span>&nbsp;<span style="font-size: 10pt; color: black">&nbsp;&nbsp;</span><span style="font-size: 10pt; color: black; font-family: 宋体"><span>&nbsp; </span></span></p><p><span style="font-size: 10pt; color: black; font-family: 宋体">修改 </span><span style="font-size: 10pt; color: blue; font-family: 宋体">applicationContext.xml </span><span style="font-size: 10pt; color: black; font-family: 宋体">文件，内容如下：</span></p><p>&nbsp;<span style="font-size: 10pt; color: blue; font-family: 宋体">------------------------------------------------------------------------------</span> </p><span style="font-size: 10pt; color: teal; font-family: 'Courier New'"><pre name="code" class="xml">&lt;? xml version = &quot;1.0&quot; encoding = &quot;UTF-8&quot; ?&gt; 

&lt;! DOCTYPE beans PUBLIC &quot;-//SPRING//DTD BEAN//EN&quot; &quot;http://www.springframework.org/dtd/spring-beans.dtd&quot; &gt;   

&lt; beans &gt;     

&lt; bean id = &quot; helloBean &quot; class = &quot;com.test.services.impl.HelloService&quot; /&gt; 

&lt;/ beans &gt;
</pre></span><p>&nbsp;<span style="font-size: 10pt; font-family: 宋体">------------------------------------------------------------------------------</span>&nbsp;<span style="font-size: 10pt; font-family: 宋体">&nbsp;&nbsp;</span><span style="font-size: 10pt; font-family: 宋体"><span>&nbsp;</span></span></p><p><span style="font-size: 10pt; font-family: 宋体"><span>&nbsp;</span>在 WEB-INF 目录下新建 </span><span style="font-size: 10pt; color: blue; font-family: 'Courier New'">xfire</span> <span style="font-size: 10pt; color: blue; font-family: 宋体">-servlet.xml </span><span style="font-size: 10pt; font-family: 宋体">文件，文件内容如下：</span> </p><p><span style="font-size: 10pt; color: blue; font-family: 宋体">------------------------------------------------------------------------------</span></p><span style="font-size: 10pt; font-family: 宋体"><pre name="code" class="xml">&lt;? xml version = &quot;1.0&quot; encoding = &quot;UTF-8&quot; ?&gt; 

&lt;! DOCTYPE beans PUBLIC &quot;-//SPRING//DTD BEAN//EN&quot; &quot;http://www.springframework.org/dtd/spring-beans.dtd&quot; &gt; 

&lt; beans &gt;     

&lt; bean  class = &quot;org.springframework.web.servlet.handler.SimpleUrlHandlerMapping&quot; &gt;      

&lt; property name = &quot;urlMap&quot; &gt;

            &lt; map &gt; 

              &lt;!-- 配置 service 名称和 Service Bean --&gt;

               &lt; entry key = &quot;/Hello&quot; &gt; 

                  &lt; ref bean = &quot; hello &quot; /&gt; 

              &lt;/ entry &gt;            

            &lt;/ map &gt;

&lt;/ property &gt;

&lt;/ bean &gt;

     &lt; bean id = &quot; hello &quot;        class = &quot;org.codehaus.xfire.spring.remoting.XFireExporter&quot; &gt;        &lt; property name = &quot;serviceFactory&quot; &gt; 

           &lt; ref bean = &quot;xfire.serviceFactory&quot; /&gt;

        &lt;/ property &gt;

        &lt; property name = &quot;xfire&quot; &gt;

            &lt; ref bean = &quot;xfire&quot; /&gt; 

       &lt;/ property &gt;

        &lt; property name = &quot;serviceBean&quot; &gt; 

           &lt; ref bean = &quot; helloBean &quot; /&gt;

        &lt;/ property &gt;

        &lt; property name = &quot;serviceClass&quot; &gt;

            &lt; value &gt; com.test.services.IHelloService &lt;/ value &gt;

        &lt;/ property &gt;

     &lt;/ bean &gt;

 &lt;/ beans &gt;</pre><p>&nbsp;&nbsp;</p></span><p><span style="font-size: 10pt; font-family: 宋体">------------------------------------------------------------------------------</span></p><p>&nbsp;<span style="font-size: 10pt; color: red; font-family: 宋体"><span>&nbsp; </span>注意：红色字体部份必需一r致，深红色字体部份要和 spring 的配置文件部份一致</span> <span style="font-size: 10pt">&nbsp; </span><span style="font-size: 10pt; font-family: 宋体"><span>&nbsp; </span>修改 <span style="color: blue">web.xml </span>文件，增加 <span style="color: blue">spring </span>配置部份，修改 <span style="color: blue">xfire </span>的名称</span></p><p>&nbsp;<span style="font-size: 10pt; color: blue; font-family: 宋体">------------------------------------------------------------------------------</span></p><span style="font-size: 10pt; color: blue; font-family: 宋体"><pre name="code" class="xml">&lt;? xml version = &quot;1.0&quot; encoding = &quot;UTF-8&quot; ?&gt; 

&lt; web-app xmlns = &quot;http://java.sun.com/xml/ns/j2ee&quot; 

    xmlns:xsi = &quot;http://www.w3.org/2001/XMLSchema-instance&quot; version = &quot;2.4&quot; 

    xsi:schemaLocation = &quot;http://java.sun.com/xml/ns/j2ee   http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd&quot; &gt; 

    &lt; context-param &gt; 

       &lt; param-name &gt; contextConfigLocation &lt;/ param-name &gt; 

       &lt; param-value &gt; 

           /WEB-INF/applicationContext.xml 

           classpath:org/codehaus/xfire/spring/xfire.xml 

       &lt;/ param-value &gt; 

    &lt;/ context-param &gt; 

    &lt; listener &gt; 

       &lt; listener-class &gt; 

           org.springframework.web.context.ContextLoaderListener 

       &lt;/ listener-class &gt; 

    &lt;/ listener &gt; 

    &lt; servlet &gt; 

       &lt; servlet-name &gt; xfire &lt;/ servlet-name &gt; 

       &lt; servlet-class &gt; 

           org.springframework.web.servlet.DispatcherServlet 

       &lt;/ servlet-class &gt; 

       &lt; load-on-startup &gt; 0 &lt;/ load-on-startup &gt; 

    &lt;/ servlet &gt; 

    &lt; servlet-mapping &gt; 

       &lt; servlet-name &gt; xfire &lt;/ servlet-name &gt; 

       &lt; url-pattern &gt; /services/* &lt;/ url-pattern &gt; 

    &lt;/ servlet-mapping &gt; 

&lt;/ web-app &gt; 
</pre></span><span style="font-size: x-small"><span style="font-family: 宋体">&nbsp; 重启服务，进行测试！！！</span></span> <span style="font-size: 10pt; color: black; font-family: 宋体">&nbsp; </span><p class="MsoNormal" align="left" style="margin: 0cm 0cm 0pt; text-align: left"><span style="font-size: 10pt; color: black; font-family: 宋体"><span>&nbsp; </span>一切正常，现在用一个web service测试工具进行一下测试</span> </p>
          <br/>
          <span style="color:red;">
            <a href="http://fzfx88.javaeye.com/blog/178467#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>Tue, 01 Apr 2008 16:06:24 +0800</pubDate>
        <link>http://fzfx88.javaeye.com/blog/178467</link>
        <guid>http://fzfx88.javaeye.com/blog/178467</guid>
      </item>
      <item>
        <title>XFire 入门教程</title>
        <author>fzfx88</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fzfx88.javaeye.com">fzfx88</a>&nbsp;
          链接：<a href="http://fzfx88.javaeye.com/blog/178458" style="color:red;">http://fzfx88.javaeye.com/blog/178458</a>&nbsp;
          发表时间: 2008年04月01日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>转载:作者:golden</p><p>Java 社区一直试图将 POJO 的作用发挥到极致，降低 Java 应用实现的难度，最近的尝试是将 EJB3.0 建立在 POJO 之上；另一方面，SOA 是目前 Java 社区炙手可热的名词，非常多的<a href="http://clk.qunsee.com/click/click.php?cpid=12&amp;ads_id=227&amp;pid=99001226&amp;cid=1234&amp;url=http%3A//www.chanet.com.cn/click.cgi%3Fa%3D59068%26d%3D21733%26u%3D%26e%3D&amp;k=%u4F01%u4E1A&amp;s=http%3A//www.goldenbg.com/article.asp%3Fid%3D1213&amp;rn=959122&amp;v=1&amp;ref=http%3A//www.google.cn/search%3Fcomplete%3D1%26hl%3Dzh-CN%26newwindow%3D1%26q%3Dxfire+%25E6%2595%2599%25E7%25A8%258B%26meta%3D%26aq%3D7%26oq%3Dxfire&amp;province=%u5317%u4EAC&amp;city=%u5317%u4EAC" class="qs_highlight1" id="hl_2" onmouseover="window.clearTimeout(_ht[2]);qs_show_frame(event,this,2);" onclick="_write_cookie('click227',2);" onmouseout="_on_div[2]=false;_ht[2]=window.setTimeout('qs_is_on_div(2)',500);" target="_blank" style="font-size: 1em">企业</a>都在努力应用和实施 SOA；XFire 为这两方面的需求提供了一种魔术般的<a href="http://clk.qunsee.com/click/click.php?cpid=12&amp;ads_id=28&amp;pid=99001226&amp;cid=1234&amp;url=http%3A//www.zhaopin.com&amp;k=%u89E3%u51B3&amp;s=http%3A//www.goldenbg.com/article.asp%3Fid%3D1213&amp;rn=539643&amp;v=1&amp;ref=http%3A//www.google.cn/search%3Fcomplete%3D1%26hl%3Dzh-CN%26newwindow%3D1%26q%3Dxfire+%25E6%2595%2599%25E7%25A8%258B%26meta%3D%26aq%3D7%26oq%3Dxfire&amp;province=%u5317%u4EAC&amp;city=%u5317%u4EAC" class="qs_highlight1" id="hl_9" onmouseover="window.clearTimeout(_ht[9]);qs_show_frame(event,this,9);" onclick="_write_cookie('click28',9);" onmouseout="_on_div[9]=false;_ht[9]=window.setTimeout('qs_is_on_div(9)',500);" target="_blank" style="font-size: 1em">解决</a>方式，我们很快能够发现使用 XFire 创建和发布 Web <a href="http://clk.qunsee.com/click/click.php?cpid=1021&amp;ads_id=376&amp;pid=99001226&amp;cid=1234&amp;url=http%3A//click.lianmark.com/%3FgId%3DG000000457%26linkId%3DL000000711%26linkType%3D002%26mId%3DM000004751%26cId%3D&amp;k=%u670D%u52A1&amp;s=http%3A//www.goldenbg.com/article.asp%3Fid%3D1213&amp;rn=959396&amp;v=1&amp;ref=http%3A//www.google.cn/search%3Fcomplete%3D1%26hl%3Dzh-CN%26newwindow%3D1%26q%3Dxfire+%25E6%2595%2599%25E7%25A8%258B%26meta%3D%26aq%3D7%26oq%3Dxfire&amp;province=%u5317%u4EAC&amp;city=%u5317%u4EAC" class="qs_highlight1" id="hl_5" onmouseover="window.clearTimeout(_ht[5]);qs_show_frame(event,this,5);" onclick="_write_cookie('click376',5);" onmouseout="_on_div[5]=false;_ht[5]=window.setTimeout('qs_is_on_div(5)',500);" target="_blank" style="font-size: 1em">服务</a>可以直接基于 POJO，将烦人的继承关系和一大堆其他可能的约束丢在一边 </p><p>POJO（Plain Old Java Object，简单 Java 对象）是 Java 社区中最早的成员（回想您学习 Java 时第一个兴奋的时刻，那个简单的 &quot;Hello World！&quot; 例子），也是最简单、最容易实现的方式。</p><p>然而现实中 Java 的发展已经远远超越了 POJO 的<a href="http://clk.qunsee.com/click/click.php?cpid=12&amp;ads_id=16&amp;pid=99001226&amp;cid=1234&amp;url=http%3A//www.intel.com/cd/business/enterprise/apac/zho/364490.htm%3Fppc_cid%3DCPT2H07cn_4&amp;k=%u8303%u56F4&amp;s=http%3A//www.goldenbg.com/article.asp%3Fid%3D1213&amp;rn=315912&amp;v=1&amp;ref=http%3A//www.google.cn/search%3Fcomplete%3D1%26hl%3Dzh-CN%26newwindow%3D1%26q%3Dxfire+%25E6%2595%2599%25E7%25A8%258B%26meta%3D%26aq%3D7%26oq%3Dxfire&amp;province=%u5317%u4EAC&amp;city=%u5317%u4EAC" class="qs_highlight1" id="hl_0" onmouseover="window.clearTimeout(_ht[0]);qs_show_frame(event,this,0);" onclick="_write_cookie('click16',0);" onmouseout="_on_div[0]=false;_ht[0]=window.setTimeout('qs_is_on_div(0)',500);" target="_blank" style="font-size: 1em">范围</a>，成为面向对象技术应用中最成功的编程<a href="http://clk.qunsee.com/click/click.php?cpid=1021&amp;ads_id=375&amp;pid=99001226&amp;cid=1234&amp;url=http%3A//click.lianmark.com/%3FgId%3DG000000438%26linkId%3DL000001095%26linkType%3D002%26mId%3DM000004751%26cId%3D&amp;k=%u8BED%u8A00&amp;s=http%3A//www.goldenbg.com/article.asp%3Fid%3D1213&amp;rn=791221&amp;v=1&amp;ref=http%3A//www.google.cn/search%3Fcomplete%3D1%26hl%3Dzh-CN%26newwindow%3D1%26q%3Dxfire+%25E6%2595%2599%25E7%25A8%258B%26meta%3D%26aq%3D7%26oq%3Dxfire&amp;province=%u5317%u4EAC&amp;city=%u5317%u4EAC" class="qs_highlight1" id="hl_4" onmouseover="window.clearTimeout(_ht[4]);qs_show_frame(event,this,4);" onclick="_write_cookie('click375',4);" onmouseout="_on_div[4]=false;_ht[4]=window.setTimeout('qs_is_on_div(4)',500);" target="_blank" style="font-size: 1em">语言</a>，尤其是继承、多态的应用为我们造就了一大批开发框架（如 Struts）和标准（如 EJB），随之而来的就是实现的复杂化，我们必须面对一大堆继承关系的限制。比如说：要开发一个基于 Struts 的应用，我们必须了解 Struts 特定的继承关系如 ActionForm、ValidateActionForm；要开发一个 EJB 应用，我们必须继承 EJBObject、SessionEJB 等。</p><p>为了抛开这些限制，降低 Java 应用实现的难度，Java 社区开始重新审视 POJO 的价值，试图将 POJO 的作用发挥到极致，最新的努力是 EJB3.0。Java 社区将 EJB3.0 设计为基于 POJO，而不是为他准备更多的继承关系等限制。</p><p>SOA 已经成为了目前 Java 社区中炙手可热的名词，几乎所有的软件厂商都在讨论它，为他提供解决方案和产品支持，大部分的企业也已经在企业内部实施或者正在考虑实施 SOA。</p><p>然而 SOA 在企业内的实施却不是一项简单的任务，即使抛开新建系统直接基于 SOA 架构实施的因素，要把企业已有系统纳入 SOA 框架也不是一件容易的事情。企业必须在对当前架构深入了解的基础上，对已有系统进行大规模的改造才能满足新的要求。如何经济的从原有技术架构切换到 SOA 架构成为很多企业的难题。</p><p>XFire 是 codeHaus 组织提供的一个开源框架，它构建了 POJO 和 SOA 之间的桥梁，主要特性就是支持将 POJO 通过非常简单的方式发布成 Web 服务，这种处理方式不仅充分发挥了 POJO 的作用，简化了 Java 应用转化为 Web 服务的步骤和过程，也直接降低了 SOA 的实现难度，为企业转向 SOA 架构提供了一种简单可行的方式。</p><p>XFire 目前最新的版本是 1.2.2，目前支持的特性主要包括：</p><ul><li>支持将 Web 服务绑定到 POJO、XMLBeans、JAXB1.1、JAXB2.0 和 Castor； </li><li>支持基于 HTTP、JMS、XMPP 等多种协议访问 Web 服务； </li><li>支持多种 Web 服务业界重要标准如 SOAP、WSDL、Web 服务寻址（WS-Addressing）、Web 服务安全（WS-Security）等； </li><li>支持 JSR181，可以通过 JDK5 配置 Web 服务； </li><li>高<a href="http://clk.qunsee.com/click/click.php?cpid=12&amp;ads_id=16&amp;pid=99001226&amp;cid=1234&amp;url=http%3A//www.intel.com/cd/business/enterprise/apac/zho/364490.htm%3Fppc_cid%3DCPT2H07cn_4&amp;k=%u6027%u80FD&amp;s=http%3A//www.goldenbg.com/article.asp%3Fid%3D1213&amp;rn=635940&amp;v=1&amp;ref=http%3A//www.google.cn/search%3Fcomplete%3D1%26hl%3Dzh-CN%26newwindow%3D1%26q%3Dxfire+%25E6%2595%2599%25E7%25A8%258B%26meta%3D%26aq%3D7%26oq%3Dxfire&amp;province=%u5317%u4EAC&amp;city=%u5317%u4EAC" class="qs_highlight1" id="hl_3" onmouseover="window.clearTimeout(_ht[3]);qs_show_frame(event,this,3);" onclick="_write_cookie('click16',3);" onmouseout="_on_div[3]=false;_ht[3]=window.setTimeout('qs_is_on_div(3)',500);" target="_blank" style="font-size: 1em">性能</a>的 SOAP 实现； </li><li>服务器端、客户端代码辅助生成； </li><li>对 Spring、Pico、Plexus 等项目的支持等。 </li></ul><p>XFire 框架目前的最新版本是 1.2.6，可以访问 xfire.codehaus.org 下载 XFire 框架的安装包，下载时请选择&ldquo;全部二进制发布包（Binary Distribution in zip package）&rdquo;，而不仅仅是&ldquo;XFire jar 文件（Jar of all XFire modules）&rdquo;。</p><p>下载完成后，我们可以将下载的 .zip 文件解压缩到任意的文件夹中（后面的章节中使用 % XFIRE_HOME % 表示 XFire 框架的安装目录），解压缩后形成的文件目录结构如下：</p><ul><li><strong>api（目录）</strong> <p>api 目录中是 XFire 框架中所有类（class）对应的 API 文档，为开发者使用 XFire 完成应用开发提供帮助。</p></li><li><strong>examples（目录）</strong> <p>examples 目录中包含了所有随 XFire 二进制包发布的实例，包括这些实例的源代码和相关 Web 应用配置内容。</p></li><li><strong>lib（目录）</strong> <p>lib 目录中包含 XFire 运行所需要的外部支持类包（.jar文件），可以根据不同项目所需的 XFire 特性选择所需要的支持类包。保守的方法是在 Web 项目中包含所有的外部支持类包（.jar文件）。</p></li><li><strong>manual（目录）</strong> <p>manual 目录中包含有 XFire 框架的帮助文档，开发者可以从这些帮助文档<a href="http://clk.qunsee.com/click/click.php?cpid=1021&amp;ads_id=342&amp;pid=99001226&amp;cid=1234&amp;url=http%3A//www.chanet.com.cn/click.cgi%3Fa%3D59068%26d%3D8227%26u%3D%26e%3D&amp;k=%u4E2D%u5B66&amp;s=http%3A//www.goldenbg.com/article.asp%3Fid%3D1213&amp;rn=823594&amp;v=1&amp;ref=http%3A//www.google.cn/search%3Fcomplete%3D1%26hl%3Dzh-CN%26newwindow%3D1%26q%3Dxfire+%25E6%2595%2599%25E7%25A8%258B%26meta%3D%26aq%3D7%26oq%3Dxfire&amp;province=%u5317%u4EAC&amp;city=%u5317%u4EAC" class="qs_highlight1" id="hl_1" onmouseover="window.clearTimeout(_ht[1]);qs_show_frame(event,this,1);" onclick="_write_cookie('click342',1);" onmouseout="_on_div[1]=false;_ht[1]=window.setTimeout('qs_is_on_div(1)',500);" target="_blank" style="font-size: 1em">中学</a>习更多运用 XFire 框架实现 SOA 的知识和技巧。</p></li><li><strong>modules（目录）</strong> <p>modules 目录中包含了 XFire 框架根据不同特性分别编译的二进制包文件。发布基于 XFire 框架的 Web 项目时，可以选择使用该目录下的所有 .jar 文件，也可以选择 XFire-all-1.2.6.jar 文件。</p></li><li><strong>XFire-all-1.2.6.jar</strong> <p>XFire 框架的二进制包文件，包含了全部的模块（modules）。</p></li><li><strong>LICENSE.txt</strong> <p>LICENSE.txt 文件中包含了 XFire 框架的授权协议。</p></li><li><strong>NOTICE.txt</strong> </li><li><strong>README.txt</strong> <p>这两个文件中包含了 XFire 发布时的一些有用的信息。</p></li></ul><p>XFire框架是一种基于Servlet技术的SOA应用开发框架，要正常运行基于XFire应用框架开发的企业应用，除了XFire框架本身之外，还需要JDK和Servlet容器的支持。</p><p>XFire 支持非常多的特性，其中不同的特性对 JDK 版本的要求有所不同，比如如果项目中选择基于 JSR181 标准发布 Web 服务，我们就需要选择 JDK5 或者以上版本，如果仅仅选择将 Web 服务绑定到最简单的 POJO，我们只需要选择 JDK1.4 版本即可。</p><p>JDK 各版本均可以在 <a href="http://java.sun.com/" target="new"><span style="color: #5c81a7">java.sun.com</span></a> 网站上下载，如何安装 JDK 请参考 SUN <a href="http://clk.qunsee.com/click/click.php?cpid=12&amp;ads_id=227&amp;pid=99001226&amp;cid=1234&amp;url=http%3A//www.chanet.com.cn/click.cgi%3Fa%3D59068%26d%3D21733%26u%3D%26e%3D&amp;k=%u516C%u53F8&amp;s=http%3A//www.goldenbg.com/article.asp%3Fid%3D1213&amp;rn=20851&amp;v=1&amp;ref=http%3A//www.google.cn/search%3Fcomplete%3D1%26hl%3Dzh-CN%26newwindow%3D1%26q%3Dxfire+%25E6%2595%2599%25E7%25A8%258B%26meta%3D%26aq%3D7%26oq%3Dxfire&amp;province=%u5317%u4EAC&amp;city=%u5317%u4EAC" class="qs_highlight1" id="hl_10" onmouseover="window.clearTimeout(_ht[10]);qs_show_frame(event,this,10);" onclick="_write_cookie('click227',10);" onmouseout="_on_div[10]=false;_ht[10]=window.setTimeout('qs_is_on_div(10)',500);" target="_blank" style="font-size: 1em">公司</a>的相关技术文档和 JDK 的帮助文档。</p><p>XFire 是一种基于 Servlet 技术的 SOA 应用开发框架，需要 Servlet 容器的支持。XFire 支持在多种 Servlet 容器中运行，包括 Websphere、Weblogic、TOMCAT 等。为了说明的简单，我们选择使用 TOMCAT（版本5.0.30）作为 XFire 的运行容器，所有配置过程和发布步骤的说明也均是针对 TOMCAT，如果读者使用 TOMCAT 之外的其它 Servlet 容器或者选择了 TOMCAT 的其它版本，下面的配置过程和步骤可能需要做出调整，请读者根据实际 Servlet 容器的帮助文档进行相应调整。</p><p>TOMCAT 各版本均可以在 <a href="http://tomcat.apache.org/" target="new"><span style="color: #5c81a7">tomcat.apache.org</span></a> 网站上下载，如何正确安装 TOMCAT 服务器请参考 TOMCAT 服务器的帮助文档。</p><p>XFire 需要 xalan 项目的支持，然而 1.2.6 版本中并没有带有相应的 jar 文件，因此请访问 <a href="http://xml.apache.org/" target="new"><span style="color: #5c81a7">xml.apache.org</span></a>，下载 xalan 项目的二进制包。</p><p>前面的章节中我们下载和安装了 XFire 安装包和所需要的支持环境，现在我们开始学习如何从零开始创建 XFire 应用开发环境。下面的所有配置过程和发布步骤均针对 TOMCAT（版本5.0.30）服务器，如果选择其它的 Servlet 容器，下面的配置过程和步骤可能需要做出调整，请读者根据实际 Servlet 容器的帮助文档进行相应调整。</p><p>&nbsp;</p><ol><li>在 %TOMCAT_HOME%/webapps 目录下创建新的 Web 应用目录 &ldquo;XFire&rdquo; <p><em>[注] 其中的 %TOMCAT_HOME% 指向 TOMCAT 的安装目录。</em> </p></li><li>在 &rdquo;XFire&rdquo;目录下创建 &rdquo;WEB-INF&rdquo;目录、 </li><li>在 &rdquo; WEB-INF&rdquo;目录下创建 &rdquo;lib&rdquo;目录和 &rdquo;classes&rdquo;目录 </li><li>在 &rdquo; WEB-INF&rdquo;目录下创建 Web 应用描述文件 &rdquo;web.xml&rdquo;， &rdquo;web.xml&rdquo;文件的内容见 <a href="http://www.ibm.com/developerworks/cn/java/j-lo-xfire/index.html#code11"><span style="color: #996699">清单 1-1</span></a>。 </li></ol><pre name="code" class="xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;ISO-8859-1&quot;?&gt;
&lt;web-app xmlns=&quot;http://java.sun.com/xml/ns/j2ee&quot;	    xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;	    xsi:schemaLocation=&quot;http://java.sun.com/xml/ns/j2ee
<a href="http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" target="_blank">http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd</a>&quot;
version=&quot;2.4&quot;&gt;
         &lt;display-name&gt;XFire实例&lt;/display-name&gt;
          &lt;description&gt;
           基于XFire框架发布Web服务的例子
       &lt;/description&gt;
&lt;/web-app&gt;
</pre>&nbsp;<br /><p>&nbsp;</p><p>拷贝 %XFIRE_HOME%/lib 目录下所有文件到 <a href="http://www.ibm.com/developerworks/cn/java/j-lo-xfire/index.html#h1"><span style="color: #996699">&ldquo;1、创建 Web 应用目录和基本元素&rdquo;</span></a> 中所创建的 &rdquo;lib&rdquo;目录下，将 %XFIRE_HOME%/XFire-all-1.2.6.jar 文件也拷贝到 <a href="http://www.ibm.com/developerworks/cn/java/j-lo-xfire/index.html#h1"><span style="color: #996699">&ldquo;1、创建 Web 应用目录和基本元素&rdquo;</span></a> 中所创建的 &rdquo;lib&rdquo;目录下。将 xalan 安装包中的所有 jar 文件和所需要的支持 jar 文件拷贝到相同的 &rdquo;lib&rdquo;目录下。</p><p><strong>[注] </strong>为了减少拷贝的 jar 文件的数目，开发者可以根据项目的需要选择需要拷贝的 jar 文件，而不是全部拷贝，如何根据需要选择拷贝合适的类包文件请访问 <a href="http://xfire.codehaus.org/Dependency+Guide"><span style="color: #5c81a7">XFire 站点</span></a>。 </p><p>&nbsp;</p><p>修改 web.xml 文件，在其中增加如下 Servlet 定义内容。</p><table cellspacing="0" border="0" width="100%" cellpadding="0"><tbody><tr><td class="code-outline"><pre class="displaycode">           </pre></td></tr></tbody></table><p>&nbsp;</p><pre name="code" class="xml">&lt;servlet&gt;
           &lt;servlet-name&gt;XFireServlet&lt;/servlet-name&gt;
           &lt;display-name&gt;XFire Servlet&lt;/display-name&gt;
            &lt;servlet-class&gt;	        org.codehaus.xfire.transport.http.XFireConfigurableServlet
            &lt;/servlet-class&gt;
&lt;/servlet&gt;
&lt;servlet-mapping&gt;
            &lt;servlet-name&gt;XFireServlet&lt;/servlet-name&gt;
            &lt;url-pattern&gt;/servlet/XFireServlet/*&lt;/url-pattern&gt;
&lt;/servlet-mapping&gt;
&lt;servlet-mapping&gt;
            &lt;servlet-name&gt;XFireServlet&lt;/servlet-name&gt;
            &lt;url-pattern&gt;/services/*&lt;/url-pattern&gt;
&lt;/servlet-mapping&gt;
</pre><p>&nbsp;</p><ol><li>在 <a href="http://www.ibm.com/developerworks/cn/java/j-lo-xfire/index.html#h1"><span style="color: #996699">&ldquo;1、创建 Web 应用目录和基本元素&rdquo;</span></a> 中创建的 classes 目录下新建目录 &rdquo;META-INF\xfire&rdquo;； </li><li>在步骤 a) 中新建的 &rdquo;xfire&rdquo;文件目录下创建新文件 services.xml，文件的默认内容如 <a href="http://www.ibm.com/developerworks/cn/java/j-lo-xfire/index.html#code12"><span style="color: #996699">清单1-2</span></a> 。 </li></ol><br /><br /><table cellspacing="0" border="0" width="100%" cellpadding="0"><tbody><tr><td class="code-outline"><pre class="displaycode">	&lt;beans xmlns=&quot;http://XFire.codehaus.org/config/1.0&quot;&gt;&lt;/beans&gt;
</pre></td></tr></tbody></table><br /><br /><p>&nbsp;</p><p>XFire 框架中，我们有两种方式将 POJO 发布成 Web 服务：</p><ul><li>一种方式是直接使用 Web 服务接口和 Web 服务实现类（POJO）来发布； </li><li>另一种方式是基于 JSR181 标准和注释技术将被注释的 POJO 发布成 Web 服务； </li></ul><p>下面的章节中我们将学习使用第一种方式来完成 POJO 的 Web 服务发布。我们将使用<a href="http://clk.qunsee.com/click/click.php?cpid=12&amp;ads_id=22&amp;pid=99001226&amp;cid=1234&amp;url=http%3A//www.jiumuwang.com/html/index.htm&amp;k=%u7ECF%u5178&amp;s=http%3A//www.goldenbg.com/article.asp%3Fid%3D1213&amp;rn=712208&amp;v=1&amp;ref=http%3A//www.google.cn/search%3Fcomplete%3D1%26hl%3Dzh-CN%26newwindow%3D1%26q%3Dxfire+%25E6%2595%2599%25E7%25A8%258B%26meta%3D%26aq%3D7%26oq%3Dxfire&amp;province=%u5317%u4EAC&amp;city=%u5317%u4EAC" class="qs_highlight1" id="hl_6" onmouseover="window.clearTimeout(_ht[6]);qs_show_frame(event,this,6);" onclick="_write_cookie('click22',6);" onmouseout="_on_div[6]=false;_ht[6]=window.setTimeout('qs_is_on_div(6)',500);" target="_blank" style="font-size: 1em">经典</a>的 &rdquo;Hello World!&rdquo;例子来演示将 POJO 发布成 Web 服务所需要的步骤，不过我们不再是简单的访问一个 Java 方法来输出 &rdquo;Hello World!&rdquo;字符串，而是转为在 SOA 环境下实现：Web 服务客户端通过访问服务器端发布成 Web 服务的 POJO 获得返回的 &rdquo;Hello World!&rdquo;字符串后输出到客户端的控制台上。</p><p>将 POJO 发布成 Web 服务的基本步骤如下：</p><ol><li>创建 Web 服务接口，声明该 Web 服务对外暴露的接口； </li><li>创建 Web 服务实现类，为 Web 服务接口提供实现； </li><li>修改 XFire 框架的服务发布文件 ---- services.xml，将 POJO 发布成 Web 服务。 </li></ol><p>下面我们通过创建 &rdquo;Hello World!&rdquo;例子来具体说明如何实现这三个步骤。</p><p>&nbsp;</p><p>要将 POJO 发布成 Web 服务，首先需要创建 Web 服务接口，在接口中声明该 Web 服务需要对外暴露的接口。</p><p>我们根据需要创建 Web 服务接口 &rdquo; HelloWorldService&rdquo;，在其中声明一个 &rdquo;sayHello&rdquo;方法，该方法返回 &rdquo;String &rdquo;类型的内容。&rdquo; HelloWorldService&rdquo;接口对应的 Java 文件代码如 <a href="http://www.ibm.com/developerworks/cn/java/j-lo-xfire/index.html#code13"><span style="color: #996699">清单 1-3</span></a>。</p><br /><br /><table cellspacing="0" border="0" width="100%" cellpadding="0"><tbody><tr><td class="code-outline"><pre class="displaycode">package org.vivianj.xfire.pojo;
/**
 * HelloWorldService 中声明需要发布成 Web 服务的所有 Java 方法
 * HelloWorldService 作为Web服务接口
 */</pre><pre class="displaycode">public interface HelloWorldService {
/**
 * sayHello 方法声明了 Web 服务对外暴露的接口
*
 * @return 返回给客户端的字符串
*/
public String sayHello();
            }
            </pre></td></tr></tbody></table><br /><p>&nbsp;</p><p>创建 Web 服务实现类 &rdquo;HelloWorldServiceImpl&rdquo;，它继承 <a href="http://www.ibm.com/developerworks/cn/java/j-lo-xfire/index.html#h1"><span style="color: #996699">&rdquo;1、创建Web服务接口 ---- HelloWorldService&rdquo;</span></a> 中创建的 HelloWorldService 接口，并且为它声明的 &rdquo;sayHello&rdquo;方法提供具体实现： 返回字符串&rdquo;Hello World!&rdquo;。 &rdquo;HelloWorldServiceImpl&rdquo;类对应的 Java 文件代码如 <a href="http://www.ibm.com/developerworks/cn/java/j-lo-xfire/index.html#code14"><span style="color: #996699">清单 1-4</span></a>。</p><br /><br /><table cellspacing="0" border="0" width="100%" cellpadding="0"><tbody><tr><td class="code-outline"><pre class="displaycode">package org.vivianj.xfire.pojo;
/**
 * HelloWorldServiceImpl 中为 Web 服务接口中声明的所有 Java 方法提供具体实现
 * HelloWorldServiceImpl 作为 Web 服务的实现类
 */
public class HelloWorldServiceImpl implements HelloWorldService {
/*
 * sayHello 方法为 HelloWorldService 服务接口定义的 sayHello 方法提供具体实现
 *
 * @see org.vivianj.XFire.pojo.HelloWorldService#sayHelloToXFire()
 */
public String sayHello() {
            return &quot;Hello World!&quot;;
 }            </pre><pre class="displaycode">}
            </pre></td></tr></tbody></table><br /><p>&nbsp;</p><p>我们可以在 WEB-INF\classes\META-INF\XFire\services.xml 文件中的 &lt;beans &hellip;&gt; 和 &lt;/beans&gt; 元素中间加入如下的 xml 内容将上面创建的 HelloWorldService 发布成 Web 服务。</p><table cellspacing="0" border="0" width="100%" cellpadding="0"><tbody><tr><td class="code-outline"><pre class="displaycode">&lt;service&gt;
    &lt;name&gt;HelloWorldService&lt;/name&gt;
            &lt;namespace&gt;http://vivianj.org/HelloWorldService&lt;/namespace&gt;
            &lt;serviceClass&gt;
                        org.vivianj.xfire.pojo.HelloWorldService
            &lt;/serviceClass&gt;
            &lt;implementationClass&gt;
                        org.vivianj.xfire.pojo.HelloWorldServiceImpl
            &lt;/implementationClass&gt;
&lt;/service&gt;
            </pre></td></tr></tbody></table><br /><p>其中各元素的功能如下：</p><ul><li><strong>service</strong> <p>service 标签和它所包含的 xml 内容为发布成 Web 服务的 POJO 提供完整的描述。</p></li><li><strong>name</strong> <p>Web 服务被发布时所采用的唯一名称。</p></li><li><strong>namespace</strong> <p>Web 服务发布时所使用的命名<a href="http://clk.qunsee.com/click/click.php?cpid=1021&amp;ads_id=319&amp;pid=99001226&amp;cid=1234&amp;url=http%3A//www.chanet.com.cn/click.cgi%3Fa%3D59068%26d%3D7568%26u%3D%26e%3D&amp;k=%u7A7A%u95F4&amp;s=http%3A//www.goldenbg.com/article.asp%3Fid%3D1213&amp;rn=993964&amp;v=1&amp;ref=http%3A//www.google.cn/search%3Fcomplete%3D1%26hl%3Dzh-CN%26newwindow%3D1%26q%3Dxfire+%25E6%2595%2599%25E7%25A8%258B%26meta%3D%26aq%3D7%26oq%3Dxfire&amp;province=%u5317%u4EAC&amp;city=%u5317%u4EAC" class="qs_highlight1" id="hl_7" onmouseover="window.clearTimeout(_ht[7]);qs_show_frame(event,this,7);" onclick="_write_cookie('click319',7);" onmouseout="_on_div[7]=false;_ht[7]=window.setTimeout('qs_is_on_div(7)',500);" target="_blank" style="font-size: 1em">空间</a>。</p></li><li><strong>serviceClass</strong> <p>Web 服务接口类的全名，包括包名和类名。</p></li><li><strong>implemetationClass</strong> <p>Web 服务实现类的全名，包括包名和类名。</p></li></ul><p>更多 service 元素的子元素和它们的用法请参考 <a href="http://xfire.codehaus.org/services.xml+Reference"><span style="color: #5c81a7">XFire 站点</span></a>。</p><p>通过上面的三个步骤，我们已经将新创建的HelloWorldService发布成了Web服务，我们可以使用下面的步骤测试一下创建的Web服务是否能够正常运行：</p><ol><li>编译上面的步骤中创建的 Java 接口和类； </li><li>启动 TOMCAT 服务器。 </li><li>等 TOMCAT 服务器完全启动后，打开浏览器，在地址栏中输入 http://localhost:8080/XFire/services/HelloWorldService?wsdl。 </li></ol><p>其中 HelloWorldServcie 是配置文件中 service\name 元素所定义的内容，&rdquo;wsdl&rdquo;参数表示查看该 Web 服务的 WSDL（Web服务描述语言）文件。</p><p>如果浏览器中出现如下图所示类似的内容，表示 Web 服务发布成功，我们可以编写客户端访问该 Web 服务从服务器获取返回字符串，本文下载资源中提供的下载文件中包含有可供参考的客户端类 org.vivianj.xfire.pojo.client.HelloWorldServiceClient。</p><br /><br /><a href="http://www.ibm.com/developerworks/cn/java/j-lo-xfire/fig001.jpg" title="在新窗口打开图片" target="_blank"><img src="http://www.ibm.com/developerworks/cn/java/j-lo-xfire/fig001.jpg" alt="" width="550" /></a> <br /><p>如果浏览器中出现错误提示，请按照上面的步骤和说明检查已经完成的开发、配置过程是否完全正确。</p><p>本文中作者首先讲解了 XFire 框架的主要特性，XFire 框架的运行环境以及基于 XFire 框架开发 SOA 应用的基本步骤，并且借助于 SOA 环境下的 &rdquo;Hello World!&rdquo;例子，详细的讲解和演示了如何基于 XFire 框架、经过简单的开发、配置步骤就将一个 POJO 类中包含的方法发布成Web服务。从 &rdquo;Hello World!&rdquo;例子实现的过程中，我们可以发现 XFire 框架最大化的发挥了 POJO 的作用，减少了 SOA 实施时对框架本身的依赖，降低了 SOA 实施的难度，企业实施 SOA 时并不需要增加太多的投入就可以实现目标。</p><p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://fzfx88.javaeye.com/blog/178458#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>Tue, 01 Apr 2008 15:41:30 +0800</pubDate>
        <link>http://fzfx88.javaeye.com/blog/178458</link>
        <guid>http://fzfx88.javaeye.com/blog/178458</guid>
      </item>
      <item>
        <title>JCS 应用</title>
        <author>fzfx88</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fzfx88.javaeye.com">fzfx88</a>&nbsp;
          链接：<a href="http://fzfx88.javaeye.com/blog/147346" style="color:red;">http://fzfx88.javaeye.com/blog/147346</a>&nbsp;
          发表时间: 2007年12月10日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><font face="Arial"><font color="#0000ff">JCS在一般用在，查询数据库比较频繁，每次查询的结果都差不多，这样讲数据进行缓冲，可以 减轻数据库负担：<br />
下面举个例子：<br />
在一个点击量比较频繁的页面，调用一个数据列表，每个用户进去在某一时间段数据都一样，这时将考虑将数据进行缓冲。<br />
</font>1、配置 JCS cache.ccf 文件，将该文件直接放到src根目录下即可：</font><font face="Arial"></font></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="comment">/**缓冲区名称**/</span><span>&nbsp;&nbsp;</span></span></li>
    <li class=""><span>jcs.region.chatCache=DC &nbsp;&nbsp;</span></li>
    <li class="alt"><span></span><span class="comment">/****/</span><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>jcs.region.chatCache.cacheattributes=org.apache.jcs.engine.CompositeCacheAttributes &nbsp;&nbsp;</span></li>
    <li class="alt"><span></span><span class="comment">/**缓冲区的大小为存放1000个对象**/</span><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>jcs.region.chatCache.cacheattributes.MaxObjects=</span><span class="number">10000</span><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span></span><span class="comment">/**内存缓冲器使用LRUMemoryCache对象**/</span><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>jcs.region.chatCache.cacheattributes.MemoryCacheName=org.apache.jcs.engine.memory.lru.LRUMemoryCache &nbsp;&nbsp;</span></li>
    <li class="alt"><span></span><span class="comment">/****/</span><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>jcs.region.chatCache.cacheattributes.UseMemoryShrinker=</span><span class="keyword">true</span><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span></span><span class="comment">/**指明对象超过2000秒则过期**/</span><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>jcs.region.chatCache.cacheattributes.MaxMemoryIdleTimeSeconds=</span><span class="number">2000</span><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span></span><span class="comment">/**每隔60秒检查一次**/</span><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>jcs.region.chatCache.cacheattributes.ShrinkerIntervalSeconds=</span><span class="number">60</span><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span></span><span class="comment">/****/</span><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>jcs.region.chatCache.cacheattributes.MaxSpoolPerRun=</span><span class="number">500</span><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span></span><span class="comment">/****/</span><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>jcs.region.chatCache.elementattributes=org.apache.jcs.engine.ElementAttributes &nbsp;&nbsp;</span></li>
    <li class="alt"><span></span><span class="comment">/****/</span><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>jcs.region.chatCache.elementattributes.IsEternal=</span><span class="keyword">false</span><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span></span><span class="comment">/****/</span><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>jcs.region.chatCache.elementattributes.IsSpool=</span><span class="keyword">true</span><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span></span><span class="comment">/****/</span><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>jcs.region.chatCache.elementattributes.IsRemote=</span><span class="keyword">false</span><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span></span><span class="comment">/****/</span><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>jcs.region.chatCache.elementattributes.IsLateral=</span><span class="keyword">true</span><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span></span><span class="comment">/****/</span><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>jcs.region.chatCache.elementattributes.MaxLifeSeconds=</span><span class="number">3600</span><span>&nbsp;&nbsp;</span></li>
</ol>
</div>
<p>2、程序中这样应用即可：</p>
<div class="code_title"></div>
<div class="dp-highlighter">
<div class="bar"></div>
<ol class="dp-j">
    <li class="alt"><span><span>JCS&nbsp;chatCache&nbsp;&nbsp;=&nbsp;JCS.getInstance(</span><span class="string">&quot;chatCache&quot;</span><span>);&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//获得JCS缓冲区对象 </span><span>&nbsp;&nbsp;</span></span></li>
    <li class=""><span>String&nbsp;chatCacheKey&nbsp;=&nbsp;</span><span class="string">&quot;chat_cache_&quot;</span><span>+roomID;&nbsp;&nbsp;</span><span class="comment">//&nbsp;构建key </span><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span></span><span class="keyword">if</span><span>(chatCache.get(chatCacheKey)!=</span><span class="keyword">null</span><span>){ &nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp; roomintroList&nbsp;=&nbsp;(List)chatCache.get(chatCacheKey); &nbsp;&nbsp;</span></li>
    <li class="alt"><span>}</span><span class="keyword">else</span><span>{&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp; roomintroList = 数据库查询;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp; <font face="Courier New" style="BACKGROUND-COLOR: #fafafa">chatCache.put(chatCacheKey, roomintroList);</font></span></li>
    <li class="alt"><span>}&nbsp;</span></li>
</ol>
</div>
<p>&nbsp;<br />
</p>
          <br/>
          <span style="color:red;">
            <a href="http://fzfx88.javaeye.com/blog/147346#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>Mon, 10 Dec 2007 17:38:28 +0800</pubDate>
        <link>http://fzfx88.javaeye.com/blog/147346</link>
        <guid>http://fzfx88.javaeye.com/blog/147346</guid>
      </item>
      <item>
        <title>JCS 资料</title>
        <author>fzfx88</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fzfx88.javaeye.com">fzfx88</a>&nbsp;
          链接：<a href="http://fzfx88.javaeye.com/blog/147321" style="color:red;">http://fzfx88.javaeye.com/blog/147321</a>&nbsp;
          发表时间: 2007年12月10日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><font face="Arial"><strong><font style="BACKGROUND-COLOR: #ffcc00">1、关于JCS<br />
</font></strong>JCS是Jakarta的项目Turbine的子项目。它是一个复合式的缓冲工具。可以将对象缓冲到内存、硬盘。具有缓冲对象时间过期设定。还可以通过JCS构建具有缓冲的分布式构架，以实现高性能的应用。 对于一些需要频繁访问而每访问一次都非常消耗资源的对象，可以临时存放在缓冲区中，这样可以提高服务的性能。而JCS正是一个很好的缓冲工具。缓冲工具对于读操作远远多于写操作的应用性能提高非常显著。<br />
<font style="BACKGROUND-COLOR: #ffcc00"><strong>2、JCS的特性</strong></font><br />
JCS除了简单的将对象缓冲在内存中以外，还具有几个特性，以适应企业级缓冲系统的需要。这些特性包括时间过期、索引式硬盘缓冲、并行式的分布缓冲等。 <br />
<strong><font style="BACKGROUND-COLOR: #ff9900">3、内存缓冲</font></strong><br />
JCS现在支持两种内存缓冲算法LRU和MRU。通常都是使用LRU算法。 org.apache.stratum.jcs.engine.memory.lru.LRUMemoryCache 使用内存缓冲区需要定义缓冲区大小，当超过缓冲区限制时，会将缓冲内容抛弃掉。如果有配硬盘缓冲，则将挤出来的缓冲内容写入硬盘缓冲区。 <br />
<strong><font style="BACKGROUND-COLOR: #ff9900">4、时间过期</font></strong><br />
JCS对于缓冲的对象，可以设定缓冲过期时间，一个对象在缓冲区中停留的时间超过这个时间，就会被认为是&ldquo;不新鲜&rdquo;而被放弃。<br />
<strong><font style="BACKGROUND-COLOR: #ff9900">5、索引式硬盘缓冲</font></strong><br />
一方面，为了避免缓冲区过大，撑爆虚拟机的内存，另一方面又希望能够缓冲更多的对象，JCS可以将超出缓冲区大小的对象缓存到硬盘上。配置上也比较方便，只需要指定缓冲临时文件的存放目录位置。硬盘缓冲将缓冲对象的内容写到文件上，但是将访问索引保存在内存中，因此也能够达到尽可能高的访问效率。<br />
<strong><font style="BACKGROUND-COLOR: #ffcc00">6、并行式的分布缓冲(Lateral)</font></strong><br />
通常，将对象缓冲在内存中，一方面提高了应用的性能，而另一方面却使得应用不可以分布式发布。因为假设一个应用配置在两台服务器上并行运行，而两台服务器单独缓冲，则很容易导致两个缓冲区内容出现版本上的不一致而出错。一个机器上修改了数据，这个动作会影响到本地内存缓冲区和数据库服务器，但是却不会通知到另一台服务器，导致另一台上缓冲的数据实际上已经无效了。 并行式的分布缓冲就是解决这个问题。可以通过配置，将几台服务器配成一个缓冲组，组内每台服务器上有数据更新，会横向将更新的内容通过TCP/IP协议传输到其他服务器的缓冲层，这样就可以保证不会出现上述情况。这个的缺点是如果组内的并行的服务器数量增大后，组内的数据传输量将会迅速上升。这种方案适合并行服务器的数量比较少的情况。 <br />
<strong><font style="BACKGROUND-COLOR: #ff9900">7、Client/Server式的缓冲(Remote)</font></strong><br />
客户/服务端式的缓冲集群。这种方式支持一个主服务器和最高达到256个客户端。客户端的缓冲层会尝试连接主服务器，如果连接成功，就会在主服务器上注册。每个客户端有数据更新，就会通知到主服务器，主服务器会将更新通知到除消息来源的客户端以外的所有的客户端。 每个客户端可以配置超过一个服务器，第一个服务器是主服务器，如果与第一个服务器连接失败，客户端会尝试与备用的服务器连接，如果连接成功，就会通过备用服务器与其他客户端对话，同时会定期继续尝试与主服务器取得连接。如果备用服务器也连接失败，就会按照配置顺序尝试与下一个备用服务器连接。 这种方式下，更新通知是一种轻量级的，一个机器上的数据更新，不会把整个数据传输出去，而只是通知一个ID，当远程的其他机器收到更新通知后，就会把对应ID的缓冲对象从本地的内存缓冲区中移除，以保证不会在缓冲区内出现错误数据。 这种构造需要分别配置客户端和服务器，配置比较麻烦。 <br />
<strong><font style="BACKGROUND-COLOR: #ff9900">8、配置方法</font></strong><br />
JCS的好处之一，就是应用在开发的时候，可以不用去构思底层的缓冲配置构架。同一个应用，只需要修改配置，就可以改变缓冲构架，不需要修改应用的源代码。配置方法也比较简单，就是修改配置文件cache.ccf。这个文件放置在WEB-INF/classes目录下。配置格式类似log4j的配置文件格式。下面介绍一下使用各种缓冲结构的配置方法。<br />
<strong><font style="BACKGROUND-COLOR: #ff6600">9、内存缓冲</font></strong><br />
#WEB-INF/classes/cache.ccf(以下内容不要换行)&nbsp;<br />
</font><font face="Arial">
<div class="dp-highlighter">
<div class="bar"></div>
<ol class="dp-j">
    <li class="alt"><span><span>jcs.</span><span class="keyword">default</span><span>=&nbsp;jcs.</span><span class="keyword">default</span><span>.cache &nbsp;&nbsp;</span></span></li>
    <li class=""><span>attributes=org.apache.jcs.engine.CompositeCacheAttributes &nbsp;&nbsp;</span></li>
    <li class="alt"><span>jcs.</span><span class="keyword">default</span><span>.cacheattributes.MaxObjects=</span><span class="number">1000</span><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>jcs.</span><span class="keyword">default</span><span>.cacheattributes.MemoryCacheName=org.apache.jcs.engine.memory.lru.LRUMemoryCache&nbsp;&nbsp;</span></li>
</ol>
</div>
<p>&nbsp;上面配置了默认缓冲属性。一个应用中，由于对象类型的不同，可能会使用多个缓冲区，每个缓冲区都会有一个名字，如果在配置文件中没有指明特定的缓冲区的属性，所有的缓冲区都会根据默认属性来构建。上面的内容，指明缓冲区的大小为存放1000个对象，内存缓冲器使用LRUMemoryCache对象。可选的还有MRUMemoryCache，应该可以自定义新的内存缓冲区。1000个缓冲对象这个容量，是指每个缓冲区都缓冲1000个，而不是指所有缓冲区总容量。以上配置，就可以让应用运行起来。</p>
<p><strong><font style="BACKGROUND-COLOR: #ff9900">10、时间过期</font></strong><br />
如果需要引入时间过期机制，则需要加上 </p>
<div class="code_title"></div>
<div class="dp-highlighter">
<div class="bar"></div>
<ol class="dp-j">
    <li class="alt"><span><span>jcs.</span><span class="keyword">default</span><span>.cacheattributes.cacheattributes.UseMemoryShrinker=</span><span class="keyword">true</span><span>&nbsp;&nbsp;</span></span></li>
    <li class=""><span>jcs.</span><span class="keyword">default</span><span>.cacheattributes.cacheattributes.MaxMemoryIdleTimeSeconds=</span><span class="number">3600</span><span>&nbsp; &nbsp;&nbsp;</span></li>
    <li class="alt"><span>jcs.</span><span class="keyword">default</span><span>.cacheattributes.cacheattributes.ShrinkerIntervalSeconds=</span><span class="number">60</span><span>&nbsp;&nbsp;&nbsp;</span></li>
</ol>
</div>
<p>这里指明对象超过3600秒则过期，每隔60秒检查一次。<br />
<strong><font style="BACKGROUND-COLOR: #ff9900">11、索引式硬盘缓冲<br />
</font></strong></p>
</font>索引式硬盘缓冲是辅助缓冲的一种，使用时需要做以下事情
<pre>#定义一个硬盘缓冲区产生器(Factory)，取名为DC </pre>
<pre><div class="code_title">java 代码</div><div class="dp-highlighter"><ol class="dp-j"><li class="alt"><span><span>jcs.auxiliary.DC=org.apache.stratum.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory&nbsp; &nbsp;&nbsp;</span></span></li><li class=""><span>jcs.auxiliary.DC.attributes=org.apache.stratum.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes&nbsp;jcs.auxiliary.DC.attributes.DiskPath=g:/dev/jakarta-turbine-stratum/raf&nbsp;&nbsp;&nbsp;</span></li></ol></div></pre>
<pre>#这里其实就是指明了缓冲文件存放到那里去。 </pre>
<p>然后，做以下修改 <span class="searchword">jcs</span>.default=DC 这样，所有未特别指定属性的缓冲区都会自己使用一个硬盘缓冲区，缓冲文件会以缓冲区的名字来命名。存放在指定的目录下</p>
<p><strong><font style="BACKGROUND-COLOR: #ff9900">12、横向式的并行缓冲</font></strong></p>
<p>并行式的<span class="searchword">配置</span>如下&nbsp;：</p>
<div class="dp-highlighter">
<div class="bar"></div>
<ol class="dp-j">
    <li class="alt"><span><span>jcs.auxiliary.LTCP=org.apache.jcs.auxiliary.lateral.LateralCacheFactory &nbsp;&nbsp;</span></span></li>
    <li class=""><span>jcs.auxiliary.LTCP.attributes=org.apache.jcs.auxiliary.lateral.LateralCacheAttributes &nbsp;&nbsp;</span></li>
    <li class="alt"><span>jcs.auxiliary.LTCP.attributes.TransmissionTypeName=TCP &nbsp;&nbsp;</span></li>
    <li class=""><span>jcs.auxiliary.LTCP.attributes.TcpServers=</span><span class="number">192.168</span><span>.</span><span class="number">10.129</span><span>:</span><span class="number">1121</span><span>,</span><span class="number">192.168</span><span>.</span><span class="number">10.222</span><span>:</span><span class="number">1121</span><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>jcs.auxiliary.LTCP.attributes.TcpListenerPort=</span><span class="number">1121</span><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>jcs.auxiliary.LTCP.attributes.PutOnlyMode=</span><span class="keyword">false</span><span>&nbsp;&nbsp;</span></li>
</ol>
</div>
<p>&nbsp;这里的<span class="searchword">配置</span>是在41,129,221三台机器上实现并行缓冲的。 大家都在1121端口上监听，同时与另外两台机器连接。如果连接失败，就会等待一个时间后再连接一次，直到连接成功为止。三台机器中任意一台的缓冲区发生更新，比如put和remove动作，就会把更新传递给另外两台。 </p>
<p><strong><font style="BACKGROUND-COLOR: #ff9900">13、单独指明某个缓冲区的属性</font></strong></p>
<p>如果，针对某个缓冲区，比如叫做TestCache1，需要单独<span class="searchword">配置</span>属性，可以如下<span class="searchword">配置</span>。</p>
<div class="dp-highlighter">
<div class="bar"></div>
<ol class="dp-j">
    <li class="alt"><span><span>&nbsp;jcs.region.testCache1=DC,LTCP&nbsp; &nbsp;&nbsp;</span></span></li>
    <li class=""><span>jcs.region.testCache1.cacheattributes=org.apache.stratum.jcs.engine.CompositeCacheAttributes&nbsp;jcs.region.testCache1.cacheattributes.MaxObjects=</span><span class="number">1000</span><span>&nbsp; &nbsp;&nbsp;</span></li>
    <li class="alt"><span>jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.stratum.jcs.engine.memory.lru.LRUMemoryCache&nbsp; &nbsp;&nbsp;</span></li>
    <li class=""><span>jcs.region.testCache1.cacheattributes.UseMemoryShrinker=</span><span class="keyword">true</span><span>&nbsp; &nbsp;&nbsp;</span></li>
    <li class="alt"><span>jcs.region.testCache1.cacheattributes.MaxMemoryIdleTimeSeconds=</span><span class="number">3600</span><span>&nbsp; &nbsp;&nbsp;</span></li>
    <li class=""><span>jcs.region.testCache1.cacheattributes.ShrinkerIntervalSeconds=</span><span class="number">60</span><span>&nbsp; &nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;</span></li>
</ol>
</div>
<p><strong><font style="BACKGROUND-COLOR: #ff9900">14、system.GroupIdCache</font></strong> </p>
<p><span class="searchword">JCS</span>文档中指出<span class="searchword">配置</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>jcs.system.groupIdCache=DC&nbsp; &nbsp;&nbsp;</span></span></li>
    <li class=""><span>jcs.system.groupIdCache.cacheattributes=org.apache.stratum.jcs.engine.CompositeCacheAttributes&nbsp; &nbsp;&nbsp;</span></li>
    <li class="alt"><span>jcs.system.groupIdCache.cacheattributes.MaxObjects=</span><span class="number">10000</span><span>&nbsp; &nbsp;&nbsp;</span></li>
    <li class=""><span>jcs.system.groupIdCache.cacheattributes.MemoryCacheName=org.apache.stratum.jcs.engine.memory.lru.LRUMemoryCache&nbsp; &nbsp;&nbsp;</span></li>
</ol>
</div>
<p>这可能是JCS自己的组管理体系上的缓冲区。</p>
<p><font style="BACKGROUND-COLOR: #ff0000"><strong>15、Client/Server式的缓冲(Remote)</strong></font></p>
<p>这种构架需要单独<span class="searchword">配置</span>客户端和服务端 </p>
</p>
<div class="code_title">java 代码</div>
          <br/>
          <span style="color:red;">
            <a href="http://fzfx88.javaeye.com/blog/147321#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>Mon, 10 Dec 2007 17:04:10 +0800</pubDate>
        <link>http://fzfx88.javaeye.com/blog/147321</link>
        <guid>http://fzfx88.javaeye.com/blog/147321</guid>
      </item>
      <item>
        <title>Eclipse 快捷键整理</title>
        <author>fzfx88</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fzfx88.javaeye.com">fzfx88</a>&nbsp;
          链接：<a href="http://fzfx88.javaeye.com/blog/141360" style="color:red;">http://fzfx88.javaeye.com/blog/141360</a>&nbsp;
          发表时间: 2007年11月17日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          Alt+/:代码提示<br />
Ctrl+/:注释/取消注释<br />
Ctrl+D:删除光标所在行<br />
Ctrl+K:将光标停留在变量上，按Ctrl+K键可以查找到下一个同样的变量<br />
Shift+Ctrl+K:和Ctrl+K查找的方向相反<br />
Shift+Ctrl+F:代码格式化。如果选择了代码，仅对所选代码格式化<br />
Shift+Ctrl+O:快速地导入import<br />
Shift+Ctrl+X:将所选字符转为大写<br />
Shift+Ctrl+Y:将所选字符转为小写<br />
Ctrl+M:快速对当前视图最大化<br />
Ctrl+O:在代码中打开类似大纲视图的小窗口<br />
Ctrl+单击:可以跟踪方法和类的源码<br />
Alt+左右方向键:跳到前一次/后一次的编辑位置。<br />
Ctrl+鼠标停留:可以显示类和方法的源码<br />
双击左括号（小括号、中括号、大括号），将选择括号内的所有内容。<br />
Ctrl+1:光标停在某变量上，按Ctrl+1键，可以提供快速重构方案。选中若干行，按Ctrl+1键可将此段代码放入for、while、if、do或try等代码块中。<br />
F3:打开声明该引用的文件<br />
F4:打开类型层次结构<br />
F5:单步跳入<br />
F6:单步跳过<br />
F7:单步跳出<br />
F8:继续，如果后面没有断点，程序将运行完<br />
Ctrl+H:打开搜索窗口<br />
Ctrl+Shift+S:保存全部<br />
Alt+Left:回退一步<br />
Alt+Right:前跳一步<br />
Ctrl+Shift+T:打开类型<br />
Ctrl+Shift+R:打开资源<br />
Ctrl+Q:回到最后一次编辑的地方<br />
Ctrl+Shift+G: 在workspace中搜索引用<br />
Ctrl+Alt+Down: 复制高亮显示的一行或多行<br />
Alt+Up(Down):将一行或者多行向上或者向下移动
          <br/>
          <span style="color:red;">
            <a href="http://fzfx88.javaeye.com/blog/141360#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>Sat, 17 Nov 2007 12:36:49 +0800</pubDate>
        <link>http://fzfx88.javaeye.com/blog/141360</link>
        <guid>http://fzfx88.javaeye.com/blog/141360</guid>
      </item>
      <item>
        <title>MyEclipse 6.0 新特性</title>
        <author>fzfx88</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fzfx88.javaeye.com">fzfx88</a>&nbsp;
          链接：<a href="http://fzfx88.javaeye.com/blog/139533" style="color:red;">http://fzfx88.javaeye.com/blog/139533</a>&nbsp;
          发表时间: 2007年11月09日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <div class="postText">Genuitec宣布：MyEclipse 6.0发布了。MyEclipse 6.0的发布极大的增强了Eclipse 3.3/Europa集成开发环境的功能，增加了Java 6支持的组件和加快了AJAX的开发率，革命性的提高了开发者的开发效率。 <br />
<br />
　　另外，MyEclipse 6.0现在已经和Spring、JPA整合。这项整合，允许用户们创建实体管理器和事务beans, 生成实体和DOA。这些功能很大程度上多亏有了MyEclipse。<br />
<br />
　　Genuitec的前开发负责人Wayne Parrott说：&ldquo;我极度的自豪，因为当前这个MyEclipse版本的发布，MyEclipse用户将会发现我们改掉了许多存在于我们开发环境中的小弊病，呈现给大家一个高开发效率，极容易定制，和用户友好体验的开发环境&rdquo;。<br />
<br />
　　在以前版本的基础上，MyEclipse 6.0增强了下面的功能：<br />
<br />
　　1 平台和安装支持<br />
<br />
1）兼容Eclipse 3.3/Europa 1.0<br />
2）支持Java 5 &amp; Java 6<br />
3）可运行在Windows (XP, Vista)、Linux、 Mac操作系统<br />
<br />
　　2 改进了Java EE 5 和 Spring功能部件<br />
<br />
1）提高EJB3工程项目的灵活度，从数据库模式直接产生bean<br />
2）支持Java持久化结构开发<br />
3）对Spring 2.0升级，增强配置管理功能<br />
4）升级Hibernate<br />
5）Spring-JPA高度集成<br />
<br />
　　3&nbsp;&nbsp;支持AJAX开发和测试<br />
<br />
1）支持美国Apple公司&mdash;所有的AJAX特征能在Mac操作系统上运行<br />
2）改进了AJAX Web 浏览器<br />
3）改进了AJAX工具<br />
4）增强了JavaScript调试<br />
<br />
　　4 支持RAD Web 开发<br />
<br />
　　5 具备Matisse4MyEclipse可视化Swing设计器<br />
<br />
　　6 快速Java EE部署和测试<br />
<br />
1）项目自动部署和启动服务：根据指定的调试和运行模式，自动配置项目和启动服务器；在配置前，自动停止运行的服务器；在现有的应用程序配置中可以重新配置<br />
2）MyEclipse Tomcat 6 服务器&mdash;&mdash;就地集成，启动只要一秒钟<br />
3）MyEclipse Derby 服务器：自动进行JDBC连接；可配置的启动选项<br />
<br />
7 MyEclipse学习中心（提供帮助和学习资料）<br />
<br />
1）包含Java EE项目源代码 <br />
2）一键安装MyEclipse Java EE示例项目<br />
<br />
　　Genuitec首任执行官Maher Masri说：&ldquo;我们的首要任务就是提供这么一个解决方案，让我们的用户更加灵活的开发。我们注意力集中开发高质量的工具，我想我们的用户很快就会在MyEclipse 6.0中发现这些特点的&rdquo;。<br />
<br />
　　　　MyEclipse的下载地址:<br />
<a href="http://www.myeclipseide.com/module-htmlpages-display-pid-4.html">http://www.myeclipseide.com/module-htmlpages-display-pid-4.html</a><br />
</div>
          <br/>
          <span style="color:red;">
            <a href="http://fzfx88.javaeye.com/blog/139533#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, 09 Nov 2007 17:32:42 +0800</pubDate>
        <link>http://fzfx88.javaeye.com/blog/139533</link>
        <guid>http://fzfx88.javaeye.com/blog/139533</guid>
      </item>
      <item>
        <title>MyEclipse 6.0.1 注册码</title>
        <author>fzfx88</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fzfx88.javaeye.com">fzfx88</a>&nbsp;
          链接：<a href="http://fzfx88.javaeye.com/blog/136963" style="color:red;">http://fzfx88.javaeye.com/blog/136963</a>&nbsp;
          发表时间: 2007年10月31日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>MyEclipse 6.0.1 注册码</p>
<pre class="bb-code-block">Subscriber: administrator
Subscription Code: nLR7ZL-655342-54657656405281154</pre>
<p>注册后：</p>
<pre class="bb-code-block">Subscriber: administrator
Product ID: E2MY (MyEclipse Standard Subscription)
License version: 1.0
Full Maintenance Included
Subscription expiration date (YYYYMMDD): 20091021
Number of licenses: 897
</pre>
<p>&nbsp;</p>
<p>下面把 6.0GA / M1 和 5.5GA 版本的&ldquo;注册信息&rdquo;&ldquo;注册码&rdquo;&ldquo;破解&rdquo;给大家：</p>
<pre class="bb-code-block">Subscriber:
Subscriber Code: jLR8ZC-655355-5450765457039125
或者
Subscriber:
Subscriber Code: jLR7ZL-655355-5450755330522962</pre>
<p>适用于早期的 5.5 M2 版本的：</p>
<pre class="bb-code-block">Subscriber:
Subscriber Code: jLR8ZC-956-55-5467865833584547</pre>
<p>适用于早期的 5.1.1 GA 和 5.5 M1 版本的：</p>
<pre class="bb-code-block">Subscriber:
Subscriber Code: jLR8ZC-444-55-4467865481680090</pre>
<p>注册成功后会发现：</p>
<pre class="bb-code-block">Subscriber:
Product ID: E3MP (MyEclipse Professional Subscription)
License version: x.x
Full Maintenance Included
Subscription expiration date (YYYYMMDD): 20090520
Number of licenses: 800</pre>
          <br/>
          <span style="color:red;">
            <a href="http://fzfx88.javaeye.com/blog/136963#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>Wed, 31 Oct 2007 12:02:22 +0800</pubDate>
        <link>http://fzfx88.javaeye.com/blog/136963</link>
        <guid>http://fzfx88.javaeye.com/blog/136963</guid>
      </item>
      <item>
        <title>给自己力量</title>
        <author>fzfx88</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fzfx88.javaeye.com">fzfx88</a>&nbsp;
          链接：<a href="http://fzfx88.javaeye.com/blog/136344" style="color:red;">http://fzfx88.javaeye.com/blog/136344</a>&nbsp;
          发表时间: 2007年10月29日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><font color="#0000ff">看到墙角边总有这样的植物 <br />
&nbsp;像爬山虎一样生命力旺盛 <br />
&nbsp;只要有方向,它就一直努力地往上爬 <br />
&nbsp;给自己找一个方向，一个目标 <br />
&nbsp;即使前行的道路充满艰辛，也不要放弃，也一定要坚持 </font></p>
<p><img src="http://image.bbs.tom.com/data1/pic/385/72/72978.jpg" alt="" /></p>
<p>一直牢牢记得,厚积而薄发 <br />
&nbsp;积累的过程常常让自己失去信心，看不到未来 <br />
&nbsp;也许只是等待一个时机 <br />
&nbsp;寻找一个突破口。喷发的是积聚已久的力量。 </p>
<p><img src="http://image.bbs.tom.com/data1/pic/385/72/72979.jpg" alt="" /></p>
<p>总会有疲惫的时候 <br />
&nbsp;总会有想要不管不顾的时候 <br />
&nbsp;于是会渴望一个世外桃源一样的屋子 <br />
&nbsp;即使简陋不堪,只要能逃离这纷扰凡尘 </p>
<p><img src="http://image.bbs.tom.com/data1/pic/385/72/72981.jpg" alt="" /></p>
<p>忧伤有时是一个人的本质,无法避免 <br />
&nbsp;表面再快乐的人其实也有不为人知的脆弱 <br />
&nbsp;只是需要一个时间。属于一个人纯粹的时间。收拾心情 <br />
&nbsp;不会让别人看到难过的泪水,笑容依然灿烂。 </p>
<p><img src="http://image.bbs.tom.com/data1/pic/385/72/72983.jpg" alt="" /></p>
<p>人这一生都在寻觅。寻觅相知的朋友。寻觅相亲的爱人 <br />
&nbsp;有些温暖是别人给予 <br />
&nbsp;同样也要自己真诚付出 <br />
&nbsp;两个人可以撑起一把大伞 <br />
&nbsp;风大雨大，一路同行。到底温暖几许</p>
<p><img src="http://image.bbs.tom.com/data1/pic/385/72/72985.jpg" alt="" /></p>
<p>生命如草芥 <br />
&nbsp;脆弱时候不堪一击 <br />
&nbsp;任人践踏 <br />
&nbsp;顽强时候，即便小小夹缝 <br />
&nbsp;依然可以青葱蓬勃 </p>
<p><img src="http://image.bbs.tom.com/data1/pic/385/72/72987.jpg" alt="" /></p>
<p>幸好这世界总有这样的绿色 <br />
&nbsp;在灰暗的墙头昂扬 <br />
&nbsp;平时不过不经意的抬头一瞥 <br />
&nbsp;也会感染到这样的活力 </p>
<p><img src="http://image.bbs.tom.com/data1/pic/385/72/72988.jpg" alt="" /></p>
<p>发明了飞机 <br />
&nbsp;人类实现飞翔的梦想 <br />
&nbsp;但是依然渴望可以有一双翅膀,一双梦想的翅膀 <br />
&nbsp;梦有多大。天有多高。心有多宽 <br />
&nbsp;为自己按上一双翅膀 </p>
<p><img src="http://image.bbs.tom.com/data1/pic/385/72/72989.jpg" alt="" /></p>
<p>我们会遇到各式各样的打击与阻力 <br />
&nbsp;小小的支持与鼓励。也会是一股强大的力量 <br />
&nbsp;但常常在需要这股力量的时候,却只是孤单一人 <br />
&nbsp;于是学着,自己给自己这样的力量与支持 <br />
&nbsp;哪怕全世界冷眼旁观。也请支撑下去。守得云开见月明 <br />
<img src="http://image.bbs.tom.com/data1/pic/385/72/72990.jpg" alt="" /></p>
<p><font color="#0000ff">&nbsp;相信自己,相信自己握在手中的每一件东西 <br />
&nbsp;有些东西看不见。并不代表它不存在 <br />
&nbsp;懂得把握的人。总有一天登上他自己心目中的顶峰 <br />
<img src="http://image.bbs.tom.com/data1/pic/385/72/72991.jpg" alt="" /></font></p>
          <br/>
          <span style="color:red;">
            <a href="http://fzfx88.javaeye.com/blog/136344#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>Mon, 29 Oct 2007 14:02:22 +0800</pubDate>
        <link>http://fzfx88.javaeye.com/blog/136344</link>
        <guid>http://fzfx88.javaeye.com/blog/136344</guid>
      </item>
      <item>
        <title>EJB3.0新规范</title>
        <author>fzfx88</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fzfx88.javaeye.com">fzfx88</a>&nbsp;
          链接：<a href="http://fzfx88.javaeye.com/blog/135536" style="color:red;">http://fzfx88.javaeye.com/blog/135536</a>&nbsp;
          发表时间: 2007年10月25日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><font face="Arial">文章来源：http://it.mr-w.cn/n/200603/24/n20060324_9592.shtml</font></p>
<p><font face="Arial">引言 </font></p>
<p><font face="Arial">　　期待已久的EJB3.0规范在最近发布了它的初稿。在本文中将对新的规范进行一个概要性的介绍，包括新增的元数据支持，EJBQL的修改，实体Bean模型访问bean上下文的新方法和运行时环境等等。作者还讨论了EJB在未来要作出的调整以及EJB3.0与其他开发规范之间的关系。</font></p>
<p><font face="Arial">　　开始</font></p>
<p><font face="Arial">　　无论如何由于EJB的复杂性使之在J2EE架构中的表现一直不是很好。EJB大概是J2EE架构中唯一一个没有兑现其能够简单开发并提高生产力的组建。 EJB3.0规范正尝试在这方面作出努力以减轻其开发的复杂性。EJB3.0减轻了开发人员进行底层开发的工作量，它取消或最小化了很多（以前这些是必须实现）回调方法的实现，并且降低了实体Bean及O/R映射模型的复杂性。</font></p>
<p><font face="Arial">　　在本文中，我首先会介绍EJB