﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-study-随笔分类-Spring</title><link>http://www.blogjava.net/xixidabao/category/15380.html</link><description>GROW WITH JAVA</description><language>zh-cn</language><lastBuildDate>Sat, 21 Apr 2007 02:48:12 GMT</lastBuildDate><pubDate>Sat, 21 Apr 2007 02:48:12 GMT</pubDate><ttl>60</ttl><item><title>用 Spring 更好地处理 Struts 动作三种整合 Struts 应用程序与 Spring 的方式</title><link>http://www.blogjava.net/xixidabao/archive/2007/04/21/112404.html</link><dc:creator>JAVA之路</dc:creator><author>JAVA之路</author><pubDate>Sat, 21 Apr 2007 02:43:00 GMT</pubDate><guid>http://www.blogjava.net/xixidabao/archive/2007/04/21/112404.html</guid><description><![CDATA[<p><a name=N1008F><span class=atitle><font size=4>为什么 Spring 这么了不起？</font></span></a></p>
<p>Spring 的创立者 Rod Johnson 以一种批判的眼光看待 Java&#8482; 企业软件开发，并且提议很多企业难题都能够通过战略地使用 IOC 模式（也称作依赖注入）来解决。当 Rod 和一个具有奉献精神的开放源码开发者团队将这个理论应用于实践时，结果就产生了 Spring 框架。简言之，Spring 是一个轻型的容器，利用它可以使用一个外部 XML 配置文件方便地将对象连接在一起。每个对象都可以通过显示一个 JavaBean 属性收到一个到依赖对象的引用，留给您的简单任务就只是在一个 XML 配置文件中把它们连接好。</p>
<p>
<table cellSpacing=0 cellPadding=0 width="40%" align=right border=0>
    <tbody>
        <tr>
            <td width=10><img height=1 alt="" src="http://www.ibm.com/i/c.gif" width=10></td>
            <td>
            <table cellSpacing=0 cellPadding=5 width="100%" border=1>
                <tbody>
                    <tr>
                        <td bgColor=#eeeeee><a name=N1009C><strong>IOC 和 Spring</strong></a><br>
                        <p>IOC 是一种使应用程序逻辑外在化的设计模式，所以它是被注入而不是被写入客户机代码中。将 IOC 与接口编程应用结合，就像 Spring 框架那样，产生了一种架构，这种架构能够减少客户机对特定实现逻辑的依赖。请参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-sr2.html#resources"><font color=#996699><u>参考资料</u></font></a> 了解更多关于 IOC 和 Spring 的信息。</p>
                        </td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>依赖注入是一个强大的特性，但是 Spring 框架能够提供更多特性。Spring 支持可插拔的事务管理器，可以给您的事务处理提供更广泛的选择范围。它集成了领先的持久性框架，并且提供一个一致的异常层次结构。Spring 还提供了一种使用面向方面代码代替正常的面向对象代码的简单机制。</p>
<p>Spring AOP 允许您使用<em>拦截器</em> 在一个或多个执行点上拦截应用程序逻辑。加强应用程序在拦截器中的日志记录逻辑会产生一个更可读的、实用的代码基础，所以拦截器广泛用于日志记录。您很快就会看到，为了处理横切关注点，Spring AOP 发布了它自己的拦截器，您也可以编写您自己的拦截器。</p>
<p><br>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr>
            <td><img height=1 alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%"><br><img height=6 alt="" src="http://www.ibm.com/i/c.gif" width=8 border=0></td>
        </tr>
    </tbody>
</table>
<table class=no-print cellSpacing=0 cellPadding=0 align=right>
    <tbody>
        <tr align=right>
            <td><img height=4 alt="" src="http://www.ibm.com/i/c.gif" width="100%"><br>
            <table cellSpacing=0 cellPadding=0 border=0>
                <tbody>
                    <tr>
                        <td vAlign=center><img height=16 alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width=16 border=0><br></td>
                        <td vAlign=top align=right><a class=fbox href="http://www-128.ibm.com/developerworks/cn/java/j-sr2.html#main"><strong><font color=#996699><u>回页首</u></font></strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br><br></p>
<p><a name=N100B3><span class=atitle><font size=4>整合 Struts 和 Spring</font></span></a></p>
<p>与 Struts 相似，Spring 可以作为一个 MVC 实现。这两种框架都具有自己的优点和缺点，尽管大部分人同意 Struts 在 MVC 方面仍然是最好的。很多开发团队已经学会在时间紧迫的时候利用 Struts 作为构造高品质软件的基础。Struts 具有如此大的推动力，以至于开发团队宁愿整合 Spring 框架的特性，而不愿意转换成 Spring MVC。没必要进行转换对您来说是一个好消息。Spring 架构允许您将 Struts 作为 Web 框架连接到基于 Spring 的业务和持久层。最后的结果就是现在一切条件都具备了。</p>
<p>在接下来的小窍门中，您将会了解到三种将 Struts MVC 整合到 Spring 框架的方法。我将揭示每种方法的缺陷并且对比它们的优点。 一旦您了解到所有三种方法的作用，我将会向您展示一个令人兴奋的应用程序，这个程序使用的是这三种方法中我最喜欢的一种。</p>
<p><br>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr>
            <td><img height=1 alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%"><br><img height=6 alt="" src="http://www.ibm.com/i/c.gif" width=8 border=0></td>
        </tr>
    </tbody>
</table>
<table class=no-print cellSpacing=0 cellPadding=0 align=right>
    <tbody>
        <tr align=right>
            <td><img height=4 alt="" src="http://www.ibm.com/i/c.gif" width="100%"><br>
            <table cellSpacing=0 cellPadding=0 border=0>
                <tbody>
                    <tr>
                        <td vAlign=center><img height=16 alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width=16 border=0><br></td>
                        <td vAlign=top align=right><a class=fbox href="http://www-128.ibm.com/developerworks/cn/java/j-sr2.html#main"><strong><font color=#996699><u>回页首</u></font></strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br><br></p>
<p><a name=N100BF><span class=atitle><font size=4>三个小窍门</font></span></a></p>
<p>接下来的每种整合技术（或者窍门）都有自己的优点和特点。我偏爱其中的一种，但是我知道这三种都能够加深您对 Struts 和 Spring 的理解。在处理各种不同情况的时候，这将给您提供一个广阔的选择范围。方法如下：</p>
<ul>
    <li>使用 Spring 的 <code>ActionSupport</code> 类整合 Structs
    <li>使用 Spring 的 <code>DelegatingRequestProcessor</code> 覆盖 Struts 的 <code>RequestProcessor </code>
    <li>将 Struts <code>Action</code> 管理委托给 Spring 框架 </li>
</ul>
<p><a name=N100E4><span class=smalltitle><strong><font size=3>装载应用程序环境</font></strong></span></a></p>
<p>无论您使用哪种技术，都需要使用 Spring 的 <code>ContextLoaderPlugin</code> 为 Struts 的 <code>ActionServlet</code> 装载 Spring 应用程序环境。就像添加任何其他插件一样，简单地向您的 struts-config.xml 文件添加该插件，如下所示：</p>
<p>
<table cellSpacing=0 cellPadding=5 width="100%" bgColor=#eeeeee border=1>
    <tbody>
        <tr>
            <td>
            <pre><code class=section>
            <font face="Lucida Console">&lt;plug-in className=
            "org.springframework.web.struts.ContextLoaderPlugIn"&gt;
            &lt;set-property property=
            "contextConfigLocation" value="/WEB-INF/beans.xml"/&gt;
            &lt;/plug-in&gt;
            </font></code></pre>
            </td>
        </tr>
    </tbody>
</table>
<br></p>
<p>前面已经提到过，在 <a href="http://www-128.ibm.com/developerworks/cn/java/j-sr2.html#download"><font color=#996699><u>下载</u></font></a> 部分，您能够找到这三个完全可使用的例子的完整源代码。每个例子都为一个书籍搜索应用程序提供一种不同的 Struts 和 Spring 的整合方法。您可以在这里看到例子的要点，但是您也可以下载应用程序以查看所有的细节。</p>
<p><br>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr>
            <td><img height=1 alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%"><br><img height=6 alt="" src="http://www.ibm.com/i/c.gif" width=8 border=0></td>
        </tr>
    </tbody>
</table>
<table class=no-print cellSpacing=0 cellPadding=0 align=right>
    <tbody>
        <tr align=right>
            <td><img height=4 alt="" src="http://www.ibm.com/i/c.gif" width="100%"><br>
            <table cellSpacing=0 cellPadding=0 border=0>
                <tbody>
                    <tr>
                        <td vAlign=center><img height=16 alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width=16 border=0><br></td>
                        <td vAlign=top align=right><a class=fbox href="http://www-128.ibm.com/developerworks/cn/java/j-sr2.html#main"><strong><font color=#996699><u>回页首</u></font></strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br><br></p>
<p><a name=N10101><span class=atitle><font size=4>窍门 1. 使用 Spring 的 ActionSupport</font></span></a></p>
<p>手动创建一个 Spring 环境是一种整合 Struts 和 Spring 的最直观的方式。为了使它变得更简单，Spring 提供了一些帮助。为了方便地获得 Spring 环境，<code>org.springframework.web.struts.ActionSupport</code> 类提供了一个 <code>getWebApplicationContext()</code> 方法。您所做的只是从 Spring 的 <code>ActionSupport</code> 而不是 Struts <code>Action</code> 类扩展您的动作，如清单 1 所示：</p>
<p><br><a name=N1011F><strong>清单 1. 使用 ActionSupport 整合 Struts</strong></a><br>
<table cellSpacing=0 cellPadding=5 width="100%" bgColor=#eeeeee border=1>
    <tbody>
        <tr>
            <td>
            <pre><code class=section>
            <font face="Lucida Console">package ca.nexcel.books.actions;
            import java.io.IOException;
            import javax.servlet.ServletException;
            import javax.servlet.http.HttpServletRequest;
            import javax.servlet.http.HttpServletResponse;
            import org.apache.struts.action.ActionError;
            import org.apache.struts.action.ActionErrors;
            import org.apache.struts.action.ActionForm;
            import org.apache.struts.action.ActionForward;
            import org.apache.struts.action.ActionMapping;
            import org.apache.struts.action.DynaActionForm;
            import org.springframework.context.ApplicationContext;
            import org.springframework.web.struts.ActionSupport;
            import ca.nexcel.books.beans.Book;
            import ca.nexcel.books.business.BookService;
            public class SearchSubmit extends ActionSupport {   <span class=boldcode><strong>|(1)</strong></span>
            public ActionForward execute(
            ActionMapping mapping,
            ActionForm form,
            HttpServletRequest request,
            HttpServletResponse response)
            throws IOException, ServletException {
            DynaActionForm searchForm = (DynaActionForm) form;
            String isbn = (String) searchForm.get("isbn");
            //the old fashion way
            //BookService bookService = new BookServiceImpl();
            ApplicationContext ctx =
            getWebApplicationContext();    <span class=boldcode><strong>|(2)</strong></span>
            BookService bookService =
            (BookService) ctx.getBean("bookService");   <span class=boldcode><strong>|(3)</strong></span>
            Book book = bookService.read(isbn.trim());
            if (null == book) {
            ActionErrors errors = new ActionErrors();
            errors.add(ActionErrors.GLOBAL_ERROR,new ActionError
            ("message.notfound"));
            saveErrors(request, errors);
            return mapping.findForward("failure") ;
            }
            request.setAttribute("book", book);
            return mapping.findForward("success");
            }
            }
            </font></code></pre>
            </td>
        </tr>
    </tbody>
</table>
<br></p>
<p>让我们快速思考一下这里到底发生了什么。在 (1) 处，我通过从 Spring 的 <code>ActionSupport</code> 类而不是 Struts 的 <code>Action</code> 类进行扩展，创建了一个新的 <code>Action</code>。在 (2) 处，我使用 <code>getWebApplicationContext()</code> 方法获得一个 <code>ApplicationContext</code>。为了获得业务服务，我使用在 (2) 处获得的环境在 (3) 处查找一个 Spring bean。</p>
<p>这种技术很简单并且易于理解。不幸的是，它将 Struts 动作与 Spring 框架耦合在一起。如果您想替换掉 Spring，那么您必须重写代码。并且，由于 Struts 动作不在 Spring 的控制之下，所以它不能获得 Spring AOP 的优势。当使用多重独立的 Spring 环境时，这种技术可能有用，但是在大多数情况下，这种方法不如另外两种方法合适。</p>
<p><br>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr>
            <td><img height=1 alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%"><br><img height=6 alt="" src="http://www.ibm.com/i/c.gif" width=8 border=0></td>
        </tr>
    </tbody>
</table>
<table class=no-print cellSpacing=0 cellPadding=0 align=right>
    <tbody>
        <tr align=right>
            <td><img height=4 alt="" src="http://www.ibm.com/i/c.gif" width="100%"><br>
            <table cellSpacing=0 cellPadding=0 border=0>
                <tbody>
                    <tr>
                        <td vAlign=center><img height=16 alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width=16 border=0><br></td>
                        <td vAlign=top align=right><a class=fbox href="http://www-128.ibm.com/developerworks/cn/java/j-sr2.html#main"><strong><font color=#996699><u>回页首</u></font></strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br><br></p>
<p><a name=N10149><span class=atitle><font size=4>窍门 2. 覆盖 RequestProcessor</font></span></a></p>
<p>将 Spring 从 Struts 动作中分离是一个更巧妙的设计选择。分离的一种方法是使用 <code>org.springframework.web.struts.DelegatingRequestProcessor</code> 类来覆盖 Struts 的 <code>RequestProcessor</code> 处理程序，如清单 2 所示：</p>
<p><br><a name=N1015F><strong>清单 2. 通过 Spring 的 DelegatingRequestProcessor 进行整合</strong></a><br>
<table cellSpacing=0 cellPadding=5 width="100%" bgColor=#eeeeee border=1>
    <tbody>
        <tr>
            <td>
            <pre><code class=section>
            <font face="Lucida Console">&lt;?xml version="1.0" encoding="ISO-8859-1" ?&gt;
            &lt;!DOCTYPE struts-config PUBLIC
            "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
            "http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd"&gt;
            &lt;struts-config&gt;
            &lt;form-beans&gt;
            &lt;form-bean name="searchForm"
            type="org.apache.struts.validator.DynaValidatorForm"&gt;
            &lt;form-property name="isbn"    type="java.lang.String"/&gt;
            &lt;/form-bean&gt;
            &lt;/form-beans&gt;
            &lt;global-forwards type="org.apache.struts.action.ActionForward"&gt;
            &lt;forward   name="welcome"                path="/welcome.do"/&gt;
            &lt;forward   name="searchEntry"            path="/searchEntry.do"/&gt;
            &lt;forward   name="searchSubmit"           path="/searchSubmit.do"/&gt;
            &lt;/global-forwards&gt;
            &lt;action-mappings&gt;
            &lt;action    path="/welcome" forward="/WEB-INF/pages/welcome.htm"/&gt;
            &lt;action    path="/searchEntry" forward="/WEB-INF/pages/search.jsp"/&gt;
            &lt;action    path="/searchSubmit"
            type="ca.nexcel.books.actions.SearchSubmit"
            input="/searchEntry.do"
            validate="true"
            name="searchForm"&gt;
            &lt;forward name="success" path="/WEB-INF/pages/detail.jsp"/&gt;
            &lt;forward name="failure" path="/WEB-INF/pages/search.jsp"/&gt;
            &lt;/action&gt;
            &lt;/action-mappings&gt;
            &lt;message-resources parameter="ApplicationResources"/&gt;
            &lt;controller processorClass="org.springframework.web.struts.
            DelegatingRequestProcessor"/&gt; <span class=boldcode><strong>|(1)</strong></span>
            &lt;plug-in className="org.apache.struts.validator.ValidatorPlugIn"&gt;
            &lt;set-property property="pathnames"
            value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"/&gt;
            &lt;/plug-in&gt;
            &lt;plug-in className="org.springframework.web.struts.ContextLoaderPlugIn"&gt;
            &lt;set-property property="csntextConfigLocation" value="/WEB-INF/beans.xml"/&gt;
            &lt;/plug-in&gt;
            &lt;/struts-config&gt;
            </font></code></pre>
            </td>
        </tr>
    </tbody>
</table>
<br></p>
<p>我利用了 <code>&lt;controller&gt;</code> 标记来用 <code>DelegatingRequestProcessor</code> 覆盖默认的 Struts <code>RequestProcessor</code>。下一步是在我的 Spring 配置文件中注册该动作，如清单 3 所示：</p>
<p><br><a name=N1017C><strong>清单 3. 在 Spring 配置文件中注册一个动作</strong></a><br>
<table cellSpacing=0 cellPadding=5 width="100%" bgColor=#eeeeee border=1>
    <tbody>
        <tr>
            <td>
            <pre><code class=section>
            <font face="Lucida Console">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
            &lt;!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
            "http://www.springframework.org/dtd/spring-beans.dtd"&gt;
            &lt;beans&gt;
            &lt;bean id="bookService" class="ca.nexcel.books.business.BookServiceImpl"/&gt;
            &lt;bean name="/searchSubmit"
            class="ca.nexcel.books.actions.SearchSubmit"&gt; <span class=boldcode><strong>|(1)</strong></span>
            &lt;property name="bookService"&gt;
            &lt;ref bean="bookService"/&gt;
            &lt;/property&gt;
            &lt;/bean&gt;
            &lt;/beans&gt;
            </font></code></pre>
            </td>
        </tr>
    </tbody>
</table>
<br></p>
<p>注意：在 (1) 处，我使用名称属性注册了一个 bean，以匹配 struts-config 动作映射名称。<code>SearchSubmit</code> 动作揭示了一个 JavaBean 属性，允许 Spring 在运行时填充属性，如清单 4 所示：</p>
<p><br><a name=N10191><strong>清单 4. 具有 JavaBean 属性的 Struts 动作</strong></a><br>
<table cellSpacing=0 cellPadding=5 width="100%" bgColor=#eeeeee border=1>
    <tbody>
        <tr>
            <td>
            <pre><code class=section>
            <font face="Lucida Console">package ca.nexcel.books.actions;
            import java.io.IOException;
            import javax.servlet.ServletException;
            import javax.servlet.http.HttpServletRequest;
            import javax.servlet.http.HttpServletResponse;
            import org.apache.struts.action.Action;
            import org.apache.struts.action.ActionError;
            import org.apache.struts.action.ActionErrors;
            import org.apache.struts.action.ActionForm;
            import org.apache.struts.action.ActionForward;
            import org.apache.struts.action.ActionMapping;
            import org.apache.struts.action.DynaActionForm;
            import ca.nexcel.books.beans.Book;
            import ca.nexcel.books.business.BookService;
            public class SearchSubmit extends Action {
            private BookService bookService;
            public BookService getBookService() {
            return bookService;
            }
            public void setBookService(BookService bookService) { <span class=boldcode><strong>| (1)</strong></span>
            this.bookService = bookService;
            }
            public ActionForward execute(
            ActionMapping mapping,
            ActionForm form,
            HttpServletRequest request,
            HttpServletResponse response)
            throws IOException, ServletException {
            DynaActionForm searchForm = (DynaActionForm) form;
            String isbn = (String) searchForm.get("isbn");
            Book book = getBookService().read(isbn.trim());  <span class=boldcode><strong>|(2)</strong></span>
            if (null == book) {
            ActionErrors errors = new ActionErrors();
            errors.add(ActionErrors.GLOBAL_ERROR,new ActionError("message.notfound"));
            saveErrors(request, errors);
            return mapping.findForward("failure") ;
            }
            request.setAttribute("book", book);
            return mapping.findForward("success");
            }
            }
            </font></code></pre>
            </td>
        </tr>
    </tbody>
</table>
<br></p>
<p>在清单 4 中，您可以了解到如何创建 Struts 动作。在 (1) 处，我创建了一个 JavaBean 属性。<code>DelegatingRequestProcessor</code>自动地配置这种属性。这种设计使 Struts 动作并不知道它正被 Spring 管理，并且使您能够利用 Sping 的动作管理框架的所有优点。由于您的 Struts 动作注意不到 Spring 的存在，所以您不需要重写您的 Struts 代码就可以使用其他控制反转容器来替换掉 Spring。</p>
<p><code>DelegatingRequestProcessor</code> 方法的确比第一种方法好，但是仍然存在一些问题。如果您使用一个不同的 <code>RequestProcessor</code>，则需要手动整合 Spring 的 <code>DelegatingRequestProcessor</code>。添加的代码会造成维护的麻烦并且将来会降低您的应用程序的灵活性。此外，还有过一些使用一系列命令来代替 Struts <code>RequestProcessor</code> 的传闻。 这种改变将会对这种解决方法的使用寿命造成负面的影响。</p>
<p><br>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr>
            <td><img height=1 alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%"><br><img height=6 alt="" src="http://www.ibm.com/i/c.gif" width=8 border=0></td>
        </tr>
    </tbody>
</table>
<table class=no-print cellSpacing=0 cellPadding=0 align=right>
    <tbody>
        <tr align=right>
            <td><img height=4 alt="" src="http://www.ibm.com/i/c.gif" width="100%"><br>
            <table cellSpacing=0 cellPadding=0 border=0>
                <tbody>
                    <tr>
                        <td vAlign=center><img height=16 alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width=16 border=0><br></td>
                        <td vAlign=top align=right><a class=fbox href="http://www-128.ibm.com/developerworks/cn/java/j-sr2.html#main"><strong><font color=#996699><u>回页首</u></font></strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br><br></p>
<p><a name=N101B7><span class=atitle><font size=4>窍门 3. 将动作管理委托给 Spring</font></span></a></p>
<p>一个更好的解决方法是将 Strut 动作管理委托给 Spring。您可以通过在 <code>struts-config</code> 动作映射中注册一个代理来实现。代理负责在 Spring 环境中查找 Struts 动作。由于动作在 Spring 的控制之下，所以它可以填充动作的 JavaBean 属性，并为应用诸如 Spring 的 AOP 拦截器之类的特性带来了可能。 </p>
<p>清单 5 中的 <code>Action</code> 类与清单 4 中的相同。但是 struts-config 有一些不同：</p>
<p><br><a name=N101D0><strong>清单 5. Spring 整合的委托方法</strong></a><br>
<table cellSpacing=0 cellPadding=5 width="100%" bgColor=#eeeeee border=1>
    <tbody>
        <tr>
            <td>
            <pre><code class=section>
            <font face="Lucida Console">&lt;?xml version="1.0" encoding="ISO-8859-1" ?&gt;
            &lt;!DOCTYPE struts-config PUBLIC
            "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
            "http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd"&gt;
            &lt;struts-config&gt;
            &lt;form-beans&gt;
            &lt;form-bean name="searchForm"
            type="org.apache.struts.validator.DynaValidatorForm"&gt;
            &lt;form-property name="isbn"    type="java.lang.String"/&gt;
            &lt;/form-bean&gt;
            &lt;/form-beans&gt;
            &lt;global-forwards type="org.apache.struts.action.ActionForward"&gt;
            &lt;forward   name="welcome"                path="/welcome.do"/&gt;
            &lt;forward   name="searchEntry"            path="/searchEntry.do"/&gt;
            &lt;forward   name="searchSubmit"           path="/searchSubmit.do"/&gt;
            &lt;/global-forwards&gt;
            &lt;action-mappings&gt;
            &lt;action    path="/welcome" forward="/WEB-INF/pages/welcome.htm"/&gt;
            &lt;action    path="/searchEntry" forward="/WEB-INF/pages/search.jsp"/&gt;
            &lt;action    path="/searchSubmit"
            type="org.springframework.web.struts.DelegatingActionProxy" <span class=boldcode><strong>|(1)</strong></span>
            input="/searchEntry.do"
            validate="true"
            name="searchForm"&gt;
            &lt;forward name="success" path="/WEB-INF/pages/detail.jsp"/&gt;
            &lt;forward name="failure" path="/WEB-INF/pages/search.jsp"/&gt;
            &lt;/action&gt;
            &lt;/action-mappings&gt;
            &lt;message-resources parameter="ApplicationResources"/&gt;
            &lt;plug-in className="org.apache.struts.validator.ValidatorPlugIn"&gt;
            &lt;set-property
            property="pathnames"
            value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"/&gt;
            &lt;/plug-in&gt;
            &lt;plug-in
            className="org.springframework.web.struts.ContextLoaderPlugIn"&gt;
            &lt;set-property property="contextConfigLocation" value="/WEB-INF/beans.xml"/&gt;
            &lt;/plug-in&gt;
            &lt;/struts-config&gt;
            </font></code></pre>
            </td>
        </tr>
    </tbody>
</table>
<br></p>
<p>清单 5 是一个典型的 struts-config.xml 文件，只有一个小小的差别。它注册 Spring 代理类的名称，而不是声明动作的类名，如（1）处所示。DelegatingActionProxy 类使用动作映射名称查找 Spring 环境中的动作。这就是我们使用 <code>ContextLoaderPlugIn</code> 声明的环境。</p>
<p>将一个 Struts 动作注册为一个 Spring bean 是非常直观的，如清单 6 所示。我利用动作映射使用 <code>&lt;bean&gt;</code> 标记的名称属性（在这个例子中是 "<code>/searchSubmit</code>"）简单地创建了一个 bean。这个动作的 JavaBean 属性像任何 Spring bean 一样被填充： </p>
<p><br><a name=N101F0><strong>清单 6. 在 Spring 环境中注册一个 Struts 动作</strong></a><br>
<table cellSpacing=0 cellPadding=5 width="100%" bgColor=#eeeeee border=1>
    <tbody>
        <tr>
            <td>
            <pre><code class=section>
            <font face="Lucida Console">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
            &lt;!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
            "http://www.springframework.org/dtd/spring-beans.dtd"&gt;
            &lt;beans&gt;
            &lt;bean id="bookService" class="ca.nexcel.books.business.BookServiceImpl"/&gt;
            &lt;bean name="/searchSubmit"
            class="ca.nexcel.books.actions.SearchSubmit"&gt;
            &lt;property name="bookService"&gt;
            &lt;ref bean="bookService"/&gt;
            &lt;/property&gt;
            &lt;/bean&gt;
            &lt;/beans&gt;
            </font></code></pre>
            </td>
        </tr>
    </tbody>
</table>
<br><br>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr>
            <td><font face="Lucida Console"><img height=1 alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%"><br><img height=6 alt="" src="http://www.ibm.com/i/c.gif" width=8 border=0></font></td>
        </tr>
    </tbody>
</table>
<table class=no-print cellSpacing=0 cellPadding=0 align=right>
    <tbody>
        <tr align=right>
            <td><font face="Lucida Console"><img height=4 alt="" src="http://www.ibm.com/i/c.gif" width="100%"><br></font>
            <table cellSpacing=0 cellPadding=0 border=0>
                <tbody>
                    <tr>
                        <td vAlign=center><font face="Lucida Console"><img height=16 alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width=16 border=0><br></font></td>
                        <td vAlign=top align=right><a class=fbox href="http://www-128.ibm.com/developerworks/cn/java/j-sr2.html#main"><strong><font color=#996699><u>回页首</u></font></strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br><br></p>
<p><a name=N101F7><span class=atitle><font size=4>动作委托的优点</font></span></a></p>
<p>动作委托解决方法是这三种方法中最好的。Struts 动作不了解 Spring，不对代码作任何改变就可用于非 Spring 应用程序中。<code>RequestProcessor</code> 的改变不会影响它，并且它可以利用 Spring AOP 特性的优点。 </p>
<p>动作委托的优点不止如此。一旦让 Spring 控制您的 Struts 动作，您就可以使用 Spring 给动作补充更强的活力。例如，没有 Spring 的话，所有的 Struts 动作都必须是线程安全的。如果您设置 <code>&lt;bean&gt;</code> 标记的 singleton 属性为&#8220;false&#8221;，那么不管用何种方法，您的应用程序都将在每一个请求上有一个新生成的动作对象。您可能不需要这种特性，但是把它放在您的工具箱中也很好。您也可以利用 Spring 的生命周期方法。例如，当实例化 Struts 动作时，<code>&lt;bean&gt;</code> 标记的 init-method 属性被用于运行一个方法。类似地，在从容器中删除 bean 之前，destroy-method 属性执行一个方法。这些方法是管理昂贵对象的好办法，它们以一种与 Servlet 生命周期相同的方式进行管理。</p>
<p><br>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr>
            <td><img height=1 alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%"><br><img height=6 alt="" src="http://www.ibm.com/i/c.gif" width=8 border=0></td>
        </tr>
    </tbody>
</table>
<table class=no-print cellSpacing=0 cellPadding=0 align=right>
    <tbody>
        <tr align=right>
            <td><img height=4 alt="" src="http://www.ibm.com/i/c.gif" width="100%"><br>
            <table cellSpacing=0 cellPadding=0 border=0>
                <tbody>
                    <tr>
                        <td vAlign=center><img height=16 alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width=16 border=0><br></td>
                        <td vAlign=top align=right><a class=fbox href="http://www-128.ibm.com/developerworks/cn/java/j-sr2.html#main"><strong><font color=#996699><u>回页首</u></font></strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br><br></p>
<p><a name=N10210><span class=atitle><font size=4>拦截 Struts</font></span></a></p>
<p>前面提到过，通过将 Struts 动作委托给 Spring 框架而整合 Struts 和 Spring 的一个主要的优点是：您可以将 Spring 的 AOP 拦截器应用于您的 Struts 动作。通过将 Spring 拦截器应用于 Struts 动作，您可以用最小的代价处理横切关注点。</p>
<p>虽然 Spring 提供很多内置拦截器，但是我将向您展示如何创建自己的拦截器并把它应用于一个 Struts 动作。为了使用拦截器，您需要做三件事：</p>
<ol>
    <li>创建拦截器。
    <li>注册拦截器。
    <li>声明在何处拦截代码。 </li>
</ol>
<p>这看起来非常简单的几句话却非常强大。例如，在清单 7 中，我为 Struts 动作创建了一个日志记录拦截器。 这个拦截器在每个方法调用之前打印一句话：</p>
<p><br><a name=N10230><strong>清单 7. 一个简单的日志记录拦截器</strong></a><br>
<table cellSpacing=0 cellPadding=5 width="100%" bgColor=#eeeeee border=1>
    <tbody>
        <tr>
            <td>
            <pre><code class=section>
            <font face="Lucida Console">package ca.nexcel.books.interceptors;
            import org.springframework.aop.MethodBeforeAdvice;
            import java.lang.reflect.Method;
            public class LoggingInterceptor implements MethodBeforeAdvice {
            public void before(Method method, Object[] objects, Object o) throws Throwable {
            System.out.println("logging before!");
            }
            }
            </font></code></pre>
            </td>
        </tr>
    </tbody>
</table>
<br></p>
<p>这个拦截器非常简单。<code>before()</code> 方法在拦截点中每个方法之前运行。在本例中，它打印出一句话，其实它可以做您想做的任何事。下一步就是在 Spring 配置文件中注册这个拦截器，如清单 8 所示：</p>
<p><br><a name=N10242><strong>清单 8. 在 Spring 配置文件中注册拦截器</strong></a><br>
<table cellSpacing=0 cellPadding=5 width="100%" bgColor=#eeeeee border=1>
    <tbody>
        <tr>
            <td>
            <pre><code class=section>
            <font face="Lucida Console">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
            &lt;!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
            "http://www.springframework.org/dtd/spring-beans.dtd"&gt;
            &lt;beans&gt;
            &lt;bean id="bookService" class="ca.nexcel.books.business.BookServiceImpl"/&gt;
            &lt;bean name="/searchSubmit"
            class="ca.nexcel.books.actions.SearchSubmit"&gt;
            &lt;property name="bookService"&gt;
            &lt;ref bean="bookService"/&gt;
            &lt;/property&gt;
            &lt;/bean&gt;
            &lt;!--  Interceptors --&gt;
            &lt;bean name="logger"
            class="ca.nexcel.books.interceptors.LoggingInterceptor"/&gt; <span class=boldcode><strong>|(1)</strong></span>
            &lt;!-- AutoProxies --&gt;
            &lt;bean name="loggingAutoProxy"
            class="org.springframework.aop.framework.autoproxy.
            BeanNameAutoProxyCreator"&gt; <span class=boldcode><strong>|(2)</strong></span>
            &lt;property name="beanNames"&gt;
            &lt;value&gt;/searchSubmit&lt;/valuesgt; <span class=boldcode><strong>|(3)</strong></span>
            &lt;/property&gt;
            &lt;property name="interceptorNames"&gt;
            &lt;list&gt;
            &lt;value&gt;logger&lt;/value&gt; <span class=boldcode><strong>|(4)</strong></span>
            &lt;/list&gt;
            &lt;/property&gt;
            &lt;/bean&gt;
            &lt;/beans&gt;
            </font></code></pre>
            </td>
        </tr>
    </tbody>
</table>
<br></p>
<p>您可能已经注意到了，清单 8 扩展了 <a href="http://www-128.ibm.com/developerworks/cn/java/j-sr2.html#code6"><font color=#996699><u>清单 6</u></font></a> 中所示的应用程序以包含一个拦截器。具体细节如下：</p>
<ul>
    <li>在 (1) 处，我注册了这个拦截器。
    <li>在 (2) 处，我创建了一个 bean 名称自动代理，它描述如何应用拦截器。还有其他的方法定义拦截点，但是这种方法常见而简便。
    <li>在 (3) 处，我将 Struts 动作注册为将被拦截的 bean。如果您想要拦截其他的 Struts 动作，则只需要在 "beanNames" 下面创建附加的 <code>&lt;value&gt;</code> 标记。
    <li>在 (4) 处，当拦截发生时，我执行了在 (1) 处创建的拦截器 bean 的名称。这里列出的所有拦截器都应用于&#8220;beanNames&#8221;。 </li>
</ul>
<p>就是这样。就像这个例子所展示的，将您的 Struts 动作置于 Spring 框架的控制之下，为处理您的 Struts 应用程序提供了一系列全新的选择。在本例中，使用动作委托可以轻松地利用 Spring 拦截器提高 Struts 应用程序中的日志记录能力。</p>
<img src ="http://www.blogjava.net/xixidabao/aggbug/112404.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xixidabao/" target="_blank">JAVA之路</a> 2007-04-21 10:43 <a href="http://www.blogjava.net/xixidabao/archive/2007/04/21/112404.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hibernate 的原理与配置快速入门</title><link>http://www.blogjava.net/xixidabao/archive/2006/05/17/46596.html</link><dc:creator>JAVA之路</dc:creator><author>JAVA之路</author><pubDate>Wed, 17 May 2006 03:46:00 GMT</pubDate><guid>http://www.blogjava.net/xixidabao/archive/2006/05/17/46596.html</guid><description><![CDATA[　　也许你听说过Hibernate的大名，但可能一直不了解它，也许你一直渴望使用它进行开发，那么本文正是你所需要的！在本文中，我向大家重点介绍Hibernate的核心API调用库，并讲解一下它的基本配置。<br /><br />　　看完本文后，我相信你对什么是ORM（对像/关系映射）以及它的优点会有一个深刻的认识，我们先通过一个简单的例子开始来展现它的威力。<br /><br />　　正如一些传统的经典计算机文章大都会通过一个“hello,world”的例子开始讲解一样，我们也不例外，我们也将从一个相对简单的例子来阐述Hibernate的开发方法，但如果要真正阐述Hibernate的一些重要思想，仅仅靠在屏幕上打印一些字符是远远不够的，在我们的示例程序中，我们将创建一些对象，并将其保存在数据库中，然后对它们进行更新和查询。<br /><br /><table bordercolor="#ffcc00" cellspacing="4" width="90%" align="center" border="1"><tbody><tr><td colspan="2"><div align="center"><font color="#ff0000"><strong>阅读导航</strong></font></div></td></tr><tr><td width="35%"><a href="http://dev.yesky.com/SoftChannel/72342371961929728/20041026/1868578_1.shtml" target="_blank"><font color="#0000ff">“Hello World”</font></a></td><td width="65%">“Hello world”示例程序让您对Hibernate有一个简单的认识<strong>。</strong></td></tr><tr><td><a href="http://dev.yesky.com/SoftChannel/72342371961929728/20041026/1868578_2.shtml" target="_blank"><font color="#0000ff">理解Hibernate的架构</font></a></td><td>介绍Hibernate接口的主要功能。</td></tr><tr><td><a href="http://dev.yesky.com/SoftChannel/72342371961929728/20041026/1868578_2.shtml" target="_blank"><font color="#0000ff">核心接口</font></a></td><td>Hibernate有5个核心接口，通过这几个接口开发人员可以存储和获得持久对象，并且能够进行事务控制</td></tr><tr><td><a href="http://dev.yesky.com/SoftChannel/72342371961929728/20041026/1868578_3.shtml" target="_blank"><font color="#0000ff">一个重要的术语：Type</font></a></td><td>Type是Hibernate发明者发明的一个术语，它在整个构架中是一个非常基础、有着强大功能的元素，一个Type对象能将一个Java类型映射到数据库中一个表的字段中去。</td></tr><tr><td><a href="http://dev.yesky.com/SoftChannel/72342371961929728/20041026/1868578_3.shtml" target="_blank"><font color="#0000ff">策略接口</font></a></td><td>Hibernate与某些其它开源软件不同的还有一点――高度的可扩展性，这通过它的内置策略机制来实现。</td></tr><tr><td><a href="http://dev.yesky.com/SoftChannel/72342371961929728/20041026/1868578_3.shtml" target="_blank"><font color="#0000ff">基础配置</font></a></td><td>Hibernate可以配置成可在任何Java环境中运行，一般说来，它通常被用在2－3层的C/S模式的项目中，并被部署在服务端。</td></tr><tr><td height="36"><a href="http://dev.yesky.com/SoftChannel/72342371961929728/20041026/1868578_4.shtml" target="_blank"><font color="#0000ff">创建一个SessionFactory对象</font></a></td><td>要创建一个SessionFactory对象，必须在Hibernate初始化时创建一个Configuration类的实例，并将已写好的映射文件交由它处理。</td></tr></tbody><strong>“Hello World”</strong><br /><br />　　Hibernate应用程序定义了一些持久类，并且定义了这些类与数据库表格的映射关系。在我们这个“Hello world”示例程序中包含了一个类和一个映射文件。让我们看看这个简单的持久类包含有一些什么？映射文件是怎样定义的？另外，我们该怎样用Hibernate来操作这个持久类。<br /><br />　　我们这个简单示例程序的目的是将一些持久类存储在数据库中，然后从数据库取出来，并将其信息正文显示给用户。其中Message正是一个简单的持久类：，它包含我们要显示的信息，其源代码如下：<br /><br />　　列表1　Message.Java　一个简单的持久类<br /><br /></table><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#e6e4dd" border="1"><tbody><tr><td>package hello;<br />public class Message {<br />　private Long id;<br />　private String text;<br />　private Message nextMessage;<br />　private Message() {}<br />　public Message(String text) {<br />　　this.text = text;<br />　}<br />　public Long getId() {<br />　　return id;<br />　}<br />　private void setId(Long id) {<br />　　this.id = id;<br />　}<br />　public String getText() {<br />　　return text; <br />　}<br />　public void setText(String text) {<br />　　this.text = text;<br />　}<br />　public Message getNextMessage() {<br />　　return nextMessage;<br />　}<br />　public void setNextMessage(Message nextMessage) {<br />　　this.nextMessage = nextMessage;<br />　}<br />} </td></tr></tbody></table><br />　　Message类有三个属性：Message的id 、消息正文、以及一个指向下一条消息的指针。其中id属性让我们的应用程序能够唯一的识别这条消息，通常它等同于数据库中的主键，如果多个Message类的实例对象拥有相同的id，那它们代表数据库某个表的同一个记录。在这里我们选择了长整型作为我们的id值，但这不是必需的。Hibernate允许我们使用任意的类型来作为对象的id值，在后面我们会对此作详细描述。<br /><br />　　你可能注意到Message类的代码类似于JavaBean的代码风格，并且它有一个没有参数的构造函数，在我们以后的代码中我将继续使用这种风格来编写持久类的代码。<br /><br />　　Hibernate会自动管理Message类的实例，并通过内部机制使其持久化，但实际上Message对象并没有实现任何关于Hibernate的类或接口，因此我们也可以将它作为一个普通的Java类来使用：<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#e6e4dd" border="1"><tbody><tr><td>Message message = new Message("Hello World");<br />System.out.println( message.getText() ); </td></tr></tbody></table><br />　　以上这段代码正是我们所期望的结果：它打印“hello world”到屏幕上。但这并不是我们的最终目标；实际上Hibernate与诸如EJB容器这样的环境在持久层实现的方式上有很大的不同。我们的持久类(Message类)可以用在与容器无关的环境中，不像EJB必须要有EJB容器才能执行。为了能更清楚地表现这点，以下代码将我们的一个新消息保存到数据库中去：<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#e6e4dd" border="1"><tbody><tr><td>Session session = getSessionFactory().openSession();<br />Transaction tx = session.beginTransaction();<br />Message message = new Message("Hello World");<br />session.save(message);<br />tx.commit();<br />session.close(); </td></tr></tbody></table><br />　　以上这段代码调用了Hibernate的Session和Transaction接口（关于getSessionFactory()方法我们将会马上提到）。它相当于我们执行了以下SQL语句：<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#e6e4dd" border="1"><tbody><tr><td>insert into MESSAGES (MESSAGE_ID, MESSAGE_TEXT, NEXT_MESSAGE_ID)<br />values (1, 'Hello World', null) </td></tr></tbody></table><br />　　在以上的SQL语句中，MESSAGE_ID字段到底被初始化成了什么值呢？由于我们并没有在先前的代码中为message对象的id属性赋与初始值，那它是否为null呢？实际上Hibernate对id属性作了特殊处理：由于它是一个对象的唯一标识，因此当我们进行save()调用时，Hibernate会为它自动赋予一个唯一的值（我们将在后面内容中讲述它是如何生成这个值的）。<br /><br />　　我们假设你已经在数据库中创建了一个名为MESSAGE的表，那么既然前面这段代码让我们将Message对象存入了数据库中，那么现在我们就要将它们一一取出来。下面这段代码将按照字母顺序，将数据库中的所有Message对象取出来，并将它们的消息正文打印到屏幕上：<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#e6e4dd" border="1"><tbody><tr><td>Session newSession = getSessionFactory().openSession();<br />Transaction newTransaction = newSession.beginTransaction();<br />List messages =newSession.find("from Message as m order by m.text asc");<br />System.out.println( messages.size() + " message(s) found:" );<br />for ( Iterator iter = messages.iterator(); iter.hasNext(); ) {<br />　Message message = (Message) iter.next();<br />　System.out.println( message.getText() );<br />}<br />newTransaction.commit();<br />newSession.close(); </td></tr></tbody></table><br />　　在以上这段代码中，你可能被find()方法的这个参数困扰着："from Message as m order by m.text asc"，其实它是Hibernate自己定义的查询语言，全称叫Hibernate Query Language(HQL)。通俗地讲HQL与SQL的关系差不多就是方言与普通话之间的关系，咋一看，你会觉得它有点类似于SQL语句。其实在find()调用时，Hibernate会将这段HQL语言翻译成如下的SQL语句：<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#e6e4dd" border="1"><tbody><tr><td>select m.MESSAGE_ID, m.MESSAGE_TEXT, m.NEXT_MESSAGE_ID<br />from MESSAGES m<br />order by m.MESSAGE_TEXT asc </td></tr></tbody></table><br />　　以下就是运行结果： <br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#e6e4dd" border="1"><tbody><tr><td>1 message(s) found:<br />Hello World </td></tr></tbody></table><br />　　如果你以前没有ORM（对象－关系映射）的开发经验，那你可能想在代码的某个地方去寻找这段SQL语句，但在Hibernate中你可能会失望：它根本不存在！所有就SQL语句都是Hibernate动态生成的。 <br /><br />　　也许你会觉得还缺点什么，对！仅凭以上代码Hibernate是无法将我们的Message类持久化的。我们还需要一些更多的信息，这就是映射定义表！这个表在Hibernate中是以XML格式来体现的，它定义了Message类的属性是怎样与数据库中的MESSAGES表的字段进行一一对应的，列表2是这个示例程序的映射配置文件清单：<br /><br />　　列表2：示例程序的对象－关系映射表 <br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#e6e4dd" border="1"><tbody><tr><td>＜?xml version="1.0"?＞<br />＜!DOCTYPE hibernate-mapping PUBLIC<br />"-//Hibernate/Hibernate Mapping DTD//EN"<br />"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"＞<br />＜hibernate-mapping＞<br />＜class name="hello.Message" table="MESSAGES"＞<br />　＜id name="id" column="MESSAGE_ID"＞<br />　　＜generator class="increment"/＞<br />　＜/id＞<br />　＜property name="text" column="MESSAGE_TEXT"/＞<br />　＜many-to-one name="nextMessage" cascade="all" column="NEXT_MESSAGE_ID"/＞<br />＜/class＞<br />＜/hibernate-mapping＞ </td></tr></tbody></table><br />　　以上这个文档告诉Hibernate怎样将Message类映射到MESSAGES表中，其中Message类的id属性与表的MESSAGE_ID字段对应，text属性与表的MESSAGE_TEXT字段对应，nextMessage属性是一个多对一的关系，它与表中的NEXT_MESSAGE_ID相对应。 <br /><br />　　相对于有些开源项目来说，Hibernate的配置文件其实是很容易理解的。你可以轻松地修改与维护它。只要你定义好了持久类与数据库中表字段的对应关系就行了，Hibernate会自动帮你生成SQL语句来对Message对象进行插入、更新、删除、查找工作，你可以不写一句SQL语句，甚至不需要懂得SQL语言！<br /><br />　　现在让我们做一个新的试验，我们先取出第一个Message对象，然后修改它的消息正文，最后我们再生成一个新的Message对象，并将它作为第一个Message对象的下一条消息，其代码如下：<br /><br />　　列表3　更新一条消息<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#e6e4dd" border="1"><tbody><tr><td>Session session = getSessionFactory().openSession();<br />Transaction tx = session.beginTransaction();<br />// 1 is the generated id of the first message<br />Message message =(Message) session.load( Message.class, new Long(1) );<br />message.setText("Greetings Earthling");<br />Message nextMessage = new Message("Take me to your leader (please)");<br />message.setNextMessage( nextMessage );<br />tx.commit();<br />session.close(); </td></tr></tbody></table><br />　　以上这段代码在调用时，Hibernate内部自动生成如下的SQL语句：<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#e6e4dd" border="1"><tbody><tr><td>select m.MESSAGE_ID, m.MESSAGE_TEXT, m.NEXT_MESSAGE_ID<br />from MESSAGES m<br />where m.MESSAGE_ID = 1<br /><br />insert into MESSAGES (MESSAGE_ID, MESSAGE_TEXT, NEXT_MESSAGE_ID)<br />values (2, 'Take me to your leader (please)', null)<br /><br />update MESSAGES<br />set MESSAGE_TEXT = 'Greetings Earthling', NEXT_MESSAGE_ID = 2<br />where MESSAGE_ID = 1 </td></tr></tbody></table><br />　　当第一个Message对象的text属性和nextMessage被程序修改时，请注意Hibernate是如何检测到这种变化，并如何在数据库中自动对它更新的。这实际上是Hibernate的一个很有价值的特色，我们把它称为“自动脏数据检测”，Hibernate的这个特色使得当我们修改一个持久对象的属性后，不必显式地通知Hibernate去将它在数据库中进行更新。同样的，当第一个Message对象调用setNextMessage()方法将第二个Message对象作为它的下一条消息的引用时，第二条消息会无需调用save()方法，便可以自动地保存在数据库中。这种特色被称为“级联保存”，它也免去了我们显式地对第二个Message对象调用save()方法之苦。<br /><br />　　如果我们再运行先前的那段将数据库中所有的Message对象都打印出来的代码，那它的运行结果如下：<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#e6e4dd" border="1"><tbody><tr><td>2 message(s) found:<br />Greetings Earthling<br />Take me to your leader (please) </td></tr></tbody></table><br />　　“Hello world”示例程序现在介绍完毕。我们总算对Hibernate有了一个简单的认识，下面我们将回过头来，对Hibernate的主要API调用作一下简要的介绍：<br /><br /><br /><strong>理解Hibernate的架构</strong><br /><br />　　当你想用Hibernate开发自己的基于持久层的应用时，第一件事情应当是熟悉它的编程接口。Hibernate的API接口设计得尽量简洁明了，以方便开发人员。然而实际上由于ORM的复杂性，它的API一般都不可能设计得很简单。但是别担心，你没有必要一下子了解所有的Hibernate的API接口。下面这张图描述了Hibernate在应用层和持久层中的一些重要的接口类：<br /><br /><table width="90%" align="center" border="0"><tbody><tr><td><div align="center"><img onerror="this.src='http://www.yesky.com/image20010518/189639.jpg';" hspace="3" src="/image20010518/189639.jpg" align="center" vspace="1" border="1" /></div></td></tr></tbody></table><br />　　在上图中，我们将应用层放在了持久层的上部，实际上在传统的项目中，应用层充当着持久层的一个客户端角色。但对于一些简单的项目来说，应用层和持久层并没有区分得那么清楚，这也没什么，在这种情况下你可以将应用层和持久层合并成了一层。<br /><br />　　在上图中，Hibernate的接口大致可以分为以下几种类型：<br /><br />　　· 一些被用户的应用程序调用的，用来完成基本的创建、读取、更新、删除操作以及查询操作的接口。这些接口是Hibernate实现用户程序的商业逻辑的主要接口，它们包括Session、Transaction和Query。<br /><br />　　· Hibernate用来读取诸如映射表这类配置文件的接口，典型的代表有Configuration类。<br /><br />　　· 回调(Callback)接口。它允许应用程序能对一些事件的发生作出相应的操作，例如Interceptor、Lifecycle和Validatable都是这一类接口。<br /><br />　　· 一些可以用来扩展Hibernate的映射机制的接口，例如UserType、CompositeUserType和IdentifierGenerator。这些接口可由用户程序来实现（如果有必要）。<br /><br />　　Hibernate使用了J2EE架构中的如下技术：JDBC、JTA、JNDI。其中JDBC是一个支持关系数据库操作的一个基础层；它与JNDI和JTA一起结合，使得Hibernate可以方便地集成到J2EE应用服务器中去。<br /><br />　　在这里，我们不会详细地去讨论Hibernate API接口中的所有方法，我们只简要讲一下每个主要接口的功能，如果你想了解得更多的话，你可以在Hibernate的源码包中的net.sf.hibernate子包中去查看这些接口的源代码。下面我们依次讲一下所有的主要接口：<br /><br />　　<strong>核心接口</strong><br /><br />　　以下5个核心接口几乎在任何实际开发中都会用到。通过这些接口，你不仅可以存储和获得持久对象，并且能够进行事务控制。<br /><br />　　Session接口<br /><br />　　Session接口对于Hibernate 开发人员来说是一个最重要的接口。然而在Hibernate中，实例化的Session是一个轻量级的类，创建和销毁它都不会占用很多资源。这在实际项目中确实很重要，因为在客户程序中，可能会不断地创建以及销毁Session对象，如果Session的开销太大，会给系统带来不良影响。但值得注意的是Session对象是非线程安全的，因此在你的设计中，最好是一个线程只创建一个Session对象。<br /><br />　　在Hibernate的设计者的头脑中，他们将session看作介于数据连接与事务管理一种中间接口。我们可以将session想象成一个持久对象的缓冲区，Hibernate能检测到这些持久对象的改变，并及时刷新数据库。我们有时也称Session是一个持久层管理器，因为它包含这一些持久层相关的操作，诸如存储持久对象至数据库，以及从数据库从获得它们。请注意，Hibernate 的session不同于JSP应用中的HttpSession。当我们使用session这个术语时，我们指的是Hibernate中的session，而我们以后会将HttpSesion对象称为用户session。<br /><br />　　SessionFactory 接口<br /><br />　　这里用到了一个设计模式――工厂模式，用户程序从工厂类SessionFactory中取得Session的实例。<br /><br />　　令你感到奇怪的是SessionFactory并不是轻量级的！实际上它的设计者的意图是让它能在整个应用中共享。典型地来说，一个项目通常只需要一个SessionFactory就够了，但是当你的项目要操作多个数据库时，那你必须为每个数据库指定一个SessionFactory。<br />SessionFactory在Hibernate中实际起到了一个缓冲区的作用，它缓冲了Hibernate自动生成的SQL语句和一些其它的映射数据，还缓冲了一些将来有可能重复利用的数据。<br /><br />　　Configuration 接口<br /><br />　　Configuration接口的作用是对Hibernate进行配置，以及对它进行启动。在Hibernate的启动过程中，Configuration类的实例首先定位映射文档的位置，读取这些配置，然后创建一个SessionFactory对象。<br /><br />　　虽然Configuration接口在整个Hibernate项目中只扮演着一个很小的角色，但它是启动hibernate时你所遇到的每一个对象。<br /><br />　　Transaction 接口<br /><br />　　Transaction接口是一个可选的API，你可以选择不使用这个接口，取而代之的是Hibernate的设计者自己写的底层事务处理代码。 Transaction接口是对实际事务实现的一个抽象，这些实现包括JDBC的事务、JTA中的UserTransaction、甚至可以是CORBA事务。之所以这样设计是能让开发者能够使用一个统一事务的操作界面，使得自己的项目可以在不同的环境和容器之间方便地移值。<br /><br />　　Query和Criteria接口<br /><br />　　Query接口让你方便地对数据库及持久对象进行查询，它可以有两种表达方式：HQL语言或本地数据库的SQL语句。Query经常被用来绑定查询参数、限制查询记录数量，并最终执行查询操作。<br /><br />　　Criteria接口与Query接口非常类似，它允许你创建并执行面向对象的标准化查询。<br /><br />　　值得注意的是Query接口也是轻量级的，它不能在Session之外使用。<br /><br />　　Callback 接口 <br /><br />　　当一些有用的事件发生时――例如持久对象的载入、存储、删除时，Callback接口会通知Hibernate去接收一个通知消息。一般而言，Callback接口在用户程序中并不是必须的，但你要在你的项目中创建审计日志时，你可能会用到它。<br /><br /><br /><br /><br /><br />　　<strong>一个重要的术语：Type</strong><br /><br />　　Hibernate的设计者们发明了一个术语：Type，它在整个构架中是一个非常基础、有着强大功能的元素。一个Type对象能将一个Java类型映射到数据库中一个表的字段中去（实际上，它可以映射到表的多个字段中去）。持久类的所有属性都对应一个type。这种设计思想使用Hibernate有着高度的灵活性和扩展性。<br /><br />　　Hibernate内置很多type类型，几乎包括所有的Java基本类型，例如Java.util.Currency、Java.util.calendar、byte[]和Java.io.Serializable。<br /><br />　　不仅如此，Hibernate还支持用户自定义的type，通过实现接口UserType和接口CompositeUserType，你可以加入自己的type。你可以利用这种特色让你的项目中使用自定义的诸如Address、Name这样的type，这样你就可以获得更大的便利，让你的代码更优雅。自定义type在Hibernate中是一项核心特色，它的设计者鼓励你多多使用它来创建一个灵活、优雅的项目！<br /><br />　　<strong>策略接口</strong><br /><br />　　Hibernate与某些其它开源软件不同的还有一点――高度的可扩展性，这通过它的内置策略机制来实现。当你感觉到Hibernate的某些功能不足，或者有某些缺陷时，你可以开发一个自己的策略来替换它，而你所要做的仅仅只是继承它的某个策略接口，然后实现你的新策略就可以了，以下是它的策略接口：<br /><br />　　· 主键的生成 (IdentifierGenerator 接口) <br /><br />　　· 本地SQL语言支持 (Dialect 抽象类) <br /><br />　　· 缓冲机制 (Cache 和CacheProvider 接口) <br /><br />　　· JDBC 连接管理 (ConnectionProvider接口) <br /><br />　　· 事务管理 (TransactionFactory, Transaction, 和 TransactionManagerLookup 接口) <br /><br />　　· ORM 策略 (ClassPersister 接口) <br /><br />　　· 属性访问策略 (PropertyAccessor 接口) <br /><br />　　· 代理对象的创建 (ProxyFactory接口)<br /><br />　　Hibernate为以上所列的机制分别创建了一个缺省的实现，因此如果你只是要增强它的某个策略的功能的话，只需简单地继承这个类就可以了，没有必要从头开始写代码。<br /><br />　　以上就是Hibernate的一些核心接口，但当我们真正开始用它进行开发时，你的脑海里可能总会有一个疑问：我是通过什么方式，并从哪里取得Session的呢？以下我们就解答这个问题。<br /><br />　　<strong>基础配置</strong><br /><br />　　现在回顾一下我们先前的内容：我们写出了一个示例程序，并简要地讲解了Hibernate的一些核心类。但要真正使你的项目运行起来，还有一件事必须要做：配置。Hibernate可以配置成可在任何Java环境中运行，一般说来，它通常被用在2－3层的C/S模式的项目中，并被部署在服务端。在这种项目中，Web浏览器、或Java GUI程序充当者客户端。尽管我们的焦点主要是集中在多层web应用，但实际上在一些基于命令行的应用中也可以使用Hibernate。并且，对Hibernate的配置在不同的环境下都会不同，Hibernate运行在两种环境下：可管理环境和不可管理环境<br /><br />　　· 可管理环境――这种环境可管理如下资源：池资源管理，诸如数据库连接池和，还有事务管理、安全定义。一些典型的J2EE服务器（JBoss、Weblogic、WebSphere）已经实现了这些。<br /><br />　　· 不可管理环境――只是提供了一些基本的功能，诸如像Jetty或Tomcat这样的servlet容器环境。一个普通的Java桌面应用或命令行程序也可以认为是处于这种环境下。这种环境不能提供自动事务处理、资源管理或安全管理，这些都必须由应用程序自己来定义。<br /><br />　　Hibernate的设计者们将这两种环境设计了一个统一的抽象界面，因此对于开发者来说只有一种环境：可管理环境。如果实际项目是建立在诸如Tomcat这类不可管理的环境中时，那Hibernate将会使用它自己的事务处理代码和JDBC连接池，使其变为一个可管理环境。<br />对于可管理的环境而言，Hibernate会将自己集成在这种环境中。对于开发者而言，你所要做的工作非常简单：只需从一个Configuration类中创建一个SessionFactory类就可以了。<br /><br /><br /><br /><br /><br /><strong>创建一个SessionFactory对象</strong><br /><br />　　为了能创建一个SessionFactory对象，你必须在Hibernate初始化时创建一个Configuration类的实例，并将已写好的映射文件交由它处理。这样，Configuration对象就可以创建一个SessionFactory对象，当SessionFactory对象创建成功后，Configuration对象就没有用了，你可以简单地抛弃它。如下是示例代码：<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#e6e4dd" border="1"><tbody><tr><td>Configuration cfg = new Configuration();<br />cfg.addResource("hello/Message.hbm.xml");<br />cfg.setProperties( System.getProperties() );<br />SessionFactory sessions = cfg.buildSessionFactory(); </td></tr></tbody></table><br />　　在以上代码中，Message.hb.xml这个映射文件的位置比较特殊，它与当前的classpath相关。例如classpath包含当前目录，那在上述代码中的Message.hbm.xml映射文件就可以保存在当前目录下的hello目录中。<br /><br />　　作为一种约定，Hibernate的映射文件默认以.htm.xml作为其扩展名。另一个约定是坚持为每一个持久类写一个配置文件，想一想如果你将所有持久类的映射写入一个单独的配置文件中的话，那这个配置文件肯定非常庞大，不易维护。但这里又出现了一个新问题：如果为每个类写一个配置文件的话，这么多的配置文件应该存放在哪里呢？<br /><br />　　Hibernate推荐你将每个映射文件保存在与持久类相同的目录下，并且与持久类同名。例如我们第一个示例程序中的Message持久类放在hello目录下，那你必须在这个目录下存放名为Message.hbm.xml的映射文件。这样一个持久类都有自己的一个映射文件，避免了出现像struts项目中的“struts-config.xml地狱”的情况。如果你不遵循这种规定，那你必须手动地用addResource()方法将一个个的映射文件载入；但你如果遵循这种规定，那你可以方便地用addClass()方法同时将持久类和它的映射文件载入，以下是体现这种便利性的示例代码：<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#e6e4dd" border="1"><tbody><tr><td>SessionFactory sessions = new Configuration()<br />.addClass(org.hibernate.auction.model.Item.class)<br />.addClass(org.hibernate.auction.model.Category.class)<br />.addClass(org.hibernate.auction.model.Bid.class)<br />.setProperties( System.getProperties() )<br />.buildSessionFactory(); </td></tr></tbody></table><br />　　当然，Hibernate的映射文件还有很多其它的配置选项，比如数据库连接的设定，或是能够改变Hibernate运行时行为的一些设定。所有的设置可能是非常庞杂的，足以让你喘不过气来，但是不必担心，因为Hibernate为绝大多数值都设定了一个合理缺省值，你只需要修改这些配置文件中的极小一部分值。<br /><br />　　你可以通过以下几种方式来修改Hibernate的系统配置参数：<br /><br />　　· 将一个Java.util.Properties实例作为参数传给Configuration类的setProperties()方法。<br /><br />　　· 在Hibernate启动时用Java –Dproperty=value的方式设置值。<br /><br />　　· 在classpath可以找到的路径下创建一个名为hibernate.properties的配置文件。 <br /><br />　　· 在classpath可以找到的路径下创建一个名为hibernate.cfg.xml的文件，并在其＜property＞标签中定义属性值。<br /><br />　　以上就是对Hibernate的一个大致介绍，如果你想知道得更多，那本文还是远远不够的，我将陆续推出更多关于Hibernate的资料。但有一点是毫无疑问的：它的确是一个非常优秀的持久层解决方案！<br /><br /><br /><br /><br /><img src ="http://www.blogjava.net/xixidabao/aggbug/46596.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xixidabao/" target="_blank">JAVA之路</a> 2006-05-17 11:46 <a href="http://www.blogjava.net/xixidabao/archive/2006/05/17/46596.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>