<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>ginge</title>
    <description>植晶晶</description>
    <link>http://ginge.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>把握现在，把握未来—2008 Java开发展望</title>
        <author>ginge</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://ginge.javaeye.com">ginge</a>&nbsp;
          链接：<a href="http://ginge.javaeye.com/blog/177572" style="color:red;">http://ginge.javaeye.com/blog/177572</a>&nbsp;
          发表时间: 2008年03月29日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          过去的十二个月给来年预示了什么呢？<br /><br />By Andrew, JavaWorld.com 01/24/08<br /><br />译者：ginge<br /><br /><br /><a href="http://www.javaworld.com/javaworld/jw-01-2008/jw-01-javain2008.html" target="_blank">The future is now -- Java development in 2008</a><br />What do the past 12 months tell us about the year ahead?<br />By Andrew Glover, JavaWorld.com, 01/24/08<br /><br /><br />the year 2007 was full of exciting plot twists, punctuated by growing excitement about dynamic languages, the open source evolution of the JVM, and the rise of Google as a strategic contributor to the Java community. The question is, what does all that tell us about the year ahead? Andrew Glover has some answers for Java developers who need to know -- now! -- what's coming in 2008.<br />2007充满了激荡人心的事件，动态语言的不断升温，JVM在开源社区不断发展以及Java社区的重要贡献者，Google的崛起等。问题是，这些预示了来年什么呢？安德鲁•格勒弗（Andrew Glover）准备了一些答案给那些打破砂锅问到底的Java开发者――现在，什么在2008接踵而至。<br /><br /><br />French poet Paul Valery once lamented that "the trouble with our times is that the future is not what it used to be." Valery's comment was uttered years ago, yet his words are timeless for those of us living in the age of the Internet, fueled by the rise of the Java platform.<br />法国诗人保尔•瓦雷里曾经伤心地写下“困扰我们这个时代的是，未来，并不像过去看上去的那样”。然而，对于我们这些生活在Java平台崛起推动的互联网时代的人来说，瓦雷里多年前留下的这些诗句是永恒的。<br /><br />in the span of a little more than a decade we've seen Java applets come and go. We've seen the apparent demise of EJB, the rise of JSF, Spring, and Struts (not to mention the beginnings of Strut's slow decline), and the redefinition of Java itself into both a language and a platform. The Java platform has split into three branches (Standard, Enterprise, and Micro) and the JDK has been released to the open source community. The Java language has expanded to include annotations, generics, enumerations, advanced collections, and more. It has also begun to share its home, the JRE, with dynamic languages like Groovy, JRuby, and Rhino, to name a few. In fact, if you think about it, especially over the last few years, we've collectively watched as the moniker of Java has transformed from a language into a veritable platform.<br />过去的十多年，我们见证了Java Applet的兴起和没落，见证了EJB头顶上光环的不断暗淡，见证了JSF，Spring和Struts的异军突起（暂且不谈Struts渐渐显露的颓势），见证了Java已经重新定义成为一种语言和一个平台。Java平台已经衍生出三个分支（标准版本，企业版本，微型版本），JDK也开放给了开源社区。Java语言扩充了，包含了注解，范型，枚举类型，高级集合类型，还有更多。它也开始与动态语言，如Groovy，JRuby和Rhino等，共享Java运行时（JRE）。事实上，如果稍稍留神一下，我们在过去的几年里注视着Java不断地从一种语言演变成为一个真正的平台。<br /><br /><br />What we've learned in the last decade is that Java is much more than a language or a platform: It's a community. It's an economic ecosystem. It's a living, breathing entity that has matured and grown into a veritable lifeline for a cornucopia of applications, and for large and small companies alike.<br />在最近的十年里，我们知道Java已经不仅仅局限于一种语言或者一个平台了：它是一个社区，一个经济生态系统，一个鲜活的实体，而且这个实体已经发展成熟，成为了丰富的应用程序，或大或小公司的真正的生命线。<br /><br /><br />And so, despite some rumors to the contrary, I would argue that Java isn't going anywhere but up in 2008. Rather than peer into a crystal ball and try to divine the future, let's reflect on the major events and trends of the past year. Taken together, they reveal all we need to know about what's ahead in 2008.<br />因此，尽管流言不少，我还是坚持认为Java在2008会持续红火。与其拿起卦子掐算未来，我们不如回顾一下过去的一年的趋势以及发生的重大事件。这些事件汇集起来，它们会告诉我们2008将发生什么。<br /><br />Halcyon days<br />遍地开花<br /><br />The year 2007 was a roller-coaster ride driven, most dramatically, by growing interest in dynamic languages, the open source evolution of the JVM, and the rise of Google as a strategic contributor to the Java community. What's more, wider adoption of unit testing, continuous integration, and other agile development techniques suggests that Java developers are beginning to view our craft as a profession that requires accountability. We are finally starting to focus on the quality and longevity of our code as much as its speed to market or immediate applicability in the enterprise.<br />2007年犹如过山车一样，非常引人注目。人们对动态语言的不断关注， JVM在开源社区不断发展以及Java社区的重要贡献者，Google的崛起。更多的是，单元测试，持续化集成和其他敏捷开发技术得到了更广泛的接受，这些都表面Java开发者开始认识到我们的技艺是一门有责任要求的行业。我们终于开始重视代码的质量和寿命，将其与推向市场的速度，或者是在企业的即时应用放到同等重要的地位上来。<br /><br />All told, 2007 was a year of some clear triumphs, as well as some disappointments and squabbles that made for more bumps along the way than some in the Java community had anticipated. Consider the following major factors that shaped the year behind us.<br />每个人都说，2007年有一些绝对的胜利，但是同时也有一些失望和争论，这给Java社区产生了超出预期更多的阻碍。留心一下以下这些体现过去一年的重大因素。<br /><br /><br />Dynamic languages come of age<br />动态语言的成熟<br /><br />Groovy reached a pivotal milestone in 2007 with its 1.0 release, followed in short order by Groovy 1.5. Having come a long way over the course of five or so years, Groovy is positioned as an additional language for the JRE, not a replacement for the Java language.<br />随着1.0以及随后的1.5版本的发布，Groovy在2007的发展达到了一个关键的里程碑。走过过去5年或者多年的历程，Groovy没有替代Java，相反定位成了Java运行时（JRE）的补充语言。<br /><br />Groovy's big selling point is its shorthand syntax, which simplifies everyday programming activities. For instance, opening and reading a file is a typically verbose construct to code in normal Java:<br />Groovy的大卖点是简练的语法，简化了日常的开发工作。例如，打开和读取一个文件在Java语言是典型的冗长结构：<br /><br /><pre name="code" class="java">
try {
     BufferedReader in = new BufferedReader(
        new FileReader(path));
     String line;
     while((line = in.readLine()) != null){
       System.out.println(line);
     }
     in.close();
    }catch(IOException e){
      System.err.println("Exception reading");
    }
</pre><br />But the same code in Groovy can be written much more quickly:<br />但是同样的代码，Groovy可以写的更加敏捷：<br /><br /><pre name="code" class="java">
new File(path).eachLine{ line ->
     println line
}
</pre><br /><br />Basically, Groovy (like other dynamic languages) permits you to drop exception handling, types, and semi-colons, and even permits more concise coding constructs that make the code ultimately easier to read (yes, that File object above is Java's java.io.File).<br />根本上，Groovy，像其他动态语言一样，可以让你你扔掉异常处理，类型和分号，还可以使得代码更加简练，而代码简练最终使得代码的可读性更强（是的，上面那个File对象是一个Java java.io.File对象）。<br /><br /><br />Cast your net wide<br />把网撒开<br />Groovy wasn't the only player on the dynamic language block in 2007, however. Java 6 (released in 2006) introduced a standard API for interacting with dynamic languages, which many Java developers began exploring in earnest late last year. The flagship integration for that API was Rhino, but it seems that more engines will be integrated with the Java 7 release.<br />然而， Groovy并不是2007年动态语言阵营的唯一参与者。2006年发布的Java 6版本引入了一个与动态语言交互的标准API，很多Java开发者在去年临近年底才开始体验。对该API进行旗舰式集成的是Rhino。但是，看起来在Java7版本发布时还会有更多集成进来。<br /><br />One of the first languages slated for integration is undoubtedly JRuby, which rose to rapid prominence with its 1.0 release and the surprising realization that it is faster than Ruby itself! Like Groovy, JRuby (which allows Ruby to run on the JVM and interact with normal Java objects) makes Java development simpler by permitting a more relaxed syntax and adding a wee bit of magic. For example, using Ruby allows you to enhance normal objects, such as Ruby's String to do things perhaps a bit more easily. In normal Java, checking if a String instance is blank may require using a method like what's below (which is the Apache commons-lang implementation of isBlank).<br />最早进行集成的语言之一不容置疑是JRuby，1.0版本的发布和令人咋舌的比Ruby本身运行速度还快的实现，使得它备受瞩目。像Groovy一样，由于可以使用更加宽松的语法，加入了一些特殊机制的JRuby（它可以使RubyJVM里运行，且与正常的Java对象交互）使Java开发更加简单。例如，使用Ruby可以增强标准的对象，象用Ruby的String操作会更加容易。在标准的Java里，检查一个String实例是否为空值可能要做象如下方法的一样的操作（这是一个Apache commons-lang的 isBlank实现）。<br /><br /><pre name="code" class="java">
public static boolean isBlank(String str) {
 int strLen;
 if (str == null || (strLen = str.length()) == 0) {
  return true;
 }
 for (int i = 0; i &lt; strLen; i++) {
  if ((Character.isWhitespace(str.charAt(i)) == false)) {
   return false;
  }
 }
 return true;
}
</pre><br /><br />String in Java is a final class, so you can't extend it to add a new enhanced string type to support an isBlank method, for instance. Consequently, you have to rely on a separate library, like common-lang. With Ruby, you can alternatively define a blank? method on Ruby's String object itself, like so:<br />在Java里，String是一个final类，所以你无法为了让String类型支持一个象isBlank的方法而扩展它。后果是，你不得不依赖第三方类库，象common-lang。有了Ruby，你就可以在Ruby的String上另外定义一个blank?方法，如：<br /><br /><pre name="code" class="java">
class String
 def blank?
  empty? || strip.empty?
 end
end
</pre><br /><br />Ruby's style of dynamism permits adding behavior (like adding a blank? method to String) to core libraries -- or any object, in fact -- at runtime. What's more, with JRuby you can retroactively add methods to core Java objects, too. Thus it takes just a little magic to add a blank? method to Java's String class!<br />实际上，Ruby式的动态允许运行时添加额外的行为到核心类库或任意对象（象给String增加一个blank?方法）。更进一步，JRuby可以进行反作用对核心Java对象增加方法。因此，稍一施法就可以给Java String类添加一个blank?方法。<br /><br /><br />Opening up the heart<br />开放Java核心<br />The open sourcing of Java last year means that the evolution of the Java platform is no longer solely in the hands of core Sun engineers: now it is up to all of us. OpenJDK, which embodies a GPL license around the Java class library, javac, and even the JVM itself, promises to usher in a whole new cycle of innovation -- in fact, we're already seeing it.<br />去年Java的开源意味Java平台的发展不再由Sun核心工程师们说了算了：现在它的前途由我们掌握了。对Java类库，Javac，甚至JVM本身都采取GPL协议，OpenJDK保证将会开创一个创新的周期。实际上，我们已经看到了。<br /><br />In October of 2007, a project dubbed Multi-Language VM was proposed under the OpenJDK charter. The aim of this project is to mollify the underlying infrastructure of Java for "prototyping JVM features aimed at efficiently supporting languages other than Java." Clearly, this initiative blends two of last year's most exciting developments -- that is, the enthusiasm surrounding dynamic languages and the OpenJDK -- to usher in a new age of innovation at the heart of Java.<br />在2007年十月，一个名为Multi-Language VM的项目在OpenJDK旗下开展了。这个项目旨在通过修改Java的底层架构，实现“以JVM特性为原型，高效支持Java之外的语言”。很明显，这项目结合了去年最令人振奋的两个发展潮流，也就是围绕在动态语言的热衷和OpenJDK，这宣称我们处在了一个Java核心创新的时代。<br /><br />Sun's openness certainly didn't start with the OpenJDK project -- Glassfish, a Sun supported open source application server, also continued to gain a wider community throughout 2007. More recently, it is impossible to ignore Sun's acquisition of MySQL AB, the corporate entity behind MySQL, which is arguably the prevailing open source database today.<br />Sun的开放当然不是从OpenJDk开始的，而是Glassfish，作为Sun支持的开源应用服务器，它在2007自始至终获得了社区更多的追捧。最近，我们无法忽略Sun对MySQL AB的收购， MySQL背后的公司是MySQL AB，而MySQL似乎是当今最流行的开源数据库。<br /><br /><br />All of these developments suggest that Java's progenitor is embracing a business model that leverages open source software in a big way, which means we can look forward to seeing more openness in the Java platform in 2008 and beyond. Of course, all of this may have far-reaching consequences for commercial aspects of the Java ecosystem -- which thus far appears to be quite healthy given Oracle's recent 7 billion dollar purchase of BEA.<br />所有这些发展都表明Java的鼻祖采取了一种受开源软件很大影响的商业模式。这意味我们在2008或者更远将看到Java平台更多的开放。当然，这会对Java生态系统的商业方面产生深远影响。相比最近Oracle以70十亿美金收购BEA，这似乎很绿色，很健康。<br /><br /><br />Google flexes<br />Google flexes<br />In late 2007 the mobile Java landscape, which had recently been somewhat scorched, was reinvigorated by the announcement of Google's Android platform. Android aims to bring software applications to a new breed of mobile devices running an open source OS primarily led by Google. While Android is an entire platform (much like Java), the SDK for building Android applications is built on Java.<br />移动Java领域曾经变的不景气，但是临近2007年尾时，却因Google的Android平台的发布而重焕青春。Android的目标是为新一代移动设备引入应用软件，且运行在由Google主导的开源操作系统之上。虽然Android是一个完整的平台（很像Java），但是构建Android应用程序的SDK却是建立在Java之上。<br /><br />Moreover, Android's Java is distinctly different from the Java of J2ME. In fact, the underlying JVM for Android is unique as far as JVMs go: it doesn't run normal Java bytecode but a highly optimized format designed just for Android. Having multiple implementations of Java running on mobile devices means that we'll most likely be seeing some interesting applications -- which of course only adds to the ubiquity of the Java platform.<br />此外，Android的Java与J2ME的Java截然不同。实际上，在JVM层面，Android的JVM就已相当独特了。除了运行专门为Android而设计，高度优化的字节码格式的代码，它不可以运行标准Java字节码。移动设备上运行不同实现的Java意味这我们将可以看到一些有趣的应用程序――当然，这也仅进一步说明了Java的无处不在。<br /><br /><br />Google's hand in Java went well beyond mobility in 2007, however. Of particular interest was the release of Guice, an open source dependency injection framework built on top of Java 5's annotations and generics. While the big dog in the IOC market is still Spring, at the time of Guice's public release it was a trailblazer, eschewing XML files in favor of annotations and Guice's own Module types.<br />2007年Google在Java世界移动领域之外也进展的很顺利。但是，备受关注的是Guice的发布，Guice是一个基于Java 5注解和范型的依赖注入开源框架。虽然IOC市场上的佼佼者还是Spring，因其摒弃XML文件，提倡使用注解和Guice本身的Module类型，注定了Guice在公开发布时就是一个先行者。<br /><br />Given the weight of Google behind a second-generation IOC framework and the fact that Guice is relied upon for Google's own AdWords infrastructure, it's a good bet that it will continue to gain mindshare in the next year.<br />考虑到Google对第二代IOC框架的影响和Google AdWrods本身的基础架构都是依赖Guice的，Guice在来年很有可能将得到更多的关注。<br /><br />Agility goes mainstream -- testing arrives!<br />敏捷成为主流――测试时代到来了<br /><br />The term agile isn't new, nor are the practices of unit testing and continuous integration. Nonetheless, 2007 appears to be have been the year these practices became more mainstream. You couldn't attend a conference without encountering one or more presentations focused on agility. More telling, a quick scan of the 2008 Jolt Awards finalists (which are chosen in 2007) for General Books and Technical Books shows a solid foothold for books about unit testing and continuous integration. Most important of all, however, is the fact that both established frameworks and new players to the field have begun to tout how easy their particular architecture is to test! It seems that developer testing has finally arrived.<br /><br />敏捷（agile）这个名称对大家来说并不新鲜，单元测试与持续化集成也不陌生。不过，2007年似乎是这些实践更加成为主流的年份。你不会碰到一个会议里没有一到两个关注在敏捷上的演示的。再哆嗦几句，瞥一眼2008年度Jolt Award大奖关于综合性和技术性书籍（从2007年甄选的）的最终名单，就可以看出关于单元测试和持续化集成的书籍占有一席之地。然而，更重要的是，不管是享有盛誉的，还是刚刚发展的框架都已经开始宣称它们的架构是多么容易地进行测试了。似乎，开发人员的测试时代终于到来了。<br /><br /><br />Java's growing pains<br />Java成长之痛<br /><br />While it's clear that Java is becoming more a platform than just a language, the Java language has continued to grow and expand. For better or for worse, features have been added and will continue to be added, should the community find them acceptable.<br />Java在不断的成长，不断的扩充，然而它在逐渐变化成为一个平台，而不仅仅是一种语言。不知是好还是坏，独具特性的东西一直在不断的添加进来，以后还将会有，社区会接受特性吗？<br /><br />Some features are not as welcome as others, however. For instance, annotations were a win for the masses -- frameworks like JUnit 4, TestNG, Spring, and Google's Guice grabbed impressive developer mind-share through innovative uses of annotations. Conversely, generics (which were introduced in Java 5) have so far been inconsistently adopted-- at least in their full spirit.<br />然而，一些特性就没有其他特性那样受欢迎了。举个例子来说，注解就很受欢迎――象JUnit4， TestNG， Spring和Google的Guice这些框架，由于对注解的创新的使用，就得到了不少开发人员的青睐。相反的是，到目前为止，人们对范型（在Java 5中引入）并没有保持对其自始至终的热情。<br /><br /><br />No closure(s) in sight ...<br />闭包（Closure）未见踪影<br /><br />If generics didn't cloud the coding landscape enough, one might find the current discussions surrounding the proposed addition of closures and local functions into Java 7 foggy indeed. While I certainly won't argue their usefulness as constructs, adding them to the Java language syntax could obviate their usefulness by increasing conceptual entropy.<br />如果范型不足以使编程的前景变的灰暗，有人可能会发现当前围绕关于在Java 7 foggy中加入闭包和局部函数提议的争论。虽然我绝不会否认它们是有用的组成部分，只是，将它们增加到Java语言的语义中，概念的复杂性增加只会降低它们的有用性。<br /><br />For example, in a prototype reference implementation of closures, one can find the following code, which defines a simple closure supporting Integer addition:<br />例如，在一个闭包的典型参考实现中，找到如下代码，它定义了一个简单的支持整数加法的闭包：<br /><br /><pre name="code" class="java">
{Integer,Integer=>Integer} plus1 = {Integer x, Integer y => x+y};
</pre><br /><br /><br />What's particularly interesting is the verbosity of the statement due to Java's innate syntactical requirements -- one could easily rewrite the same functionality in Groovy, for example, as<br />非常有趣的是，由于Java天生的对语义要求，语句变的拖沓冗余――用Groovy来重写同样功能，却很容易。例如<br /><br /><pre name="code" class="java">plus1 = { x, y -> x+y }</pre> <br /><br />Note that the dearth of types arguably makes human parsing of the code's intent easier in the Groovy example. Of course, Ruby's version would be as terse too.<br />注意到，在Groovy的例子中，类型的缺失无疑使得代码的意图一目了然。当然，Ruby版本也会同样简明扼要。<br /><br />It's clear that outside forces, such as the popularity of dynamic languages (which already include closures) are influencing Java. You don't have to wait for native closures in Java 7 if you want to use them, though -- both Groovy and JRuby support them quite nicely.<br />显然，象动态语言普遍受到欢迎此类的外部力量在不断地影响Java。如果想使用闭包，你完全不必等待Java自带的闭包――Groovy和JRuby对其的支持就已经很优雅。<br /><br /><br />True concurrency<br />真正的并发<br /><br />Something else to look forward to with Java 7 is the release of the java.util.concurrent packages, which aim to address true concurrency for Java applications by leveraging underlying hardware. While Java has always supported threading, hardware assets continue to become more robust through a greater emphasis on parallelism; consequently, the Java language is growing to meet these demands.<br />Java7值得期待的其他事情是java.util.concurrent包的发布，这个包致力于通过充分利用底层硬件来达到真正的并发。虽然Java已经支持多线程，但是通过对并行性的进一步重视，硬件资源将变的越来越健壮。最终，Java语言也发展的可以应付这些要求。<br /><br />Led by the JSR 166 Expert Group, Java 7 will most likely include a few new features including a fine-grained parallel computation framework dubbed join-fork. The good news is that it appears these features are new classes (and APIs) and are not syntactical in nature.<br />由JSR 166专家组领导的Java 7将很有可能包含一些新特性，包括名为join-fork的细粒度的并行计算框架。好消息是，看起来这些新特性是崭新的类（和API），与生俱来就不符合句法规则。<br /><br />The race to RIA<br />奔向RIA<br /><br />Rich Internet Applications continued to generate lots of interest among Java Web application developers last year, especially after Sun unveiled JavaFX at JavaOne 2007. The JavaFX product family currently consists of JavaFX Script and JavaFX Mobile.<br />去年，特别是Sun在2007年JavaOne上让JavaFx对公众面世后，RIA（Rich Internet Application）继续让Java Web应用程序开发人员产生莫大的兴趣，。JavaFX产品家族现在由JavaFX Script和JavaFX Mobile组成。<br /><br /><br />Reaction to JavaFX appears mixed given the ubiquity of JavaScript for developing Ajax-like applications. It has also been suggested that JavaFX Mobile could widen rifts in an already fragmented mobile environment. All told, many in the community found the JavaFX announcement rushed, and some question whether it is vaporware. Nevertheless, Sun's entrance into the RIA space surely signals a long-term strategy, which further secures Java's future.<br />由于开发类Ajax应用的JavaScript无处不在，对JavaFx的反应显得见仁见智。看起来JavaFX将会加剧本来就已经四分五裂的移动环境之间的裂缝。很多人感觉JavaFX的公告有点操之过急，还有一些人怀疑它究竟是不是一个雾件。不管怎样，Sun进入RIA领域传达了一个长期战略的消息，这会使Java的前景更加光明。<br /><br /><br />In conclusion<br />结语<br /><br />An African proverb states that Tomorrow belongs to the people who prepare for it today. Thus, the future of Java (at least for the next year) has already been brewing for some time. The events of 2008 will largely be shaped by the JVM itself, as languages like JRuby and Groovy grow in popularity and eventually gain enterprise-wide adoption. The promise of using Java to develop consumer mobile applications also seems more accessible than it has for some time, given Google's foray with Android and Sun's with JavaFX Mobile. Most of us will also be concerned with leveraging the emerging multicore systems and looking to Java 7's java.util.concurrent packages for answers. Lastly, open source Java and the business model surrounding it will continue to grow.<br />有句非洲谚语说“明天属于那些今天为它准备的人”。因此，Java的未来（至少来年）已经孕育了一段时间了。2008年的大事的很大部分将不仅由JVM本身促成，而且也会随着JRuby和Groovy不断受欢迎，最终得到更多厂商的采纳而形成。由于Google Android的出击和Sun JavaFX Mobile的发布，使用Java开发用户移动应用的前景也好像比以前更加容易到达了。大部分人的注意力将被多核系统的出现吸引过去，期待Java 7 java.util.concurrent包对其的回应。最后，围绕它的开源的Java和商业模型也会不断的成长。<br /><br />Acknowledgments<br />致谢<br /><br />I'd like to thank the following individuals whose valuable insights regarding all things Java helped shaped this article: Neal Ford, Andres Almiray, Dan Allen, Ted Neward, Scott Stirling, Scott Moore, John Smart, Nate Schutta, Michael Nyika, Venkat Subramaniam, Guillaume Laforge, Scott Delap, Paul Duvall, Yvonne, David Pinkham, Rod Coffin, Andrew Binstock, Ken Brooks, Jay Zimmerman, Paul Julius, Tom Copeland, Navjeet Chabbewal, Jason Rudolph, Chris Judd, Dave Aronson, Cliff Berg, David Bock, and finally Alex Ruiz. Thank you all for answering my questions!<br />我真心感谢以下的个人，是他们关于Java的真知灼见促成了本文：Neal Ford, Andres Almiray, Dan Allen, Ted Neward, Scott Stirling, Scott Moore, John Smart, Nate Schutta, Michael Nyika, Venkat Subramaniam, Guillaume Laforge, Scott Delap, Paul Duvall, Yvonne, David Pinkham, Rod Coffin, Andrew Binstock, Ken Brooks, Jay Zimmerman, Paul Julius, Tom Copeland, Navjeet Chabbewal, Jason Rudolph, Chris Judd, Dave Aronson, Cliff Berg, David Bock, 最后还有Alex Ruiz。非常感谢你们回答了我的问题。<br /><br /><br />Author Bio<br />Andrew Glover is president of Stelligent Incorporated, a consulting firm that helps development teams accelerate software development. He blogs regularly at thediscoblog.com and testearly.com.<br /><br />作者简介<br />Andrew Glover是Stelligent Incorporated的总裁，Stelligent Incorporated是一家帮助开发团队加速软件开发的咨询公司。他的blog通常是thediscoblog.com and testearly.com。<br /><br /><br /><br />Resources<br /><br />•	"Scripting on the Java platform" (Gregor Roth, JavaWorld, November 2007) introduces the when and how of using scripts in your Java applications, with examples based on Groovy, Jython, and JRuby. <br />•	"JRuby on Rails: The power of Java, the simplicity of Rails" (Joshua Fox, JavaWorld, February 2007) explains why JRuby may be a better RoR development choice than Ruby. <br />•	"Multicore processing for client-side Java applications" (Kirill Grouchnikov, JavaWorld, September 2007) offers an overview of the multicore processing challenge, as well as a client-side solution based on the new concurrency utilities. <br />•	The Multi-Language VM is an OpenJDK project aimed at prototyping JVM features that will support languages other than Java. <br />•	"Your plastic pal who's fun to be with" (Simon Morris's blog, December 2007) is a quick foray into developing on the Android platform. <br />•	See "Sun to acquire MySQL for US$1 billion" (Jeremy Kirk, IDG News Service, January 2008) to learn more about Sun's expansion in the open source database market. <br />•	Also see Network World's IT Buyer's Guides: Side-by-side comparison of hundreds of products in over 70 categories. <br />JavaWorld podcasts<br />•	Find out what's so great about Groovy on your way to work, by listening to the JavaWorld podcast interview with AboutGroovy editor Scott Davis (JavaWorld's Java Technology Insider, November 2007). <br />•	You can learn more about what's so great about JRuby by listening to Andrew Glover's podcast interview with Neal Ford (JavaWorld's Java Technology Insider, November 2007). <br />•	In another podcast interview in the same series, No Fluff Just Stuff creator Jay Zimmerman shares his thoughts about smart migrations for 2008 (JavaWorld's Java Technology Insider, January 2008). <br /><br /><br />资源<br /><br />•	"Scripting on the Java platform" (Gregor Roth, JavaWorld, November 2007) 介绍了在Java应用中何时以及怎样使用脚本，附有基于Groovy，JPython，JRuby的例子。<br />•	"JRuby on Rails: The power of Java, the simplicity of Rails" (Joshua Fox, JavaWorld, February 2007) 解释了在RoR开发者，JRuby可能是一个比Ruby更好的选择。<br />•	"Multicore processing for client-side Java applications" (Kirill Grouchnikov, JavaWorld, September 2007)提供了多核处理挑战的纵览，以及基于崭新的多并发工具的客户端解决方案。<br />•	Multi-Language VM 是一个开源JDK项目，旨在 “以JVM特性为原型，高效地支持除Java之外的语言”<br />•	"Your plastic pal who's fun to be with" (Simon Morris's blog, December 2007) 在Androi平台上开发的一个开创性尝试<br />•	查看 "Sun to acquire MySQL for US$1 billion" (Jeremy Kirk, IDG News Service, January 2008)以获悉Sun在开源数据库市场扩张的更多讯息。<br />•	Network World's IT Buyer's Guides:  超过70个种类，数以百计产品的对比。<br />JavaWorld播客<br />•	听听JavaWorld播客对AboutGroovy editor Scott Davis(JavaWorld's Java Technology Insider, November 2007)的采访，了解了解Groovy对你的工作的高明之处。<br />•	听听Andrew Glover的podcast interview with Neal Ford (JavaWorld's Java Technology Insider, November 2007)，你可以知道JRuby有什么高明之处。<br />•	在同系列的另外一个播客采访中，No Fluff Just Stuff的创始人Jay Zimmerman分享了他的关于smart migrations for 2008 (JavaWorld's Java Technology Insider, January 2008)的想法
          <br/>
          <span style="color:red;">
            <a href="http://ginge.javaeye.com/blog/177572#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sat, 29 Mar 2008 12:22:22 +0800</pubDate>
        <link>http://ginge.javaeye.com/blog/177572</link>
        <guid>http://ginge.javaeye.com/blog/177572</guid>
      </item>
      <item>
        <title>Note on JGroup Cluster of TCP_NIO Transport</title>
        <author>ginge</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://ginge.javaeye.com">ginge</a>&nbsp;
          链接：<a href="http://ginge.javaeye.com/blog/175348" style="color:red;">http://ginge.javaeye.com/blog/175348</a>&nbsp;
          发表时间: 2008年03月24日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          Our application need to meet the reliable communication and the least data loss requirements for the JGroup cluster. The JGroup-2.6.1 release provides some out-of-box configurations in xml format. I choose the tcp-nio.xml configuration, because the inefficiency of the traditional IO model and unreliable data transmission of UDP. In this article I will try to explain why we prefer TCP-NIO method and then the configuration details from tcp-nio.xml.<br /><br />1<br />1.1<br />Why TCP-NIO?<br /><br />Traditional I/O classes have primarily been stream-oriented, often invoking methods on several layers of objects to handle individual bytes or characters.<br /><br />This object-oriented approach, composing behaviors by plugging I/O objects together, offering tremendous flexibility but can be a performance killer when large amounts of data must be handled. Efficiency is the goal of I/O, and efficient I/O often doesn't map well to objects. Efficient I/O usually means that you must take the shortest path from Point A to Point B. Complexity destroys performance when doing high-volume I/O.<br /><br />The traditional I/O abstractions of the Java platform have served well and are appropriate for a wide range of uses. But these classes do not scale well when moving large amounts of data, nor do they provide some common I/O functionality widely available on most operating systems today. These features — such as file locking, non-blocking I/O, readiness selection, and memory mapping — are essential for scalability and may be required to interact properly with non-Java applications, especially at the enterprise level. The classic Java I/O mechanism doesn't model these common I/O services.<br /><br />Java Specification Request#51 (http://jcp.org/jsr/detail/51.jsp) details the need for high-speed, scalable I/O, which better leverages the I/O capabilities of the underlying operating system.<br /><br />—from O’Reilly Java NIO<br /><br />1.2<br />Why not UDP?<br />Our application might need to go over WAN, and there is chance that some routers over become overloaded which result in discarding packets. The Order the router drops a packet is Broadcast, Multicast, and finally Unicast.<br /><br /><br />2 <br />2.1 Overview<br />JGroups uses a JChannel as the main API to connect to a cluster, send and receive messages, and to register listeners that are called when things (such as member joins) happen. <br /><br />What is sent around are Messages, which contain a byte buffer (the payload), plus the sender's and receiver's address. Addresses are subclasses of org.jgroups.Address, and usually contain an IP address plus a port.<br /><br />To join a cluster, we'll use a JChannel. An instance of JChannel is created with a configuration (e.g. an XML file) which defines the properties of the channel.<br /><br />The protocol stack contains a number of protocol layers in a bidirectional list. All messages sent and received over the channel have to pass through the protocol stack. Every layer may modify, reorder, pass or drop a message, or add a header to a message.<br /><br />The protocol stack in the xml configuration file outlines the protocols bottom-up, take tcp-nio,xml for example, bottom protocol is TCP_NIO and the upmost protocol is pbcast.STREAMING_STATE_TRANSFER. The order shouldn’t be changed.<br /><br />2.2<br />Let’s take a look at the configuration:<br /><pre name="code" class="xml">
&lt;config>
&lt;TCP_NIO
        bind_addr="localhost"
            start_port="7800"
            loopback="true"
            recv_buf_size="20000000"
            send_buf_size="640000"
            discard_incompatible_packets="true"
            max_bundle_size="64000"
            max_bundle_timeout="30"
            use_incoming_packet_handler="true"
            enable_bundling="true"
            use_send_queues="false"
            sock_conn_timeout="300"
            skip_suspected_members="true"
            use_concurrent_stack="true"

            thread_pool.enabled="true"
            thread_pool.min_threads="1"
            thread_pool.max_threads="25"
            thread_pool.keep_alive_time="5000"
            thread_pool.queue_enabled="false"
            thread_pool.queue_max_size="100"
            thread_pool.rejection_policy="Run"

            oob_thread_pool.enabled="true"
            oob_thread_pool.min_threads="1"
            oob_thread_pool.max_threads="8"
            oob_thread_pool.keep_alive_time="5000"
            oob_thread_pool.queue_enabled="false"
            oob_thread_pool.queue_max_size="100"
            oob_thread_pool.rejection_policy="Run"

            reader_threads="3"
            writer_threads="3"
            processor_threads="0"
            processor_minThreads="0"
            processor_maxThreads="0"
            processor_queueSize="100"
            processor_keepAliveTime="9223372036854775807"/>
    &lt;TCPPING timeout="3000"
             initial_hosts="${jgroups.tcpping.initial_hosts:localhost[7800],localhost[7801]}"
             port_range="1"
             num_initial_members="3"/>
    &lt;MERGE2 max_interval="100000"
              min_interval="20000"/>
    &lt;FD_SOCK/>
    &lt;FD timeout="10000" max_tries="5"   shun="true"/>
    &lt;VERIFY_SUSPECT timeout="1500"  />
    &lt;pbcast.NAKACK
                   use_mcast_xmit="false" gc_lag="0"
                   retransmit_timeout="300,600,1200,2400,4800"
                   discard_delivered_msgs="true"/>
    &lt;pbcast.STABLE stability_delay="1000" desired_avg_gossip="50000"
                   max_bytes="400000"/>
    &lt;VIEW_SYNC avg_send_interval="60000"/>
    &lt;pbcast.GMS print_local_addr="true" join_timeout="3000"
                shun="true"
                view_bundling="true"/>
    &lt;FC max_credits="2000000"
        min_threshold="0.10"/>
    &lt;FRAG2 frag_size="60000"  />
    &lt;pbcast.STREAMING_STATE_TRANSFER/>
&lt;/config>
</pre><br /><br /><br />1）	TCP is a replacement of UDP as bottom layer in cases where IP Multicast based on UDP is not desired. This may be the case when operating over a WAN, where routers will discard IP MCAST. As a rule of thumb UDP is used as transport for LANs, whereas TCP is used for WANs. Whereas TCPNIO is a replacement of TCP, TCP_NIO performs much better because it fully take advantage of the NIO services.<br />2）	TCPPING The TCPPING protocol layer retrieves the initial membership in answer to the GMS's FIND_INITIAL_MBRS event.<br />3）	MERGE2 If a group gets split for some reasons (e.g. network partition), this protocol merges the subgroups back into one group.<br />4）	FD_SOCK Failure detection protocol based on a ring of TCP sockets created between group members.<br />5）	FD Failure detection based on heartbeat messages. If reply is not received without timeout ms, max_tries times, a member is declared suspected, and will be excluded by GMS. If we use FD_SOCK instead, then we don't send heartbeats, but establish TCP sockets and declare a member dead only when a socket is closed.<br />6）	VERIFY_SUBSPECT Verifies that a suspected member is really dead by pinging that member once again. Drops suspect message if member does respond. Tries to minimize false suspicions.<br />7）	pbcast.NAKACK Lossless and FIFO delivery of multicast messages, using negative acks. E.g. when receiving P:1, P:3, P:4, a receiver asks P for retransmission of message 2.<br />8）	VIEW_SYNC Periodically sends the view to the group. When a view is received which is greater than the current view, we install it. Otherwise we simply discard it. This is used to solve the problem for unreliable view dissemination outlined in JGroups/doc/ReliableViewInstallation.txt. This protocol is supposed to be just below GMS.<br />9）	pbcast.GMS Group Membership Service. Responsible for joining/leaving members. Also handles suspected members, and excludes them from the membership. Sends Views (topology configuration) to all members when a membership change has occurred.<br />10）	FC Credit based flow control protocol. When senders send faster than receivers can process the messages, over time the receivers will run out of memory. Therefore the senders have to be throttled to the fastest rate at which all receivers can process messages.<br />11）	FRAG2  Fragments messages larger than frag_size bytes<br />12）	STREAMING_STATE_TRANSFER   In order to transfer application state to a joining member of a group pbcast.STATE_TRANSFER has to load entire<br />state into memory and send it to a joining member. Major limitation of this approach is that the state transfer that isvery large (>1Gb) would likely result in OutOfMemoryException. In order to alleviate this problem a new state transfer methodology, based on a streaming state transfer<br /><br /><br /><br /><br />Details descriptions of each protocols and its configuration parameter can be found on <a href="http://wiki.jboss.org/wiki/Wiki.jsp?page=JGroups" target="_blank">JGroup WIKI</a><br /><br /><br /><br />2.2 Notes on some important parameters:<br />2.2.1 bind_addr on TCP-NIO<br /><br />On which address JGroup to create the server socket. Though optional, it’s Useful in case of a multi-homed machine and you just want it bind on the specific address. If not specified, the server socket will be created on all available interfaces<br /><br />2.2.2 initial_hosts on TCPPING<br />The comma-separated lists of hosts names and ports used to connect to get the initial memberships. Note that there should not be spaces between the entries in the list. TCPPING.initial_hosts should contain the universe of all possible members. If you decide to add a new member who isn't listed in TCP.initial_hosts, that node will still be able to join, but you may have the problem<br /><br /><br />For example, there are 192.168.1.1, 192.168.1.2, 192.168.1.3 and 192.168.1.4 starting at port 7800 in the cluster:<br /><br />Your TCPPING’s configuration should be :<br /><pre name="code" class="xml">
&lt;TCPPING timeout="3000"
             initial_hosts="${jgroups.tcpping.initial_hosts: 192.168.1.1 [7800], 192.168.1.2 [7800], 192.168.1.3 [7800], 192.168.1.4 [7800]}"
             port_range="1"
             num_initial_members="4"/>
</pre><br /><br /><br /><br />All the other protocols and their respective parameters can remain untouched.
          <br/>
          <span style="color:red;">
            <a href="http://ginge.javaeye.com/blog/175348#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 24 Mar 2008 11:22:08 +0800</pubDate>
        <link>http://ginge.javaeye.com/blog/175348</link>
        <guid>http://ginge.javaeye.com/blog/175348</guid>
      </item>
      <item>
        <title>Have you known enough about DBCP？</title>
        <author>ginge</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://ginge.javaeye.com">ginge</a>&nbsp;
          链接：<a href="http://ginge.javaeye.com/blog/172788" style="color:red;">http://ginge.javaeye.com/blog/172788</a>&nbsp;
          发表时间: 2008年03月16日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>【本文如需转载，请注明作者及出处】 </p><p>&nbsp;</p><p><br />I think a lot of people have misunderstanding about DBCP. What makes them think so? <br />Cause' DBCP seems don't want to release database connection after use. Finally, all available connections got exhausted, and our application runs out of services. <br /><br />DBCP is weak and can not bear production pressures, according to them. It&rsquo;s worse that there are a lot of guys on the internet said so. <br /><br /><br />In fact, DBCP can absolutely take the job! <br /><br />Firstly, its release number has reached 1.2.2. Base on the Apache Version Numbering Project's theory, any products whose version number has evolved up to 1, it is eligible to be used in production environment. <br /><br />Second, I've run into such problem from my previous working experience, and my ex-colleague and I have made extensive tests on various Connection Pool products, such as Proxool, c3p0 and DBCP. <br />Result shows that DBCP behaves very well not only at responsiveness, stability, but also at performance. Once the network resume, it auto-reconnects instantly even after more than 8 hours network disconnection. <br /><br /><br /><span style="color: #ff0000">Third, I do the test again, but this time it&rsquo;s only between DBCP and c3p0. The test starts from running 3000&nbsp;to 5000 threads, which infinitely&nbsp;execute a query lasting at least 1 second. Effort have been made to let DBCP and C3p0 start equally, like the same initial pool size 0, the same max pool size and the same time out, etc. </span></p><p>&nbsp;</p><p>&nbsp;</p><p><br />Finally, I try to give you a detail introduction on the configurations of DBCP, focusing on the important parameters.</p><p>&nbsp;</p><p>&nbsp;All information comes from http://commons.apache.org/dbcp/configuration.html <br /><br /><br /><br />Part1, Besides the Normal parameters: <br /><br />username&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<span style="color: #0000ff">The connection username to be passed to our JDBC driver to establish a connection.</span> <br /><br />password&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; <span style="color: #0000ff">The connection password to be passed to our JDBC driver to establish a connection.</span> <br /><br />url&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">The connection URL to be passed to our JDBC driver to establish a connection.</span> <br /><br />driverClassName&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #0000ff">The fully qualified Java class name of the JDBC driver to be used. </span><br /><br /><br />Part2, the following are related to performances: <br /><br />initialSize&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #0000ff">The initial number of connections that are created when the pool is started. </span><br /><br />maxActive&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #0000ff">The maximum number of active connections that can be allocated from this pool at the same time, or non-positive for no limit. </span><br /><br />maxIdle&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">The maximum number of connections that can remain idle in the pool, without extra ones being released, or negative for no limit. </span><br /><br />minIdle&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">The minimum number of connections that can remain idle in the pool, without extra ones being created, or zero to create none.</span> <br /><br />maxWait&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #0000ff">&nbsp;The maximum number of milliseconds that the pool will wait (when there are no available connections) for a connection to be returned before throwing an exception, or -1 to wait indefinitely.</span> <br /><br />poolPreparedStatements&nbsp;&nbsp;&nbsp; <span style="color: #0000ff">Enable prepared statement pooling for this pool.</span> <br /><br />maxOpenPreparedStatements&nbsp; <span style="color: #0000ff">The maximum number of open statements that can be allocated from the statement pool at the same time, or zero for no limit.</span> <br /><br /><br /><br />Part3, but setting the above parameters or combining only some of the them won&rsquo;t help you get rid of exhaustion of connection problem due to poorly written code, maybe that's source of problems. The following configuration matters: <br /><br /><br />validationQuery&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #0000ff">The SQL query that will be used to validate connections from this pool before returning them to the caller. If specified, this query MUST be an SQL SELECT statement that returns at least one row. </span><br /><br /><br />timeBetweenEvictionRunsMillis <span style="color: #0000ff">The number of milliseconds to sleep between runs of the idle object evictor thread. When non-positive, no idle object evictor thread will be run.</span> <br /><br /><br />minEvictableIdleTimeMillis&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #0000ff">The minimum amount of time an object may sit idle in the pool before it is eligable for eviction by the idle object evictor (if any).</span> <br /><br /><br />removeAbandoned <span style="color: #0000ff">Flag to remove abandoned connections if they exceed the removeAbandonedTimout. If set to true a connection is considered abandoned and eligible for removal if it has been idle longer than the removeAbandonedTimeout. Setting this to true can recover db connections from poorly written applications which fail to close a connection. </span><br /><br /><br />removeAbandonedTimeout <span style="color: #0000ff">Timeout in seconds before an abandoned connection can be removed. the above two parameter must be set at the same time to make connection pool manageable.If we set</span> <br /><br /><br /><span style="color: #0000ff">validationQuery=&quot;SELECT SYSDATE FROM DUAL&quot; <br />removeAbandoned=true <br />removeAbandonedTimeout=30 <br />timeBetweenEvictionRunsMillis=500 <br />minEvictableIdleTimeMillis=60000</span> <br /><br /><br />then, we should interpreted these as: <br /><br /><br /><span>1) If there&rsquo;s poorly written code which forget to close connections after use, and it lasts for 30 seconds, it will be removed from the pool! <br /><br />2) There&rsquo;ll be an evictor thread up to monitor connection objects. If one of the connection objects becomes idle and last for 5000 milliseconds, it will be marked as removable. After another short nap of 500 milliseconds, that's at between 60000 and 60500 milliseconds, if the same connection is still found idle, it will be removed from the pool. <br /></span><br /><br /><br />So a typical configuration for oracle would be like this: <br /><br /><br />driverClassName=driverclass <br />url=dburl <br />username=user <br />password=password <br /><br /><br />maxActive=100 <br />maxWait=-1 <br />defaultAutoCommit=true <br />minIdle=0 <br />maxIdle=30 <br />poolPreparedStatements=true <br /><br />validationQuery=&quot;SELECT SYSDATE FROM DUAL&quot; <br />testOnBorrow=&quot;true&quot; <br />testOnReturn=&quot;false&quot; <br />testWhileIdle = &quot;false&quot; <br />timeBetweenEvictionRunsMillis=500 <br />removeAbandoned=true <br />removeAbandonedTimeout=30 <br />minEvictableIdleTimeMillis=60000 <br /><br /><br /><span style="color: #0000ff">1) It means when the pool starts up, poolPreparedStatements ability is enabled, transaction will be auto committed and there is no connections in it. <br /><br />2) Any connections will be created on demand. If a new connection is requested, after creation, the new one will be tested against &quot;SELECT SYSDATE FROM DUAL&quot; before returning it to user, if it failed validation, yielding no result, the connection will be dropped, and another connection will be created and validated again until it pass. <br /><br />3) If suddenly, floods of requests come in, the pool will create as many connections as it can to serve the request until the size reach 100. If requests continue to arrive, they will have wait before some connections finished the previous serving. <br /><br />4) If there&rsquo;s poorly written code which forget to close connections after use, and it lasts for 30 seconds, it will be removed from the pool! <br /><br />5) When the flood begins to ebb, some of the connections will become idle and have nothing to do. If any connection object becomes idle and last for 60000 milliseconds, it will be marked as removable. After another short nap of 500 milliseconds, that's at between 60000 and 60500 milliseconds, if the same connection is still found idle, it will be removed from the pool.</span> <br /><br /><br /><br /><span style="color: #ff0000">For commons-dbcp-1.2.2 and commons-pool-1.3 and <br />we have to set <br /><br />minIdle=0 <br />testWhileIdle=false <br /><br />to avoid a potential deadlock as described by <br />https://issues.apache.org/jira/browse/DBCP-44</span> <br /><br /><br /><br /><br />Here is the test: <br /><br /><span style="color: #0000ff"><span style="color: #0000ff">Environment: <br />Hardware: AMD Turion(TM) 64 X2 Mobile 1.8G&nbsp;&nbsp;&nbsp; and 1.5G Memory <br /><br />Operating System: Windows XP <br /><br />Database:</span></span></p><p><span style="color: #0000ff"></span></p><p><span style="color: #0000ff"><span style="color: #0000ff">mysql :&nbsp;5.0.45-community-nt MySQL Community Edition (GPL) <br />Max_used_connections 100 </span></span></p><p>&nbsp;</p><p>&nbsp;</p><p><span style="color: #0000ff"><span style="color: #0000ff">Oracle: 10G default settings</span></span></p><p>&nbsp;</p><p><span style="color: #0000ff">Pool implementaions: </span></p><p><span style="color: #0000ff"><span style="color: #0000ff">1)commons-dbcp-1.2.2(<span style="color: #0000ff">commons-pool-1.3</span>)</span></span></p><p><span style="color: #0000ff"><span style="color: #0000ff">2)c3p0-0.9.1.2</span></span><br /><br /></p><p><br /><span style="color: #ff0000">database&nbsp;&nbsp;dbcp/c3p0&nbsp;&nbsp;&nbsp;concurrent_threads&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;maxActive/poolSize&nbsp;&nbsp;&nbsp;10minutes queries executed</span></p><p><br /><span style="color: #ff0000">mysql&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dbcp/c3p0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;100&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 16200/1600<br />oracle&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dbcp/c3p0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3691/1900 <br />oracle&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dbcp/c3p0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;50&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 20900/6500<br />oracle&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dbcp/c3p0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;50&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8400/2000<br />oracle&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dbcp/c3p0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;80&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8800/1800</span></p><p>&nbsp;</p><p><br /><br /><span style="color: #ff0000">oracle&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dbcp/c3p0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 100&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ORA-12519/very slow, but no ORA-12519<br /></span></p><p><span style="color: #ff0000">(ORA-12519, TNS:no appropriate service handler found)</span><br /><br /><br /><span style="color: #ff0000">But if you want performance gained from dbcp, you should increase the value of &quot;PROCESSES&quot; parameter in oracle</span></p><p>&nbsp;</p><div class="quote_title"><span style="color: #ff0000">http://www.webservertalk.com/archive149-2006-2-1410832.html 写道</span></div><div class="quote_div"><span style="color: #ff0000">PROCESSES specifies the maximum number of operating system user <br />processes that can simultaneously connect to Oracle. Its value should <br />allow for all background processes such as locks, job queue processes, <br />and parallel execution processes.</span> <br /></div><p>&nbsp;</p><p><br /><br /><br />Jdbc.properties <br />cabernet.jdbc.driverClassName=com.mysql.jdbc.Driver <br />cabernet.jdbc.url=jdbc:mysql://g-mobile:3306/jbpm?useUnicode=true&amp;characterEncoding=utf8&amp;autoReconnect=true <br />cabernet.jdbc.username=root <br />cabernet.jdbc.password=root <br /><br />#dbcp <br />cabernet.jdbc.maxActive=100 </p><p><span style="color: #ff0000"><span style="color: #ff0000">##max.Wait means waiting until one is available</span><br /></span>cabernet.jdbc.maxWait=-1 <br />cabernet.jdbc.defaultAutoCommit=true <br />cabernet.jdbc.minIdle=0 <br />cabernet.jdbc.maxIdle=30 <br />cabernet.jdbc.removeAbandoned=true <br />cabernet.jdbc.removeAbandonedTimeout=30 <br />cabernet.jdbc.poolPreparedStatements=true <br />cabernet.jdbc.validationQuery=select current_date(); <br />cabernet.jdbc.testOnBorrow=true <br />cabernet.jdbc.testOnReturn=false <br />cabernet.jdbc.testWhileIdle=false <br />cabernet.jdbc.timeBetweenEvictionRunsMillis=500 <br />cabernet.jdbc.minEvictableIdleTimeMillis=16000 <br />cabernet.jdbc.logAbandoned=true <br /><br />#c3p0 <br />cabernet.jdbc.acquireIncrement=5 <br />cabernet.jdbc.idleConnectionTestPeriod=3000 <br />cabernet.jdbc.maxIdleTime=60 </p><p><span style="color: #ff0000">###checkoutTimeout=0 means waiting until one is available</span><br />cabernet.jdbc.checkoutTimeout=0 <br />cabernet.jdbc.maxPoolSize=100 <br />cabernet.jdbc.minPoolSize=0 <br />cabernet.jdbc.maxStatements=1000 <br />cabernet.jdbc.maxStatementsPerConnection=1000 <br />cabernet.jdbc.initialPoolSize=0 <br />cabernet.jdbc.autoCommitOnClose=true <br /><br /><br /><br /><br />Test Code: </p><pre name="code" class="java">package com.cabernet.dbcp;

import java.sql.SQLException;

import javax.sql.DataSource;

import com.cabernet.BaseTestCase;

/**
 * 
 * @author ginge
 *
 */
public class TestPooling extends BaseTestCase
{
	protected DataSource	datasource;

	public void testConnection() throws SQLException, InterruptedException
	{
		for (int i = 1000; i &gt; 0; i--)
		{
			new QueryThread(this.datasource).start();

			log.debug(&quot;PoolingThread[&quot; + i + &quot;] is up and running.&quot;);
		}

		while (true)
			Thread.sleep(100000);
	}

	public DataSource getDatasource()
	{
		return datasource;
	}

	public void setDatasource(DataSource datasource)
	{
		this.datasource = datasource;
	}

	@Override
	protected String[] getConfigLocations()
	{
		// TODO Auto-generated method stub
		return new String[] { &quot;classpath*:applicationContext-resources.xml&quot;, &quot;classpath*:applicationContext-jbpm.xml&quot;,
				&quot;classpath*:applicationContext-hibernate.xml&quot; };
	}

}
</pre><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><pre name="code" class="java">package com.cabernet.dbcp;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.Random;

import javax.sql.DataSource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * 
 * @author ginge
 *
 */
public class QueryThread extends Thread
{

	private Log		log		= LogFactory.getLog(this.getClass());
	DataSource		datasource;

	private Random	random	= new Random();

	QueryThread(DataSource datasource)
	{
		this.datasource = datasource;
	}

	@Override
	public void run()
	{
		// TODO Auto-generated method stub
		Connection connection = null;

		int i = 0;
		while (true)
		{
			if (i &lt; Integer.MAX_VALUE)
				i++;
			else
				i = 0;

			try
			{
				connection = datasource.getConnection();
			} catch (Exception e)
			{
				log.error(&quot;getConnection exception :&quot;, e);
			}

			try
			{
				if (connection != null)
				{
					String query = &quot;select * from jbpm_log where id_ = &quot; + i;
					connection.createStatement().execute(query);
					log.debug(&quot;Thread[&quot; + this.getId() + &quot;] executeing [&quot; + query + &quot;]&quot;);
					sleep(1000);
					this.close(connection);
//					this.forgetToCloseSomeConnections(connection);
				}
			} catch (Exception e)
			{
				log.error(&quot;query exception :&quot;, e);
			}

		}
	}

	private void close(Connection connection)
	{
		try
		{
			connection.close();
		} catch (SQLException e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	private void forgetToCloseSomeConnections(Connection connection)
	{
		if (random.nextInt(20) != 9)
			try
			{
				connection.close();
			} catch (SQLException e)
			{
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		else
		{
			if (log.isWarnEnabled())
			{
				log.warn(&quot;Connection not closed.&quot;);
			}
		}
	}
}</pre><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://ginge.javaeye.com/blog/172788#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/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 16 Mar 2008 22:25:01 +0800</pubDate>
        <link>http://ginge.javaeye.com/blog/172788</link>
        <guid>http://ginge.javaeye.com/blog/172788</guid>
      </item>
      <item>
        <title>参加了Spring Framework 2.5 Reference翻译项目</title>
        <author>ginge</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://ginge.javaeye.com">ginge</a>&nbsp;
          链接：<a href="http://ginge.javaeye.com/blog/172248" style="color:red;">http://ginge.javaeye.com/blog/172248</a>&nbsp;
          发表时间: 2008年03月15日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          哈哈，没想到俺也进入开源组织了，刚好将自己的翻译爱好继续下去<br />虽然大家都是自愿加入的，没钱，还有纪律要求，完成后最多也只是一个拥有一个署名权，但是还是高兴，像以前参与matrix翻译项目一样高兴，有事情做总比睡觉好。<br /><br /><br /><br />来，转转这个项目的信息：<br />Spring Framework 2.5 Reference翻译项目：<br />http://wiki.redsaga.com/confluence/display/Spring2/Spring2.5<br />项目计划:概述:1、时间安排方面，在确保质量的前提下整个翻译工作在8周内完成，一期安排在4周内完成翻译（将有一个预览版本发布），随后4周进行一审和二审（不断发布迭代版本），校对工作完成后发布正式版本。一般任务按照章节进行分配，大的章节将被拆为不同的小节。<br />2、参与者以自愿方式在网上加入翻译工作，参与者在申请时必须留下明确的联系方式（电话/手机）以方便Leader进行联系，并注明期望得到的 wiki/cvs的用户名和希望认领的章节。工作分配由Leader安排，原则上按照先到先得的方式。具体的安排在wiki上公布。参与者将被加入不公开 的邮件列表中。吸取以往翻译的教训，为保证Leader的管理时间，原则上不安排Leader的翻译工作，或安排较少的章节。<br />3、在翻译开始后，翻译者必须每周的周三、周六两天晚上10点前在Wiki上通报翻译进度，对未在规定时间通报进度者负责人将直接与其联系询问情况，连续两次无理由未通报进度者将被认为已经脱离联系，为不影响整体进度，原工作将安排另外人员接手。Wiki仅做交流通报使用，参与者通过CVS交换文档，每位参与者完成翻译后在本地编译通过后提交CVS。<br />4、Leader将维护翻译术语表，翻译者可将翻译时遇到的术语提交在Wiki上，负责人将进行整理和总结，添加至术语表中。参与翻译与校对工作的参与者请尽力确保整篇文档各个部分的术语翻译一致。<br />5、文档将按原Spring Reference英文文档的协议发布，全体参与者一致同意放弃除署名权外的所有权利。在前言中将按章节列出所有参与者，参与翻译，但因个人原因退出者将被列在致谢名单中。<br />6、所有参与者将可以获得此次活动的纪念专题纪念品一件！
          <br/>
          <span style="color:red;">
            <a href="http://ginge.javaeye.com/blog/172248#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><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, 15 Mar 2008 22:52:55 +0800</pubDate>
        <link>http://ginge.javaeye.com/blog/172248</link>
        <guid>http://ginge.javaeye.com/blog/172248</guid>
      </item>
      <item>
        <title>Spring, JBPM持久化系列--摆脱LazyInitializationException 二</title>
        <author>ginge</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://ginge.javaeye.com">ginge</a>&nbsp;
          链接：<a href="http://ginge.javaeye.com/blog/167974" style="color:red;">http://ginge.javaeye.com/blog/167974</a>&nbsp;
          发表时间: 2008年03月04日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          Spring, Springmodules, JBPM持久化集成--摆脱 <br />LazyInitializationException(Part2) <br />Spring, Springmodules, JBPM持久化集成理解系列三 <br />【本系列如需转载，请注明作者及出处】 <br /><br /><br />到此，如果有朋友还是比较清醒的话，应该还会有疑问，在OpenSessionInViewFilter里如果是isSingleSession为true，并没有看到session的关闭，到底是在什么地方关闭了呢？它其实是在OpenSessionInViewInterceptor里关闭了的。 <br /><br /><p>&nbsp;</p><pre name="code" class="java">public void afterCompletion(WebRequest request, Exception ex) throws DataAccessException {
		String participateAttributeName = getParticipateAttributeName();
		Integer count = (Integer) request.getAttribute(participateAttributeName, WebRequest.SCOPE_REQUEST);
		if (count != null) {
			// Do not modify the Session: just clear the marker.
			if (count.intValue() &gt; 1) {
				request.setAttribute(participateAttributeName, new Integer(count.intValue() - 1), WebRequest.SCOPE_REQUEST);
			}
			else {
				request.removeAttribute(participateAttributeName, WebRequest.SCOPE_REQUEST);
			}
		}
		else {
			if (isSingleSession()) {
				// single session mode
				SessionHolder sessionHolder =
						(SessionHolder) TransactionSynchronizationManager.unbindResource(getSessionFactory());
				logger.debug(&quot;Closing single Hibernate Session in OpenSessionInViewInterceptor&quot;);
				SessionFactoryUtils.closeSession(sessionHolder.getSession());
			}
			else {
				// deferred close mode
				SessionFactoryUtils.processDeferredClose(getSessionFactory());
			}
		}
	}</pre><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span style="font-family: 宋体"><span style="font-size: small">总结一下：</span></span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span style="font-size: small"><span><span style="font-family: Times New Roman">OpenSessionInViewFilter</span></span><span style="font-family: 宋体">首先会确保</span><span><span style="font-family: Times New Roman">sessionFactory</span></span><span style="font-family: 宋体">的存在，</span></span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span style="font-size: small"><span style="font-family: 宋体">如果启用了</span><span><span style="font-family: Times New Roman">session</span></span><span style="font-family: 宋体">延迟关闭策略，也就是</span><span><span style="font-family: Times New Roman">isSingleSession</span></span><span style="font-family: 宋体">为false</span><span style="font-family: 宋体">，</span><span><span style="font-family: Times New Roman">session</span></span><span style="font-family: 宋体">的创建和打开会在</span><span><span style="font-family: Times New Roman">HibernateTemplate</span></span><span style="font-family: 宋体">的</span><span><span style="font-family: Times New Roman">execute</span></span><span style="font-family: 宋体">里发生，而关闭会统一在</span><span><span style="font-family: Times New Roman">OpenSessionInViewFilter</span></span><span style="font-family: 宋体">返回时。</span></span></p><span><span style="font-size: small; font-family: Times New Roman">&nbsp;</span></span> <p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span style="font-size: small"><span style="font-family: 宋体">如果</span><span><span style="font-family: Times New Roman">isSingleSession</span></span><span style="font-family: 宋体">为</span><span><span style="font-family: Times New Roman">true</span></span><span style="font-family: 宋体">时，</span><span><span style="font-family: Times New Roman">session</span></span><span style="font-family: 宋体">的打开会在</span><span><span style="font-family: Times New Roman">OpenSessionInViewFilter</span></span><span style="font-family: 宋体">里或者之前的某个时候，而关闭会在</span><span><span style="font-family: Times New Roman">OpenSessionInViewInterceptor</span></span><span style="font-family: 宋体">里。</span></span></p><span><span style="font-size: small; font-family: Times New Roman">&nbsp;</span></span> <p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span style="font-size: small"><span style="font-family: 宋体">这样我们就可用自己在</span><span><span style="font-family: Times New Roman">Junit</span></span><span style="font-family: 宋体">或者其他应用场景使用延迟关闭策略来使我们的程序收益。以下附带前面篇章提及到的BaseTestCase，如果存在SessionFactory，则激活延迟关闭session策略。各位可用参考使用。</span></span></p><p>&nbsp;</p><pre name="code" class="java">package com.cabernet;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.FlushMode;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.orm.hibernate3.SessionFactoryUtils;
import org.springframework.orm.hibernate3.SessionHolder;
import org.springframework.test.AbstractDependencyInjectionSpringContextTests;
import org.springframework.transaction.support.TransactionSynchronizationManager;

/**
 * Supports OpenSessionInViewFilter like Hibernate Lazy-loading when
 * SessionFactory is present
 * 
 * @author ginge
 * 
 * @see OpenSessionInViewFilter
 */
public class BaseTestCase extends AbstractDependencyInjectionSpringContextTests
{
	protected Log				log			= LogFactory.getLog(this.getClass());

	private FlushMode			flushMode	= FlushMode.MANUAL;

	protected SessionFactory	sessionFactory;

	@Override
	protected void prepareTestInstance() throws Exception
	{
		// TODO Auto-generated method stub
		super.prepareTestInstance();

		if (isSessionFactoryPresent())
		{
			afterSessionFactorySet();
			SessionFactoryUtils.initDeferredClose(sessionFactory);
			TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(this.getSession()));
		}
	}

	@Override
	protected void onTearDown() throws Exception
	{
		// TODO Auto-generated method stub

		if (isSessionFactoryPresent())
		{
			SessionFactoryUtils.processDeferredClose(sessionFactory);
			TransactionSynchronizationManager.unbindResource(sessionFactory);
		}

		super.onTearDown();
	}

	private boolean isSessionFactoryPresent()
	{
		return this.sessionFactory != null;
	}

	protected void afterSessionFactorySet()
	{

	}

	public SessionFactory getSessionFactory()
	{
		return sessionFactory;
	}

	public void setSessionFactory(SessionFactory sessionFactory)
	{
		this.sessionFactory = sessionFactory;
	}

	@Override
	protected String[] getConfigLocations()
	{
		return new String[] { &quot;classpath*:applicationContext-resources.xml&quot; };
	}

	protected Session getSession() throws DataAccessResourceFailureException
	{
		Session session = SessionFactoryUtils.getSession(sessionFactory, true);
		FlushMode flushMode = getFlushMode();
		if (flushMode != null)
		{
			session.setFlushMode(flushMode);
		}
		return session;
	}

	private FlushMode getFlushMode()
	{
		return this.flushMode;
	}
}</pre><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>到了这个时刻，我们回到Jbpm跟Springmodules, Spring的持久化集成上来，虽然Jbpm本身提供了JbpmContextFilter，它的功能是在Filter开始打开JbpmContext，Filter返回时关闭JbpmContext。但是在前面的篇章中，我们知道JbpmTemplate中会在操作开始前注入session。因此，使用了OpenSessionInViewFilter和JbpmTemplate之后，JbpmContextFilter将会英雄无用武之地。这个OpenSessionInViewFilter必须配置在其他Filter之前以确保在进入其他Filter之前激活延迟关闭策略或者绑定Session到当前线程中。</p><p>&nbsp;</p><p>&nbsp;</p><p>（完结）</p>
          <br/>
          <span style="color:red;">
            <a href="http://ginge.javaeye.com/blog/167974#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</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, 04 Mar 2008 23:45:43 +0800</pubDate>
        <link>http://ginge.javaeye.com/blog/167974</link>
        <guid>http://ginge.javaeye.com/blog/167974</guid>
      </item>
      <item>
        <title>Spring, JBPM持久化系列--摆脱LazyInitializationException</title>
        <author>ginge</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://ginge.javaeye.com">ginge</a>&nbsp;
          链接：<a href="http://ginge.javaeye.com/blog/167969" style="color:red;">http://ginge.javaeye.com/blog/167969</a>&nbsp;
          发表时间: 2008年03月04日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <span style="font-size: 12pt; font-family: 宋体"><span style="font-size: xx-small"><span></span></span></span><span><span style="font-size: small; font-family: Times New Roman"><span style="font-size: 13.5pt; font-family: 宋体">Spring, Springmodules, JBPM</span><span style="font-size: 13.5pt; font-family: 宋体">持久化集成<span>--</span>摆脱<span></span></span><span style="font-size: 10pt; background: silver; color: black; font-family: 'Courier New'">LazyInitializationException</span><span style="font-size: 10pt; color: black; font-family: 'Courier New'">(Part1)</span><span style="font-size: 13.5pt; font-family: 宋体"></span> <p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span style="font-size: 13.5pt; font-family: 宋体">Spring, Springmodules, JBPM</span><span style="font-size: 13.5pt; font-family: 宋体">持久化集成理解系列三</span></p><span style="font-size: 12pt; font-family: 宋体">【本系列如需转载，请注明作者及出处】<span></span></span> <p class="MsoNormal" style="margin: 0cm 0cm 0pt">&nbsp;</p><p class="MsoNormal" style="margin: 0cm 0cm 0pt">&nbsp;</p></span></span><p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span style="font-size: small"><span style="font-family: 宋体">不管</span><span><span style="font-family: Times New Roman">Jbpm</span></span><span style="font-family: 宋体">的持久化策略如何，要重用</span><span><span style="font-family: Times New Roman">Spring</span></span><span style="font-family: 宋体">的持久化集成服务，我们要怎么做呢？</span><span><span style="font-family: Times New Roman">Jbpm</span></span><span style="font-family: 宋体">可以是</span><span><span style="font-family: Times New Roman">B/S</span></span><span style="font-family: 宋体">架构中的一部分，也可以是</span><span><span style="font-family: Times New Roman">C/S</span></span><span style="font-family: 宋体">架构的一部分。对于</span><span><span style="font-family: Times New Roman">B/S</span></span><span style="font-family: 宋体">架构，我们都知道有</span><span><span style="font-family: Times New Roman">OpenSessionInViewFilter</span></span><span style="font-family: 宋体">，然而</span><span><span style="font-family: Times New Roman">C/S</span></span><span style="font-family: 宋体">没有&ldquo;</span><span><span style="font-family: Times New Roman">Filter</span></span><span style="font-family: 宋体">&rdquo;，该从何入手呢？</span></span></p><span><span style="font-size: small; font-family: Times New Roman">&nbsp;</span></span><span><span style="font-size: small; font-family: Times New Roman">&nbsp;</span></span> <p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span style="font-size: small"><span style="font-family: 宋体">我们先来看看</span><span><span style="font-family: Times New Roman">OpenSessionInViewFilter</span></span><span style="font-family: 宋体">是怎样做到的，本篇不讨论它的优缺点。</span><span><span style="font-family: Times New Roman">OpenSessionInViewFilter</span></span><span style="font-family: 宋体">也是一个</span><span><span style="font-family: Times New Roman">javax.servlet.Filter</span></span><span style="font-family: 宋体">，只不过它还是</span><span><span style="font-family: Times New Roman">BeanNameAware</span></span><span style="font-family: 宋体">，</span><span><span style="font-family: Times New Roman">ServletContextAware</span></span><span style="font-family: 宋体">，</span><span><span style="font-family: Times New Roman">InitializingBean</span></span><span style="font-family: 宋体">和</span><span><span style="font-family: Times New Roman">DisposableBean</span></span><span style="font-family: 宋体">的实现。</span></span></p><span><span style="font-size: small; font-family: Times New Roman">&nbsp;</span></span><span><span style="font-size: small; font-family: Times New Roman">&nbsp;</span></span> <p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span style="font-size: small"><span style="font-family: 宋体">像所有的</span><span><span style="font-family: Times New Roman">Filter</span></span><span style="font-family: 宋体">一样，</span><span><span style="font-family: Times New Roman">Filter</span></span><span style="font-family: 宋体">的入口都是</span></span></p><span style="font-size: small"><span style="font-family: 宋体"><pre name="code" class="java">public final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
			throws ServletException, IOException;
</pre></span></span><p>&nbsp;</p><p><span style="font-size: 10.5pt; font-family: 宋体">到了</span><span style="font-size: 10.5pt; font-family: 'Times New Roman'">OpenSessionInViewFilter</span><span style="font-size: 10.5pt; font-family: 宋体">这里，执行的方法就是</span></p><p>&nbsp;</p><pre name="code" class="java">protected void doFilterInternal(
			HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
			throws ServletException, IOException;
</pre><p>&nbsp;&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span style="font-size: small"><span><span style="font-family: Times New Roman">doFilterInternal</span></span><span style="font-family: 宋体">做的事情说简单也不简单，我们来看该方法做了什么，请留意注释：</span></span></p><span style="font-size: small"><span style="font-family: 宋体"><pre name="code" class="java">protected void doFilterInternal(
			HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {

		//1，	先把SessionFactory取出来。
		SessionFactory sessionFactory = lookupSessionFactory(request);
		boolean participate = false;

		//2.1	如果是设置了isSingleSession为true，则整个request请求中都会只使用一个session。
		if (isSingleSession()) {
			// single session mode
			//2.2 再看看当前线程是不是已经存在一个可用的session
			if (TransactionSynchronizationManager.hasResource(sessionFactory)) {
				// Do not modify the Session: just set the participate flag.
				participate = true;
			}
			else {
				logger.debug(&quot;Opening single Hibernate Session in OpenSessionInViewFilter&quot;);
				//2.3	没有就创建一个
				Session session = getSession(sessionFactory);
				TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session));
			}
		}
		else {
			// deferred close mode
			//3.1 如果已经延迟关闭策略已经被激活，则什么事情也不做
			if (SessionFactoryUtils.isDeferredCloseActive(sessionFactory)) {
				// Do not modify deferred close: just set the participate flag.
				participate = true;
			}
			else {
				//3.2  如果为false，则激活延迟关闭session策略
				SessionFactoryUtils.initDeferredClose(sessionFactory);
			}
		}

		try {
			filterChain.doFilter(request, response);
		}

		finally {
			//4.1，	filter返回后，如果在进入该filter之前延迟关闭已经被激活，该filter不负责关闭session，
			if (!participate) {
				if (isSingleSession()) {
					// single session mode
					SessionHolder sessionHolder =
							(SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
					logger.debug(&quot;Closing single Hibernate Session in OpenSessionInViewFilter&quot;);
					closeSession(sessionHolder.getSession(), sessionFactory);
				}
				else {
					//4.2  如延迟关闭是该filter激活的，就在此关闭session
					// deferred close mode
					SessionFactoryUtils.processDeferredClose(sessionFactory);
				}
			}
		}
	}</pre><p class="MsoNormal" style="margin: 0cm 0cm 0pt">&nbsp;&nbsp;</p></span></span><span style="font-family: 宋体"></span><span style="font-family: 宋体"><p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span style="font-size: small"><span><span style="font-family: Times New Roman">isSingleSession</span></span><span style="font-family: 宋体">为</span><span><span style="font-family: Times New Roman">false</span></span><span style="font-family: 宋体">时，也就是延迟关闭策略，应该有一部分会感到很奇怪了，并没有看到</span><span><span style="font-family: Times New Roman">session</span></span><span style="font-family: 宋体">的打开，这时就有必要要探讨一下了</span><span><span style="font-family: Times New Roman">HibernateTemplate</span></span><span style="font-family: 宋体">。</span><span><span style="font-family: Times New Roman">HibernateTemplate</span></span><span style="font-family: 宋体">也是经典的回调模型，它的核心是</span><span><span style="font-family: Times New Roman">execute</span></span><span style="font-family: 宋体">方法。看到这段代码之后，是不是豁然开朗呢？</span><span style="font-family: Times New Roman"> </span><span style="font-family: 宋体">原来</span><span><span style="font-family: Times New Roman">execute</span></span><span style="font-family: 宋体">里一开始就将</span><span><span style="font-family: Times New Roman">session</span></span><span style="font-family: 宋体">取出来了，执行了</span><span><span style="font-family: Times New Roman">callback</span></span><span style="font-family: 宋体">之后就开始做</span><span><span style="font-family: Times New Roman">session</span></span><span style="font-family: 宋体">的管理了。注意</span><span><span style="font-family: Times New Roman">HibernateTemplate</span></span><span style="font-family: 宋体">里默认是</span><span><span style="font-family: Times New Roman">allowCreate = true; alwaysUseNewSession = false;</span></span></span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span style="font-size: small; font-family: Times New Roman"></span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span style="font-size: small; font-family: Times New Roman"></span></p><span style="font-size: small; font-family: Times New Roman"><span><pre name="code" class="java">public Object execute(HibernateCallback action, boolean exposeNativeSession) throws DataAccessException {
		Assert.notNull(action, &quot;Callback object must not be null&quot;);

		Session session = getSession();
		/*
          *省略一段代码
*/
			Object result = action.doInHibernate(sessionToExpose);
		/*
          *省略一段代码
*/
		SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, getSessionFactory());

	}
</pre></span></span></span><p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span style="font-size: small"></span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span style="font-size: small"></span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span style="font-size: small"></span></p><span style="font-size: small"><span style="font-family: 宋体"><p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span style="font-size: 10pt; color: black; font-family: 'Courier New'">SessionFactoryUtils.<em>closeSessionOrRegisterDeferredClose</em>(session, getSessionFactory());</span><span style="font-size: 10pt; color: black; font-family: 宋体">就像它字面要表达的，如果延迟关闭策略处于激活状态，则只是将</span><span style="font-size: 10pt; color: black; font-family: 'Courier New'">session</span><span style="font-size: 10pt; color: black; font-family: 宋体">注册到一个容器里，到某个时刻再统一关闭，例如在</span><span><span style="font-family: Times New Roman">OpenSessionInViewFilter</span></span><span style="font-family: 宋体">返回时。</span></p><span><span style="font-family: Times New Roman">&nbsp;</span></span></span></span> <p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span style="font-size: small"></span></p>
          <br/>
          <span style="color:red;">
            <a href="http://ginge.javaeye.com/blog/167969#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</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, 04 Mar 2008 23:23:51 +0800</pubDate>
        <link>http://ginge.javaeye.com/blog/167969</link>
        <guid>http://ginge.javaeye.com/blog/167969</guid>
      </item>
      <item>
        <title>Spring, Springmodules, JBPM持久化集成--优雅的背后(Part2)</title>
        <author>ginge</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://ginge.javaeye.com">ginge</a>&nbsp;
          链接：<a href="http://ginge.javaeye.com/blog/167117" style="color:red;">http://ginge.javaeye.com/blog/167117</a>&nbsp;
          发表时间: 2008年03月04日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><strong><span style="font-size: 13.5pt; font-family: 宋体">Spring, Springmodules, JBPM</span><span style="font-size: 13.5pt; font-family: 宋体">持久化集成理解系列二</span></strong></p><p><strong><span style="font-size: 13.5pt; font-family: 宋体"><span style="font-size: 12pt; font-family: 宋体">【本系列如需转载，请注明作者及出处】</span></span></strong>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>本系列文章假设阅者具备以下知识：<br />1，ThreadLocal相关知识<br />2，Spring持久化，事务管理相关知识<br />3，Hibernate 持久化相关知识<br />4，Jbpm 持久化相关知识<br />5，Springmodules项目相关知识<br />6，相关J2EE知识</p><p><br />且具备以下材料：<br />1，Spring源代码<br />2，Hibernate源代码<br />3，Jbpm源代码<br />4，Springmodules源代码</p><p>&nbsp;</p><p>&nbsp;</p><p>第二部分，Session的关闭： 到了这里，我们就到了验证的最后一部分了，JbpmContext的关闭了。 <br /><br /><br />【位置JbpmContext】 </p><pre name="code" class="java">public void close() {
    log.debug(&quot;closing JbpmContext&quot;);
    try {
      if (services!=null) {
        try {
          autoSave();
        } finally {
          services.close();
        }
      }
    } finally {
      if (jbpmConfiguration!=null) {
        jbpmConfiguration.jbpmContextClosed(this);
      }
    }
}
</pre>&nbsp;<br /><br />也就是说，JbpmContext关闭的时候会产生自动保存，最后关闭services,现在摘取DbPersistenceService的close里面我们关心的逻辑： <br /><br /><br /><br />【位置DbPersistenceService】 <br /><br /><pre name="code" class="java">if (mustSessionBeClosed) {
      try {
        if(session.isOpen()) {
          log.debug(&quot;closing hibernate session&quot;);
          session.close();
        } else {
          log.warn(&quot;hibernate session was already closed&quot;);
        }
      } catch (Exception e) {
        throw new JbpmPersistenceException(&quot;couldn't close hibernate session&quot;, e);
      }
    }

    if (mustConnectionBeClosed) {
      try {
        if ( (connection!=null)
            &amp;&amp; (! connection.isClosed())
           ) {
          log.debug(&quot;closing jdbc connection&quot;);
          connection.close();
        } else {
          log.warn(&quot;jdbc connection was already closed&quot;);
        }
      } catch (Exception e) {
        throw new JbpmPersistenceException(&quot;couldn't close jdbc connection&quot;, e);
      }
    }</pre><p><br /><br />总结： <br /><br /><br /><br />对于情况一，如果提供了session，mustConnectionBeClosed是false，mustSessionBeClosed也是false，所以这种情况Jbpm不会关闭Connection。 <br /><br /><br />对于情况二mustConnectionBeClosed是true，mustSessionBeClosed也是false，所以Jbpm会调用Session.close()，但是关闭一个使用已有Connection打开的Session，在close时的时候是不会关闭实际的Jdbc 连接的。有兴趣的朋友可用自己继续查看相应的Hibernate代码。 <br /><br /><br /><br />SpringModules集成Jbpm，它向JbpmContext提供了Session，那么它就应该负责Session的创建和关闭了，这些事情Springmodules的核心类JbpmTemplate使用了HibernateTemplate，重用了Spring对Hibernate数据库事务的封装。也就能进一步享受Spring的事务管理和延迟加载，也就是OpenSessionInView的便利。 <br /><br /><br />我后来写了一个Junit测试类来验证，附Junit测试代码：</p><p>&nbsp;</p><pre name="code" class="java">package com.cabernet;

import java.util.List;

import junit.framework.Assert;

import org.jbpm.taskmgmt.exe.TaskInstance;
import org.springmodules.workflow.jbpm31.JbpmTemplate;

public class TestSetUp extends BaseTestCase
{
	protected JbpmTemplate	jbpmTemplate;

	public void test()
	{
		Assert.assertNotNull(this.jbpmTemplate);

		boolean isDebugEnabled = log.isDebugEnabled();

		if (isDebugEnabled)
		{
			log.debug(&quot;findTaskInstances&quot;);
		}
		
		List&lt;TaskInstance&gt; tasks = this.jbpmTemplate.findTaskInstances(&quot;bert&quot;);

		if (tasks != null)
		{
			if (isDebugEnabled)
			{
				log.debug(&quot;Tasks found, Swimlane: [&quot; + tasks.get(0).getTask()
						.getSwimlane().getName() + &quot;].&quot;);
			}

			return;
		}

		if (isDebugEnabled)
		{
			log.debug(&quot;No tasks found.&quot;);
		}
	}

	public JbpmTemplate getJbpmTemplate()
	{
		return jbpmTemplate;
	}

	public void setJbpmTemplate(JbpmTemplate jbpmTemplate)
	{
		this.jbpmTemplate = jbpmTemplate;
	}

}
</pre><p>&nbsp;</p><p>上述Junit&nbsp;类继承的父类BaseTestCase是AbstractDependencyInjectionSpringContextTests的子类，</p><p>&nbsp;启用了与OpenSessionInView一样的数据LazyLoading和JDBC Connection延迟关闭策略。</p><p>&nbsp;</p><p>附件是测试这个这个流程所发生的Log，首先是SessionFactoryUtils打开了Hibernate Session，最后是SessionFactoryUtils关闭了Hibernate Session，符合Jbpm声称的Context哲学。 </p><pre name="code" class="java">2008-03-04 00:14:12 DEBUG (SessionFactoryUtils.java:690)     - Initializing deferred close of Hibernate Sessions
2008-03-04 00:14:12 DEBUG (SessionFactoryUtils.java:316)     - Opening Hibernate Session
2008-03-04 00:14:12 DEBUG (TestSetUp.java:22)     - findTaskInstances
2008-03-04 00:14:12 DEBUG (JbpmContextInfo.java:142)     - creating jbpm context with service factories '[message, scheduler, logging, persistence, authentication]'
2008-03-04 00:14:12 DEBUG (JbpmContext.java:124)     - creating JbpmContext
2008-03-04 00:14:12 DEBUG (HibernateTemplate.java:364)     - Found thread-bound Session for HibernateTemplate
2008-03-04 00:14:12 DEBUG (DbPersistenceServiceFactory.java:55)     - creating persistence service
2008-03-04 00:14:12 DEBUG (DbPersistenceService.java:303)     - injecting a session disables transaction
Hibernate: select taskinstan0_.ID_ as ID1_27_, taskinstan0_.NAME_ as NAME3_27_, taskinstan0_.DESCRIPTION_ as DESCRIPT4_27_, taskinstan0_.ACTORID_ as ACTORID5_27_, taskinstan0_.CREATE_ as CREATE6_27_, taskinstan0_.START_ as START7_27_, taskinstan0_.END_ as END8_27_, taskinstan0_.DUEDATE_ as DUEDATE9_27_, taskinstan0_.PRIORITY_ as PRIORITY10_27_, taskinstan0_.ISCANCELLED_ as ISCANCE11_27_, taskinstan0_.ISSUSPENDED_ as ISSUSPE12_27_, taskinstan0_.ISOPEN_ as ISOPEN13_27_, taskinstan0_.ISSIGNALLING_ as ISSIGNA14_27_, taskinstan0_.ISBLOCKING_ as ISBLOCKING15_27_, taskinstan0_.TASK_ as TASK16_27_, taskinstan0_.TOKEN_ as TOKEN17_27_, taskinstan0_.SWIMLANINSTANCE_ as SWIMLAN18_27_, taskinstan0_.TASKMGMTINSTANCE_ as TASKMGM19_27_ from JBPM_TASKINSTANCE taskinstan0_ where taskinstan0_.ACTORID_=? and taskinstan0_.ISSUSPENDED_&lt;&gt;1 and taskinstan0_.ISOPEN_=1
2008-03-04 00:14:13 DEBUG (HibernateTemplate.java:388)     - Not closing pre-bound Hibernate Session after HibernateTemplate
2008-03-04 00:14:13 DEBUG (JbpmContext.java:133)     - closing JbpmContext
2008-03-04 00:14:13 DEBUG (Services.java:210)     - closing service 'persistence': org.jbpm.persistence.db.DbPersistenceService@1ce663c
Hibernate: select task0_.ID_ as ID1_14_0_, task0_.NAME_ as NAME2_14_0_, task0_.PROCESSDEFINITION_ as PROCESSD3_14_0_, task0_.DESCRIPTION_ as DESCRIPT4_14_0_, task0_.ISBLOCKING_ as ISBLOCKING5_14_0_, task0_.ISSIGNALLING_ as ISSIGNAL6_14_0_, task0_.DUEDATE_ as DUEDATE7_14_0_, task0_.ACTORIDEXPRESSION_ as ACTORIDE8_14_0_, task0_.POOLEDACTORSEXPRESSION_ as POOLEDAC9_14_0_, task0_.TASKMGMTDEFINITION_ as TASKMGM10_14_0_, task0_.TASKNODE_ as TASKNODE11_14_0_, task0_.STARTSTATE_ as STARTSTATE12_14_0_, task0_.ASSIGNMENTDELEGATION_ as ASSIGNM13_14_0_, task0_.SWIMLANE_ as SWIMLANE14_14_0_, task0_.TASKCONTROLLER_ as TASKCON15_14_0_ from JBPM_TASK task0_ where task0_.ID_=?
Hibernate: select swimlane0_.ID_ as ID1_13_0_, swimlane0_.NAME_ as NAME2_13_0_, swimlane0_.ACTORIDEXPRESSION_ as ACTORIDE3_13_0_, swimlane0_.POOLEDACTORSEXPRESSION_ as POOLEDAC4_13_0_, swimlane0_.ASSIGNMENTDELEGATION_ as ASSIGNME5_13_0_, swimlane0_.TASKMGMTDEFINITION_ as TASKMGMT6_13_0_ from JBPM_SWIMLANE swimlane0_ where swimlane0_.ID_=?
2008-03-04 00:14:13 DEBUG (TestSetUp.java:31)     - Tasks found, Swimlane: [buyer].
2008-03-04 00:14:13 DEBUG (SessionFactoryUtils.java:714)     - Processing deferred close of Hibernate Sessions</pre><p>&nbsp;</p><p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://ginge.javaeye.com/blog/167117#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/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 04 Mar 2008 00:15:11 +0800</pubDate>
        <link>http://ginge.javaeye.com/blog/167117</link>
        <guid>http://ginge.javaeye.com/blog/167117</guid>
      </item>
      <item>
        <title>Spring, Springmodules, JBPM持久化集成--优雅的背后(Part1)</title>
        <author>ginge</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://ginge.javaeye.com">ginge</a>&nbsp;
          链接：<a href="http://ginge.javaeye.com/blog/166244" style="color:red;">http://ginge.javaeye.com/blog/166244</a>&nbsp;
          发表时间: 2008年02月29日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><span style="font-size: 12pt; font-family: 宋体"><span style="font-size: 12pt; font-family: 宋体"><strong>Spring, Springmodules, JBPM持久化集成理解系列二&nbsp;</strong></span></span></p><p>&nbsp;</p><p><span style="font-size: 12pt; font-family: 宋体"><span style="font-size: 12pt; font-family: 宋体"><strong>【本系列如需转载，请注明作者及出处】</strong></span>&nbsp;</span></p><p>&nbsp;</p><p>本系列文章假设阅者具备以下知识：<br />1，ThreadLocal相关知识<br />2，Spring持久化，事务管理相关知识<br />3，Hibernate 持久化相关知识<br />4，Jbpm 持久化相关知识<br />5，Springmodules项目相关知识<br />6，相关J2EE知识</p><p><br />且具备以下材料：<br />1，Spring源代码<br />2，Hibernate源代码<br />3，Jbpm源代码<br />4，Springmodules源代码&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p><span style="font-size: 12pt; font-family: 宋体">&nbsp; 本篇尝试探讨<span>SpringModules</span>集成的背后逻辑，这涉及到<span>JbpmContext</span>持久化的哲学。</span><span style="font-size: 12pt; font-family: 宋体">&nbsp;</span> </p><p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span style="font-size: 12pt; font-family: 宋体">&nbsp; JbpmContext</span><span style="font-size: 12pt; font-family: 宋体">持久化管理的哲学是，如果用户提供<span>Context</span>数据库连接，那么用户就要管理该数据库的打开与关闭。如果使用<span>JbpmContext</span>自己产生的持久化服务，那么该服务就要管理与持久化相关的操作。很像各人自扫门前雪，哪管他人瓦上霜。</span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt">&nbsp;</p><p class="MsoNormal" style="margin: 0cm 0cm 0pt">&nbsp;</p><span style="font-size: 12pt; font-family: 宋体"><div class="quote_title">这里首先引用Jbpm User Guide里面关于持久化的描述：</div><div class="quote_div">7.5. User provided stuff <br /><br />You can also programmatically provide JDBC connections, hibernate sessions and hibernate session factories to jBPM. <br /><br />When such a resource is provided to jBPM, it will use the provided resources rather then the configured ones. <br /><br />The JbpmContext class contains some convenience methods to inject resources programmatically. For example, to provide a JDBC connectio to jBPM, use the following code: <br /><br />JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext(); <br />try { <br />Connection connection = ...; <br />jbpmContext.setConnection(connection); <br /><br />// invoke one or more persistence operations <br /><br />} finally { <br />jbpmContext.close(); <br />} <br /><br />the JbpmContext class has following convenience methods for providing resource programmatically: <br /><br />JbpmContext.setConnection(Connection); <br />JbpmContext.setSession(Session); <br />JbpmContext.setSessionFactory(SessionFactory); <br /></div><p class="MsoNormal" style="margin: 0cm 0cm 0pt">&nbsp;</p><p class="MsoNormal" style="margin: 0cm 0cm 0pt">&nbsp;</p><p class="MsoNormal" style="margin: 0cm 0cm 0pt">&nbsp;</p><span style="font-size: 12pt; font-family: 宋体"><span><span style="font-size: 12pt; font-family: 宋体">上面的文字<span>Jbpm</span>就声明了它只管它自己的持久化逻辑，至于别人塞过来的，对不起，那是别人的事情。我想，很多人在看到<span>Jbpm User guide</span>的这些文字的时候，都会想弄明白藏在这些文字背后的逻辑的。</span></span></span><span style="font-size: 12pt; font-family: 宋体">&nbsp;</span><span style="font-size: 12pt; font-family: 宋体">&nbsp;</span> <p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span style="font-size: 12pt; font-family: 宋体">&nbsp; Jbpm中所有数据库操作的入口都是<span>JbpmContext</span>，各种的数据库操作例如<span>save</span>，<span>JbpmContext</span>都会委派给不同的<span>xxxSession,</span>例如<span>GraphSession</span>，</span><span style="font-size: 10pt; background: silver; color: black; font-family: 'Courier New'">TaskMgmtSession</span><span style="font-size: 12pt; font-family: 宋体">等来处理。</span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt">&nbsp;</p><p class="MsoNormal" style="margin: 0cm 0cm 0pt">&nbsp;</p><span style="font-size: 12pt; font-family: 宋体"><span>&nbsp;</span></span><span style="font-size: 12pt; font-family: 宋体"><span><span style="font-size: 12pt; font-family: 宋体"> <p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span style="font-size: 12pt; font-family: 宋体">假设这个操作是</span><span style="font-size: 12pt; background: silver; color: black; font-family: 'Courier New'">loadTaskInstance</span><span style="font-size: 12pt; color: black; font-family: 宋体">，我将整个过程就缩小到我们关心的领域，一个是连接的打开，另外一个是连接的关闭：</span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt">&nbsp;</p><p class="MsoNormal" style="margin: 0cm 0cm 0pt">&nbsp;</p><p class="MsoNormal" style="margin: 0cm 0cm 0pt">&nbsp;</p><span style="font-size: 12pt; color: black; font-family: 宋体"><p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span style="color: #000000"><strong><span style="font-size: small"><span style="font-size: 10pt; color: black; font-family: 宋体">第一部分，</span><span style="font-size: 10pt; color: black; font-family: 'Courier New'">Session</span><span style="font-size: 10pt; color: black; font-family: 宋体">的打开：</span></span></strong></span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt">&nbsp;</p><p class="MsoNormal" style="margin: 0cm 0cm 0pt">&nbsp;</p><p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span style="color: #000000"><strong><span style="font-size: small"><span style="font-size: 10pt; color: black; font-family: 宋体"><em>【位置JbpmContext】</em></span></span></strong></span></p><span style="font-size: 10pt; color: black; font-family: 'Courier New'">&nbsp;</span><span style="font-size: 10pt; color: black; font-family: 'Courier New'"><pre name="code" class="java">public TaskInstance loadTaskInstance(long taskInstanceId) {
    return getTaskMgmtSession().loadTaskInstance(taskInstanceId);
}

public TaskMgmtSession getTaskMgmtSession() {
    PersistenceService persistenceService = getPersistenceService();
    if (persistenceService==null) return null;
    return (persistenceService!=null ? persistenceService.getTaskMgmtSession() : null);
</pre><p class="MsoNormal" style="margin: 0cm 0cm 0pt">&nbsp;</p></span></span></span><span>&nbsp;</span></span></span></span><span>&nbsp;</span><span> <p class="MsoNormal" align="left" style="margin: 0cm 0cm 0pt; text-align: left"><span style="font-size: 10pt; color: black; font-family: 宋体"><span style="font-size: small; color: #000000">这个PersistenceService就是jbpm.cfg.xml里面配置的org.jbpm.persistence.db.DbPersistenceService了，在上面getTaskMgmtSession这个方面里面PersistenceService就返回了一个带有一个Hibernate session的TaskMgmtSession了。</span></span></p><p class="MsoNormal" align="left" style="margin: 0cm 0cm 0pt; text-align: left"><span style="font-size: 10pt; color: black; font-family: 宋体"><span style="color: #000000"><span style="font-size: small">如下所示：</span></span></span></p><p>&nbsp;</p><span style="font-size: 10pt; color: black; font-family: 宋体"><span style="color: #000000"><p class="MsoNormal" align="left" style="margin: 0cm 0cm 0pt; text-align: left"><strong><em>【位置DbPersistenceService】</em></strong></p></span></span><p>&nbsp;</p><span style="font-size: 10pt; color: black; font-family: 宋体"><pre name="code" class="java">public TaskMgmtSession getTaskMgmtSession() {
    if (taskMgmtSession==null) {
      Session session = getSession();
      if (session!=null) {
        taskMgmtSession = new TaskMgmtSession(session);
      }
    }
    return taskMgmtSession;
  }</pre></span></span><p>&nbsp;</p><span style="font-size: small"><span style="font-size: 10pt; color: black; font-family: 宋体">好了，到此我们就差不多达到</span><span style="font-size: 10pt; color: black; font-family: 'Courier New'">Jbpm</span><span style="font-size: 10pt; color: black; font-family: 宋体">管理</span><span style="font-size: 10pt; color: black; font-family: 'Courier New'">Session</span><span style="font-size: 10pt; color: black; font-family: 宋体">的环节了，我们再进入到</span><span style="font-size: 10pt; color: black; font-family: 'Courier New'">getSession</span><span style="font-size: 10pt; color: black; font-family: 宋体">方法，看看它到底做了什么事情：</span></span> <p>&nbsp;</p><p>&nbsp;</p><p><span style="font-size: small"><span style="font-size: 10pt; color: black; font-family: 宋体">准备工作：</span><span style="font-size: 10pt; color: black; font-family: 'Courier New'">1</span><span style="font-size: 10pt; color: black; font-family: 宋体">）</span></span><span style="font-size: 10pt; color: black; font-family: 宋体"><span style="font-size: small">以下是会涉及的布尔变量，以及其默认值：</span></span></p><p>&nbsp;</p><p><span style="font-size: 10pt; color: black; font-family: 宋体"><span style="font-size: small"><strong><em>【位置<span style="font-size: 10pt; background: silver; color: black; font-family: 'Courier New'">DbPersistenceService】</span></em></strong></span></span></p><p>&nbsp;</p><pre name="code" class="java">Connection connection = null;
  boolean mustConnectionBeClosed = false;

  Transaction transaction = null;
  boolean isTransactionEnabled = true;
  boolean isCurrentSessionEnabled = false;
  boolean isRollbackOnly = false;

  Session session;
  boolean mustSessionBeFlushed = false;
boolean mustSessionBeClosed = false;</pre><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p><span style="font-size: 10pt; color: black; font-family: 宋体">准备工作</span><span style="font-size: 10pt; color: black; font-family: 'Courier New'">2</span><span style="font-size: 10pt; color: black; font-family: 宋体">）</span><span style="font-size: 10pt; background: silver; color: black; font-family: 宋体">由于</span><span style="font-size: 10pt; background: silver; color: black; font-family: 'Courier New'">DbPersistenceService</span><span style="font-size: 10pt; color: black; font-family: 宋体">只有一个</span><span style="font-size: 10pt; color: black; font-family: 'Courier New'">Constructor</span><span style="font-size: 10pt; color: black; font-family: 宋体">，也就是</span></p><p>&nbsp;</p><p><span style="font-size: 10pt; color: black; font-family: 宋体"><span style="font-size: 10pt; color: black; font-family: 宋体"><span style="font-size: small"><strong><em>【位置<span style="font-size: 10pt; background: silver; color: black; font-family: 'Courier New'">DbPersistenceService】</span></em></strong></span></span></span></p><p>&nbsp;</p><pre name="code" class="java">public DbPersistenceService(DbPersistenceServiceFactory persistenceServiceFactory) {
    this.persistenceServiceFactory = persistenceServiceFactory;
    this.isTransactionEnabled = persistenceServiceFactory.isTransactionEnabled();
    this.isCurrentSessionEnabled = persistenceServiceFactory.isCurrentSessionEnabled();
  }</pre><p>&nbsp;</p><p class="MsoNormal" style="margin: 0cm 0cm 0pt">&nbsp;</p><p><span style="font-size: small"><span style="font-size: 10pt; color: black; font-family: 宋体">&nbsp; <span style="font-size: small">在这里我们就知道了，进行数据库操作所用到</span></span></span><span style="font-size: small"><span style="font-size: 10pt; color: black; font-family: 'Courier New'">Session</span><span style="font-size: 10pt; color: black; font-family: 宋体">，</span><span style="font-size: 10pt; color: black; font-family: 'Courier New'">SessionFactory</span></span><span style="font-size: small"><span style="font-size: 10pt; color: black; font-family: 宋体">就只能通过相关的</span><span style="font-size: 10pt; color: black; font-family: 'Courier New'">Setter</span><span style="font-size: 10pt; color: black; font-family: 宋体">和</span><span style="font-size: 10pt; color: black; font-family: 'Courier New'">Getter</span><span style="font-size: 10pt; color: black; font-family: 宋体">方法来取到了。</span></span><span style="font-size: 10pt; color: black; font-family: 'Courier New'"><span style="font-size: small">&nbsp;</span></span><span style="font-size: 10pt; color: black; font-family: 'Courier New'"><span style="font-size: small">&nbsp;</span></span><span style="font-size: 10pt; color: black; font-family: 宋体"><span style="font-size: small">现在进入这个方法：</span></span></p><p>&nbsp;</p><p><span style="font-size: 10pt; color: black; font-family: 宋体"><span style="font-size: small"><span style="font-size: 10pt; color: black; font-family: 宋体"><span style="font-size: small"><strong><em>【位置<span style="font-size: 10pt; background: silver; color: black; font-family: 'Courier New'">DbPersistenceService】</span></em></strong></span></span></span></span></p><pre name="code" class="java">public Session getSession() {
    if ( (session==null)
         &amp;&amp; (getSessionFactory()!=null) 
       ) {
      Connection connection = getConnection(false); 
      if (isCurrentSessionEnabled) {
        session = getSessionFactory().getCurrentSession();
        mustSessionBeClosed = false;
        mustSessionBeFlushed = false;
        mustConnectionBeClosed = false;
      } else if (connection!=null) {
        log.debug(&quot;creating hibernate session with connection &quot;+connection);
        session = getSessionFactory().openSession(connection);
        mustSessionBeClosed = true;
        mustSessionBeFlushed = true;
        mustConnectionBeClosed = false;
      } else {
        log.debug(&quot;creating hibernate session&quot;);
        session = getSessionFactory().openSession();
        mustSessionBeClosed = true;
        mustSessionBeFlushed = true;
        mustConnectionBeClosed = false;
      }
      
      if (isTransactionEnabled) {
        log.debug(&quot;beginning hibernate transaction&quot;);
        transaction = session.beginTransaction();
      }
    }
    return session;
  }
</pre><p>&nbsp;&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><span style="font-size: small"><span><span style="font-family: 宋体">因为注入到</span><span><span style="font-family: Times New Roman">JbpmContext</span></span><span style="font-family: 宋体">的</span><span><span style="font-family: Times New Roman">session</span></span><span style="font-family: 宋体">和</span><span><span style="font-family: Times New Roman">sessionFactory Setter</span></span><span style="font-family: 宋体">方法都是将其注入到</span></span><span style="font-size: 10pt; color: black; font-family: 'Courier New'">persistenceService</span><span style="font-size: 10pt; color: black; font-family: 宋体">里面的</span></span><span style="font-size: 10pt; color: black; font-family: 'Courier New'"><span style="font-size: small">&nbsp;</span></span><span style="font-size: small"><span style="font-size: 10pt; color: black; font-family: 宋体">在上面这个方法里</span></span> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 10.5pt"><span style="font-size: small"><span style="font-size: 10pt; color: black; font-family: 'Courier New'">1</span><span style="font-size: 10pt; color: black; font-family: 宋体">）如果用户向</span><span style="font-size: 10pt; color: black; font-family: 'Courier New'">JbpmContext</span><span style="font-size: 10pt; color: black; font-family: 宋体">提供了</span><span style="font-size: 10pt; color: black; font-family: 'Courier New'">Session</span><span style="font-size: 10pt; color: black; font-family: 宋体">，那么会立刻返回该</span><span style="font-size: 10pt; color: black; font-family: 'Courier New'">session</span><span style="font-size: 10pt; color: black; font-family: 宋体">，并且不会修改</span><span style="font-size: 10pt; color: #0000c0; font-family: 'Courier New'">mustConnectionBeClosed</span><span style="font-size: 10pt; color: #0000c0; font-family: 宋体">，</span><span style="font-size: 10pt; color: #0000c0; font-family: 'Courier New'">mustSessionBeClosed</span><span style="font-size: 10pt; color: #0000c0; font-family: 宋体">等的值。</span></span></p><span style="font-size: small"><span><span><span style="font-family: Times New Roman">2</span></span><span style="font-family: 宋体">）如果用户向</span><span><span style="font-family: Times New Roman">JbpmContext</span></span><span style="font-family: 宋体">提供了</span><span><span style="font-family: Times New Roman">SessionFactory</span></span><span style="font-family: 宋体">，在</span><span><span style="font-family: Times New Roman">getConnection</span></span><span style="font-family: 宋体">时将</span></span><span style="font-size: 10pt; background: silver; color: #0000c0; font-family: 'Courier New'">mustConnectionBeClosed</span><span style="font-size: 10pt; color: #0000c0; font-family: 宋体">设置成了</span><span style="font-size: 10pt; color: #0000c0; font-family: 'Courier New'">false</span><span style="font-size: 10pt; color: #0000c0; font-family: 宋体">，另外使用返回的</span><span style="font-size: 10pt; color: #0000c0; font-family: 'Courier New'">Connection</span><span style="font-size: 10pt; color: #0000c0; font-family: 宋体">创建了一个</span><span style="font-size: 10pt; color: #0000c0; font-family: 'Courier New'">Hibernate Session</span><span style="font-size: 10pt; color: #0000c0; font-family: 宋体">，即</span></span><span style="font-size: small"><span style="font-size: 10pt; color: #0000c0; font-family: 'Courier New'">session</span><span style="font-size: 10pt; color: black; font-family: 'Courier New'"> = getSessionFactory().openSession(connection);</span></span><span style="font-size: small"><span style="font-size: 10pt; background: silver; color: #0000c0; font-family: 宋体">紧接着将</span><span style="font-size: 10pt; background: silver; color: #0000c0; font-family: 'Courier New'">mustSessionBeClosed</span><span style="font-size: 10pt; color: #0000c0; font-family: 宋体">和</span><span style="font-size: 10pt; background: silver; color: #0000c0; font-family: 'Courier New'">mustSessionBeFlushed</span><span style="font-size: 10pt; color: #0000c0; font-family: 宋体">设置成了</span><span style="font-size: 10pt; color: #0000c0; font-family: 'Courier New'">true</span><span style="font-size: 10pt; color: #0000c0; font-family: 宋体">。</span></span> <p>&nbsp;</p><p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://ginge.javaeye.com/blog/166244#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/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 29 Feb 2008 19:31:10 +0800</pubDate>
        <link>http://ginge.javaeye.com/blog/166244</link>
        <guid>http://ginge.javaeye.com/blog/166244</guid>
      </item>
      <item>
        <title>Spring, Springmodules, JBPM持久化集成--优雅的回调</title>
        <author>ginge</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://ginge.javaeye.com">ginge</a>&nbsp;
          链接：<a href="http://ginge.javaeye.com/blog/165996" style="color:red;">http://ginge.javaeye.com/blog/165996</a>&nbsp;
          发表时间: 2008年02月29日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><strong>Spring, Springmodules, JBPM持久化集成理解系列一</strong></p><p>&nbsp;</p><p>&nbsp;</p><p><strong>【本系列如需转载，请注明作者及出处】 </strong></p><p>&nbsp;</p><p><strong>本系列文章假设阅者具备以下知识：<br />1，ThreadLocal相关知识<br />2，Spring持久化，事务管理相关知识<br />3，Hibernate 持久化相关知识<br />4，Jbpm 持久化相关知识<br />5，Springmodules项目相关知识<br />6，相关J2EE知识</strong></p><strong><br />且具备以下材料：<br />1，Spring源代码<br />2，Hibernate源代码<br />3，Jbpm源代码<br />4，Springmodules源代码</strong><strong> <p><br /><br />接触JBPM始于两年多前，当时还在广州一个公司实习，公司打算研发ITIL相关的项目，于是就开始知道了工作流，也就开始