<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>Jim Jiang's Java EE Blog</title>
    <description></description>
    <link>http://jimjiang.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>GLASSFISH 的里里外外</title>
        <author>jlj008</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://jimjiang.javaeye.com">jlj008</a>&nbsp;
          链接：<a href="http://jimjiang.javaeye.com/blog/214348" style="color:red;">http://jimjiang.javaeye.com/blog/214348</a>&nbsp;
          发表时间: 2008年07月13日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          GlassFish 有很广大的用户，仅仅一年之内就有4.5万次下载，这是一些文摘：<br />http://www.sun.com/featured-articles/2008-0610/feature/index.jsp<br /><br />GlassFish 有很广泛的社区，这是社区论坛网站, 你能在论坛讨论问题http://forums.java.net/jive/forum.jspa?forumID=56&start=0<br /><br /><br />有这么多人下载，这么多人安装和设置GlassFish，使GlassFish在不同的电脑和操作系统上得到了有效的测试，这样你就不会碰到基本的故障，又因为GlassFish在网络有很多的信息，你只要在google搜索“GlassFish issue”，你多半都能够得到满意的答复。<br /><br /><br />GlassFish 据有企业功能，能应用到企业生产线上，在这个博文里我会向你推荐一些GlassFish 企业功能<br /><br />你能在下面这个链接免费下载GlassFish：https://glassfish.dev.java.net/downloads/v2ur2-b04.html<br /><br />这是GlassFish简便操作指南：https://glassfish.dev.java.net/downloads/quickstart/index.html<br /><br />你能用GlassFish管理平台很方便来管理 GlassFish 多种功能，可以部署。可以修改，然后再部署。<br /><br />如果你要用集群，用下面这个步骤来安装，然后用下面推荐的HA文档来构架。<br /><br />https://glassfish.dev.java.net/javaee5/build/GlassFish_LB_Cluster.html<br /><br />http://wiki.glassfish.java.net/Wiki.jsp?page=GlassFishV2Architecture<br /><br />下面是一篇非常好的关于GlassFish集群文章<br />http://developers.sun.com/appserver/reference/techart/glassfishcluster/<br /><br /><br />我们还有High Availability操作指南<br />http://docs.sun.com/app/docs/doc/819-3679<br /><br />GlassFish 有两种high availability，一种是in-memory，GlassFish 的原装用的是in-memory<br /><br />如果你需要高availability，你可以免费下载有HADB组装的功能<br />http://www.sun.com/download/products.xml?id=46df3223<br /><br /><br />GlassFish支持软件和硬件Loadbalancer<br />http://blogs.sun.com/Prashanth/entry/load_balancing_glassfish_v2_with<br /><br />用GlassFish Enterprise bits 来组装loadbalancer plugin，我们有自动组装的方法，这是操作指南<br />http://docs.sun.com/app/docs/doc/819-3193<br /><br />看到这里，你是否被我搞糊涂了，搞不清GlassFish和GlassFish enterprise 的区别，下面是它们的不同之处<br />http://wiki.glassfish.java.net/Wiki.jsp?page=FaqGlassFishV2vsSJSAS91<br /><br />如果你需要SSL。GlassFish有全套的支持，<br />http://blogs.sun.com/enterprisetechtips/entry/using_ssl_with_glassfish_v2<br /><br />如果你想知道有哪些企业推荐，这里可以找到许多GlassFish用户的成功故事<br />http://blogs.sun.com/stories<br /><br /><br />如果你想知道ISV，GlassFish有很多成功的合作夥伴<br />http://www.sun.com/software/products/appsrvr/gf-isv-partners.jsp<br /><br />如果你要用GlassFish放在企业工作系统，你并且需要有及时的用户支持，你可以来买GlassFish的用户收费支持<br />http://globalspecials.sun.com/servlet/ControllerServlet?Action=DisplayPage&Env=BASE&Locale=en_US&SiteID=sunstor&id=ProductDetailsPage&productID=81508900
          <br/>
          <span style="color:red;">
            <a href="http://jimjiang.javaeye.com/blog/214348#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 13 Jul 2008 15:13:00 +0800</pubDate>
        <link>http://jimjiang.javaeye.com/blog/214348</link>
        <guid>http://jimjiang.javaeye.com/blog/214348</guid>
      </item>
      <item>
        <title>常用正则表达式</title>
        <author>jlj008</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://jimjiang.javaeye.com">jlj008</a>&nbsp;
          链接：<a href="http://jimjiang.javaeye.com/blog/194331" style="color:red;">http://jimjiang.javaeye.com/blog/194331</a>&nbsp;
          发表时间: 2008年05月19日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          正则表达式用于字符串处理、表单验证等场合，实用高效。现将一些常用的表达式收集于此，以备不时之需。<br /><br />匹配中文字符的正则表达式： [\u4e00-\u9fa5]<br />评注：匹配中文还真是个头疼的事，有了这个表达式就好办了<br /><br />匹配双字节字符(包括汉字在内)：[^\x00-\xff]<br />评注：可以用来计算字符串的长度（一个双字节字符长度计2，ASCII字符计1）<br /><br />匹配空白行的正则表达式：\n\s*\r<br />评注：可以用来删除空白行<br /><br />匹配HTML标记的正则表达式：&lt;(\S*?)[^>]*>.*?&lt;/\1>|&lt;.*? /><br />评注：网上流传的版本太糟糕，上面这个也仅仅能匹配部分，对于复杂的嵌套标记依旧无能为力<br /><br />匹配首尾空白字符的正则表达式：^\s*|\s*$<br />评注：可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等)，非常有用的表达式<br /><br />匹配Email地址的正则表达式：\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*<br />评注：表单验证时很实用<br /><br />匹配网址URL的正则表达式：[a-zA-z]+://[^\s]*<br />评注：网上流传的版本功能很有限，上面这个基本可以满足需求<br /><br />匹配帐号是否合法(字母开头，允许5-16字节，允许字母数字下划线)：^[a-zA-Z][a-zA-Z0-9_]{4,15}$<br />评注：表单验证时很实用<br /><br />匹配国内电话号码：\d{3}-\d{8}|\d{4}-\d{7}<br />评注：匹配形式如 0511-4405222 或 021-87888822<br /><br />匹配腾讯QQ号：[1-9][0-9]{4,}<br />评注：腾讯QQ号从10000开始<br /><br />匹配中国邮政编码：[1-9]\d{5}(?!\d)<br />评注：中国邮政编码为6位数字<br /><br />匹配身份证：\d{15}|\d{18}<br />评注：中国的身份证为15位或18位<br /><br />匹配ip地址：\d+\.\d+\.\d+\.\d+<br />评注：提取ip地址时有用<br /><br />匹配特定数字：<br />^[1-9]\d*$　 　 //匹配正整数<br />^-[1-9]\d*$ 　 //匹配负整数<br />^-?[1-9]\d*$　　 //匹配整数<br />^[1-9]\d*|0$　 //匹配非负整数（正整数 + 0）<br />^-[1-9]\d*|0$　　 //匹配非正整数（负整数 + 0）<br />^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$　　 //匹配正浮点数<br />^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$　 //匹配负浮点数<br />^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$　 //匹配浮点数<br />^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$　　 //匹配非负浮点数（正浮点数 + 0）<br />^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$　　//匹配非正浮点数（负浮点数 + 0）<br />评注：处理大量数据时有用，具体应用时注意修正<br /><br />匹配特定字符串：<br />^[A-Za-z]+$　　//匹配由26个英文字母组成的字符串<br />^[A-Z]+$　　//匹配由26个英文字母的大写组成的字符串<br />^[a-z]+$　　//匹配由26个英文字母的小写组成的字符串<br />^[A-Za-z0-9]+$　　//匹配由数字和26个英文字母组成的字符串<br />^\w+$　　//匹配由数字、26个英文字母或者下划线组成的字符串<br />评注：最基本也是最常用的一些表达式
          <br/>
          <span style="color:red;">
            <a href="http://jimjiang.javaeye.com/blog/194331#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 19 May 2008 12:16:11 +0800</pubDate>
        <link>http://jimjiang.javaeye.com/blog/194331</link>
        <guid>http://jimjiang.javaeye.com/blog/194331</guid>
      </item>
      <item>
        <title>Building struts2 app with out xml gluecode</title>
        <author>jlj008</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://jimjiang.javaeye.com">jlj008</a>&nbsp;
          链接：<a href="http://jimjiang.javaeye.com/blog/163293" style="color:red;">http://jimjiang.javaeye.com/blog/163293</a>&nbsp;
          发表时间: 2008年02月19日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          本文转自TSS<br /><br />http://www.theserverside.com/tt/articles/article.tss?l=SmartURLs<br /><br />In this article, we jettison XML gluecode for "convention over configuration". Using the SmartURLs plugin for Struts 2, we can autowire Action classes to page templates with search-engine-optimized URIs.<br /><br />This article covers:<br /><br />    * Exploiting convention over configuration<br />    * Eliminating XML gluecode<br />    * Validating input with annotations<br /><br />What's XML gluecode?<br /><br />Success breeds success, and successful applications tend to grow larger and more complex over time. Most applications are so large and so complex that we can't think about the entire application at once. To get through the day, we need to focus our attention on one thing at time.<br /><br />One way to simplify complex applications is to separate concerns. We group similar tasks together, so that we can focus on one element of the application at a time. Two concerns that we like to separate are presentation logic and business logic. It's easier to design presentation logic using a page template, and it's easier to design business logic using conventional source code. Each concern is easy to manage on its own, but we need a way to put the concerns back together.<br /><br />In a conventional Struts application, we glue concerns together using declarative statements in an XML document. In practice, we write a lot of XML stanzas that just say: "For this request, run this Java class and then render this page template." "Example 1: struts.xml" shows a bit of XML gluecode.<br /><br />"Example 1: struts.xml"<br /><br />&lt;action name="hello-world" class="actions.HelloWorld"><br />  &lt;result>/results/hello-world.jsp&lt;/result><br />&lt;/action><br /><br />At first, a dash of gluecode may seem trivial, but as applications grow in size, we can waste as much time fussing with gluecode as we spend on coding Action classes or writing JSP pages.<br /><br />Nowadays, a popular way to avoid XML "gluecode" is to use "convention over configuration".<br />What's convention over configuration?<br /><br />Instead of wiring components together with configuration files, another strategy is to use consistent naming conventions, and then make the conventions part of the application framework. Many Struts developers already use naming conventions to track which components go together. We just need to program the framework to observe the same kind of conventions that most of us already use.<br /><br />For example, if a client requests a "hello-world.action", it makes sense for the framework to look for a "HelloWorld.class" and/or a "hello-world.jsp". If the Action class returns "small" as a result code, it makes sense to first look for a "hello-world-small.jsp" (or a "hello-world-small.vm", you prefer Velocity templates). If "hello-world-small.jsp" is not found, then it would also make sense to check for a plain-old "hello-world.jsp".<br /><br />These matching rules may sound simplistic, but, in practice, a few simple rules is all that we need to write entire Struts applications without even a smidgeon of XML gluecode!<br /><br />Should our conventions fall short, the SmartURLs plugin also provides annotations that we can use to override the matched action or result, on a case-by-case basis.<br />Does Struts 2 support convention over configuration by default?<br /><br />The Struts 2 core offers a few features that can reduce configuration. But to get the full benefit of "convention over configuration", we need to add a new plugin to the mix.<br /><br />The SmartURLs plugin for Struts 2 (http://cwiki.apache.org/S2PLUGINS/smarturls-plugin.html) offers a full-featured approach to convention over configuration. A request for "/my-action" is automatically mapped to a MyAction class and the result to a my-action.jsp page. To keep the system flexible, heuristic defaults look for alternative matches if MyAction class or my-action.jsp is not present. The matching rules are laid out in "Sidebar 1: SmartURLs Rules"<br /><br />"Sidebar 1: SmartURLs rules"<br /><br />URL to Action class (/my/package/hello-world):<br /><br />    * A-1 Extract the final URL path segment (hello-world).<br />    * A-2 Upper-case the initial letter, and if any hyphen appears within the URL path, upper-case any following letter, and remove the hyphen (HelloWorld).<br />    * A-3 Convert the rest of the path to lowercase, and substitute slashes with dots (my.package.).<br />    * A-4 Check the base action packages for a class matching package + action (actions.my.package.HelloWorld).<br />    * A-5 If a matching Action is not found, use the package's default Action class (ActionSupport).<br /><br />Result code to Path:<br /><br />    * B-1 Append the result-code returned by an Action to original URL path (/my/package/hello-world-success).<br />    * B-2 Check the base result folders for a matching JSP, Freemarker Template, or Velocity Template (/WEB-INF/results/my/package/hello-world-success.jsp).<br />    * B-3 If the template is not found, remove the response code, and try again (/WEB-INF/result/my/package/hello-world.jsp).<br />    * B-4 Raise a standard 404 error is a matching template is not found.<br /><br />SmartURLs provides features like:<br /><br />    * Extensionless URIs<br />    * Automatic binding of action URLs to conventional class and page names<br />    * Action URI format that is "Search Engine Optimization" (SEO) compliant<br />    * Annotations to specify a different action name, or even multiple names<br />    * Automatic support of JSP, Freemarker, and Velocity result types<br />    * Robust "index" page handling (/products will match actions.Products or actions.products.Index)<br /><br />How would we write a SmartURLs "Hello World" page?<br /><br />Frameworks like Struts decompose an application's workflow into a series of actions. Each action might have associated with it several concerns, including input validation, business logic, persistence logic, message resources, text formatting, and an output resource. Each action has its own context, and which concerns are applied to any given action may vary according to circumstance.<br /><br />The simplest use case for an action is rendering a page template without specifying any other concerns. (Just show me the @%#$^ page!) For our SmartURLs hello world example, let's try the simplest case first and then add in some of the other concerns. "Sidebar 2: Render page template" outlines the use case.<br /><br />"Sidebar 2: Render page template"<br /><br />System renders a page template without a custom Action class.<br /><br />   1. Client requests an action resource.<br />   2. System determines there is no custom Action class configured for the resource.<br />   3. System renders page template for the resource using a default Action class.<br />   4. Client presents HTML version of the page template.<br /><br />We can configure SmartURLs to expect page resources (JSP, Freemarker, or Velocity) to be found under "WEB-INF/results". This location is accessible to the Struts 2 framework, but it is not directly accessible to a web browser. The page resources cannot be accessed except through Struts 2 (or another server-side component).<br /><br />Into the "WEB-INF/results" folder, we can drop a simple JSP template, as shown by "Example 2: hello-world.jsp".<br /><br />"Example 2: hello-world.jsp"<br /><br />&lt;html><br /> &lt;body><br />  &lt;p><br />   Hello World!<br />  &lt;/p><br />  &lt;p><br />   It is now &lt;%= new java.util.Date() %>.<br />  &lt;/p><br /> &lt;/body><br />&lt;/html><br /><br />With the SmartURLs plugin installed, we can fire up our web container and open the URL "http://localhost:8080/smartapp/hello-world". (The hostname and port for your container may vary!)<br /><br />In response, SmartURLs will render the "WEB-INF/results/hello-world.jsp" template, as shown in "Figure 1: Hello World!"<br /><br />"Figure 1: Hello World!"<br /><br />If the page renders, we know that SmartURLs is working!<br /><br />Already, SmartURLs lets us<br /><br />    * use extensionless URIs,<br />    * store templates under the secure WEB-INF folder, and<br />    * do without "gluecode" XML<br /><br />How would we display our own data on the page?<br /><br />As handy as checking the server time may be, we usually want to merge our own data into a page template. Typically, we want to set a property on a Struts Action and then display that property in the page.<br /><br />The value of the property might come from a database, and be filtered through a set of business rules, but the page doesn't need to know that. All the page needs to know is that the property is available, and it's the page's job to display the value, whatever it is. Conversely, the Action class doesn't need to know anything about HTML or expression languages. It just sets the property.<br /><br />Right now, our concern is whether the Action class and page template are automatically wired together by the framework. So all we really need to do is set an Action property to a known value, and see if the page displays the value we expect.<br /><br />To test SmartURL's autowiring, let's add a HelloWorld class to an "actions" package in our application, as show in "Example 3: HelloWorldAction.java".<br /><br />"Example 3: HelloWorldAction.java"<br /><br />package actions;<br />public class HelloWorldAction  {<br />  private String greeting;<br />  public String getGreeting() {<br />    return greeting;<br />  }<br />  public String execute() {<br />    greeting = "The server time is " + new java.util.Date().toString();<br />    return "success";<br />  }<br />}<br /><br />Notice that this is a "POJO" Action class (a standard Struts 2 feature). We don't need any of the framework's special services, so we didn't extend a base class or implement a special interface. The closest thing to a special feature is the execute method! One other concession is that we need to append "Action" as a suffix to the classname.<br /><br />Also note that we changed the message slightly, so that we can be sure that our page is updated. The updated page is shown in "Example 4: hello-world.jsp (2)"<br /><br />"Example 4: hello-world.jsp (2)"<br /><br />&lt;html><br /> &lt;body><br />  &lt;p><br />   Hello World!<br />  &lt;/p><br />  &lt;p><br />   ${greeting}<br />  &lt;/p><br /> &lt;/body><br />&lt;/html><br /><br />Of course, we could use a Struts 2 tag instead of the JSTL expression, but &lt;s:property value="greeting"/> seems verbose compared to "${greeting]". Figure 2: "Hello World! (2)" shows the updated page.<br /><br />"Figure 2: Hello World! (2)"<br /><br />Can SmartURLs handle a data-entry workflow with input validation?<br /><br />A strength of action frameworks, like Struts 2, is that, depending on the runtime circumstances, an action can change the workflow by selecting different output pages. For example, we might want to collect input on one page. If the input is correct, we might want to go to an output page. If the input is not correct, we might want return to the input page.<br /><br />Since validation workflow is one of the special services that the framework provides, in "Example 5: HelloWorld.java (2)", we extend our class from the ActionSupport class.<br /><br />"Example 5: HelloWorld.java (2)"<br /><br />package actions;<br />import com.opensymphony.xwork2.ActionSupport;<br />import com.opensymphony.xwork2.validator.annotations.*;<br />@Validation()<br />public class HelloWorld extends ActionSupport {<br />  private String greeting;<br />  @RequiredStringValidator(message="Please enter a greeting!")<br />  public String getGreeting() {<br />    return greeting;<br />  }<br />  public void setGreeting(String value) {<br />    greeting = value;<br />  }<br />}<br /><br />Since we now extend the Action interface, the SmartURLs rules also lets us drop the "Action" suffix from the classname.<br /><br />In Example 5, we use validation by annotation (another standard Struts 2 feature) to ensure that a message is entered. (Annotations, introduced in Java 5, are specified in the program source by using the @ symbol.) Struts 2 and the SmartURLs plugin use annotations as an alternative to XML gluecode. In Example 5, we use an annotation to "glue" a RequiredStringValidator to the message property. The core framework provides annotations for all the usual validators.<br /><br />To collect an input message to validate, we can add another page template, as shown in "Example 6: hello-world-input.jsp".<br /><br />"Example 6: hello-world-input.jsp"<br /><br />&lt;%@ taglib uri="/struts-tags" prefix="s" %><br />&lt;html><br /> &lt;body><br />  &lt;p><br />   What would you like to say to the world?<br />  &lt;/p><br />  &lt;s:form action="hello-world"><br />    &lt;s:textfield label="Greeting" name="greeting" /><br />    &lt;s:submit /><br />  &lt;/s:form><br /> &lt;/body><br />&lt;/html><br /><br />"Figure 3: Hello World Input!" shows the page as it would be rendered.<br /><br />"Figure 3: Hello World Input!"<br /><br />If the message field is left blank, validation will fail, the HelloWorld Action will return an "input" result code, and SmartURLs will forward control back to "hello-world-input.jsp", as shown by "Figure 4: Hello World Input! (2)".<br /><br />"Figure 4: Hello World Input! (2)"<br /><br />If we manage to pass validation, a page renders like the one shown in "Example 5: Howdy".<br /><br />"Figure 5: Hello World Input! (3)!"<br /><br />Note that we can implement this common workflow without any XML gluecode! In this workflow, the only metadata of any kind is the RequiredStringValidator annotation. The rest is driven by convention over configuration!<br />What if we wanted to redirect after submitting a form?<br /><br />If a form passes validation, and we use it to update a database, we often want to "redirect" to a confirmation page. A redirect updates the page location in the web browser's address bar. Among other things, a redirect ensures that people do not resubmit the form again by pressing refresh.<br /><br />Struts 2 supports redirects through the @Result annotation. To redirect to another location on "success", we can add a "@Result" annotation to the Action class. "Example 7: HelloWorld.java (3)" shows the @Result annotation.<br /><br />"Example 7: HelloWorld.java (3)"<br /><br />@Result(name="success", type="redirect", location="hello-world-view")<br />public class HelloWorld extends ActionSupport<br /><br />The annotation in Example 7 implies that there is a hello-world-view action. To create one, all we need to do is rename hello-world.jsp to hello-world-view.jsp.<br /><br />On success, the system will redirect from the Hello Action to "hello-world-view.jsp", and display the greeting we entered through the "hello-world-input" action.<br /><br />Or not.<br /><br />By default, the Action properties are retained in request scope. If we redirect, we lose the first request scope and create a second. For now, the simplest solution is to keep our greeting in session scope. The complete, updated class is shown in "Example 8: HelloWorld.java (4)".<br /><br />"Example 8: HelloWorld.java (4)"<br /><br />package actions;<br />import java.util.Map;<br />import com.opensymphony.xwork2.ActionSupport;<br />import com.opensymphony.xwork2.validator.annotations.*;<br />import org.apache.struts2.interceptor.SessionAware;<br />import org.texturemedia.smarturls.Result;<br />@Validation()<br />@Result(name="success", type="redirect-action", location="hello-world-view")<br />public class HelloWorld extends ActionSupport implements SessionAware {<br />    private Map&lt;String, String> session;<br />    public void setSession(Map value) {<br />        session = value;<br />    }<br />    protected Map&lt;String, String> getSession() {<br />        Map&lt;String, String> value = session;<br />        return value;<br />    }<br />    public static String GREETING_KEY = "greeting";<br />    @RequiredStringValidator(message="Please enter a greeting!")<br />    public String getGreeting() {<br />        return (String) getSession().get(GREETING_KEY);<br />    }<br />    public void setGreeting(String value) {<br />        getSession().put(GREETING_KEY,value);<br />    }<br />}<br /><br />Now, to enter a greeting we can open "hello-world-input", which submits to "hello-world". If we successfully enter a greeting, "hello-world" stores the property in session scope, and redirects to "hello-world-view". To complete the loop, we can add a link back to the data-entry page. "Example 9: hello-world-view.jsp" shows the updated page.<br /><br />"Example 9: hello-world-view.jsp"<br /><br />&lt;html><br /> &lt;body><br />  &lt;p><br />   Hello World!<br />  &lt;/p><br />  &lt;p><br />   ${greeting}<br />  &lt;/p><br />  &lt;p><br />  &lt;a href="hello-world-input.do">Try again!&lt;/a><br />  &lt;/p><br /> &lt;/body><br />&lt;/html><br /><br />At this point, our complete Hello World data-entry workflow is shown by<br /><br />    * "Example 6: hello-world-input.jsp",<br />    * "Example 7: HelloWorld.java (3)", and<br />    * "Example 4: hello-world-view.jsp"<br /><br />without a single line of XML gluecode!<br />How do we install the SmartURLs plugin?<br /><br />To install the plugin, first add the SmartURLs JAR to the web application's lib folder, along with the other Struts JARs. To get the most benefit from SmartURLs, we should make two small changes to the configuration. Among other things, these changes will let us use extensionless URLs.<br /><br />Second, replace the standard Struts filter with the SmartURLs version. "Example web.xml" shows the SmartURLs &lt;filter> and &lt;filter-mapping> stanzas.<br /><br />"Example 8: web.xml"<br /><br />    &lt;filter><br />        &lt;filter-name><br />            struts2<br />        &lt;/filter-name><br />        &lt;filter-class><br />            org.texturemedia.smarturls.SmartURLsFilter<br />        &lt;/filter-class><br />    &lt;/filter><br />    &lt;filter-mapping><br />        &lt;filter-name><br />            struts2<br />        &lt;/filter-name><br />        &lt;url-pattern><br />            /*<br />        &lt;/url-pattern><br />    &lt;/filter-mapping><br /><br />Third, in the application's struts.xml, add the "constant" stanza shown in "Example 9: struts.xml".<br /><br />"Example 9: struts.xml"<br /><br />&lt;?xml version="1.0" encoding="UTF-8" ?><br />&lt;!DOCTYPE struts PUBLIC<br />    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"<br />    "http://struts.apache.org/dtds/struts-2.0.dtd"><br />    &lt;constant name="struts.devMode" value="false" /><br />    &lt;constant name="struts.action.extension" value="" /><br />    &lt;constant name="smarturls.action.packages" value="actions" /><br />    &lt;constant name="smarturls.base.result.location" value="/WEB-INF/results/" >&lt;/constant><br />    &lt;constant name="struts.custom.i18n.resources" value="support.package" >&lt;/constant><br />&lt;/struts><br /><br />A larger application may need to define some other one-time settings or package defaults. But not gluecode!<br /><br />What's the minimum installation we need for a SmartURLs application?<br /><br />If you are using MyEclipse or Eclipse with Web Tools (WTP), you can create a Dynamic Web Application, and then<br /><br />   1. Drop the usual Struts 2 JARs (freemarker, ognl, struts2-core, xwork2) under the standard "lib" folder, along with the SmartURLs plugin JARs (java-net-commons and smarturls-s2).<br />   2. Under "WebContent/WEB-INF", create a "results" folder for page templates.<br />   3. Under the "src" folder, create a "struts.xml" based on Example 9, and a "actions" package for Action classes.<br /><br />And you are ready to go!<br />Is that all there is?<br /><br />We've walked through the simplest way to use SmartURLs. We've shown the simplest approach that requires the fewest annotations. Aside from the annotations we've shown, SmartURLs supports several others. For example, we can give an Action multiple names, or call methods other than execute.<br /><br />The SmartURLs documentation details the various annotations and configuration options. For more of SmartURLS in action, a complete SmartURLs MailReader example application is also available as a ready-to-deploy WAR (check Resources at the end of the article).<br /><br />Using SmartURLs conventions, we can write less code and still create powerful, enterprise-ready applications. We can then put the time we save toward improving the user interface and other parts of the application that make it more useful.<br /><br />Today, SmartURLs is a third-party plugin, but work is underway to merge it with the standard CodeBehind Plugin for Struts 2.1. The CodeBehind plugin for Struts 2.0 offers similar capabilities, but fewer features.<br />Resources<br /><br />    * SmartURLs plugin site (http://code.google.com/p/smarturls-s2/)<br />    * SmartURLs MailReader Example for Java 5 (http://husted.com/smart-urls/smart-urls.war)<br />    * Apache Struts site (http://struts.apache.org)
          <br/>
          <span style="color:red;">
            <a href="http://jimjiang.javaeye.com/blog/163293#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 19 Feb 2008 11:32:57 +0800</pubDate>
        <link>http://jimjiang.javaeye.com/blog/163293</link>
        <guid>http://jimjiang.javaeye.com/blog/163293</guid>
      </item>
      <item>
        <title>关于struts2标签取值的备忘录</title>
        <author>jlj008</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://jimjiang.javaeye.com">jlj008</a>&nbsp;
          链接：<a href="http://jimjiang.javaeye.com/blog/160687" style="color:red;">http://jimjiang.javaeye.com/blog/160687</a>&nbsp;
          发表时间: 2008年01月31日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          取值要通过&lt;s:property value="" />或在任意的&lt;s:/>标签内使用%{}；<br /><br />当Action的valueStack中有该属性的值时，只需直接使用该属性的名字即可；<br /><br />当Action的valueStack中没有该属性的值时，比如在session,application范围中的属性值时，需要加#或者#attr.；<br /><br />例子：<br />假设某Action中有person成员变量，在application中存在company属性<br />那么我们可以通过以下方法取值：<br />&lt;s:property value="person.name" /><br />&lt;s:property value="#person.name" /><br />&lt;s:property value="company.name" /> //无法取到，因为company不在action的valueStack中<br />&lt;s:property value="#company.name" /><br /><br />&lt;s:textfield name="person.name" value="person.name" /> //错误，value会直接显示person.name字样<br />&lt;s:textfield name="person.name" value="%{person.name}" /><br />&lt;s:textfield name="person.company.name" value="%{#company.name}" /><br />&lt;s:textfield name="person.company.name" value="%{#attr.company.name}" />
          <br/>
          <span style="color:red;">
            <a href="http://jimjiang.javaeye.com/blog/160687#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 31 Jan 2008 11:21:42 +0800</pubDate>
        <link>http://jimjiang.javaeye.com/blog/160687</link>
        <guid>http://jimjiang.javaeye.com/blog/160687</guid>
      </item>
      <item>
        <title>使用JDK1.4运行Struts2.0(转)</title>
        <author>jlj008</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://jimjiang.javaeye.com">jlj008</a>&nbsp;
          链接：<a href="http://jimjiang.javaeye.com/blog/141132" style="color:red;">http://jimjiang.javaeye.com/blog/141132</a>&nbsp;
          发表时间: 2007年11月16日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <div class="postTitle"><a href="http://www.blogjava.net/puras/archive/2007/11/14/160590.html" class="postTitle2" id="viewpost1_TitleUrl">使用JDK1.4运行Struts2.0</a> </div>
<div class="postTitle"></div>
<div class="postTitle">转自<font face="Arial">http://www.blogjava.net/puras/archive/2007/11/14/160590.html</font></div>
<p>刚刚把做完的项目从JDK5上移植到JDK1.4,事后整理一下,常常记记备忘录是个灰常好的习惯滴.呵.</p>
<p>Struts2.0默认的平台需求是:</p>
<ul>
    <li>Servlet API 2.4 </li>
    <li>JSP API 2.0 </li>
    <li>Java 5 </li>
</ul>
<p>但是因为一些原因,我们必须使用JDK1.4来编译,所以只能应用Struts提供的J4,来进行一下移植了,说实话,还是挺好的,只需要简单的操作,便可以把JDK更改为1.4的了.原本我以为弄不好还得重新写代码呢,结果才发现,嗯,如此的简单.</p>
<p>好了,不废话了.</p>
<p>要想应用JDK1.4,使用的主要的是Struts2.0的发行包里提供的J4目录中的Retrotranslator.利用它可以将原JDK5的包转化成JDK1.4的.关于Retrotranstator的介绍,可以查看<a href="http://retrotranslator.sourceforge.net/">http://retrotranslator.sourceforge.net/</a>,里面写的很详细.</p>
<p>在J4目录中,已经将Struts2.0基本的两个Jar文件转好了,分别是struts2-core-j4-2.0.9.jar和xwork-j4-2.0.4.jar.如果你的程序中还用到的其他的Jar包,可以通过脚本把Jar包转成J4版本的.我们的程序中用到了spring和sitemesh两个Plugin的Jar包,所以需要将这两个包转成J4的.</p>
<p>java -jar retrotranslator-transformer-1.2.2.jar -advanced -srcjar ../lib/struts2-sitemesh-plugin-2.0.9.jar -destjar struts2-sitemesh-plugin-j4-2.0.9.jar<br />
java -jar retrotranslator-transformer-1.2.2.jar -advanced -srcjar ../lib/struts2-spring-plugin-2.0.9.jar -destjar struts2-spring-plugin-j4-2.0.9.jar </p>
<p>可以将它们写到一个Bat文件中,如果你用的是Windows的系统的话,使用Linux的用户可以存成sh文件.</p>
<p>执行Bat文件,将生成两个新的J4版本的包,struts2-sitemesh-plugin-j4-2.0.9.jar和struts2-spring-plugin-j4-2.0.9.jar.</p>
<p>将这四个Jar包放到WEB-INF/lib中,再将J4目录中的retrotranslator-transformer-1.2.2.jar, backport-util-concurrent-3.0.jar和retrotranslator-runtime-1.2.2.jar一起放到WEB-INF/lib下.</p>
<p>之后再把自己写的程序中所使用的JDK5的特性去掉,嗯,我们只用了Annotations等几个特性,所以改起来还是相当容易了.</p>
<p>至此,你的程序应该就可以在JDK1.4上运行了.</p>
<p>我使用的环境Tomcat5.0+jdk1.4.运行我修改后的程序,测试通过......</p>
<p>Over</p>
          <br/>
          <span style="color:red;">
            <a href="http://jimjiang.javaeye.com/blog/141132#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 16 Nov 2007 11:49:07 +0800</pubDate>
        <link>http://jimjiang.javaeye.com/blog/141132</link>
        <guid>http://jimjiang.javaeye.com/blog/141132</guid>
      </item>
      <item>
        <title>Weblogic + SqlServer2000 JTA 配置 step by step</title>
        <author>jlj008</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://jimjiang.javaeye.com">jlj008</a>&nbsp;
          链接：<a href="http://jimjiang.javaeye.com/blog/137560" style="color:red;">http://jimjiang.javaeye.com/blog/137560</a>&nbsp;
          发表时间: 2007年11月02日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>JTA在处理分布式事务闻名已久，但是一直没有真正去玩过JTA，趁着这几天空闲，心血来潮想玩一把。经过一番周折，通过weblogic的JTA，并结合spring提供的简单配置，跑通了自己的第一个JTA事务。<br />
记录一下，留个纪念，如果有朋友在实验中遇到同样的问题，也可以略加参考，希望对你有点帮助。<br />
<br />
Step by Step<br />
1. 安装Sqlserver 2000 + sp4<br />
<br />
2. 在<a href="http://www.bea.com">www.bea.com</a>下载weblogic express 8.1。<br />
<br />
3. 安装weblogic，并创建自己的domain实例，然后启动domain实例。<br />
<br />
4. 浏览<a href="http://localhost:7001/console">http://localhost:7001/console</a>，如果出现管理页面，则安装已成功。<br />
<br />
5. 进入管理页面后，选择Services Configurations - JDBC - Connection Pools，配置连接池。<br />
选择创建一个新的连接池，Database Type选择MS Sql Server，然后在Database Driver中选择*BEA's MS Sql Server Driver (Type 4 XA)。注意，要真正使用JTA事务，必须选择带XA的驱动，以支持JTA事务的两阶段提交。<br />
然后Continue，输入HOST，数据库名称，用户名和密码，Continue<br />
<br />
6. 进入下一个页面后，测试一下是否配置正确，Test Driver&nbsp;Configuration，此时对于第一次使用JTA的朋友来说，一般是测试通不过的，weblogic可能会给出一些原因，比如：sp_xxx存储过程找不到、DTC是否已经开启啊、xa_open (0) returns -3之类的错误，解决办法如下：<br />
sp_xxx存储过程找不到 - 在需要JTA事务的master数据库中运行%BEA_HOME%/<font face="Arial">weblogic81/server/lib/<font face="Arial">instjdbc.sql，并且复制<font face="Arial">sqljdbc.dll到%SQLSERVER_HOME%/<font face="Arial">MSSQL/Binn目录下。</font></font></font></font><br />
DTC是否已经开启 - 在服务中，启动 <font face="Arial">Distributed Transaction Coordinator。<br />
</font>xa_open (0) returns -3 - 数据库用户名必须是系统管理员，如果还是不行，则修改注册表HKLM\Software\Microsoft\MSDTC\Security的XaTransactions，如果该值为0，说明现在不支持分布式事务，我们把它改成1，然后重起Sqlserver和DTC。<br />
以上问题都解决了，如果看到测试通过，恭喜您，主要问题都解决了。<br />
<br />
5. 配置Datasource，写好jndi名字，选择刚才配好的连接池。可以尝试配置多个不同的服务器和数据库，然后再程序里测试JTA。<br />
<br />
6. 配置Spring<br />
</p>
<div class="code_title">xml 代码</div>
<div class="dp-highlighter">
<div class="bar"></div>
<ol class="dp-xml">
    <li class="alt"><span><span class="tag">&lt;?</span><span class="tag-name">xml</span><span>&nbsp;</span><span class="attribute">version</span><span>=</span><span class="attribute-value">&quot;1.0&quot;</span><span>&nbsp;</span><span class="attribute">encoding</span><span>=</span><span class="attribute-value">&quot;UTF-8&quot;</span><span class="tag">?&gt;</span><span>&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&lt;!DOCTYPE&nbsp;beans&nbsp;PUBLIC&nbsp;&quot;-//SPRING//DTD&nbsp;BEAN//EN&quot;&nbsp;&quot;http://www.springframework.org/dtd/spring-beans.dtd&quot;</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span></span><span class="tag">&lt;</span><span class="tag-name">beans</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">bean</span><span>&nbsp;</span><span class="attribute">id</span><span>=</span><span class="attribute-value">&quot;dataSource1&quot;</span><span>&nbsp;</span><span class="attribute">class</span><span>=</span><span class="attribute-value">&quot;org.springframework.jndi.JndiObjectFactoryBean&quot;</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">property</span><span>&nbsp;</span><span class="attribute">name</span><span>=</span><span class="attribute-value">&quot;jndiName&quot;</span><span>&nbsp;</span><span class="attribute">value</span><span>=</span><span class="attribute-value">&quot;jdbc/datasource1&quot;</span><span>&nbsp;</span><span class="tag">/&gt;</span><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;/</span><span class="tag-name">bean</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">bean</span><span>&nbsp;</span><span class="attribute">id</span><span>=</span><span class="attribute-value">&quot;dataSource2&quot;</span><span>&nbsp;</span><span class="attribute">class</span><span>=</span><span class="attribute-value">&quot;org.springframework.jndi.JndiObjectFactoryBean&quot;</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">property</span><span>&nbsp;</span><span class="attribute">name</span><span>=</span><span class="attribute-value">&quot;jndiName&quot;</span><span>&nbsp;</span><span class="attribute">value</span><span>=</span><span class="attribute-value">&quot;jdbc/datasource2&quot;</span><span>&nbsp;</span><span class="tag">/&gt;</span><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;/</span><span class="tag-name">bean</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">bean</span><span>&nbsp;</span><span class="attribute">id</span><span>=</span><span class="attribute-value">&quot;transactionManager&quot;</span><span>&nbsp;</span><span class="attribute">class</span><span>=</span><span class="attribute-value">&quot;org.springframework.transaction.jta.JtaTransactionManager&quot;</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;/</span><span class="tag-name">bean</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comments">&lt;!--&nbsp;Dao&nbsp;configuration&nbsp;--&gt;</span><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">bean</span><span>&nbsp;</span><span class="attribute">id</span><span>=</span><span class="attribute-value">&quot;memberDao&quot;</span><span>&nbsp;</span><span class="attribute">class</span><span>=</span><span class="attribute-value">&quot;com.dgc.jta.dao.impl.MemberDaoImpl&quot;</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">property</span><span>&nbsp;</span><span class="attribute">name</span><span>=</span><span class="attribute-value">&quot;dataSource&quot;</span><span>&nbsp;</span><span class="attribute">ref</span><span>=</span><span class="attribute-value">&quot;dataSource1&quot;</span><span>&nbsp;</span><span class="tag">/&gt;</span><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;/</span><span class="tag-name">bean</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">bean</span><span>&nbsp;</span><span class="attribute">id</span><span>=</span><span class="attribute-value">&quot;orderDao&quot;</span><span>&nbsp;</span><span class="attribute">class</span><span>=</span><span class="attribute-value">&quot;com.dgc.jta.dao.impl.OrderDaoImpl&quot;</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">property</span><span>&nbsp;</span><span class="attribute">name</span><span>=</span><span class="attribute-value">&quot;dataSource&quot;</span><span>&nbsp;</span><span class="attribute">ref</span><span>=</span><span class="attribute-value">&quot;dataSource2&quot;</span><span>&nbsp;</span><span class="tag">/&gt;</span><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;/</span><span class="tag-name">bean</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comments">&lt;!--&nbsp;Service&nbsp;configuration&nbsp;--&gt;</span><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">bean</span><span>&nbsp;</span><span class="attribute">id</span><span>=</span><span class="attribute-value">&quot;commonManagerTarget&quot;</span><span>&nbsp;</span><span class="attribute">class</span><span>=</span><span class="attribute-value">&quot;com.dgc.jta.service.impl.commonManagerImpl&quot;</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">property</span><span>&nbsp;</span><span class="attribute">name</span><span>=</span><span class="attribute-value">&quot;memberDao&quot;</span><span>&nbsp;</span><span class="attribute">ref</span><span>=</span><span class="attribute-value">&quot;memberDao&quot;</span><span>&nbsp;</span><span class="tag">/&gt;</span><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">property</span><span>&nbsp;</span><span class="attribute">name</span><span>=</span><span class="attribute-value">&quot;orderDao&quot;</span><span>&nbsp;</span><span class="attribute">ref</span><span>=</span><span class="attribute-value">&quot;orderDao&quot;</span><span>&nbsp;</span><span class="tag">/&gt;</span><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;/</span><span class="tag-name">bean</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">bean</span><span>&nbsp;</span><span class="attribute">id</span><span>=</span><span class="attribute-value">&quot;commonManager&quot;</span><span>&nbsp;</span><span class="attribute">class</span><span>=</span><span class="attribute-value">&quot;org.springframework.transaction.interceptor.TransactionProxyFactoryBean&quot;</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">property</span><span>&nbsp;</span><span class="attribute">name</span><span>=</span><span class="attribute-value">&quot;target&quot;</span><span>&nbsp;</span><span class="attribute">ref</span><span>=</span><span class="attribute-value">&quot;commonManagerTarget&quot;</span><span class="tag">/&gt;</span><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">property</span><span>&nbsp;</span><span class="attribute">name</span><span>=</span><span class="attribute-value">&quot;transactionManager&quot;</span><span>&nbsp;</span><span class="attribute">ref</span><span>=</span><span class="attribute-value">&quot;transactionManager&quot;</span><span class="tag">/&gt;</span><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">property</span><span>&nbsp;</span><span class="attribute">name</span><span>=</span><span class="attribute-value">&quot;transactionAttributes&quot;</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">props</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">prop</span><span>&nbsp;</span><span class="attribute">key</span><span>=</span><span class="attribute-value">&quot;*&quot;</span><span class="tag">&gt;</span><span>PROPAGATION_REQUIRED</span><span class="tag">&lt;/</span><span class="tag-name">prop</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;/</span><span class="tag-name">props</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;/</span><span class="tag-name">property</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;/</span><span class="tag-name">bean</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li class="alt"><span></span><span class="tag">&lt;/</span><span class="tag-name">beans</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></li>
</ol>
</div>
<p><br />
7. 部署war应用，测试得到，使用commonManagerTarget是不带分布式事务的，使用commonManager是带分布式事务的，成功！</p>
          <br/>
          <span style="color:red;">
            <a href="http://jimjiang.javaeye.com/blog/137560#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 02 Nov 2007 13:14:32 +0800</pubDate>
        <link>http://jimjiang.javaeye.com/blog/137560</link>
        <guid>http://jimjiang.javaeye.com/blog/137560</guid>
      </item>
      <item>
        <title>JTA经典问答</title>
        <author>jlj008</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://jimjiang.javaeye.com">jlj008</a>&nbsp;
          链接：<a href="http://jimjiang.javaeye.com/blog/133140" style="color:red;">http://jimjiang.javaeye.com/blog/133140</a>&nbsp;
          发表时间: 2007年10月18日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          FAQs: JTA<br />
<br />
<br />
<br />
<br />
Can I use a non-XA driver in distributed transactions? <br />
<br />
Can I use more than one non-XA connection pool in distributed transactions? <br />
<br />
How do XA and non-XA drivers differ in distributed transactions? <br />
<br />
What XA drivers can I use in addition to the WebLogic jDriver for Oracle/XA? <br />
<br />
Can I use the Oracle thin driver as an XA driver in distributed transactions? <br />
<br />
Why do I get SQLException &quot;Result set already closed&quot; message? <br />
<br />
Do I need a 2PC licence when I use JMS with one JDBC non-XA driver? <br />
<br />
Why am I getting an exception when I use JMS with a non-XA driver? <br />
<br />
Why do I get an exception when I use EJB CMP 1.1? <br />
<br />
Can I obtain a JDBC connection before I start a distributed transaction? <br />
<br />
Can I close a JDBC connection after the distributed transaction is committed or rolled back? <br />
<br />
<br />
Can I use a non-XA driver in distributed transactions? <br />
<br />
When the non-XA connection pool is the only resource participating in a transaction distributed across multiple servers, you just need to configure a TxDataSource for the non-XA driver. (This configuration is the same as the JTS driver usage in WLS 5.1.) <br />
<br />
However, when more than one resource participates in the distributed transaction, you must also set the TxDataSource property EnableTwoPhaseCommit=true. For more information, see Managing JDBC Connectivity in the Administration Guide. In both cases, always obtain a connection via the DataSource interface, not through the deprecated DriverManager interface. If you obtain a connection via DriverManager, the interface cannot pick up the EnableTwoPhaseCommit setting of the TxDataSource; this may result in unexpected behavior in distributed transactions. Also, when you use the DataSource interface, you do not need to distinguish either the URL or the specific WebLogic multitier driver (JTS, RMI, or pool.) The URL and specific driver are obtained through the config.xml file and JNDI lookup.<br />
<br />
<br />
Can I use more than one non-XA connection pool in distributed transactions? <br />
<br />
No. Even if you set EnableTwoPhaseCommit=true for both TxDataSources of the connection pools, attempting to use two non-XA connection pools in the same distributed transaction will result in <br />
<br />
&quot;java.sql.SQLException: Connection has already been created in this tx context for pool named <first name=""></first>. Illegal attempt to create connection from another pool: <second name=""></second>&quot; <br />
<br />
when you attempt to get the connection from the second non-XA connection pool.<br />
<br />
<br />
How do XA and non-XA drivers differ in distributed transactions? <br />
<br />
The differences between XA and non-XA JDBC drivers are: <br />
<br />
<br />
Atomicity Guarantee. An XA driver implements the XAResource interface and can participate fully in the 2PC protocol driven by the WLS Transaction Manager. This guarantees atomicity of updates across multiple participating resources. <br />
However, a non-XA driver does not implement the XAResource interface and cannot fully participate in the 2PC protocol. When using a non-XA driver in a distributed transaction, WLS implements the XAResource wrapper on behalf of the non-XA driver. If the data source property enableTwoPhaseCommit is set to true, then the WLS XAResource wrapper returms XA_OK when the Transaction Manager calls prepare on it. When the Transaction Manager calls commit or rollback on it during the second phase, the WLS XAResource wrapper delegates the commit/rollback call to the non-XA JDBC connection. Any failure during commit/rollback results in heuristic exceptions. Application data may be left in an inconsistent state as a result of heuristic failure.<br />
<br />
<br />
Redirecting Connections. As in WLS 5.1, a non-XA driver can be configured to perform updates in the same distributed transaction from more than one process, as explained in Can I use a non-XA driver in distributed transactions?. WLS internally redirects the JDBC calls made from different processes to the same physical JDBC connection in one process. However, when you use a XA driver, no such redirection will be done. Each process will use its own local XA database connection, and the database ensures that all the distributed updates made in the same distributed transaction from different processes will be committed atomically. <br />
<br />
Connection Management. Whether you are using the non-XA driver or XA driver in distributed transactions, WLS implements JDBC wrappers that intercept all the JDBC calls and obtains a physical JDBC connection from the connection pool on demand. <br />
<br />
When you use a non-XA driver in distributed transactions, in order to ensure that updates made from different processes are committed atomically, WLS associates the same physical JDBC connection with the distributed transaction until it is committed or rolled back. As a result, the number of active distributed transactions using the non-XA connection pool is limited by the maximum capacity of the JDBC connection pool. <br />
<br />
When you use an XA driver, the connection management is more scalable. WLS does not hold on to the same physical XA connection until the transaction is committed or rolled back. In fact, in most cases, the XA connection as only held for the duration of a method invocation. WLS JDBC wrappers intercept all JDBC calls and enlist the XAResource associated with the XA connection on demand. When the method invocation returns to the caller, or when it makes another call to another server, WLS delists the XAResource associated with the XA connection. <br />
<br />
WLS also returns the XA connection to the connection pool on delistment if there are no open result sets. Also, during commit processing, any XAResource object can be used to commit any number of distributed transactions in parallel. As a result, neither the number of active distributed transactions using the XA connection pool nor the number of concurrent commit/rollbacks is limited by the maximum capacity of the connection pool. Only the number of concurrent database access connections is limited by the maximum capacity of the connection pool. <br />
<br />
<br />
What XA drivers can I use in addition to the WebLogic jDriver for Oracle/XA? <br />
<br />
Theoretically, you can use any third party XA driver that is compliant with the JDBC 2.0 standard extension specification with WLS. However, an individual vendor's XA driver may have bugs that prevent it from working properly. <br />
<br />
Refer to JDBC Configuration guidelines for details about how to configure them at ../adminguide/managetx.html.<br />
<br />
<br />
Can I use the Oracle thin driver as an XA driver in distributed transactions? <br />
<br />
Oracle 8.1.6 thin driver has a bug that does not accept any foreign Xid, and so does not work at all with any other vendor's transaction manager, including WLS. <br />
<br />
Oracle 8.1.7 thin driver has threading problems and we do not recommend using it at this point. A workaround is not yet available in SP1. It will be available in the Silversword release. For this workaround, we use a dedicated XA connection for the duration of prepare, commit, and rollback operation. This is different from the default XA connection management model (see FAQ 3 for description) in that any XAResource object is used to commit any number of transactions in parallel. This limits the number of concurrent commits to the max capacity of the XA connection pool. Note that this workaround is an Oracle specific workaround and will not affect the usage of other XA drivers.<br />
<br />
Meanwhile, if you still want to try it out in SP1 without the workaround, you can configure the XA connection pool. For more information, see Managing JDBC Connectivity in the Administration Guide.<br />
<br />
Why do I get SQLException &quot;Result set already closed&quot; message?<br />
<br />
Problem: I am using Weblogic jDriver for Oracle/XA (transaction mode) from the client side. Updating in a distributed transaction works fine. However, when I try to perform a query, I get SQLException Result set already closed. How do I work around this?<br />
<br />
Weblogic jDriver for Oracle has a limitation that closes all open result sets when the method returns to the caller. For more information, see Limitations of the Weblogic jDriver for Oracle XA in Using WebLogic jDriver for Oracle/XA in Distributed Transations. <br />
<br />
Using the driver from the server side, for example, in a bean, does not have this limitation. Using the driver from the server side is also recommended from application architecture and performance perspective. Using the driver from the client side incurs round-trip cost for every JDBC call being made.<br />
<br />
This limitation exists because Weblogic jDriver for Oracle XA is implemented using Oracle's OCI API and C XA switch, and there is an Oracle problem when using OCI with XA in multi-threaded mode. Closing an OCI cursor in a thread that is different than the thread in which it is opened may result in server crash or unexpected behavior. As a result, the Weblogic driver implicitly closes all open result sets upon returning a call to the caller.<br />
<br />
<br />
Do I need a 2PC licence when I use JMS with one JDBC non-XA driver? <br />
<br />
Yes, you do. JMS is also a XAResource that participates in the distributed transaction. Therefore, there are two resources participating in the distributed transaction, and a 2PC license is needed. <br />
<br />
<br />
Why am I getting an exception when I use JMS with a non-XA driver? <br />
<br />
Problem: I am using JMS with one JDBC non-XA driver. Transaction fails to commit with the following exception: javax.transaction.xa.XAException: JDBC driver does not support XA, hence cannot be a participant in two-phase commit. <br />
<br />
As mentioned in the previous question Do I need a 2PC licence when I use JMS with one JDBC non-XA driver?, JMS is also a XAResource that participates in the distributed transaction. When more than one resource is participating in the distributed transaction, you need to set the data source property EnableTwoPhaseCommit=true as explained in &quot; Can I use a non-XA driver in distributed transactions?&quot; <br />
<br />
<br />
Why do I get an exception when I use EJB CMP 1.1? <br />
<br />
Problem: I am using distributed transactions with EJB CMP 1.1 and a non-XA connection pool. I configured the JDBC connection pool and the TxDataSource according to instructions in Can I use a non-XA driver in distributed transactions?. However, commit still gives javax.transaction.xa.XAException: JDBC driver does not support XA, hence cannot be a participant in two-phase commit. Why?<br />
<br />
The old style CMP 1.1 DTD does not allow you to specify the data source name. When only the connection pool name is specified, the EnableTwoPhaseCommit setting of the TxDataSource is ignored. You should use the new style CMP 1.1 DTD and specify the data source name instead of the pool name. <br />
<br />
To ensure that the descriptor is using the latest DTD file, verify that the DOCTYPE header for the WebLogic CMP 1.1 descriptor file is as follows:<br />
<br />
<br />
<!--CTYPE weblogic-rdbms-jar PUBLIC '-//BEA Systems, Inc.//DTD WebLogic 6.0.0 EJB 1.1 RDBMS Persistence//EN'http://www.bea.com/servers/wls600/dtd/weblogic-rdbms11-persistence-600.dt--><br />
<br />
To see the DTD file, go to http://www.bea.com/servers/wls600/dtd/weblogic-rdbms11-persistence-600.dtd.<br />
<br />
<br />
Can I obtain a JDBC connection before I start a distributed transaction? <br />
<br />
This depends on whether you are using a non-XA or XA driver. <br />
<br />
<br />
When you use a non-XA driver in a distributed transaction, always obtain a JDBC connection after the distributed transaction is begun. <br />
<br />
If you are using an XA driver, you can obtain the connection before the distributed transaction is begun. <br />
<br />
<br />
Can I close a JDBC connection after the distributed transaction is committed or rolled back? <br />
<br />
For both non-XA and XA driver, you can close the connection after the distributed transaction is completed. <br />
<br />
<a href="http://edocs.bea.com/wls/docs60/faq/transactions.html" target="_blank">http://edocs.bea.com/wls/docs60/faq/transactions.html</a><br />
          <br/>
          <span style="color:red;">
            <a href="http://jimjiang.javaeye.com/blog/133140#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 18 Oct 2007 11:12:38 +0800</pubDate>
        <link>http://jimjiang.javaeye.com/blog/133140</link>
        <guid>http://jimjiang.javaeye.com/blog/133140</guid>
      </item>
      <item>
        <title>Adapting Spring's JUnit 3.x base classes to JUnit 4(FromTSS)</title>
        <author>jlj008</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://jimjiang.javaeye.com">jlj008</a>&nbsp;
          链接：<a href="http://jimjiang.javaeye.com/blog/127247" style="color:red;">http://jimjiang.javaeye.com/blog/127247</a>&nbsp;
          发表时间: 2007年09月26日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>I&rsquo;ve recently switched from using JUnit 3.x to JUnit 4 for most new unit tests I write. One area that causes trouble is the use of JUnit 3.x based test base classes. <a href="http://www.springframework.org/">Spring</a> has a tree of helper classes based on <code>junit.framework.TestCase</code> that make writing tests that use an ApplicationContext, dependency injection or transactions easier. These base classes can autowire your test so that your member variables are initialized and ready to go, pointing to beans managed by Spring.</p>
<p>I wanted the functionality provided by these base classes but wanted to continue to write tests in the JUnit4 style. The two best features of JUnit 4 are the <code>@BeforeClass/@AfterClass</code> annotations and the ability to have multiple setUp and tearDown methods using <code>@Before</code> and <code>@After</code>. Switching back to JUnit 3 just to use the base class seemed unfortunate.</p>
<p>My first attempt was to extend my JUnit 4 test from Spring&rsquo;s class, <code>AbstractDependencyInjectionSpringContextTests</code>. When JUnit runs, it inspects your class through reflection and decides if it&rsquo;s a JUnit 3 or 4 class. It sees that since Spring&rsquo;s class derives from junit.framework.TestCase and so runs it as a JUnit 3 test using <code>org.junit.internal.runners.OldTestClassRunner</code>.</p>
<p>You can circumvent JUnit&rsquo;s decision about this test and force it to be run as a JUnit 4 test instead using the annotation <code>RunWith((TestClassRunner.class)</code>. This forces JUnit to use the new test runner (TestClassRunner) even though the class derives from <code>TestCase</code>. I created a class called <code>SpringManagedTests</code> that derives from <code>AbstractDependencyInjectionSpringContextTests</code> and is annotated with <code>RunWith</code>. (My tests will extend <code>SpringManagedTests</code>).</p>
<p>Next, JUnit 4 only cares about annotations and won&rsquo;t run the old setUp and tearDown methods defined by the Spring classes. To get around this, add methods with <code>Before</code> and <code>After</code> annotations to call setUp and tearDown.</p>
<!-- Generator: GNU source-highlight 2.3
by Lorenzo Bettini
<a href="http://www.lorenzobettini.it" target="_blank">http://www.lorenzobettini.it</a>
<a href="http://www.gnu.org/software/src-highlite" target="_blank">http://www.gnu.org/software/src-highlite</a> -->
<pre><tt>@Before <strong><font color="#0000ff">final</font></strong> <strong><font color="#0000ff">public</font></strong> <font color="#009900">void</font> <strong><font color="#000000">callSetup</font></strong><font color="#990000">()</font> <strong><font color="#0000ff">throws</font></strong> Exception <font color="#ff0000">{</font>
  <strong><font color="#0000ff">super</font></strong><font color="#990000">.</font><strong><font color="#000000">setUp</font></strong><font color="#990000">();</font>
<font color="#ff0000">}</font>

@After <strong><font color="#0000ff">public</font></strong> <font color="#009900">void</font> <strong><font color="#000000">callTearDown</font></strong><font color="#990000">()</font> <strong><font color="#0000ff">throws</font></strong> Exception <font color="#ff0000">{</font>
  <strong><font color="#0000ff">super</font></strong><font color="#990000">.</font><strong><font color="#000000">tearDown</font></strong><font color="#990000">();</font>
<font color="#ff0000">}</font>
</tt></pre>
<p>All features of the base class are now available, and JUnit 4 annotated test methods run as you would expect. The final test base class is below. To use it, derive your test from <code>SpringManagedTests</code> and read the <a href="http://static.springframework.org/spring/docs/2.0.x/api/org/springframework/test/AbstractDependencyInjectionSpringContextTests.html">docs on <code>AbstractDependencyInjectionSpringContextTests</code></a> for information on having Spring wire members of your class. In my case I use field injection &ndash; I have member variables declared as protected with the field name matching the bean name. When the test runs the field are populated. </p>
<p>This technique could be used for other JUnit 3 based test frameworks as well. It&rsquo;s not as clean as having a pure JUnit 4 implementation but works well until that happens.</p>
<!-- Generator: GNU source-highlight 2.3
by Lorenzo Bettini
<a href="http://www.lorenzobettini.it" target="_blank">http://www.lorenzobettini.it</a>
<a href="http://www.gnu.org/software/src-highlite" target="_blank">http://www.gnu.org/software/src-highlite</a> -->
<pre><tt><strong><font color="#000080">import</font></strong> org<font color="#990000">.</font>junit<font color="#990000">.</font>After<font color="#990000">;</font>
<strong><font color="#000080">import</font></strong> org<font color="#990000">.</font>junit<font color="#990000">.</font>Before<font color="#990000">;</font>
<strong><font color="#000080">import</font></strong> org<font color="#990000">.</font>junit<font color="#990000">.</font>internal<font color="#990000">.</font>runners<font color="#990000">.</font>TestClassRunner<font color="#990000">;</font>
<strong><font color="#000080">import</font></strong> org<font color="#990000">.</font>junit<font color="#990000">.</font>runner<font color="#990000">.</font>RunWith<font color="#990000">;</font>
<strong><font color="#000080">import</font></strong> org<font color="#990000">.</font>springframework<font color="#990000">.</font>test<font color="#990000">.</font>AbstractDependencyInjectionSpringContextTests<font color="#990000">;</font>

<em><font color="#9a1900">/**</font></em>
<em><font color="#9a1900"> * A base class for tests that load a spring application context</font></em>
<em><font color="#9a1900"> * and use dependency injection to populate fields in the test class.</font></em>
<em><font color="#9a1900"> * Unlike AbstractDependencyInjectionSpringContextTests, this</font></em>
<em><font color="#9a1900"> * class can be used as a base class for JUnit 4 tests.</font></em>
<em><font color="#9a1900"> * </font></em><font color="#009900">@author</font><em><font color="#9a1900"> dyoung</font></em>
<em><font color="#9a1900"> */</font></em>
<em><font color="#9a1900">// RunWith is required to force what would otherwise look like a JUnit 3.x test</font></em>
<em><font color="#9a1900">// to run with the JUnit 4 test runner.</font></em>
@<strong><font color="#000000">RunWith</font></strong><font color="#990000">(</font>TestClassRunner<font color="#990000">.</font><strong><font color="#0000ff">class</font></strong><font color="#990000">)</font>
<strong><font color="#0000ff">public</font></strong> <strong><font color="#0000ff">class</font></strong> SpringManagedTests <strong><font color="#0000ff">extends</font></strong> AbstractDependencyInjectionSpringContextTests <font color="#ff0000">{</font>

    <em><font color="#9a1900">// pass through to the junit 3 calls, which are not annotated</font></em>
    @Before <strong><font color="#0000ff">final</font></strong> <strong><font color="#0000ff">public</font></strong> <font color="#009900">void</font> <strong><font color="#000000">callSetup</font></strong><font color="#990000">()</font> <strong><font color="#0000ff">throws</font></strong> Exception <font color="#ff0000">{</font>
        <strong><font color="#0000ff">super</font></strong><font color="#990000">.</font><strong><font color="#000000">setUp</font></strong><font color="#990000">();</font>
    <font color="#ff0000">}</font>

    @After <strong><font color="#0000ff">public</font></strong> <font color="#009900">void</font> <strong><font color="#000000">callTearDown</font></strong><font color="#990000">()</font> <strong><font color="#0000ff">throws</font></strong> Exception <font color="#ff0000">{</font>
        <strong><font color="#0000ff">super</font></strong><font color="#990000">.</font><strong><font color="#000000">tearDown</font></strong><font color="#990000">();</font>
    <font color="#ff0000">}</font>
<font color="#ff0000">}<br /></font>
<br /><br /><br />From : <font face="Arial">http://dmy999.com/article/21/adapting-a-springs-junit-3x-base-classes-to-junit-4</font></tt></pre>
          <br/>
          <span style="color:red;">
            <a href="http://jimjiang.javaeye.com/blog/127247#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 26 Sep 2007 11:58:56 +0800</pubDate>
        <link>http://jimjiang.javaeye.com/blog/127247</link>
        <guid>http://jimjiang.javaeye.com/blog/127247</guid>
      </item>
      <item>
        <title>ManageTestDataSpringandDBunit(From TSS)</title>
        <author>jlj008</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://jimjiang.javaeye.com">jlj008</a>&nbsp;
          链接：<a href="http://jimjiang.javaeye.com/blog/127246" style="color:red;">http://jimjiang.javaeye.com/blog/127246</a>&nbsp;
          发表时间: 2007年09月26日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <h2>Introduction</h2>
<p>Most enterprise applications rely on the database as the persistence mechanism. Integration tests for these applications require data in the database to run correctly. For integration tests to be repeatable, the tests should carry the test data they need with them and insert it before running the tests and delete it after the tests, since the data in the database can change with time.</p>
<p>DBUnit is a tool which provides this functionality.</p>
<p>This article will look at configuring integration tests using Spring and DBUnit so that test data is inserted into the database before every test. This article also looks at a utility to export/import test data in the database using DBunit.</p>
<strong>Background knowledge</strong>
<p>It is assumed that the reader is familiar with the following concepts and tools:</p>
<ul>
    <li>Unit testing and integration testing </li>
    <li>Spring 2 and JUnit 3.8 </li>
    <li>XML </li>
    <li>General database concepts </li>
</ul>
<strong>Unit tests versus integration tests</strong>
<p>Unit tests should run in isolation without relying on any other external dependency. Business layer classes should also be unit tested in isolation without relying on the database. </p>
<p>Tests which rely on another dependency (e.g. database) are integration tests. Testing Data Access Objects (DAOs) is integration testing as it tests the integration between database and the DAOs. Business layer classes which use DAOs also indirectly depend on the database. </p>
<p>This article deals with integration testing of DAOs and integration testing of business layer classes which use DAOs to read/write data.</p>
<p>See further reading links at the end for an interesting discussion of the unit tests, integration testing and DBUnit.</p>
<strong>Several possible ways of managing test data for integration tests</strong>
<p>The test data could be managed manually in several ways:</p>
<table cellspacing="0" border="1" cellpadding="5">
    <tbody>
        <tr bgcolor="#d4d0c8">
            <td valign="top" width="284">
            <p><strong>Approach to managing test data </strong></p>
            </td>
            <td valign="top" width="274">
            <p><strong>Disadvantage </strong></p>
            </td>
        </tr>
        <tr>
            <td valign="top" width="284">
            <p>Manually insert test data using SQL scripts and delete is after the tests have run</p>
            </td>
            <td valign="top" width="274">
            <p>Manual process. The scripts have to be written to insert all the data required</p>
            </td>
        </tr>
        <tr>
            <td valign="top" width="284">
            <p>Use test data available in a copy of the production database</p>
            </td>
            <td valign="top" width="274">
            <p>The test data might change. </p>
            </td>
        </tr>
    </tbody>
</table>
<p>The ideal approach is to:</p>
<ul>
    <li>Export a subset of the data in the database to a flat file (XML preferred) </li>
    <li>Developers use this flat file as template and change the values some of the interesting values they want to change. This flat file now has the test data </li>
    <li>Before the integration tests run, the data in the flat file is inserted into the database </li>
    <li>After the integration tests run, the data is deleted from the database </li>
</ul>
<h2>DBunit</h2>
<strong>Exporting data in the database using DBUnit</strong>
<p>This is an offline task which is done before integration tests are written. The steps involved in exporting a subset of data in the database to XML are:</p>
<ul>
    <li>Connect to the database </li>
    <li>Specify the SQL to run to retrieve the data </li>
    <li>Specify the location of the flat file(XML) </li>
    <li>Export the data </li>
</ul>
<p>This is shown in the code below:</p>
<pre>import java.io.FileOutputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import org.dbunit.database.DatabaseConnection;
import org.dbunit.database.IDatabaseConnection;
import org.dbunit.database.QueryDataSet;
import org.dbunit.dataset.xml.FlatXmlWriter;

public class TestDBUnit
{
	public static void main(String[] args)
		throws Exception
	{
		//Connect to the database
		DriverManager.registerDriver(new net.sourceforge.jtds.jdbc.Driver());
		Connection conn = DriverManager.getConnection(&quot;URL_TO_CONNECT&quot;, &quot;username&quot;, &quot;password&quot;);

		IDatabaseConnection connection = new DatabaseConnection( conn );

		QueryDataSet partialDataSet = new QueryDataSet(connection);
		//Specify the SQL to run to retrieve the data
		partialDataSet.addTable(&quot;person&quot;, &quot; SELECT * FROM person WHERE name='Test name' &quot;);
		partialDataSet.addTable(&quot;address&quot;, &quot; SELECT * FROM address WHERE addressid=1 &quot;);

		//Specify the location of the flat file(XML)
		FlatXmlWriter datasetWriter = new FlatXmlWriter(new FileOutputStream(&quot;temp.xml&quot;));

		//Export the data
	    datasetWriter.write( partialDataSet );
	}
}
</pre>
<p>The data in the 2 tables is shown below:</p>
<p>Table &lsquo;Person&rsquo;</p>
<table cellspacing="0" border="1" cellpadding="5">
    <tbody>
        <tr bgcolor="#d4d0c8">
            <td valign="top" width="213">
            <p><strong>PersonId </strong></p>
            </td>
            <td valign="top" width="213">
            <p><strong>Name </strong></p>
            </td>
            <td valign="top" width="213">
            <p><strong>DOB </strong></p>
            </td>
        </tr>
        <tr>
            <td valign="top" width="213">
            <p>1</p>
            </td>
            <td valign="top" width="213">
            <p>Test name</p>
            </td>
            <td valign="top" width="213">
            <p>5/7/2007</p>
            </td>
        </tr>
        <tr>
            <td valign="top" width="213">
            <p>&hellip;</p>
            </td>
            <td valign="top" width="213">
            <p>&hellip;</p>
            </td>
            <td valign="top" width="213">
            <p>&hellip;</p>
            </td>
        </tr>
    </tbody>
</table>
<p>The SQL to create this table on Microsoft SQL Server is &lsquo; create table person (personid int not null primary key identity , name varchar (20 ), dob datetime )&rsquo; </p>
<p>Table &lsquo;Address&rsquo;</p>
<table cellspacing="0" border="1" cellpadding="5">
    <tbody>
        <tr bgcolor="#d4d0c8">
            <td valign="top" width="213">
            <p><strong>AddressId </strong></p>
            </td>
            <td valign="top" width="213">
            <p><strong>Address </strong></p>
            </td>
        </tr>
        <tr>
            <td valign="top" width="213">
            <p>1</p>
            </td>
            <td valign="top" width="213">
            <p>23 Some St</p>
            </td>
        </tr>
        <tr>
            <td valign="top" width="213">
            <p>&hellip;</p>
            </td>
            <td valign="top" width="213">
            <p>&hellip;</p>
            </td>
        </tr>
    </tbody>
</table>
<p>The SQL to create this table on Microsoft SQL Server is &lsquo; create table address (addressid int not null primary key identity , address varchar (20 ))&lsquo;. </p>
<p>The XML file produced by running the program above is shown below:</p>
<pre><!--l version='1.0' encoding='UTF-8-->
<dataset></dataset>
  <person name="Test name" dob="2007-04-20 00:00:00.0" personid="1"></person>
  <address address="23 Some street" addressid="1">

</address></pre>
<p>The developer can now edit the file or add new rows. This is now the test data and is ready to be inserted by DBUnit when the tests are run.</p>
<strong>Importing test data using DBUnit</strong>
<p>The export of data in the database to XML is an offline process which is done before (or during) writing integration tests. </p>
<p>The import of data from XML to database is done when the integration tests are run. </p>
<p>For a JUnit test, the test data is inserted in the &lsquo;setUp&rsquo; method and removed in the &lsquo;tearDown&rsquo; method as shown below:</p>
<pre>public class DBUnitTests extends TestCase
{
	public void setUp()
	{
		System.out.println(&quot;In setup&quot;);
		Connection conn = null;
		try
		{
			DriverManager.registerDriver(new net.sourceforge.jtds.jdbc.Driver());
			conn = DriverManager.getConnection(&quot;URL&quot;, &quot;username&quot;, &quot;password&quot;);
			IDatabaseConnection connection = new DatabaseConnection( conn );
			DatabaseOperation.INSERT.execute(connection, new FlatXmlDataSet(new FileInputStream(&quot;temp.xml&quot;)));
			conn.close();
		}
		catch(Exception exc)
		{
			exc.printStackTrace();
		}
	}

	public void tearDown()
	{
		System.out.println(&quot;In tearDown&quot;);
		Connection conn = null;
		try
		{
			DriverManager.registerDriver(new net.sourceforge.jtds.jdbc.Driver());
			conn = DriverManager.getConnection(&quot;URL&quot;, &quot;username&quot;, &quot;password&quot;);
			IDatabaseConnection connection = new DatabaseConnection( conn );
		    DatabaseOperation.DELETE.execute(connection, new FlatXmlDataSet(new FileInputStream(&quot;temp.xml&quot;)));
		    conn.close();
		}
		catch(Exception exc)
		{
			exc.printStackTrace();
		}
	}

	public void testDBUnitImport1()
	{
		System.out.println(&quot;In testDBUnitImport1&quot;);
		//Run the test
	}

	public void testDBUnitImport2()
	{
		System.out.println(&quot;In testDBUnitImport2&quot;);
		//Run the test
	}
}
</pre>
<p>Note: The IdentityInsertOperation.INSERT operation is required for MS-SQL Server instead of DatabaseOperation.INSERT. </p>
<h2>Enhance Junit tests using Spring and DBUnit</h2>
<p>The code shown in section above has data access logic mixed in the integration test. This is common to all tests and can be moved to a super class. We also would need some mechanism to make it easier for integration tests to access DAO and service layer classes.</p>
<p>Spring provides support for both of these.</p>
<strong>Use Spring and DBUnit to insert test data</strong>
<p>Spring provides &lsquo; AbstractTransactionalDataSourceSpringContextTests&rsquo; class which extends JUnit TestCase class. This class has &lsquo; onSetUpInTransaction&rsquo; and &lsquo; onTearDownInTransaction&rsquo; methods which run inside a transaction and can be used to insert test data. We can extend this class and override these 2 methods to insert and delete test data.</p>
<p>This is shown below:</p>
<pre>public class AbstractTransactionalHibernateTests extends AbstractTransactionalDataSourceSpringContextTests
{
	private static String TEST_DATA_FILE = &quot;dbunit-test-data.xml&quot;;

	protected void onSetUpInTransaction()
		throws Exception
	{
		logger.info(&quot;*** Inserting test data ***&quot;);
		//Use spring to get the datasource
		DataSource ds = this.jdbcTemplate.getDataSource();
		Connection conn = ds.getConnection();
		try
		{
			IDatabaseConnection connection = new DatabaseConnection( conn );
			DatabaseOperation.INSERT.execute(connection, new FlatXmlDataSet(new FileInputStream(TEST_DATA_FILE)));
		}
		finally
		{
			DataSourceUtils.releaseConnection(conn, ds);
			logger.info(&quot;*** Finished inserting test data ***&quot;);
		}
	}

	protected void onTearDownInTransaction()
		throws Exception
	{
		//Commit or rollback the transaction
		endTransaction();

		//Delete the data
		DataSource ds = this.jdbcTemplate.getDataSource();
		Connection conn = ds.getConnection();
		try
		{
			IDatabaseConnection connection = new DatabaseConnection( conn );
		    DatabaseOperation.DELETE.execute(connection, new FlatXmlDataSet(new FileInputStream(TEST_DATA_FILE)));
		}
		finally
		{
			DataSourceUtils.releaseConnection(conn, ds);
			logger.info(&quot;*** Finished removing test data ***&quot;);
		}
	}
}
</pre>
<p>Note:</p>
<ul>
    <li>The test data is in file &lsquo;dbunit-test-data.xml&rsquo; for the example above </li>
    <li>This class relies on spring to setup database connection </li>
    <li>The IdentityInsertOperation.INSERT is required for MS-SQL Server instead of DatabaseOperation.INSERT </li>
</ul>
<p>The Spring provided class &lsquo; AbstractTransactionalDataSourceSpringContextTests&rsquo; extends JUnit &lsquo;TestCase&rsquo; class. The developer writes integration tests by extending &lsquo; AbstractTransactionalDataSourceSpringContextTests&rsquo; class. All the features provided by JUnit are available to him.</p>
<strong>Use Spring to inject DAOs and business layer classes</strong>
<p>If the integration tests extend the Spring-provided &lsquo; AbstractTransactionalDataSourceSpringContextTests&rsquo; class, then any Spring-managed beans defined in the integration tests are injected into the integration tests. </p>
<p>Here is a class which extends &lsquo; AbstractTransactionalDataSourceSpringContextTests&rsquo;. We have overridden &lsquo;<strong> protected</strong> String[] getConfigLocations()&rsquo; to specify the location of Spring config files. For integration tests which extend &lsquo; AbstractTransactionalDataSourceSpringContextTests&rsquo; spring will inject Spring managed bean defined in the config files into the integration test. This class is shown below:</p>
<pre>public class AbstractTransactionalHibernateTests extends AbstractTransactionalDataSourceSpringContextTests
{
    protected String[] getConfigLocations()
    {
        return new String[] {&quot;classpath: springConfig.xml�};
    }
}
</pre>
<p>Sample Spring config file (springconfig.xml) is shown below:</p>
<pre><!--l version="1.0" encoding="UTF-8-->
<!--CTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
    "http://www.springframework.org/dtd/spring-beans.dt-->

<beans></beans>
	<bean parent="abstractHibernateDao" class="test.TestDaoImpl" id="testDao"></bean>

</pre>
<p>An integration test is shown below:</p>
<pre>public class TestDaoTests extends AbstractTransactionalHibernateTests
{
	private TestDao testDao = null;

	public void testGetUsingId()
	{
		//do something
	}

//Called by spring to inject the testDao
	public void setTestDao(TestDao testDao)
	{
		this.testDao = testDao;
	}
}
</pre>
<h2>Summing up implementation details</h2>
<p>A quick summary of what is discussed in the previous sections is shown below:</p>
<ul>
    <li>Use DBUnit to export data from the database. This is done offline before or during writing integration tests. The XML file holds the test data and is stored in version control system along with source code. Developers use this as a template and modify this file as required to setup their test data. </li>
    <li>Write your own class &lsquo; AbstractTransactionalHibernateTests&rsquo; which extends Spring &lsquo; AbstractTransactionalDataSourceSpringContextTests&rsquo;. Override &lsquo; onSetUpInTransaction&rsquo; and &lsquo; onTearDownInTransaction &rsquo; to insert and delete test data held in the XML file. These 2 methods run within the context of a transaction. Also override &lsquo;<strong> protected</strong> String[] getConfigLocations()&rsquo; to specify the location of Spring config file </li>
    <li>Integration tests extend &lsquo; AbstractTransactionalHibernateTests&rsquo; class which we developed. Any Spring managed beans(DAOs or business layer classes) defined in the spring config are auto injected into the integration tests if there is a setter present for the bean. </li>
</ul>
<h2>Advantages and disadvantages of using Spring and DBUnit</h2>
<strong>Advantages</strong>
<ul>
    <li>Simple, elegant and easy to implement. </li>
    <li>Test data is inserted during the test and removed after the test. So test data is always in a known state for every test and changes to test data when running a test won&rsquo;t affect any other test. </li>
    <li>Dependencies injected automatically by Spring if they are defined in the Spring configuration file. </li>
    <li>Can be used for integration testing of DAOs and business layer classes </li>
    <li>Integration tests written by developers do not have to deal with inserting and deleting data. Test data is available to them at start of the test </li>
    <li>DBUnit provides facility to export subset of data in the database to XML. This is used as a template and developers can modify this XML file to setup their test data. </li>
</ul>
<strong>Disadvantages</strong>
<ul>
    <li>Test data is inserted before each test. This is inefficient in some cases where the integration tests do not change the test data. It should be inserted once at the start of running the test suite and deleted once the test suite completes. This should be easier with Junit 4 and TestNG but is more difficult with Junit 3.8 </li>
</ul>
<h2>Other tools</h2>
<strong>Junit 4 and annotations</strong>
<p>JUnit 4 introduces a more sophisticated JUnit unit test lifecycle. Any method in a POJO class can be marked as a JUnit test case method. Any method can be marked as a special method to run it once for the whole test suite (class scoped setup() using @BeforeClass annotation &ndash; no equivalent method in Junit 3.8), or for the test case(using @Before) or for the test methods(using @Test). </p>
<p>However the annotations used in Junit4 interfere with spring dependency injection and Spring cannot be used with Junit4. </p>
<p>The Gienah project ( <a href="http://code.google.com/p/gienah-testing/" target="_blank">http://code.google.com/p/gienah-testing/</a> ) provides a workaround but has not been tried by the author.</p>
<p>Also see another article at <a href="http://dmy999.com/article/21/adapting-a-springs-junit-3x-base-classes-to-junit-4" target="_blank">http://dmy999.com/article/21/adapting-a-springs-junit-3x-base-classes-to-junit-4</a> which deals with using Junit 4 and Spring.</p>
<strong>TestNG</strong>
<p>TestNG provides sophisticated features such as parallel text execution, test classes as POJOs and annotations.</p>
<p>DBUnit should work just as well with TestNG. TestNG uses annotations in POJOs. Any method can be used as a test method ( by annotating it with @Test). TestNG gives the developer choice of inserting test data once for each test(using @BeforeMethod and @AfterMethod) or before each test case (using @BeforeClass and @AfterClass) or once per text execution (using @BeforeSuite and @AfterSuite).</p>
<p>See further reading section at the end for a ServerSide article on running Junit 3 tests in TestNG</p>
<p>Although the author has not tested it, Spring seems to work with TestNG annotations. Please see link in further reading section</p>
<h2>Other resources required for integration tests</h2>
<p>Integration tests could require other test data e.g. some service layer classes might be involved with processing of excel or csv files. On production system, binary files can be uploaded using a browser and processed by the service layer classes as byte arrays. </p>
<p>Binary files representing test data can be stored in version control system along with the test data. The disadvantage of this approach is this takes up space and they don&rsquo;t belong in version control systems. </p>
<p>They can be stored in a file server and retrieved using FTP. The Apache commons-net library provides a FTP client which can be incorporated into a java application to retrieve a file from an FTP server. Apache commons-net library provides facility to read data in files on a FTP server into a byte array.</p>
<h2>Conclusion</h2>
<p>Unit testing is testing code in isolation without relying on any dependencies. Integration testing typically depends on presence of test data in the database.</p>
<p>Test data can be managed using DBUnit. Spring can be used with DBUnit to ensure test data is inserted into the database before every test and deleted after the test.</p>
<p>DBUnit also provides a facility to export a subset of data in the database to an XML flat file. This file is used by DBUnit to insert data before running each test.</p>
<p>JUnit 4 and TestNG provide a more sophisticated lifecycle. Test data can be inserted once at the start and deleted at the end. This makes running tests more efficient and is suitable for cases where the integration tests do not change the test data.<br />
<br />
From : <font face="Arial">http://www.theserverside.com/tt/articles/article.tss?l=ManageTestDataSpringandDBunit</font></p>
          <br/>
          <span style="color:red;">
            <a href="http://jimjiang.javaeye.com/blog/127246#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 26 Sep 2007 11:57:05 +0800</pubDate>
        <link>http://jimjiang.javaeye.com/blog/127246</link>
        <guid>http://jimjiang.javaeye.com/blog/127246</guid>
      </item>
      <item>
        <title>ANT十五大最佳实践(转)</title>
        <author>jlj008</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://jimjiang.javaeye.com">jlj008</a>&nbsp;
          链接：<a href="http://jimjiang.javaeye.com/blog/123901" style="color:red;">http://jimjiang.javaeye.com/blog/123901</a>&nbsp;
          发表时间: 2007年09月14日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          转自:<font face="Arial">http://www.oreilly.com.cn/news/ant15toppractices.php?c=java<br />
<br />
<p>在Ant出现之前，构建和部署Java应用需要使用包括特定平台的脚本、Make文件、各种版本的IDE甚至手工操作的&ldquo;大杂烩&rdquo;。现在，几乎所有的开源Java项目都在使用Ant，大多数公司的内部项目也在使用Ant。Ant在这些项目中的广泛使用自然导致了读者对一整套Ant最佳实践的迫切需求。</p>
<p>本文总结了我喜爱的Ant技巧或最佳实践，多数是从我亲身经历的项目错误或我听说的其他人经历的 &ldquo;恐怖&rdquo;故事中得到灵感的。比如，有人告诉我有个项目把XDoclet 生成的代码放入带有锁定文件功能的版本控制工具中。当开发者修改源代码时，他必须记住手工检出（Check out）并锁定所有将要重新生成的文件。然后，手工运行代码生成器，只到这时他才能够让Ant编译代码，这一方法还存在如下一些问题：</p>
<ul>
    <li>生成的代码无法存储在版本控制系统中。 </li>
    <li>Ant（本案例中是Xdoclet）应该自动确定下一次构建涉及的源文件，而不应由程序员手工确定。 </li>
    <li>Ant的构建文件应该定义好正确的任务依赖关系，这样程序员就不必为了完成构建而不得不按照特定顺序调用任务。 </li>
</ul>
<p>当我开始一个新项目时，我首先编写Ant构建文件。Ant文件明确地定义构建的过程，并被团队中的每个程序员使用。本文所列的技巧基于这样的假定：Ant构建文件是一个必须仔细编写的重要文件，它应在版本控制系统中得到维护，并被定期进行重构。下面是我的十五大Ant最佳实践。</p>
<h3>1. 采用一致的编码规范</h3>
<p>Ant用户有的喜欢有的痛恨其构建文件的XML语法。与其跳进这一令人迷惑的争论中，不如让我们先看一些能保持XML构建文件简洁的方法。</p>
<p>首先也是最重要的，花费时间格式化你的XML让它看上去很清晰。不论XML是否美观，Ant都可以工作。但是丑陋的XML很难令人读懂。倘若你在任务之间留出空行，有规则的缩进，每行文字不超过90列左右，那么XML令人惊讶地易读。再加上使用能够高亮XML语法的优秀编辑器或IDE工具，你就不会有阅读的麻烦。</p>
<p>同样，精选含意明确、容易读懂的词汇来命名任务和属性。比如，<em>dir.reports</em>就比<em>rpts</em>好<em>。</em>特定的编码规范并不重要，只要拿出一套规范并坚持使用就行。</p>
<h3>2. 将<em>build.xml</em>放在项目根目录中</h3>
<p>Ant构建文件<em>build.xml</em>可以放在任何位置，但是放在项目顶级目录中可以保持项目简洁。这是最常用的规范，开发者能够在顶级目录中找到预期的<em>build.xml</em>。把构建文件放在根目录中，也能够使人容易了解项目目录树中不同目录之间的逻辑关系。以下是一个典型的项目目录层次：</p>
<p>[root dir]<br />
&nbsp; | build.xml&nbsp; <br />
&nbsp; +--src&nbsp;<br />
&nbsp; +--lib (包含第三方 JAR包)&nbsp;<br />
&nbsp; +--build (由 build任务生成)&nbsp; <br />
&nbsp; +--dist (由 build任务生成) </p>
<p>当<em>build.xml</em>在顶级目录时，假设你处于项目某个子目录中，只要输入：ant -find compile 命令，不需要改变工作目录就能够以命令行方式编译代码。参数-find告诉Ant寻找存在于上级目录中的<em>build.xml</em>并执行。</p>
<h3>3. 使用单一的构建文件</h3>
<p>有人喜欢将一个大项目分解成几个小的构建文件，每个构建文件分担整个构建过程的一小部分工作。这确实是看法不同的问题，但是应该认识到，将构建文件分割会增加对整体构建过程的理解难度。要注意在单一构建文件能够清楚表现构建层次的情况下不要过工程化(over-engineer)。</p>
<p>即使你把项目划分为多个构建文件，也应使程序员能够在项目根目录下找到核心<em>build.xml</em>。尽管该文件只是将实际构建工作委派给下级构建文件，也应保证该文件可用。</p>
<h3>4. 提供良好的帮助说明</h3>
<p>应尽量使构建文件自文档化。增加任务描述是最简单的方法。当你输入ant -projecthelp时，你就可以看到带有描述的任务清单。比如，你可以这样定义任务：</p>
&lt;target name=&quot;compile&quot; &nbsp;<br />
&nbsp;&nbsp; description=&quot;Compiles code, output goes to the build dir.&quot;&gt;
<p>最简单的规则是把所有你想让程序员通过命令行就可以调用的任务都加上描述。对于一般用来执行中间处理过程的内部任务，比如生成代码或建立输出目录等，就无法使用描述属性。</p>
<p>这时，可以通过在构建文件中加入XML注释来处理。或者专门定义一个help任务，当程序员输入ant help时来显示详细的使用说明。</p>
&lt;target name=&quot;help&quot; description=&quot;Display detailed usage information&quot;&gt;<br />
&nbsp; &lt;echo&gt;Detailed help...&lt;/echo&gt;&lt;/target&gt;
<h3>5. 提供清除任务</h3>
<p>每个构建文件都应包含一个清除任务，用来删除所有生成的文件和目录，使系统回到构建文件执行前的初始状态。执行清空任务后还存在的文件都应处在版本控制系统的管理之下。比如：</p>
&lt;target name=&quot;clean&quot; <br />
&nbsp;&nbsp;&nbsp;&nbsp;description=&quot;Destroys all generated files and dirs.&quot;&gt;<br />
&nbsp; &lt;delete dir=&quot;${dir.build}&quot;/&gt;<br />
&nbsp; &lt;delete dir=&quot;${dir.dist}&quot;/&gt;<br />
&lt;/target&gt;
<p>除非是在产生整个系统版本的特殊任务中，否则不要自动调用clean任务。当程序员仅仅执行编译任务或其他任务时，他们不需要构建文件事先执行既令人讨厌又没有必要的清空任务。要相信程序员能够确定何时需要清空所有文件。</p>
<h3>6. 使用ANT管理任务从属关系</h3>
<p>假设你的应用由Swing GUI组件、Web界面、EJB层和公共应用代码组成。在大型系统中，你需要清晰地定义每个Java包属于系统的哪一层。否则任何一点修改都要被迫重新编译成百上千个文件。糟糕的任务从属关系管理会导致过度复杂而脆弱的系统。改变GUI面板的设计不应造成Servlet和EJB的重编译。</p>
<p>当系统变得庞大后，稍不注意就可能将依赖于客户端的代码引入到服务端。这是因为典型的IDE项目文件编译任何文件都使用单一的classpath。而Ant能让你更有效地控制构建活动。</p>
<p>设计你的Ant构建文件编译大型项目的步骤：首先，编译公共应用代码，将编译结果打成JAR包文件。然后，编译上一层的项目代码，编译时依靠第一步产生的JAR文件。不断重复这一过程，直到最高层的代码编译完成。</p>
<p>分步构建强化了任务从属关系管理。如果你工作在底层Java框架上，偶然引用到高层的GUI模板组件，这时代码不需要编译。这是由于构建文件在编译底层框架时在源路径中没有包含高层GUI面板组件的代码。</p>
<h3>7. 定义并重用文件路径</h3>
<p>如果文件路径在一个地方一次性集中定义，并在整个构建文件中得到重用，那么构建文件更易于理解。以下是这样做的一个例子：</p>
&lt;project name=&quot;sample&quot; default=&quot;compile&quot; basedir=&quot;.&quot;&gt;<br />
&nbsp; &lt;path id=&quot;classpath.common&quot;&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;pathelement location=&quot;${jdom.jar.withpath}&quot;/&gt;<br />
&nbsp;&nbsp;&nbsp; ...etc&nbsp; &lt;/path&gt;<br />
&nbsp; &lt;path id=&quot;classpath.client&quot;&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;pathelement location=&quot;${guistuff.jar.withpath}&quot;/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;pathelement location=&quot;${another.jar.withpath}&quot;/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;!-- reuse the common classpath --&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;path refid=&quot;classpath.common&quot;/&gt;<br />
&nbsp; &lt;/path&gt;<br />
&nbsp; &lt;target name=&quot;compile.common&quot; depends=&quot;prepare&quot;&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;javac destdir=&quot;${dir.build}&quot; srcdir=&quot;${dir.src}&quot;&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;classpath refid=&quot;classpath.common&quot;/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;include name=&quot;com/oreilly/common/**&quot;/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/javac&gt;<br />
&nbsp; &lt;/target&gt;<br />
&lt;/project&gt;
<p>当项目不断增长构建日益复杂时，这一技术越发体现出其价值。你可能需要为编译不同层次的应用定义各自的文件路径，比如运行单元测试的、运行应用程序的、运行Xdoclet的、生成JavaDocs的等等不同路径。这种组件化路径定义的方法比为每个任务单独定义路径要优越得多。否则，很容易丢失任务从属关系的轨迹。</p>
<h3>8. 定义恰当的任务从属关系</h3>
<p>假设dist任务从属于jar任务，那么哪个任务从属于compile任务哪个任务从属于prepare任务呢？Ant构建文件最终定义了任务的从属关系图，它必须被仔细地定义和维护。</p>
<p>应该定期检查任务的从属关系以保证构建工作得到正确执行。大的构建文件随着时间推移趋向于增加更多的任务，所以到最后可能由于不必要的从属关系导致构建工作非常困难。比如，你可能发现在程序员只需编译一些没有使用EJB的GUI代码时又重新生成了EJB代码。</p>
<p>以&ldquo;优化&rdquo;的名义忽略任务的从属关系是另一种常见的错误。这种错误迫使程序员为了得到恰当的结果必须记住并按照特定的顺序调用一串任务。更好的做法是：提供描述清晰的公共任务，这些任务包含正确的任务从属关系；另外提供一套&ldquo;专家&rdquo;任务让你能够手工执行个别的构建步骤，这些任务不提供完整的构建过程，但是让那些专家用户在快速而恼人的编码期间能够跳过某些步骤。</p>
<h3>9.使用属性</h3>
<p>任何需要配置或可能发生变化的信息都应作为Ant属性定义下来。对于在构建文件中多次出现的值也同样处理。属性既可以在构建文件头部定义，也可以为了更好的灵活性而在单独的属性文件中定义。以下是在构建文件中定义属性的样式：</p>
&lt;project name=&quot;sample&quot; default=&quot;compile&quot; basedir=&quot;.&quot;&gt;<br />
&nbsp; &lt;property name=&quot;dir.build&quot; value=&quot;build&quot;/&gt;<br />
&nbsp; &lt;property name=&quot;dir.src&quot; value=&quot;src&quot;/&gt;<br />
&nbsp; &lt;property name=&quot;jdom.home&quot; value=&quot;../java-tools/jdom-b8&quot;/&gt;<br />
&nbsp; &lt;property name=&quot;jdom.jar&quot; value=&quot;jdom.jar&quot;/&gt;<br />
&nbsp; &lt;property name=&quot;jdom.jar.withpath&quot;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;value=&quot;${jdom.home}/build/${jdom.jar}&quot;/&gt;<br />
&nbsp;&nbsp;&nbsp; etc...<br />
&lt;/project&gt;
<p>或者你可以使用属性文件：</p>
&lt;project name=&quot;sample&quot; default=&quot;compile&quot; basedir=&quot;.&quot;&gt;<br />
&nbsp; &lt;property file=&quot;sample.properties&quot;/&gt;<br />
&nbsp;&nbsp; etc...<br />
&lt;/project&gt;
<p>在属性文件 <em>sample.properties</em>中:</p>
dir.build=build<br />
dir.src=src<br />
jdom.home=../java-tools/jdom-b8<br />
jdom.jar=jdom.jarjdom.jar.withpath=${jdom.home}/build/${jdom.jar}
<p>用一个独立的文件定义属性是有好处的，它可以清晰地定义构建中的可配置部分。另外，在开发者工作在不同操作系统的情况下，你可以在不同的平台上提供该文件的不同版本。</p>
<h3>10. 保持构建过程独立</h3>
<p>为了最大限度的扩展性，不要应用外部路径和库文件。最重要的是不要依赖于程序员的CLASSPATH设置。取而代之的是，在构建文件中使用相对路径并定义自己的路径。如果你引用了绝对路径如<em>C:\java\tools</em>，其他开发者未必使用与你相同的目录结构，所以就无法使用你的构建文件。</p>
<p>如果你部署开放源码项目，应该提供包含编译代码所需的所有JAR文件的发行版本。当然，这是在遵守许可协议的基础上。对于内部项目，相关的JAR文件都应在版本控制系统的管理中，并捡出（check out）到大家都知道的位置。</p>
<p>当你必须引用外部路径时，应将路径定义为属性。使程序员能够用适合他们自己的机器环境的参数重载这些属性。你也可以使用以下语法引用环境变量：</p>
&lt;property environment=&quot;env&quot;/&gt;<br />
&lt;property name=&quot;dir.jboss&quot; value=&quot;${env.JBOSS_HOME}&quot;/&gt;
<h3>11. 使用版本控制系统</h3>
<p>构建文件是一个重要的制品，应该像代码一样进行版本控制。当你标记你的代码时，也应用同样的标签标记构建文件。这样当你需要回溯到旧版本并进行构建时，能够使用相应版本的构建文件。</p>
<p>除构建文件之外，你还应在版本控制中维护第三方JAR文件。同样，这使你能够重新构建旧版本的软件。这也能够更容易保证所有开发者拥有一致的JAR文件，因为他们都是同构建文件一起从版本控制系统中捡出的。</p>
<p>通常应避免在版本控制系统中存放构建成果。倘若你的源代码很好地得到了版本控制，那么通过构建过程你能够重新生成任何版本的产品。</p>
<h3>12. 把Ant作为&ldquo;最小公分母&rdquo;</h3>
<p>假设你的开发团队使用IDE工具，当程序员通过点击图标就能够构建整个应用时为什么还要为Ant而烦恼呢？</p>
<p>IDE的问题是一个关于团队一致性和重现性的问题。几乎所有的IDE设计初衷都是为了提高程序员的个人生产率，而不是开发团队的持续构建。典型的IDE要求每个程序员定义自己的项目文件。程序员可能拥有不同的目录结构，可能使用不同版本的库文件，还可能工作在不同的平台上。这将导致出现这种情况：在Bob那里运行良好的代码，到Sally那里就无法运行。</p>
<p>不管你的开发团队使用何种IDE，一定要建立所有程序员都能够使用的Ant构建文件。要建立一个程序员在将新代码提交版本控制系统前必须执行Ant构建文件的规则。这将确保代码是经过同一个Ant构建文件构建的。当出现问题时，要使用项目标准的Ant构建文件，而不是通过某个IDE来执行一个干净的构建。</p>
<p>程序员可以自由选择任何他们习惯使用的IDE工具或编辑器。但是Ant应作为公共基线以保证代码永远是可构建的。</p>
<h3>13. 使用zipfileset属性</h3>
<p>人们经常使用Ant产生WAR、JAR、ZIP和 EAR文件。这些文件通常都要求有一个特定的内部目录结构，但其往往与你的源代码和编译环境的目录结构不匹配。</p>
<p>一个最常用的方法是写一个Ant任务，按照期望的目录结构把一大堆文件拷贝到临时目录中，然后生成压缩文件。这不是最有效的方法。使用zipfileset属性是更好的解决方案。它让你从任何位置选择文件，然后把它们按照不同目录结构放进压缩文件中。以下是一个例子：</p>
&lt;ear earfile=&quot;${dir.dist.server}/payroll.ear&quot;<br />
&nbsp;&nbsp;&nbsp; appxml=&quot;${dir.resources}/application.xml&quot;&gt;<br />
&nbsp; &lt;fileset dir=&quot;${dir.build}&quot; includes=&quot;commonServer.jar&quot;/&gt;<br />
&nbsp; &lt;fileset dir=&quot;${dir.build}&quot;&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;include name=&quot;payroll-ejb.jar&quot;/&gt;<br />
&nbsp; &lt;/fileset&gt;<br />
&nbsp; &lt;zipfileset dir=&quot;${dir.build}&quot; prefix=&quot;lib&quot;&gt;<br />
&nbsp; &nbsp;&nbsp;&lt;include name=&quot;hr.jar&quot;/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;include name=&quot;billing.jar&quot;/&gt;<br />
&nbsp; &lt;/zipfileset&gt;<br />
&nbsp; &lt;fileset dir=&quot;.&quot;&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;include name=&quot;lib/jdom.jar&quot;/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;include name=&quot;lib/log4j.jar&quot;/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;include name=&quot;lib/ojdbc14.jar&quot;/&gt;<br />
&nbsp; &lt;/fileset&gt;<br />
&nbsp; &lt;zipfileset dir=&quot;${dir.generated.src}&quot; prefix=&quot;META-INF&quot;&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;include name=&quot;jboss-app.xml&quot;/&gt;<br />
&nbsp; &lt;/zipfileset&gt;<br />
&lt;/ear&gt;
<p>在这个例子中，所有JAR文件都放在EAR文件包的<em>lib</em>目录中。hr.jar和billing.jar是从构建目录拷贝过来的。因此我们使用zipfileset属性把它们移动到EAR文件包内部的<em>lib</em>目录。prefix属性指定了其在EAR文件中的目标路径。</p>
<h3>14. 测试Clean任务</h3>
<p>假设你的构建文件中有clean和compile的任务，执行以下的测试。第一步，执行ant clean；第二步，执行ant compile；第三步，再执行ant compile。第三步应该不作任何事情。如果文件再次被编译，说明你的构建文件有问题。</p>
<p>构建文件应该只在与输出文件相关联的输入文件发生变化时执行任务。一个构建文件在不必执行诸如编译、拷贝或其他工作任务的时候执行这些任务是低效的。当项目规模增长时，即使是小的低效工作也会成为大的问题。</p>
<h3>15. 避免特定平台的Ant封装</h3>
<p>不管什么原因，有人喜欢用简单的、名称叫做<em>compile</em>之类的批文件或脚本装载他们的产品。当你去看脚本的内容你会发现以下内容：</p>
<p>ant compile</p>
<p>其实开发人员都很熟悉Ant，并且完全能够自己键入ant compile。请不要仅仅为了调用Ant而使用特定平台的脚本。这只会使其他人在首次使用你的脚本时增加学习和理解的烦扰。除此之外，你不可能提供适用于每个操作系统的脚本，这是真正烦扰其他用户的地方。</p>
<h3>总结</h3>
<p>太多的公司依靠手工方法和特别程序来编译代码和生成软件发布版本。那些不使用Ant或类似工具定义构建过程的开发团队，花费了太多的时间来捕捉代码编译过程中出现的问题：在某些开发者那里编译成功的代码，到另一些开发者那里却失败了。</p>
<p>生成并维护构建脚本不是一项富有魅力的工作，但却是一项必需的工作。一个好的Ant构建文件将使你能够集中到更喜欢的工作&mdash;&mdash;写代码中去！</p>
<h3>参考</h3>
<ul>
    <li><a href="http://ant.apache.org/">Ant</a> </li>
    <li><a href="http://www.ericburke.com/">AntGraph</a>: Ant依赖性的可视化工具 </li>
    <li><a href="http://www.oreilly.com/catalog/anttdg/index.html?CMP=IL7015">Ant: The Definitive Guide</a>, O'Reilly </li>
    <li><a href="http://www.oreilly.com/catalog/jextprockbk/index.html?CMP=IL7015">Java Extreme Programming Cookbook</a>, O'Reilly </li>
</ul>
</font>
          <br/>
          <span style="color:red;">
            <a href="http://jimjiang.javaeye.com/blog/123901#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 14 Sep 2007 17:55:30 +0800</pubDate>
        <link>http://jimjiang.javaeye.com/blog/123901</link>
        <guid>http://jimjiang.javaeye.com/blog/123901</guid>
      </item>
      <item>
        <title>Ant 学习笔记(转)</title>
        <author>jlj008</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://jimjiang.javaeye.com">jlj008</a>&nbsp;
          链接：<a href="http://jimjiang.javaeye.com/blog/123820" style="color:red;">http://jimjiang.javaeye.com/blog/123820</a>&nbsp;
          发表时间: 2007年09月14日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><span class="tag"><span class="tag"><span><span class="tag"><span><span class="tag"><span class="tag"><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span class="tag"><span class="tag"><span><span class="tag"><span><span class="tag"><span class="tag">详见附件</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></p>
          <br/>
          <span style="color:red;">
            <a href="http://jimjiang.javaeye.com/blog/123820#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 14 Sep 2007 15:03:35 +0800</pubDate>
        <link>http://jimjiang.javaeye.com/blog/123820</link>
        <guid>http://jimjiang.javaeye.com/blog/123820</guid>
      </item>
      <item>
        <title>Java反射经典实例 Java Reflection Cookbook (转) </title>
        <author>jlj008</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://jimjiang.javaeye.com">jlj008</a>&nbsp;
          链接：<a href="http://jimjiang.javaeye.com/blog/123704" style="color:red;">http://jimjiang.javaeye.com/blog/123704</a>&nbsp;
          发表时间: 2007年09月14日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          Java提供了一套机制来动态执行方法和构造方法，以及数组操作等，这套机制就叫&mdash;&mdash;反射。反射机制是如今很多流行框架的实现基础，其中包括Spring、Hibernate等。原理性的问题不是本文的重点，接下来让我们在实例中学习这套精彩的机制。<br />
<br />
1. 得到某个对象的属性<br />
<br />
<div>&lt;!--&lt;br&gt;&lt;br&gt;Code highlighting produced by Actipro CodeHighlighter (freeware)&lt;br&gt;http://www.CodeHighlighter.com/&lt;br&gt;&lt;br&gt;--&gt;<span>1</span>&nbsp;<span>public</span><span>&nbsp;Object&nbsp;getProperty(Object&nbsp;owner,&nbsp;String&nbsp;fieldName)&nbsp;</span><span>throws</span><span>&nbsp;Exception&nbsp;{<br />
</span><span>2</span>&nbsp;<span>&nbsp;&nbsp;&nbsp;&nbsp;Class&nbsp;ownerClass&nbsp;</span><span>=</span><span>&nbsp;owner.getClass();<br />
</span><span>3</span>&nbsp;<span><br />
</span><span>4</span>&nbsp;<span>&nbsp;&nbsp;&nbsp;&nbsp;Field&nbsp;field&nbsp;</span><span>=</span><span>&nbsp;ownerClass.getField(fieldName);<br />
</span><span>5</span>&nbsp;<span><br />
</span><span>6</span>&nbsp;<span>&nbsp;&nbsp;&nbsp;&nbsp;Object&nbsp;property&nbsp;</span><span>=</span><span>&nbsp;field.get(owner);<br />
</span><span>7</span>&nbsp;<span><br />
</span><span>8</span>&nbsp;<span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span>return</span><span>&nbsp;property;<br />
</span><span>9</span>&nbsp;<span>}</span></div>
<br />
Class ownerClass = owner.getClass()：得到该对象的Class。<br />
<br />
Field field = ownerClass.getField(fieldName)：通过Class得到类声明的属性。<br />
<br />
Object property = field.get(owner)：通过对象得到该属性的实例，如果这个属性是非公有的，这里会报IllegalAccessException。<br />
<br />
<br />
<br />
2. 得到某个类的静态属性<br />
<br />
<div>&lt;!--&lt;br&gt;&lt;br&gt;Code highlighting produced by Actipro CodeHighlighter (freeware)&lt;br&gt;http://www.CodeHighlighter.com/&lt;br&gt;&lt;br&gt;--&gt;<span>&nbsp;1</span>&nbsp;<span>public</span><span>&nbsp;Object&nbsp;getStaticProperty(String&nbsp;className,&nbsp;String&nbsp;fieldName)<br />
</span><span>&nbsp;2</span>&nbsp;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>throws</span><span>&nbsp;Exception&nbsp;{<br />
</span><span>&nbsp;3</span>&nbsp;<span>&nbsp;&nbsp;&nbsp;&nbsp;Class&nbsp;ownerClass&nbsp;</span><span>=</span><span>&nbsp;Class.forName(className);<br />
</span><span>&nbsp;4</span>&nbsp;<span><br />
</span><span>&nbsp;5</span>&nbsp;<span>&nbsp;&nbsp;&nbsp;&nbsp;Field&nbsp;field&nbsp;</span><span>=</span><span>&nbsp;ownerClass.getField(fieldName);<br />
</span><span>&nbsp;6</span>&nbsp;<span><br />
</span><span>&nbsp;7</span>&nbsp;<span>&nbsp;&nbsp;&nbsp;&nbsp;Object&nbsp;property&nbsp;</span><span>=</span><span>&nbsp;field.get(ownerClass);<br />
</span><span>&nbsp;8</span>&nbsp;<span><br />
</span><span>&nbsp;9</span>&nbsp;<span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span>return</span><span>&nbsp;property;<br />
</span><span>10</span>&nbsp;<span>}</span></div>
<br />
<br />
Class ownerClass = Class.forName(className) ：首先得到这个类的Class。<br />
<br />
Field field = ownerClass.getField(fieldName)：和上面一样，通过Class得到类声明的属性。<br />
<br />
Object property = field.get(ownerClass) ：这里和上面有些不同，因为该属性是静态的，所以直接从类的Class里取。<br />
<br />
<br />
3. 执行某对象的方法<br />
<br />
<div>&lt;!--&lt;br&gt;&lt;br&gt;Code highlighting produced by Actipro CodeHighlighter (freeware)&lt;br&gt;http://www.CodeHighlighter.com/&lt;br&gt;&lt;br&gt;--&gt;<span>&nbsp;1</span>&nbsp;<span>public</span><span>&nbsp;Object&nbsp;invokeMethod(Object&nbsp;owner,&nbsp;String&nbsp;methodName,&nbsp;Object[]&nbsp;args)&nbsp;</span><span>throws</span><span>&nbsp;Exception&nbsp;{<br />
</span><span>&nbsp;2</span>&nbsp;<span><br />
</span><span>&nbsp;3</span>&nbsp;<span>&nbsp;&nbsp;&nbsp;&nbsp;Class&nbsp;ownerClass&nbsp;</span><span>=</span><span>&nbsp;owner.getClass();<br />
</span><span>&nbsp;4</span>&nbsp;<span><br />
</span><span>&nbsp;5</span>&nbsp;<span>&nbsp;&nbsp;&nbsp;&nbsp;Class[]&nbsp;argsClass&nbsp;</span><span>=</span><span>&nbsp;</span><span>new</span><span>&nbsp;Class[args.length];<br />
</span><span>&nbsp;6</span>&nbsp;<span><br />
</span><span>&nbsp;7</span>&nbsp;<span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span>for</span><span>&nbsp;(</span><span>int</span><span>&nbsp;i&nbsp;</span><