﻿<?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-随笔分类-J2EE介绍</title><link>http://www.blogjava.net/xixidabao/category/15382.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>设计模式之Observer </title><link>http://www.blogjava.net/xixidabao/archive/2007/04/18/111546.html</link><dc:creator>JAVA之路</dc:creator><author>JAVA之路</author><pubDate>Wed, 18 Apr 2007 03:14:00 GMT</pubDate><guid>http://www.blogjava.net/xixidabao/archive/2007/04/18/111546.html</guid><description><![CDATA[<div class=postTitle><a class=postTitle2 id=viewpost1_TitleUrl href="http://www.blogjava.net/Sprite-bei/archive/2007/04/16/110976.html"><u><font color=#800080>设计模式之Observer</font></u></a> </div>
<p><span>Java深入到一定程度,就不可避免的碰到设计模式(design pattern)这一概念,了解设计模式,将使自己对java中的接口或抽象类应用有更深的理解.设计模式在java的中型系统中应用广泛,遵循一定的编程模式,才能使自己的代码便于理解,易于交流,Observer(观察者)模式是比较常用的一个模式,尤其在界面设计中应用广泛,而本站所关注的是Java在电子商务系统中应用,因此想从电子商务实例中分析Observer的应用.</span></p>
<p>虽然网上商店形式多样<span>,每个站点有自己的特色,但也有其一般的共性,单就"商品的变化,以便及时通知订户"这一点,是很多网上商店共有的模式,这一模式类似Observer patern.</span></p>
<p>具体的说<span>,如果网上商店中商品在名称 价格等方面有变化,如果系统能自动通知会员,将是网上商店区别传统商店的一大特色.这就需要在商品product中加入Observer这样角色,以便product细节发生变化时,Observer能自动观察到这种变化,并能进行及时的update或notify动作.</span></p>
<p><span></span></p>
<p><span>Java的API还为为我们提供现成的Observer接口Java.util.Observer.我们只要直接使用它就可以.</span></p>
<p>我们必须<span>extends Java.util.Observer才能真正使用它:<br>1.提供Add/Delete observer的方法;<br>2.提供通知(notisfy) 所有observer的方法;</span></p>
<table cellSpacing=3 cellPadding=0 width="80%" bgColor=#cccccc border=0>
    <tbody>
        <tr>
            <td>
            <p><span>import java.util.Observable;</span></p>
            <p><span>public class product extends Observable {</span></p>
            <p><span>&nbsp;private String name;</span></p>
            <p><span>&nbsp;private float price;<br>&nbsp;public product(){<br>&nbsp;}</span></p>
            <p><span>&nbsp;public String getName() {<br>&nbsp;&nbsp;return name;<br>&nbsp;}</span></p>
            <p><span>&nbsp;public void setName(String name) {<br>&nbsp;&nbsp;this.name = name;<br>&nbsp;&nbsp;//设置变化点 <br>&nbsp;&nbsp;setChanged();<br>&nbsp;&nbsp;notifyObservers(name);</span></p>
            <p><span>&nbsp;}</span></p>
            <p><span>&nbsp;public float getPrice() {<br>&nbsp;&nbsp;return price;<br>&nbsp;}</span></p>
            <p><span>&nbsp;public void setPrice(float price) {<br>&nbsp;&nbsp;this.price = price;<br>&nbsp;&nbsp;//设置变化点<br>&nbsp;&nbsp;setChanged();<br>&nbsp;&nbsp;notifyObservers(new Float(price));</span></p>
            <p><span>&nbsp;}</span></p>
            <p><span>&nbsp;//以下可以是数据库更新 插入命令.<br>&nbsp;public void saveToDb() {<br>&nbsp;&nbsp;//&nbsp; .....................</span></p>
            <p><span>&nbsp;}</span></p>
            <p><span>&nbsp;public static void main(String[] args) {<br>&nbsp;&nbsp;product p=new product();<br>&nbsp;&nbsp;p.addObserver(new NameObserver());<br>&nbsp;&nbsp;p.addObserver(new PriceObserver());<br>&nbsp;&nbsp;p.setPrice(100);<br>&nbsp; p.setName("name");<br>&nbsp;}<br>}</span></p>
            </td>
        </tr>
    </tbody>
</table>
<p><span><br>我们注意到,在product类中 的setXXX方法中,我们设置了 notify(通知)方法, 当调用setXXX,实际上就触发了notisfyObservers方法,这将通知相应观察者应该采取行动了.</span></p>
<p>下面看看这些观察者的代码<span>,他们究竟采取了什么行动:</span></p>
<table cellSpacing=3 cellPadding=0 width="99%" border=0>
    <tbody>
        <tr>
            <td>
            <p><span>//观察者NameObserver主要用来对产品名称(name)进行观察的<br>public class NameObserver implements Observer{</span></p>
            <p>　　<span>private String name=null;</span></p>
            <p>　　<span>public void update(Observable obj,Object arg){<br><br>　　　　if (arg <a href="http://www-900.ibm.com/developerWorks/java/l-leditor/index.shtml" target=_blank><u><font color=#0000ff>instanceof</font></u></a> String){</span></p>
            <p>　　　　<span> name=(String)arg;<br>　　　　 //产品名称改变值在name中<br>　　　　 System.out.println("NameObserver :name changet to "+name);</span></p>
            <p>　　　　<span>}</span></p>
            <p>　　<span>}</span></p>
            <p><span>}</span></p>
            <p><span>//观察者PriceObserver主要用来对产品价格(price)进行观察的<br>public class PriceObserver implements Observer{</span></p>
            <p>　　<span>private float price=0;</span></p>
            <p>　　<span>public void update(Observable obj,Object arg){<br><br>　　　　if (arg instanceof Float){</span></p>
            <p>　　　　<span> price=((Float)arg).floatValue();<br>　　<br>　　　　 System.out.println("PriceObserver :price changet to "+price);</span></p>
            <p>　　　　<span>}</span></p>
            <p>　　<span>}</span></p>
            <p><span>}<br><br></span></p>
            </td>
        </tr>
    </tbody>
</table>
输出结果如下：<br>PriceObserver :price changet to 100.0<br>NameObserver :name changet to name<br><br>转自：<a href="http://www.blogjava.net/Sprite-bei/archive/2007/04/16/110976.html">http://www.blogjava.net/Sprite-bei/archive/2007/04/16/110976.html</a>
<img src ="http://www.blogjava.net/xixidabao/aggbug/111546.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-18 11:14 <a href="http://www.blogjava.net/xixidabao/archive/2007/04/18/111546.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Struts,Spring,Hibernate优缺点 </title><link>http://www.blogjava.net/xixidabao/archive/2007/04/14/110605.html</link><dc:creator>JAVA之路</dc:creator><author>JAVA之路</author><pubDate>Sat, 14 Apr 2007 02:38:00 GMT</pubDate><guid>http://www.blogjava.net/xixidabao/archive/2007/04/14/110605.html</guid><description><![CDATA[1.struts<br><br>struts框架具有组件的模块化，灵活性和重用性的优点，同时简化了基于MVC的web应用程序的开发。<br><br>优点：<br>Struts跟Tomcat、Turbine等诸多Apache项目一样，是开源软件，这是它的一大优点。使开发者能更深入的了解其内部实现机制。<br>除此之外，Struts的优点主要集中体现在两个方面：Taglib和页面导航。Taglib是Struts的标记库，灵活动用，能大大提高开发效率。另外，就目前国内的JSP开发者而言，除了使用JSP自带的常用标记外，很少开发自己的标记，或许Struts是一个很好的起点。<br>关于页面导航，我认为那将是今后的一个发展方向，事实上，这样做，使系统的脉络更加清晰。通过一个配置文件，即可把握整个系统各部分之间的联系，这对于后期的维护有着莫大的好处。尤其是当另一批开发者接手这个项目时，这种优势体现得更加明显。<br><br><br>另外，struts是业界"标准"（很多成功案例），学习资源丰富，HTML标签非常优秀<br><br>缺点：<br>Taglib是Struts的一大优势，但对于初学者而言，却需要一个持续学习的过程，甚至还会打乱你网页编写的习惯，但是，当你习惯了它时，你会觉得它真的很棒。<br>Struts将MVC的Controller一分为三，在获得结构更加清晰的同时，也增加了系统的复杂度。<br>ActionForms使用不便、无法进行单元测试（StrutsTestCase只能用于集成）<br><br><br><strong>【IT168技术文档</strong>】 <br>&nbsp;&nbsp;&nbsp; Struts跟Tomcat、Turbine等诸多Apache项目一样，是开源软件，这是它的一大优点。使开发者能更深入的了解其内部实现机制。 Struts开放源码框架的创建是为了使开发者在构建基于Java Servlet和JavaServer Pages（JSP）技术的Web应用时更加容易。Struts框架为开放者提供了一个统一的标准框架，通过使用Struts作为基础，开发者能够更专注于应用程序的商业逻辑。Struts框架本身是使用Java Servlet和JavaServer Pages技术的一种Model-View-Controller（MVC）实现. <br>具体来讲,Struts的优点有:&nbsp;<br><br>&nbsp;&nbsp;&nbsp; 1. 实现MVC模式，结构清晰,使开发者只关注业务逻辑的实现.&nbsp;<br><br>&nbsp;&nbsp;&nbsp; 2. 有丰富的tag可以用 ,Struts的标记库(Taglib)，如能灵活动用，则能大大提高开发效率。另外，就目前国内的JSP开发者而言，除了使用JSP自带的常用标记外，很少开发自己的标记，或许Struts是一个很好的起点。&nbsp;<br><br>&nbsp;&nbsp;&nbsp; 3. 页面导航.页面导航将是今后的一个发展方向，事实上，这样做，使系统的脉络更加清晰。通过一个配置文件，即可把握整个系统各部分之间的联系，这对于后期的维护有着莫大的好处。尤其是当另一批开发者接手这个项目时，这种优势体现得更加明显。&nbsp;<br><br>&nbsp;&nbsp;&nbsp; 4. 提供Exception处理机制 .&nbsp;<br><br>&nbsp;&nbsp;&nbsp; 5. 数据库链接池管理&nbsp;<br><br>&nbsp;&nbsp;&nbsp; 6. 支持I18N&nbsp;<br><br>&nbsp;&nbsp;&nbsp; 缺点:&nbsp;<br>&nbsp;&nbsp;&nbsp; 一、 转到展示层时，需要配置forward，每一次转到展示层，相信大多数都是直接转到jsp，而涉及到转向，需要配置forward，如果有十个展示层的jsp，需要配置十次struts，而且还不包括有时候目录、文件变更，需要重新修改forward，注意，每次修改配置之后，要求重新部署整个项目，而tomcate这样的服务器，还必须重新启动服务器，如果业务变更复杂频繁的系统，这样的操作简单不可想象。现在就是这样，几十上百个人同时在线使用我们的系统，大家可以想象一下，我的烦恼有多大。<br>&nbsp;<br>&nbsp;&nbsp;&nbsp; 二、 Struts 的Action必需是thread－safe方式，它仅仅允许一个实例去处理所有的请求。所以action用到的所有的资源都必需统一同步，这个就引起了线程安全的问题。&nbsp;<br><br>&nbsp;&nbsp;&nbsp; 三、 测试不方便. Struts的每个Action都同Web层耦合在一起，这样它的测试依赖于Web容器，单元测试也很难实现。不过有一个Junit的扩展工具Struts TestCase可以实现它的单元测试。&nbsp;<br><br>&nbsp;&nbsp;&nbsp; 四、 类型的转换. Struts的FormBean把所有的数据都作为String类型，它可以使用工具Commons-Beanutils进行类型转化。但它的转化都是在Class级别，而且转化的类型是不可配置的。类型转化时的错误信息返回给用户也是非常困难的。&nbsp;<br><br>&nbsp;&nbsp;&nbsp; 五、 对Servlet的依赖性过强. Struts处理Action时必需要依赖ServletRequest 和ServletResponse，所有它摆脱不了Servlet容器。&nbsp;<br><br>&nbsp;&nbsp;&nbsp; 六、 前端表达式语言方面.Struts集成了JSTL，所以它主要使用JSTL的表达式语言来获取数据。可是JSTL的表达式语言在Collection和索引属性方面处理显得很弱。&nbsp;<br><br>&nbsp;&nbsp;&nbsp; 七、 对Action执行的控制困难. Struts创建一个Action，如果想控制它的执行顺序将会非常困难。甚至你要重新去写Servlet来实现你的这个功能需求。&nbsp;<br><br>&nbsp;&nbsp;&nbsp; 八、 对Action 执行前和后的处理. Struts处理Action的时候是基于class的hierarchies，很难在action处理前和后进行操作。&nbsp;<br><br>&nbsp;&nbsp;&nbsp; 九、 对事件支持不够. 在struts中，实际是一个表单Form对应一个Action类(或DispatchAction)，换一句话说：在Struts中实际是一个表单只能对应一个事件，struts这种事件方式称为application event，application event和component event相比是一种粗粒度的事件。&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp; Struts重要的表单对象ActionForm是一种对象，它代表了一种应用，这个对象中至少包含几个字段，这些字段是Jsp页面表单中的input字段，因为一个表单对应一个事件，所以，当我们需要将事件粒度细化到表单中这些字段时，也就是说，一个字段对应一个事件时，单纯使用Struts就不太可能，当然通过结合JavaScript也是可以转弯实现的。<br><br><br><br><br>2．Hibernate<br>Hibernate是一个开放源代码的对象关系映射框架，它对JDBC进行了非常轻量级的对象封装，使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。<br>Hibernate可以应用在任何使用JDBC的场合，既可以在Java的客户端程序实用，也可以在Servlet/JSP的Web应用中使用，最具革命意义的是，Hibernate可以在应用EJB的J2EE架构中取代CMP，完成数据持久化的重任。<br>大多数开发机构经常采取创建各自独立的数据持久层。一旦底层的数据结构发生改变，那么修改应用的其余部分使之适应这种改变的代价将是十分巨大的。Hibernate适时的填补了这一空白，它为Java应用提供了一个易用的、高效率的对象关系映射框架。hibernate是个轻量级的持久性框架，功能却非常丰富。<br><br>优点：<br>a.??????? Hibernate 使用 Java 反射机制 而不是字节码增强程序来实现透明性。<br>b.??????? ?Hibernate 的性能非常好，因为它是个轻量级框架。 映射的灵活性很出色。<br>c.??????? 它支持各种关系数据库，从一对一到多对多的各种复杂关系。 <br><br><br>缺点：它限制您所使用的对象模型。(例如，一个持久性类不能映射到多个表)其独有的界面和可怜的市场份额也让人不安，尽管如此，Hibernate 还是以其强大的发展动力减轻了这些风险。其他的开源持久性框架也有一些，不过都没有 Hibernate 这样有市场冲击力。<br><br><span class=tpc_content>上面回贴情绪有点激动，希望谅解，我不是因为有人批评Hibernate而感到不快，而是因为帖子里面的观点实在让我觉得荒谬。不管觉得Hibernate好也吧，不好也吧，我唯一觉得遗憾的是，在中文论坛里面找不到一个对Hibernate的真正高水平的评价。在TSS上有一个关于Hibernate的hot thread，跟了几百贴，其中包括Hibernate作者Gavin和LiDO JDO的CTO，对于JDO和Hibernate有过一些激烈的争论，我曾经耐心的看了一遍，仍然没有发现针对Hibernate真正有力的攻击，那些所谓的攻击无非针对Hibernate没有一个GUI的配置工具，没有商业公司支持，没有标准化等等这些站不住脚的理由。<br><br>补充几点我的意见：<br><br>一、Hibernate是JDBC的轻量级的对象封装，它是一个独立的对象持久层框架，和App Server，和EJB没有什么必然的联系。Hibernate可以用在任何JDBC可以使用的场合，例如Java应用程序的数据库访问代码，DAO接口的实现类，甚至可以是BMP里面的访问数据库的代码。从这个意义上来说，Hibernate和EB不是一个范畴的东西，也不存在非此即彼的关系。<br><br>二、Hibernate是一个和JDBC密切关联的框架，所以Hibernate的兼容性和JDBC驱动，和数据库都有一定的关系，但是和使用它的Java程序，和App Server没有任何关系，也不存在兼容性问题。<br><br>三、Hibernate不能用来直接和Entity Bean做对比，只有放在整个J2EE项目的框架中才能比较。并且即使是放在软件整体框架中来看，Hibernate也是做为JDBC的替代者出现的，而不是Entity Bean的替代者出现的，让我再列一次我已经列n次的框架结构：<br><br>传统的架构：<br>1) Session Bean &lt;-&gt; Entity Bean &lt;-&gt; DB<br>为了解决性能障碍的替代架构：<br>2) Session Bean &lt;-&gt; DAO &lt;-&gt; JDBC &lt;-&gt; DB<br>使用Hibernate来提高上面架构的开发效率的架构：<br>3) Session Bean &lt;-&gt; DAO &lt;-&gt; Hibernate &lt;-&gt; DB <br><br>就上面3个架构来分析：<br>1、内存消耗：采用JDBC的架构2无疑是最省内存的，Hibernate的架构3次之，EB的架构1最差。<br><br>2、运行效率：如果JDBC的代码写的非常优化，那么JDBC架构运行效率最高，但是实际项目中，这一点几乎做不到，这需要程序员非常精通JDBC，运用Batch语句，调整PreapredStatement的Batch Size和Fetch Size等参数，以及在必要的情况下采用结果集cache等等。而一般情况下程序员是做不到这一点的。因此Hibernate架构表现出最快的运行效率。EB的架构效率会差的很远。<br><br>3、开发效率：在有JBuilder的支持下以及简单的项目，EB架构开发效率最高，JDBC次之，Hibernate最差。但是在大的项目，特别是持久层关系映射很复杂的情况下，Hibernate效率高的惊人，JDBC次之，而EB架构很可能会失败。<br><br>4、分布式，安全检查，集群，负载均衡的支持<br>由于有SB做为Facade，3个架构没有区别。<br><br>四、EB和Hibernate学习难度在哪里？<br><br>EB的难度在哪里？不在复杂的XML配置文件上，而在于EB运用稍微不慎，就有严重的性能障碍。所以难在你需要学习很多EJB设计模式来避开性能问题，需要学习App Server和EB的配置来优化EB的运行效率。做EB的开发工作，程序员的大部分精力都被放到了EB的性能问题上了，反而没有更多的精力关注本身就主要投入精力去考虑的对象持久层的设计上来。<br><br>Hibernate难在哪里？不在Hibernate本身的复杂，实际上Hibernate非常的简单，难在Hibernate太灵活了。<br><br>当你用EB来实现持久层的时候，你会发现EB实在是太笨拙了，笨拙到你根本没有什么可以选择的余地，所以你根本就不用花费精力去设计方案，去平衡方案的好坏，去费脑筋考虑选择哪个方案，因为只有唯一的方案摆在你面前，你只能这么做，没得选择。<br><br>Hibernate相反，它太灵活了，相同的问题，你至少可以设计出十几种方案来解决，所以特别的犯难，究竟用这个，还是用那个呢？这些方案之间到底有什么区别呢？他们的运行原理有什么不同？运行效率哪个比较好？光是主键生成，就有七八种方案供你选择，你为难不为难？集合属性可以用Set，可以用List，还可以用Bag，到底哪个效率高，你为难不为难？查询可以用iterator，可以用list，哪个好，有什么区别？你为难不为难？复合主键你可以直接在hbm里面配置，也可以自定义CustomerType，哪种比较好些？你为难不为难？对于一个表，你可以选择单一映射一个对象，也可以映射成父子对象，还可以映射成两个1:1的对象，在什么情况下用哪种方案比较好，你为难不为难？<br><br>这个列表可以一直开列下去，直到你不想再看下去为止。当你面前摆着无数的眼花缭乱的方案的时候，你会觉得幸福呢？还是悲哀呢？如果你是一个负责的程序员，那么你一定会仔细研究每种方案的区别，每种方案的效率，每种方案的适用场合，你会觉得你已经陷入进去拔不出来了。如果是用EB，你第一秒种就已经做出了决定，根本没得选择，比如说集合属性，你只能用Collection，如果是Hibernate，你会在Bag，List和Set之间来回犹豫不决，甚至搞不清楚的话，程序都没有办法写。<br><br><br></span><br><br><br><br>3． Spring<br>它是一个开源的项目，而且目前非常活跃；它基于IoC（Inversion of Control，反向控制）和AOP的构架多层j2ee系统的框架，但它不强迫你必须在每一层 中必须使用Spring，因为它模块化的很好，允许你根据自己的需要选择使用它的某一个模块；它实现了很优雅的MVC，对不同的数据访问技术提供了统一的 接口，采用IoC使得可以很容易的实现bean的装配，提供了简洁的AOP并据此实现Transcation Managment，等等<br>优点 <br>? ?a. Spring能有效地组织你的中间层对象，不管你是否选择使用了EJB。如果你仅仅使用了Struts或其他为J2EE的 API特制的framework，Spring致力于解决剩下的问题。 <br>? ?b. Spring能消除在许多工程中常见的对Singleton的过多使用。根据我的经验，这是一个很大的问题，它降低了系统的可测试性和面向对象的程度。 <br>? ?c. 通过一种在不同应用程序和项目间一致的方法来处理配置文件，Spring能消除各种各样自定义格式的属性文件的需要。曾经对某个类要寻找的是哪个魔法般的属性项或系统属性感到不解，为此不得不去读Javadoc甚至源编码？有了Spring，你仅仅需要看看类的JavaBean属性。Inversion of Control的使用（在下面讨论）帮助完成了这种简化。 <br>??d.? 通过把对接口编程而不是对类编程的代价几乎减少到没有，Spring能够促进养成好的编程习惯。 <br>??e. Spring被设计为让使用它创建的应用尽可能少的依赖于他的APIs。在Spring应用中的大多数业务对象没有依赖于Spring。 <br>??f. 使用Spring构建的应用程序易于单元测试。 <br>??g.? Spring能使EJB的使用成为一个实现选择,而不是应用架构的必然选择。你能选择用POJOs或local EJBs来实现业务接口，却不会影响调用代码。 <br>??h. Spring帮助你解决许多问题而无需使用EJB。Spring能提供一种EJB的替换物，它们适用于许多web应用。例如，Spring能使用AOP提供声明性事务管理而不通过EJB容器，如果你仅仅需要与单个数据库打交道，甚至不需要一个JTA实现。 <br>? i. ?Spring为数据存取提供了一个一致的框架,不论是使用的是JDBC还是O/R mapping产品（如Hibernate）。 <br>Spring确实使你能通过最简单可行的解决办法来解决你的问题。而这是有有很大价值的。<br><br>?缺点：使用人数不多、jsp中要写很多代码、控制器过于灵活，缺少一个公用控制器 
<img src ="http://www.blogjava.net/xixidabao/aggbug/110605.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-14 10:38 <a href="http://www.blogjava.net/xixidabao/archive/2007/04/14/110605.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>设计模式：用Java动态代理实现AOP </title><link>http://www.blogjava.net/xixidabao/archive/2007/04/08/109208.html</link><dc:creator>JAVA之路</dc:creator><author>JAVA之路</author><pubDate>Sun, 08 Apr 2007 02:55:00 GMT</pubDate><guid>http://www.blogjava.net/xixidabao/archive/2007/04/08/109208.html</guid><description><![CDATA[<table width="100%" align=center>
    <tbody>
        <tr>
            <td class=title align=middle>设计模式：用Java动态代理实现AOP </td>
        </tr>
        <tr>
            <td align=middle><a href="http://www.itisedu.com/"><u><font color=#800080>http://www.itisedu.com</font></u></a>&nbsp;&nbsp;&nbsp;2006-12-7 15:08:52&nbsp;&nbsp;&nbsp;<a href="http://www.itisedu.com/"><u><font color=#800080>中科永联</font></u></a> </td>
        </tr>
        <tr>
            <td align=left>[关键字]设计模式 Java 动态 代理 AOP </td>
        </tr>
        <tr>
            <td>目前整个开发社区对<a href="http://www.itisedu.com/phrase/200604231341385.html" target=_new><u><font color=#0000ff>AOP</font></u></a>(Aspect&nbsp;Oriented&nbsp;Programing)推崇备至，也涌现出大量支持AOP的优秀<a href="http://www.itisedu.com/phrase/200604241001145.html" target=_new><u><font color=#0000ff>Framework</font></u></a>,--Spring,&nbsp;<a href="http://www.itisedu.com/phrase/200605111438435.html" target=_new><u><font color=#0000ff>JAC</font></u></a>,&nbsp;<a href="http://www.itisedu.com/phrase/200605111343075.html" target=_new><u><font color=#0000ff>Jboss</font></u></a>&nbsp;AOP&nbsp;等等。AOP似乎一时之间成了潮流。Java初学者不禁要发出感慨，<a href="http://www.itisedu.com/phrase/200604240956125.html" target=_new><u><font color=#0000ff>OOP</font></u></a>还没有学通呢，又来AOP。本文不是要在理论上具体阐述何为AOP,&nbsp;为何要进行AOP&nbsp;.&nbsp;要详细了解学习AOP可以到它老家http://aosd.net去瞧瞧。这里只是意图通过一个简单的例子向初学者展示一下如何来进行AOP. <br><br>　　为了简单起见，例子没有没有使用任何第三方的AOP&nbsp;Framework,&nbsp;而是利用Java语言本身自带的动态代理功能来实现AOP.&nbsp; <br><br>　　让我们先回到AOP本身，AOP主要应用于日志记录，性能统计，安全控制,事务处理等方面。它的主要意图就要将日志记录，性能统计，安全控制等等代码从商业逻辑代码中清楚的划分出来，我们可以把这些行为一个一个单独看作系统所要解决的问题，就是所谓的面向问题的编程(不知将AOP译作面向问题的编程是否欠妥)。通过对这些行为的分离，我们希望可以将它们独立地配置到商业方法中，而要改变这些行为也不需要影响到商业方法代码。&nbsp; <br><br>　　假设系统由一系列的BusinessObject所完成业务逻辑功能，系统要求在每一次业务逻辑处理时要做日志记录。这里我们略去具体的业务逻辑代码。&nbsp; <br><br>public&nbsp;interface&nbsp;BusinessInterface&nbsp;{&nbsp; <br>　public&nbsp;void&nbsp;processBusiness();&nbsp; <br>}&nbsp; <br><br>public&nbsp;<a href="http://www.itisedu.com/phrase/200604231359565.html" target=_new><u><font color=#0000ff>class</font></u></a>&nbsp;BusinessObject&nbsp;implements&nbsp;BusinessInterface&nbsp;{&nbsp; <br>　private&nbsp;Logger&nbsp;logger&nbsp;=&nbsp;Logger.getLogger(this.getClass().getName());&nbsp; <br>　public&nbsp;void&nbsp;processBusiness(){&nbsp; <br>　　try&nbsp;{&nbsp; <br>　　　logger.info("start&nbsp;to&nbsp;processing...");&nbsp; <br>　　　//business&nbsp;logic&nbsp;here.&nbsp; <br>　　　System.out.println(&#8220;here&nbsp;is&nbsp;business&nbsp;logic&#8221;);&nbsp; <br>　　　logger.info("end&nbsp;processing...");&nbsp; <br>　　}&nbsp;catch&nbsp;(Exception&nbsp;e){&nbsp; <br>　　　logger.info("exception&nbsp;happends...");&nbsp; <br>　　　//exception&nbsp;handling&nbsp; <br>　　}&nbsp; <br>　}&nbsp; <br>}&nbsp; <br><br>　　这里处理商业逻辑的代码和日志记录代码混合在一起，这给日后的维护带来一定的困难，并且也会造成大量的代码重复。完全相同的log代码将出现在系统的每一个BusinessObject中。&nbsp; <br><br>按照AOP的思想，我们应该把日志记录代码分离出来。要将这些代码分离就涉及到一个问题，我们必须知道商业逻辑代码何时被调用，这样我们好插入日志记录代码。一般来说要截获一个方法，我们可以采用回调方法或者动态代理。动态代理一般要更加灵活一些，目前多数的AOP&nbsp;Framework也大都采用了动态代理来实现。这里我们也采用动态代理作为例子。&nbsp; <br><br>　　<a href="http://www.itisedu.com/phrase/200604181646475.html" target=_new><u><font color=#0000ff>JDK</font></u></a>1.2以后提供了动态代理的支持，<a href="http://www.itisedu.com/phrase/200604232224305.html" target=_new><u><font color=#0000ff>程序</font></u></a>员通过实现java.lang.reflect.InvocationHandler接口提供一个执行处理器，然后通过java.lang.reflect.Proxy得到一个代理<a href="http://www.itisedu.com/phrase/200603090845215.html" target=_new><u><font color=#0000ff>对象</font></u></a>，通过这个代理对象来执行商业方法,在商业方法被调用的同时，执行处理器会被自动调用。&nbsp; <br><br>　　有了JDK的这种支持，我们所要做的仅仅是提供一个日志处理器。&nbsp; <br><br>public&nbsp;class&nbsp;LogHandler&nbsp;implements&nbsp;InvocationHandler&nbsp;{&nbsp; <br><br>　private&nbsp;Logger&nbsp;logger&nbsp;＝&nbsp;Logger.getLogger(this.getClass().getName());&nbsp; <br>　　private&nbsp;<a href="http://www.itisedu.com/phrase/200604231338435.html" target=_new><u><font color=#0000ff>Object</font></u></a>&nbsp;delegate;&nbsp; <br>　　public&nbsp;LogHandler(Object&nbsp;delegate){&nbsp; <br>　　　this.delegate&nbsp;=&nbsp;delegate;&nbsp; <br>　　}&nbsp; <br><br>　public&nbsp;Object&nbsp;invoke(Object&nbsp;proxy,&nbsp;Method&nbsp;method,&nbsp;Object[]&nbsp;args)&nbsp;throws&nbsp;Throwable&nbsp;{&nbsp; <br>　　Object&nbsp;o&nbsp;=&nbsp;null;&nbsp; <br>　　try&nbsp;{&nbsp; <br>　　　logger.info("method&nbsp;stats..."&nbsp;＋&nbsp;method);&nbsp; <br>　　　o&nbsp;=&nbsp;method.invoke(delegate,args);&nbsp; <br>　　　logger.info("method&nbsp;ends..."&nbsp;+&nbsp;method);&nbsp; <br>　　}&nbsp;catch&nbsp;(Exception&nbsp;e){&nbsp; <br>　　　logger.info("Exception&nbsp;happends...");&nbsp; <br>　　　//excetpion&nbsp;handling.&nbsp; <br>　　}&nbsp; <br>　　return&nbsp;o;&nbsp; <br>　}&nbsp; <br>}&nbsp; <br><br>　　现在我们可以把BusinessObject里面的所有日志处理代码全部去掉了。&nbsp; <br><br>public&nbsp;class&nbsp;BusinessObject&nbsp;implements&nbsp;BusinessInterface&nbsp;{&nbsp; <br><br>　private&nbsp;Logger&nbsp;logger&nbsp;=&nbsp;Logger.getLogger(this.getClass().getName());&nbsp; <br>　public&nbsp;void&nbsp;processBusiness(){&nbsp; <br>　　//business&nbsp;processing&nbsp; <br>　　System.out.println(&#8220;here&nbsp;is&nbsp;business&nbsp;logic&#8221;);&nbsp; <br>　}&nbsp; <br>}&nbsp; <br><br>　　<a href="http://www.itisedu.com/phrase/200603082208195.html" target=_new><u><font color=#0000ff>客户端</font></u></a>调用商业方法的代码如下： <br><br>BusinessInterface&nbsp;businessImp&nbsp;=&nbsp;new&nbsp;BusinessObject();&nbsp; <br><br>InvocationHandler&nbsp;handler&nbsp;=&nbsp;new&nbsp;LogHandler(businessImp);&nbsp; <br><br>BusinessInterface&nbsp;proxy&nbsp;=&nbsp;(BusinessInterface)&nbsp;Proxy.newProxyInstance(&nbsp; <br>　businessImp.getClass().getClassLoader(),&nbsp; <br>　businessImp.getClass().getInterfaces(),&nbsp; <br>　handler);&nbsp; <br><br>proxy.processBusiness();&nbsp; <br><br>　　程序输出如下：&nbsp; <br><br>INFO:&nbsp;method&nbsp;stats...&nbsp; <br>here&nbsp;is&nbsp;business&nbsp;logic&nbsp; <br>INFO:&nbsp;method&nbsp;ends...&nbsp; <br><br>　　至此我们的第一次小尝试算是完成了。可以看到，采用AOP之后，日志记录和业务逻辑代码完全分开了，以后要改变日志记录的话只需要修改日志记录处理器就行了，而<a href="http://www.itisedu.com/phrase/200603091835065.html" target=_new><u><font color=#0000ff>业务对象</font></u></a>本身（BusinessObject）无需做任何修改。并且这个日志记录不会造成重复代码了，所有的商业处理对象都可以重用这个日志处理器。&nbsp; <br><br>　　当然在实际应用中，这个例子就显得太粗糙了。由于JDK的动态代理并没有直接支持一次注册多个InvocationHandler，那么我们对业务处理方法既要日志记录又要性能统计时，就需要自己做一些变通了。一般我们可以自己定义一个Handler接口，然后维护一个队列存放所有Handler,&nbsp;当InvocationHandler被触发的时候我们依次调用自己的Handler。所幸的是目前几乎所有的AOP&nbsp;Framework都对这方面提供了很好的支持.这里推荐大家使用Spring。 </td>
        </tr>
        <tr>
            <td align=right>来源：赛迪网论坛 </td>
        </tr>
        <tr>
            <td align=middle>中科永联高级技术培训中心本着技术交流、共享精神，部分信息资料为网上收集，如果本页内容侵犯了您的版权，请立刻通知我们，我们将在1个工作日内作出妥善处理，并向您致以诚挚的歉意。 </td>
        </tr>
    </tbody>
</table>
<img src ="http://www.blogjava.net/xixidabao/aggbug/109208.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-08 10:55 <a href="http://www.blogjava.net/xixidabao/archive/2007/04/08/109208.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>模式与J2EE </title><link>http://www.blogjava.net/xixidabao/archive/2007/04/08/109205.html</link><dc:creator>JAVA之路</dc:creator><author>JAVA之路</author><pubDate>Sun, 08 Apr 2007 02:42:00 GMT</pubDate><guid>http://www.blogjava.net/xixidabao/archive/2007/04/08/109205.html</guid><description><![CDATA[<table width="100%" align=center>
    <tbody>
        <tr>
            <td class=title align=middle>模式与J2EE </td>
        </tr>
        <tr>
            <td align=middle><a href="http://www.itisedu.com/"><u><font color=#0000ff>http://www.itisedu.com</font></u></a>&nbsp;&nbsp;&nbsp;2006-5-12 15:56:28&nbsp;&nbsp;&nbsp;<a href="http://www.itisedu.com/"><u><font color=#0000ff>中科永联</font></u></a> </td>
        </tr>
        <tr>
            <td align=left>[关键字]模式 J2EE </td>
        </tr>
        <tr>
            <td>
            <p>
            <p><font face=Verdana></font></p>
            <font face=Verdana><br>信息工程是以当前数据系统为基础，在一个企业或企业的主要部门，关于建设<a href="http://www.itisedu.com/phrase/200603011147495.html" target=_new><u><font color=#0000ff>信息系统</font></u></a>的规 划、分析、设计和构成的一整套相互关联的正规化、自动化的技术应用。
            <p>&#160;</p>
            <p>--- J<a href="http://www.itisedu.com/phrase/200603091620485.html" target=_new><u><font color=#0000ff>AM</font></u></a><a href="http://www.itisedu.com/phrase/200604231411155.html" target=_new><u><font color=#0000ff>ES</font></u></a> Martin&nbsp; </p>
            <p>&nbsp;&nbsp;&nbsp; 正如上面信息工程的创始人James Martin为信息工程的概念所做定义<a href="http://www.itisedu.com/phrase/200603090857555.html" target=_new><u><font color=#0000ff>类</font></u></a>似，<a href="http://www.itisedu.com/phrase/200603061709535.html" target=_new><u><font color=#0000ff>模式</font></u></a>(<a href="http://www.itisedu.com/phrase/200604231320535.html" target=_new><u><font color=#0000ff>pattern</font></u></a>s)的创始人建筑师Chri<a href="http://www.itisedu.com/phrase/200604231411575.html" target=_new><u><font color=#0000ff>ST</font></u></a>opher Alexander在&lt;模式语言，1977、1979&gt;一书中对模式的概念进行了如下描述(附注：书名后面的年份代表在各个不同时期的作品，下面形式同上)：<br>每一个模式描述了一个在我们周围不断重复发生的问题，以及该问题的解决方案的核心。这样，你就能一次又一次的使用该解决方案而不必做重复劳动。每个模式是由三部分组成的一个规则，这个规则描述特定环境、问题和解决方案之间的关系。简单的说，没有一个模式是独立的实体，每个模式都存在着相互支持，但支持的程度不同：大的模式可以内嵌小的模式，同等层次的模式并列存在，而小的模式被嵌入到大的模式之中。 <br>--- Christopher Alexander&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; 模式的概念在<a href="http://www.itisedu.com/phrase/200604232134205.html" target=_new><u><font color=#0000ff>软件</font></u></a>行业被采用以后，得到的广泛的发展，现在已经存在许多种<a href="http://www.itisedu.com/phrase/200603051002565.html" target=_new><u><font color=#0000ff>类型</font></u></a>的模式应用，其中比较有名的箸作有：<a href="http://www.itisedu.com/phrase/200603061811045.html" target=_new><u><font color=#0000ff>GoF</font></u></a>(Erich <a href="http://www.itisedu.com/phrase/200604230903435.html" target=_new><u><font color=#0000ff>GA</font></u></a>mma、Richard Helm、Ralph Johnson和John Vliss<a href="http://www.itisedu.com/phrase/200604261459505.html" target=_new><u><font color=#0000ff>IDE</font></u></a>s四人，简称：Gang of Four[GoF])的&lt;<a href="http://www.itisedu.com/phrase/200603061631585.html" target=_new><u><font color=#0000ff>设计模式</font></u></a>，1995&gt;，Martin Fowler的&lt;分析模式，1997&gt;，Frank Buschmann等人的&lt;<a href="http://www.itisedu.com/phrase/200603122156385.html" target=_new><u><font color=#0000ff>体系结构</font></u></a>模式，1996、2000&gt;、Jim O.Coplien、Niel Harrison等人的&lt;编程模式，1995、1996、1998、1999&gt;和Deepak Alur等人的&lt;<a href="http://www.itisedu.com/phrase/200603091447335.html" target=_new><u><font color=#0000ff>J2EE</font></u></a>核心模式，2001&gt;等，其中最具影响的是GoF的&lt;设计模式&gt;一书，书中详细讨论了三种类型，共23种模式。好的设计源于工作中经验的积累，当设计使用标准的模板以模式的方式进行交流时，模式就成了交流和重用的强大机制，并且可以改善设计和开发软件的方式。模式可以帮助我们在一个特定的环境里整理并记录已知的可重现的问题及解决方案，并且通过模式来与他人交流这些知识，这些模式可以解决在不同环境中重复出现的问题。模式可以使设计重复使用，重复使用已知的解决方案可以缩短设计和开发应用的周期，有效的使用模式，可以使我们远离重复投资的怪圈。模式的关键在于简单性和可重现性。<br>&nbsp;&nbsp;&nbsp; 举一个模式应用的简单示例。例如，在你的便携式<a href="http://www.itisedu.com/phrase/200604231234155.html" target=_new><u><font color=#0000ff>电脑</font></u></a>上运行一个进程中的<a href="http://www.itisedu.com/phrase/200603090845215.html" target=_new><u><font color=#0000ff>对象</font></u></a>，并且这些对象需要和运行在另一进程中的别的对象通信，也许这一进程并不在你的便携式电脑上，而在别的地方。你又不想让系统中的对象担心如何找寻网上的其他对象或者执行<a href="http://www.itisedu.com/phrase/200604241405415.html" target=_new><u><font color=#0000ff>远程过程调用</font></u></a>。这时，可以使用代理(Proxy模式，详见GoF的&lt;设计模式&gt;一书)模式来解决这个问题，你能做的事就是为这个远程对象在你的本地过程中建立一个代理对象，该代理对象和远程对象具有相同的接口。你的本地对象利用通常处理过程中的<a href="http://www.itisedu.com/phrase/200603090938465.html" target=_new><u><font color=#0000ff>消息</font></u></a>发送来和代理交谈。这时代理对象负责把消息传送给实在对象，而不管实在对象位于何处。<br>&nbsp;&nbsp;&nbsp; 由于下面要讲的Java 2平台的企业版(J2EE)应用模式中很多用到了设计模式与<a href="http://www.itisedu.com/phrase/200603121222205.html" target=_new><u><font color=#0000ff>重构</font></u></a>(<a href="http://www.itisedu.com/phrase/200604232047545.html" target=_new><u><font color=#0000ff>Refactoring</font></u></a>)的概念，所以在此有必要再概要介绍一下重构的概念。重构已经被证明可以阻止软件的腐朽和衰败，关于重构方面的有名箸作当然首推是Martin Fowler所写的&lt;重构，1999&gt;一书了，书中详细介绍了重构的七大类型，共70余种具体的重构手法，同时也指出测试机制在重构中的重要性。书中Martin Fowler对重构的概念进行了详细说明：<br>&nbsp;&nbsp;&nbsp; 重构是对软件内部结构的一种调整，目地是在不改变[软件之可察行为]的前提下，提高其可理解性，降低其修改成本。重构是一种有纪律的、经过训练的、有条不紊的<a href="http://www.itisedu.com/phrase/200604232224305.html" target=_new><u><font color=#0000ff>程序</font></u></a>整理方法，可以将整理过程中不小心引入的错误的机率降到最低，本质上说，重构就是在代码写好之后改进它的设计。重构之前，首先检查自己是否有一套可靠的测试机制，这些测试必须有我检验能力。</p>
            <p><br>--- Martin Fowler&nbsp; </p>
            <p>&nbsp;&nbsp;&nbsp; 建立于Java编程语言和Java技术基础之上的J2EE平台是最适用于企业级分布式环境的应用结构，它被设计为面向多层体系的结构。J2EE包含下面关键技术：Java服务器页面(Java Service Page，JSP)、<a href="http://www.itisedu.com/phrase/200603091005185.html" target=_new><u><font color=#0000ff>Servlet</font></u></a>、<a href="http://www.itisedu.com/phrase/200603091138035.html" target=_new><u><font color=#0000ff>Enterprise JavaBean</font></u></a>s(<a href="http://www.itisedu.com/phrase/200604241156485.html" target=_new><u><font color=#0000ff>EJB</font></u></a>)<a href="http://www.itisedu.com/phrase/200603302222545.html" target=_new><u><font color=#0000ff>组件</font></u></a>、<a href="http://www.itisedu.com/phrase/200604261600355.html" target=_new><u><font color=#0000ff>Java消息服务</font></u></a>(<a href="http://www.itisedu.com/phrase/200604261607125.html" target=_new><u><font color=#0000ff>Java Message Service</font></u></a>，<a href="http://www.itisedu.com/phrase/200604261605045.html" target=_new><u><font color=#0000ff>JMS</font></u></a>)、<a href="http://www.itisedu.com/phrase/200604151904545.html" target=_new><u><font color=#0000ff>JDBC</font></u></a>和Java命名与目录接口(Java Naming and <a href="http://www.itisedu.com/phrase/200604231343545.html" target=_new><u><font color=#0000ff>DI</font></u></a>r<a href="http://www.itisedu.com/phrase/200604222051415.html" target=_new><u><font color=#0000ff>EC</font></u></a>tory Interface，JNDI)。由于J2EE平台是<a href="http://www.itisedu.com/phrase/200604161254415.html" target=_new><u><font color=#0000ff>分层</font></u></a>系统，所以我们将J2EE的层次模型化，这个模型使得我们将职责逻辑地分到不同的层中，共分了五个层次：客户层、表示层、业务层、集成层和资源层。因为客户层和资源层并不是J2EE平台直接关注的问题，所以后面介绍的15个J2EE应用模式全部属于上面五层中的中间三层，其中表示层模式包含与Servlet和JSP技术相关的模式、业务层模式包含与EJB技术有关的模式、集成层模式包含与JMS和J<a href="http://www.itisedu.com/phrase/200604231245475.html" target=_new><u><font color=#0000ff>DB</font></u></a>C有关的模式。具体模式可参看下面表格：</p>
            <p>表一：表示层模式
            <table id=AutoNumber1 style="BORDER-COLLAPSE: collapse" borderColor=#111111 cellSpacing=0 cellPadding=0 width="89%" border=1>
                <tbody>
                    <tr>
                        <td align=middle width="50%"><strong>模式名</strong></td>
                        <td align=middle width="50%"><strong>简单描述</strong></td>
                    </tr>
                    <tr>
                        <td width="50%">截取过滤器(Intercepting Filter) </td>
                        <td width="50%">促进请求的预先处理和后处理</td>
                    </tr>
                    <tr>
                        <td width="50%">前端控制器(Front Controller) </td>
                        <td width="50%">提供请求处理的集中控制器</td>
                    </tr>
                    <tr>
                        <td width="50%"><a href="http://www.itisedu.com/phrase/200603141659315.html" target=_new><u><font color=#0000ff>视图</font></u></a>助手(View Helper) </td>
                        <td width="50%">把与表示层格式化无关的逻辑封装到助手组件</td>
                    </tr>
                    <tr>
                        <td width="50%">复合视图(Comp<a href="http://www.itisedu.com/phrase/200604232131175.html" target=_new><u><font color=#0000ff>OS</font></u></a>ite View) </td>
                        <td width="50%">从原子的子组件创建一个聚集视图</td>
                    </tr>
                    <tr>
                        <td width="50%">工作者服务(Service To Worker) </td>
                        <td width="50%">合并分发者组件、前端控制器和视图助手模式</td>
                    </tr>
                    <tr>
                        <td width="50%">分发者视图(Dispatcher View) </td>
                        <td width="50%">合并分发者组件、前端控制器和视图助手模式，把许多动作推迟到视图处理</td>
                    </tr>
                </tbody>
            </table>
            <br><br>表二：业务层模式<br>
            <table id=AutoNumber2 style="BORDER-COLLAPSE: collapse" borderColor=#111111 cellSpacing=0 cellPadding=0 width="90%" border=1>
                <tbody>
                    <tr>
                        <td align=middle width="50%"><strong>模式名</strong></td>
                        <td align=middle width="50%"><strong>简单描述</strong></td>
                    </tr>
                    <tr>
                        <td width="50%">业务委托(Business Delegate) </td>
                        <td width="50%">把表示层和服务层分隔开，并且提供服务的外观和代理接口</td>
                    </tr>
                    <tr>
                        <td width="50%">值对象(Value <a href="http://www.itisedu.com/phrase/200604231338435.html" target=_new><u><font color=#0000ff>object</font></u></a>) </td>
                        <td width="50%">通过减少网络对话，以加速层之间的数据交换</td>
                    </tr>
                    <tr>
                        <td width="50%">会话外观(Session Facade) </td>
                        <td width="50%">隐藏<a href="http://www.itisedu.com/phrase/200603091835065.html" target=_new><u><font color=#0000ff>业务对象</font></u></a>复性，集中化<a href="http://www.itisedu.com/phrase/200603110944215.html" target=_new><u><font color=#0000ff>工作流</font></u></a>处理</td>
                    </tr>
                    <tr>
                        <td width="50%">复合实体(Composite Entity) </td>
                        <td width="50%">通过把参数相关的对象分组进单个实体bean，表示设计粗粒度实体bean的最好经验</td>
                    </tr>
                    <tr>
                        <td width="50%">值对象组装器(Value Object <a href="http://www.itisedu.com/phrase/200604232104015.html" target=_new><u><font color=#0000ff>AS</font></u></a>sembler) </td>
                        <td width="50%">把来自多个数据源的值对象组装成一个复合值对象</td>
                    </tr>
                    <tr>
                        <td width="50%">值列表处理器(Value List Handler) </td>
                        <td width="50%">管理查询执行、结果缓冲、以及结果处理</td>
                    </tr>
                    <tr>
                        <td width="50%">服务定位器(Service Locator) </td>
                        <td width="50%">封装业务服务查找和创建的复杂性，定位业务服务工厂</td>
                    </tr>
                </tbody>
            </table>
            <br><br>表三：集成层模式<br>
            <table id=AutoNumber3 style="BORDER-COLLAPSE: collapse" borderColor=#111111 cellSpacing=0 cellPadding=0 width="91%" border=1>
                <tbody>
                    <tr>
                        <td align=middle width="50%"><strong>模式名</strong></td>
                        <td align=middle width="50%"><strong>简单描述</strong></td>
                    </tr>
                    <tr>
                        <td width="50%"><a href="http://www.itisedu.com/phrase/200604241352355.html" target=_new><u><font color=#0000ff>数据访问对象</font></u></a>(Data Access Object) </td>
                        <td width="50%">抽象数据源，提供对数据的透明访问</td>
                    </tr>
                    <tr>
                        <td width="50%">服务激发器(Service Activator) </td>
                        <td width="50%">加速EJB组件的异步处理</td>
                    </tr>
                </tbody>
            </table>
            </p>
            <p>&nbsp;&nbsp;&nbsp; 由于J2EE模式众多，篇幅有限，这里只概要介绍其中的一种应用模式 - 集成层的数据访问对象(<a href="http://www.itisedu.com/phrase/200604162200335.html" target=_new><u><font color=#0000ff>DAO</font></u></a>)模式，有兴趣的读者可以参看下面参考文献中的资料。<br>数据访问对象模式</p>
            <p>&nbsp;数据访问对象模式</p>
            <p>1、问题<br>&nbsp;&nbsp;&nbsp; 根据数据源不同，数据访问也不同。根据存储的类型(关系<a href="http://www.itisedu.com/phrase/200602271218062.html" target=_new><u><font color=#0000ff>数据库</font></u></a>、<a href="http://www.itisedu.com/phrase/200603101726185.html" target=_new><u><font color=#0000ff>面向对象</font></u></a>数据库等)和供应商不同，持久性存储(比如数据库)的访问差别也很大。当业务组件(如会话bean)或表示组件(如助手组件)需要访问某数据源时，它们可以使用合适的<a href="http://www.itisedu.com/phrase/200604241228185.html" target=_new><u><font color=#0000ff>API</font></u></a>来获得连接性，以及操作该数据源。但是在这些组件中包含连接性和数据访问代码会引入这些组件及数据源实现之间的紧密耦合。组件中这类代码依赖性使应用程序从某种数据源迁移到其它种类的数据源将变得非常麻烦和困难，当数据源变化时，组件也需要改变，以便于能够处理新类型的数据源。</p>
            <p>2、解决方案<br>&nbsp;&nbsp;&nbsp; 使用数据访问对象(DAO)来抽象和封装所有对数据源的访问。DAO管理着与数据源的连接以便于检索和存储数据，DAO实现了用来操作数据源的访问机制。依赖于DAO的业务组件为其<a href="http://www.itisedu.com/phrase/200603082208195.html" target=_new><u><font color=#0000ff>客户端</font></u></a>使用DAO提供了更简单的接口，DAO完全向客户端隐藏了数据源实现细节。由于当低层数据源实现变化时，DAO向客户端提供的接口不会变化，所以该模式允许DAO调整到不同的存储模式，而不会影响其客户端或业务组件。重要的是，DAO充当组件和数据源之间的适配器。</p>
            <p>3、实现策略<br>&nbsp;&nbsp;&nbsp; 通过调整抽象工厂(Abstract Factory)模式和工厂方法(Factory Method，这二个创建型模式的实现详情可参看GoF的&lt;设计模式&gt;一书)模式，DAO模式可以达到很高的灵活度。 </p>
            <p>当低层存储不会随着实现变化而变化时，可以使用工厂方法模式来实现该策略，以产生应用程序需要的大量DAO，如下面<a href="http://www.itisedu.com/phrase/200603071659325.html" target=_new><u><font color=#0000ff>类图</font></u></a>1所示。 <br>当低层存储随着实现的变化而变化时，策略可以通过使用抽象工厂模式而实现。抽象工厂可以基于工厂方法实现而创建，并可使用工厂方法实现，该策略提供一个DAO的抽象工厂对象，其中该对象可以构造多种类型的具体的DAO工厂，每个工厂支持一种不同类型的持久性存储实现。一旦你获取某特定实现的具体DAO工厂，你可以使用它来生成该实现中所支持和实现的DAO，如下面类图2所示。 </p>
            <p><img src="http://www.itisedu.com/manage/Upload/image/2006512155455670.jpg" border=0><br>&nbsp;</p>
            <p>4、应用<br>&nbsp;&nbsp;&nbsp; 当数据访问代码被直接嵌入到有其他不相关职责的某类中时，就会使修改变的十分困难。这时可以采用分离数据访问代码的解决方案，将数据访问代码抽取到一个新类中，并且把该新类逻辑或者物理地移动到离数据源比较近的位置，这样可以增强模块性和可重用性，如下面图3所示。具体作法可以使用提炼类(Extract <a href="http://www.itisedu.com/phrase/200604231359565.html" target=_new><u><font color=#0000ff>Class</font></u></a>，一种重构手法，细节可参看Martin的&lt;重构&gt;一书)方法创建一个新类，并将原来类中把数据访问代码移动到这个新的数据访问对象(DAO)类，使用这个新的DAO对象从控制器类中访问数据。<br>&nbsp;&nbsp;&nbsp; 示例：持久性逻辑被嵌入到一个使用新DAO对象管理的持久性的某企业新DAO对象中，把持久性代码和该企业新DAO对象代码结合起来会创建脆弱的、紧密耦合的代码。当持久性代码是该企业新DAO对象的一部分时，对该持久性存储的任何改动都要求更改该新DAO对象的持久性代码。这种耦合对企业新DAO对象代码维护会带来负面的影响。下面图4为运用分离数据访问对象方法对其进行重构改进后的结果。</p>
            <p><img src="http://www.itisedu.com/manage/Upload/image/2006512155535250.jpg" border=0></p>
            <p>&nbsp;&nbsp;&nbsp; 在15个J2EE模式中，每个模式都作用于设计模式和构架模式之间的某些方面。每个模式不是孤立存在的，需要其它模式的支持才能更加体现其含义和用处，为了最大限度的用好模式，还需要充分理解模式之间的关系。 </p>
            <p>&nbsp;参考文献 </p>
            <p>系统分析员教程 --- 罗晓沛等箸 <br>设计模式：可复用面向对象软件的元素 --- 李英军等译 <br>重构-改善既有代码的设计 --- 侯捷等译 <br>J2EE核心模式 --- 牛志奇等译 <br><a href="http://www.itisedu.com/phrase/200602271429302.html" target=_new><u><font color=#0000ff>UML</font></u></a>精粹(第二版) --- 徐家福译</p>
            </font></td>
        </tr>
    </tbody>
</table>
<img src ="http://www.blogjava.net/xixidabao/aggbug/109205.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-08 10:42 <a href="http://www.blogjava.net/xixidabao/archive/2007/04/08/109205.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hibernate二级缓存攻略</title><link>http://www.blogjava.net/xixidabao/archive/2007/04/08/109196.html</link><dc:creator>JAVA之路</dc:creator><author>JAVA之路</author><pubDate>Sun, 08 Apr 2007 02:04:00 GMT</pubDate><guid>http://www.blogjava.net/xixidabao/archive/2007/04/08/109196.html</guid><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<div id=contitle>
<h1>Hibernate二级缓存攻略</h1>
</div>
<div id=conauthor><span>2006-10-27 15:59 </span><span>作者： AreYouOK </span><span>出处： JAVAEYE </span><span>责任编辑：<a title=向本编辑提问 href="http://comments.yesky.com/t/%B7%BD%D6%DB/6,324/2612396.shtml" target=_blank>方舟</a> </span></div>
<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 很多人对二级缓存都不太了解，或者是有错误的认识，我一直想写一篇文章介绍一下hibernate的二级缓存的，今天终于忍不住了。 <br><br>　　我的经验主要来自hibernate2.1版本，基本原理和3.0、3.1是一样的，请原谅我的顽固不化。 <br><br>　　hibernate的session提供了一级缓存，每个session，对同一个id进行两次load，不会发送两条sql给数据库，但是session关闭的时候，一级缓存就失效了。<br><br>　　二级缓存是SessionFactory级别的全局缓存，它底下可以使用不同的缓存类库，比如ehcache、oscache等，需要设置hibernate.cache.provider_class，我们这里用ehcache，在2.1中就是 hibernate.cache.provider_class=net.sf.hibernate.cache.EhCacheProvider如果使用查询缓存，加上hibernate.cache.use_query_cache=true<br><br>　　缓存可以简单的看成一个Map，通过key在缓存里面找value。<br><br>　　<strong>Class的缓存</strong> <br><br>　　对于一条记录，也就是一个PO来说，是根据ID来找的，缓存的key就是ID，value是POJO。无论list，load还是iterate，只要读出一个对象，都会填充缓存。但是list不会使用缓存，而iterate会先取数据库select id出来，然后一个id一个id的load，如果在缓存里面有，就从缓存取，没有的话就去数据库load。假设是读写缓存，需要设置： <br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>
    <tbody>
        <tr>
            <td>＜cache usage="read-write"/＞ </td>
        </tr>
    </tbody>
</table>
<br>　　如果你使用的二级缓存实现是ehcache的话，需要配置ehcache.xml <br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>
    <tbody>
        <tr>
            <td>＜cache name="com.xxx.pojo.Foo" maxElementsInMemory="500" eternal="false" timeToLiveSeconds="7200" timeToIdleSeconds="3600" overflowToDisk="true" /＞ </td>
        </tr>
    </tbody>
</table>
<br>　　其中eternal表示缓存是不是永远不超时，timeToLiveSeconds是缓存中每个元素（这里也就是一个POJO）的超时时间，如果eternal="false"，超过指定的时间，这个元素就被移走了。timeToIdleSeconds是发呆时间，是可选的。当往缓存里面put的元素超过500个时，如果overflowToDisk="true"，就会把缓存中的部分数据保存在硬盘上的临时文件里面。 <br><br>　　每个需要缓存的class都要这样配置。如果你没有配置，hibernate会在启动的时候警告你，然后使用defaultCache的配置，这样多个class会共享一个配置。 <br><br>　　当某个ID通过hibernate修改时，hibernate会知道，于是移除缓存。 <br><br>　　这样大家可能会想，同样的查询条件，第一次先list，第二次再iterate，就可以使用到缓存了。实际上这是很难的，因为你无法判断什么时候是第一次，而且每次查询的条件通常是不一样的，假如数据库里面有100条记录，id从1到100，第一次list的时候出了前50个id，第二次iterate的时候却查询到30至70号id，那么30-50是从缓存里面取的，51到70是从数据库取的，共发送1+20条sql。所以我一直认为iterate没有什么用，总是会有1+N的问题。 <br><br>　　（题外话：有说法说大型查询用list会把整个结果集装入内存，很慢，而iterate只select id比较好，但是大型查询总是要分页查的，谁也不会真的把整个结果集装进来，假如一页20条的话，iterate共需要执行21条语句，list虽然选择若干字段，比iterate第一条select id语句慢一些，但只有一条语句，不装入整个结果集hibernate还会根据数据库方言做优化，比如使用mysql的limit，整体看来应该还是list快。） <br><br>　　如果想要对list或者iterate查询的结果缓存，就要用到查询缓存了<br><br>　　<strong>查询缓存 </strong><br><br>　　首先需要配置hibernate.cache.use_query_cache=true <br><br>　　如果用ehcache，配置ehcache.xml，注意hibernate3.0以后不是net.sf的包名了：<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>
    <tbody>
        <tr>
            <td>＜cache name="net.sf.hibernate.cache.StandardQueryCache" <br>maxElementsInMemory="50" eternal="false" timeToIdleSeconds="3600" <br>timeToLiveSeconds="7200" overflowToDisk="true"/＞ <br>＜cache name="net.sf.hibernate.cache.UpdateTimestampsCache" <br>maxElementsInMemory="5000" eternal="true" overflowToDisk="true"/＞ </td>
        </tr>
    </tbody>
</table>
<br>　　然后 <br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>
    <tbody>
        <tr>
            <td>query.setCacheable(true);//激活查询缓存 <br>query.setCacheRegion("myCacheRegion");//指定要使用的cacheRegion，可选 </td>
        </tr>
    </tbody>
</table>
<br>　　第二行指定要使用的cacheRegion是myCacheRegion，即你可以给每个查询缓存做一个单独的配置，使用setCacheRegion来做这个指定，需要在ehcache.xml里面配置它： <br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>
    <tbody>
        <tr>
            <td>＜cache name="myCacheRegion" maxElementsInMemory="10" eternal="false" timeToIdleSeconds="3600" timeToLiveSeconds="7200" overflowToDisk="true" /＞ </td>
        </tr>
    </tbody>
</table>
<br>　　如果省略第二行，不设置cacheRegion的话，那么会使用上面提到的标准查询缓存的配置，也就是：net.sf.hibernate.cache.StandardQueryCache<br><br>　　对于查询缓存来说，缓存的key是根据hql生成的sql，再加上参数，分页等信息（可以通过日志输出看到，不过它的输出不是很可读，最好改一下它的代码）。 <br><br>　　比如hql： <br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>
    <tbody>
        <tr>
            <td>from Cat c where c.name like ? </td>
        </tr>
    </tbody>
</table>
<br>　　生成大致如下的sql： <br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>
    <tbody>
        <tr>
            <td>select * from cat c where c.name like ? </td>
        </tr>
    </tbody>
</table>
<br>　　参数是"tiger%"，那么查询缓存的key*大约*是这样的字符串（我是凭记忆写的，并不精确，不过看了也该明白了）： <br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>
    <tbody>
        <tr>
            <td>select * from cat c where c.name like ? , parameter:tiger% </td>
        </tr>
    </tbody>
</table>
<br>　　这样，保证了同样的查询、同样的参数等条件下具有一样的key。 <br><br>　　现在说说缓存的value，如果是list方式的话，value在这里并不是整个结果集，而是查询出来的这一串ID。也就是说，不管是list方法还是iterate方法，第一次查询的时候，它们的查询方式很它们平时的方式是一样的，list执行一条sql，iterate执行1+N条，多出来的行为是它们填充了缓存。但是到同样条件第二次查询的时候，就都和iterate的行为一样了，根据缓存的key去缓存里面查到了value，value是一串id，然后在到class的缓存里面去一个一个的load出来。这样做是为了节约内存。 <br><br>　　可以看出来，查询缓存需要打开相关类的class缓存。list和iterate方法第一次执行的时候，都是既填充查询缓存又填充class缓存的。 <br>这里还有一个很容易被忽视的重要问题，即打开查询缓存以后，即使是list方法也可能遇到1+N的问题！相同条件第一次list的时候，因为查询缓存中找不到，不管class缓存是否存在数据，总是发送一条sql语句到数据库获取全部数据，然后填充查询缓存和class缓存。但是第二次执行的时候，问题就来了，如果你的class缓存的超时时间比较短，现在class缓存都超时了，但是查询缓存还在，那么list方法在获取id串以后，将会一个一个去数据库load！因此，class缓存的超时时间一定不能短于查询缓存设置的超时时间！如果还设置了发呆时间的话，保证class缓存的发呆时间也大于查询的缓存的生存时间。这里还有其他情况，比如class缓存被程序强制evict了，这种情况就请自己注意了。<br><br>　　另外，如果hql查询包含select字句，那么查询缓存里面的value就是整个结果集了。<br><br>　　当hibernate更新数据库的时候，它怎么知道更新哪些查询缓存呢？ <br><br>　　hibernate在一个地方维护每个表的最后更新时间，其实也就是放在上面net.sf.hibernate.cache.UpdateTimestampsCache所指定的缓存配置里面。 <br><br>　　当通过hibernate更新的时候，hibernate会知道这次更新影响了哪些表。然后它更新这些表的最后更新时间。每个缓存都有一个生成时间和这个缓存所查询的表，当hibernate查询一个缓存是否存在的时候，如果缓存存在，它还要取出缓存的生成时间和这个缓存所查询的表，然后去查找这些表的最后更新时间，如果有一个表在生成时间后更新过了，那么这个缓存是无效的。 <br><br>　　可以看出，只要更新过一个表，那么凡是涉及到这个表的查询缓存就失效了，因此查询缓存的命中率可能会比较低。<br><br><strong>Collection缓存 <br><br></strong>　　需要在hbm的collection里面设置：<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>
    <tbody>
        <tr>
            <td>＜cache usage="read-write"/＞ </td>
        </tr>
    </tbody>
</table>
<br>　　假如class是Cat，collection叫children，那么ehcache里面配置 <br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>
    <tbody>
        <tr>
            <td>＜cache name="com.xxx.pojo.Cat.children" <br>maxElementsInMemory="20" eternal="false" timeToIdleSeconds="3600" timeToLiveSeconds="7200" <br>overflowToDisk="true" /＞ </td>
        </tr>
    </tbody>
</table>
<br>　　Collection的缓存和前面查询缓存的list一样，也是只保持一串id，但它不会因为这个表更新过就失效，一个collection缓存仅在这个collection里面的元素有增删时才失效。 <br><br>　　这样有一个问题，如果你的collection是根据某个字段排序的，当其中一个元素更新了该字段时，导致顺序改变时，collection缓存里面的顺序没有做更新。<br><br>　　<strong>缓存策略</strong> <br><br>　　只读缓存（read-only）：没有什么好说的 <br><br>　　读/写缓存（read-write）:程序可能要的更新数据 <br><br>　　不严格的读/写缓存（nonstrict-read-write）：需要更新数据，但是两个事务更新同一条记录的可能性很小，性能比读写缓存好 <br>事务缓存（transactional）：缓存支持事务，发生异常的时候，缓存也能够回滚，只支持jta环境，这个我没有怎么研究过<br><br>　　读写缓存和不严格读写缓存在实现上的区别在于，读写缓存更新缓存的时候会把缓存里面的数据换成一个锁，其他事务如果去取相应的缓存数据，发现被锁住了，然后就直接取数据库查询。 <br><br>　　在hibernate2.1的ehcache实现中，如果锁住部分缓存的事务发生了异常，那么缓存会一直被锁住，直到60秒后超时。 <br><br>　　不严格读写缓存不锁定缓存中的数据。 使用二级缓存的前置条件。<br><br>　　你的hibernate程序对数据库有独占的写访问权，其他的进程更新了数据库，hibernate是不可能知道的。你操作数据库必需直接通过hibernate，如果你调用存储过程，或者自己使用jdbc更新数据库，hibernate也是不知道的。hibernate3.0的大批量更新和删除是不更新二级缓存的，但是据说3.1已经解决了这个问题。 <br><br>　　这个限制相当的棘手，有时候hibernate做批量更新、删除很慢，但是你却不能自己写jdbc来优化，很郁闷吧。 <br><br>　　SessionFactory也提供了移除缓存的方法，你一定要自己写一些JDBC的话，可以调用这些方法移除缓存，这些方法是： <br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>
    <tbody>
        <tr>
            <td>void evict(Class persistentClass) <br>Evict all entries from the second-level cache. <br>void evict(Class persistentClass, Serializable id) <br>Evict an entry from the second-level cache. <br>void evictCollection(String roleName) <br>Evict all entries from the second-level cache. <br>void evictCollection(String roleName, Serializable id) <br>Evict an entry from the second-level cache. <br>void evictQueries() <br>Evict any query result sets cached in the default query cache region. <br>void evictQueries(String cacheRegion) <br>Evict any query result sets cached in the named query cache region. </td>
        </tr>
    </tbody>
</table>
<br>　　不过我不建议这样做，因为这样很难维护。比如你现在用JDBC批量更新了某个表，有3个查询缓存会用到这个表，用evictQueries(String cacheRegion)移除了3个查询缓存，然后用evict(Class persistentClass)移除了class缓存，看上去好像完整了。不过哪天你添加了一个相关查询缓存，可能会忘记更新这里的移除代码。如果你的jdbc代码到处都是，在你添加一个查询缓存的时候，还知道其他什么地方也要做相应的改动吗？<br><br>　　<strong>总结</strong>： <br><br>　　不要想当然的以为缓存一定能提高性能，仅仅在你能够驾驭它并且条件合适的情况下才是这样的。hibernate的二级缓存限制还是比较多的，不方便用jdbc可能会大大的降低更新性能。在不了解原理的情况下乱用，可能会有1+N的问题。不当的使用还可能导致读出脏数据。 <br>如果受不了hibernate的诸多限制，那么还是自己在应用程序的层面上做缓存吧。 <br><br>　　在越高的层面上做缓存，效果就会越好。就好像尽管磁盘有缓存，数据库还是要实现自己的缓存，尽管数据库有缓存，咱们的应用程序还是要做缓存。因为底层的缓存它并不知道高层要用这些数据干什么，只能做的比较通用，而高层可以有针对性的实现缓存，所以在更高的级别上做缓存，效果也要好些吧。<br>
<img src ="http://www.blogjava.net/xixidabao/aggbug/109196.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-08 10:04 <a href="http://www.blogjava.net/xixidabao/archive/2007/04/08/109196.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>J2EE 全面简介</title><link>http://www.blogjava.net/xixidabao/archive/2006/09/11/69038.html</link><dc:creator>JAVA之路</dc:creator><author>JAVA之路</author><pubDate>Mon, 11 Sep 2006 13:22:00 GMT</pubDate><guid>http://www.blogjava.net/xixidabao/archive/2006/09/11/69038.html</guid><description><![CDATA[
		<table cellspacing="0" cellpadding="0" width="760" align="center" border="0">
				<tbody>
						<tr>
								<td class="title" valign="center" align="middle" height="56">
										<b>
												<font color="#ff0000" size="3">J2EE 全面简介<br /><!-- #EndEditable --></font>
										</b>
								</td>
						</tr>
						<tr>
								<td class="formtitle" align="middle" height="40">
										<!-- #BeginEditable "2" -->作者：刘湛 (jeru@163.net) 武汉大学信息与计算科学系学士 选自：Matrix-与Java共舞<!-- #EndEditable --></td>
						</tr>
				</tbody>
		</table>
		<table height="65" cellspacing="0" cellpadding="0" width="760" align="center" border="0">
				<tbody>
						<tr>
								<td class="content" height="65">
										<!-- #BeginEditable "3" -->
										<table class="content" width="77%" align="center" border="0">
												<tbody>
														<tr>
																<td class="content" valign="top">
																		<span class="myp11">
																				<font id="zoom">
																				</font>
																		</span>
																		<span class="p11b">
																		</span>
																		<p>
																				<strong>J2EE 全面简介</strong>
																				<br />本文从五个方面对J2EE进行了比较全面的介绍。从J2EE的概念说起，到它的优势，到J2EE典型的四层模型，和它的框架结构，最后是J2EE十三种核心技术的一个简介。本文分门别类的对J2EE中的服务，组件，层次，容器，API都做了比较详细的介绍，相信看完此文，读者会对J2EE有一个更清晰的认识。 </p>
																		<p>
																				<strong>一. J2EE的概念</strong>
																				<br />目前，Java 2平台有3个版本，它们是适用于小型设备和智能卡的Java 2平台Micro版（Java 2 Platform Micro Edition，J2ME）、适用于桌面系统的Java 2平台标准版（Java 2 Platform Standard Edition，J2SE）、适用于创建服务器应用程序和服务的Java2平台企业版（Java 2 Platform Enterprise Edition J2EE）。<br />J2EE是一种利用Java 2平台来简化企业解决方案的开发、部署和管理相关的复杂问题的体系结构。J2EE技术的基础就是核心Java平台或Java 2平台的标准版，J2EE不仅巩固了标准版中的许多优点，例如"编写一次、随处运行"的特性、方便存取数据库的JDBC API、CORBA技术以及能够在Internet应用中保护数据的安全模式等等，同时还提供了对 EJB（Enterprise JavaBeans）、Java Servlets API、JSP（Java Server Pages）以及XML技术的全面支持。其最终目的就是成为一个能够使企业开发者大幅缩短投放市场时间的<br />体系结构。<br />J2EE体系结构提供中间层集成框架用来满足无需太多费用而又需要高可用性、高可靠性以及可扩展性的应用的需求。通过提供统一的开发平台，J2EE降低了开发多层应用的费用和复杂性，同时提供对现有应用程序集成强有力支持，完全支持Enterprise JavaBeans，有良好的向导支持打包和部署应用，添加目录支持，增强了安全机制，提高了性能。</p>
																		<p>
																				<strong>二. J2EE的优势</strong>
																				<br />J2EE为搭建具有可伸缩性、灵活性、易维护性的商务系统提供了良好的机制:<br />保留现存的IT资产: 由于企业必须适应新的商业需求，利用已有的企业信息系统方面的投资，而不是重新制定全盘方案就变得很重要。这样，一个以渐进的（而不是激进的，全盘否定的）方式建立在已有系统之上的服务器端平台机制是公司所需求的。J2EE架构可以充分利用用户原有的投资，如一些公司使用的BEA Tuxedo、IBM CICS, IBM Encina,、InpriseVisiBroker及Netscape Application Server。这之所以成为可能是因为J2EE拥有广泛的业界支持和一些重要的'企业计算'领域供应商的参与。每一个供应商都对现有的客户提供了不用废弃已有投资，进入可移植的J2EE领域的升级途径。由于基于J2EE平台的产品几乎能够在任何操作系统和硬件配置上运行，现有的操作系统和硬件也<br />能被保留使用。<br />高效的开发: J2EE允许公司把一些通用的、很繁琐的服务端任务交给中间件供应商去完成。这样开发人员可以集中精力在如何创建商业逻辑上，相应地缩短了开发时间。高级中间件供应商提供以下这些复杂的中间件服务:<br />状态管理服务 -- 让开发人员写更少的代码，不用关心如何管理状态，这样能够更快地完成程序开发。<br />持续性服务 -- 让开发人员不用对数据访问逻辑进行编码就能编写应用程序，能生成更轻巧，与数据库无关的应用程序，这种应用程序更易于开发与维护。<br />分布式共享数据对象CACHE服务 -- 让开发人员编制高性能的系统，极大提高整体部署的伸缩性。<br />支持异构环境: J2EE能够开发部署在异构环境中的可移植程序。基于J2EE的应用程序不依赖任何特定操作系统、中间件、硬件。因此设计合理的基于J2EE的程序只需开发一次就可部署到各种平台。这在典型的异构企业计算环境中是十分关键的。J2EE标准也允许客户订购与J2EE兼容的第三方的现成的组件，把他们部署到异构环境中，节省了由自己制订整个方案所需的费用。<br />可伸缩性: 企业必须要选择一种服务器端平台，这种平台应能提供极佳的可伸缩性去满足那些在他们系统上进行商业运作的大批新客户。基于J2EE平台的应用程序可被部署到各种操作系统上。例如可被部署到高端UNIX与大型机系统，这种系统单机可支持64至256个处理器。（这是NT服务器所望尘莫及的）J2EE领域的供应商提供了更为广泛的负载平衡策略。能消除系统中的瓶颈，允许多台服务器集成部署。这种部署可达数千个处理器，实现可高度伸缩的系统，满足未来商业应用的需要。<br />稳定的可用性: 一个服务器端平台必须能全天候运转以满足公司客户、合作伙伴的需要。因为INTERNET是全球化的、无处不在的，即使在夜间按计划停机也可能造成严重损失。若是意外停机，那会有灾难性后果。J2EE部署到可靠的操作环境中，他们支持长期的可用性。一些J2EE部署在WINDOWS环境中，客户也可选择健壮性能更好的操作系统如Sun Solaris、IBM OS/390。最健壮的操作系统可达到99.999%的可用性或每年只需5分钟停机时间。这是实时性很强商业系统理想的选择。</p>
																		<p>
																				<br />
																				<strong>三. J2EE 的四层模型</strong>
																				<br />J2EE使用多层的分布式应用模型，应用逻辑按功能划分为组件，各个应用组件根据他们所在的层分布在不同的机器上。事实上，sun设计J2EE的初衷正是为了解决两层模式(client/server)的弊端，在传统模式中，客户端担当了过多的角色而显得臃肿，在这种模式中，第一次部署的时候比较容易，但难于升级或改进，可伸展性也不理想，而且经常基于某种专有的协议――通常是某种数据库协议。它使得重用业务逻辑和界面逻辑非常困难。现在J2EE 的多层企业级应用模型将两层化模型中的不同层面切分成许多层。一个多层化应用能够为不同的每种服务提供一个独立的层，以下是 J2EE 典型的四层结构:<br />运行在客户端机器上的客户层组件<br />运行在J2EE服务器上的Web层组件<br />运行在J2EE服务器上的业务逻辑层组件<br />运行在EIS服务器上的企业信息系统(Enterprise information system)层软件<br />J2EE应用程序组件<br />J2EE应用程序是由组件构成的.J2EE组件是具有独立功能的软件单元，它们通过相关的类和文件组装成J2EE应用程序，并与其他组件交互。J2EE说明书中定义了以下的J2EE组件:<br />应用客户端程序和applets是客户层组件.<br />Java Servlet和JavaServer Pages(JSP)是web层组件.<br />Enterprise JavaBeans(EJB)是业务层组件.<br />客户层组件<br />J2EE应用程序可以是基于web方式的,也可以是基于传统方式的.<br />web 层组件J2EE web层组件可以是JSP 页面或Servlets.按照J2EE规范，静态的HTML页面和Applets不算是web层组件。web层可能包含某些 JavaBean 对象来处理用户输入，并把输入发送给运行在业务层上的enterprise bean 来进行处理。</p>
																		<p>业务层组件<br />业务层代码的逻辑用来满足银行，零售，金融等特殊商务领域的需要,由运行在业务层上的enterprise bean 进行处理. 下图表明了一个enterprise bean 是如何从客户端程序接收数据，进行处理(如果必要的话), 并发送到EIS 层储存的，这个过程也可以逆向进行。<br />有三种企业级的bean: 会话(session) beans, 实体(entity) beans, 和 消息驱动(message-driven) beans. 会话bean 表示与客户端程序的临时交互. 当客户端程序执行完后, 会话bean 和相关数据就会消失. 相反, 实体bean 表示数据库的表中一行永久的记录. 当客户端程序中止或服务器关闭时, 就会有潜在的服务保证实体bean 的数据得以保存.消息驱动 bean 结合了会话bean 和 JMS的消息监听器的特性, 允许一个业务层组件异步接收JMS 消息.</p>
																		<p>
																				<br />企业信息系统层<br />企业信息系统层处理企业信息系统软件包括企业基础建设系统例如企业资源计划 (ERP), 大型机事务处理, 数据库系统,和其它的遗留信息系统. 例如，J2EE 应用组件可能为了数据库连接需要访问企业信息系统</p>
																		<p>
																				<br />
																				<strong>四. J2EE 的结构</strong>
																				<br />这种基于组件，具有平台无关性的J2EE 结构使得J2EE 程序的编写十分简单，因为业务逻辑被封装成可复用的组件，并且J2EE 服务器以容器的形式为所有的组件类型提供后台服务. 因为你不用自己开发这种服务, 所以你可以集中精力解决手头的业务问题.</p>
																		<p>
																				<br />容器和服务<br />容器设置定制了J2EE服务器所提供得内在支持，包括安全，事务管理，JNDI(Java Naming and Directory Interface)寻址,远程连接等服务，以下列出最重要的几种服务：<br />J2EE安全(Security)模型可以让你配置 web 组件或enterprise bean ,这样只有被授权的用户才能访问系统资源. 每一客户属于一个特别的角色，而每个角色只允许激活特定的方法。你应在enterprise bean的布置描述中声明角色和可被激活的方法。由于这种声明性的方法，你不必编写加强安全性的规则。<br />J2EE 事务管理（Transaction Management）模型让你指定组成一个事务中所有方法间的关系，这样一个事务中的所有方法被当成一个单一的单元. 当客户端激活一个enterprise bean中的方法，容器介入一管理事务。因有容器管理事务，在enterprise bean中不必对事务的边界进行编码。要求控制分布式事务的代码会非常复杂。你只需在布置描述文件中声明enterprise bean的事务属性，而不用编写并调试复杂的代码。容器将读此文件并为你处理此enterprise bean的事务。<br />JNDI 寻址(JNDI Lookup)服务向企业内的多重名字和目录服务提供了一个统一的接口,这样应用程序组件可以访问名字和目录服务.<br />J2EE远程连接（Remote Client Connectivity）模型管理客户端和enterprise bean间的低层交互. 当一个enterprise bean创建后, 一个客户端可以调用它的方法就象它和客户端位于同一虚拟机上一样.<br />生存周期管理（Life Cycle Management）模型管理enterprise bean的创建和移除,一个enterprise bean在其生存周期中将会历经几种状态。容器创建enterprise bean，并在可用实例池与活动状态中移动他，而最终将其从容器中移除。即使可以调用enterprise bean的create及remove方法，容器也将会在后台执行这些任务。</p>
																		<p>
																				<br />数据库连接池（Database Connection Pooling）模型是一个有价值的资源。获取数据库连接是一项耗时的工作，而且连接数非常有限。容器通过管理连接池来缓和这些问题。<br />enterprise bean可从池中迅速获取连接。在bean释放连接之可为其他bean使用。<br />容器类型<br />J2EE应用组件可以安装部署到以下几种容器中去:<br />EJB 容器管理所有J2EE 应用程序中企业级bean 的执行. enterprise bean 和它们的容器运行在J2EE 服务器上.<br />Web 容器管理所有J2EE 应用程序中JSP页面和Servlet组件的执行. Web 组件和它们的容器运行在J2EE 服务器上.<br />应用程序客户端容器管理所有J2EE应用程序中应用程序客户端组件的执行. 应用程序客户端和它们的容器运行在J2EE 服务器上.<br />Applet 容器是运行在客户端机器上的web浏览器和 Java 插件的结合.<br /><br /><strong>五. J2EE的核心API与组件</strong><br />J2EE平台由一整套服务（Services）、应用程序接口（APIs）和协议构成，它对开发基于Web的多层应用提供了功能支持，下面对J2EE中的13种技术规范进行简单的描述(限于篇幅，这里只能进行简单的描述):<br />JDBC(Java Database Connectivity):<br />JDBC API为访问不同的数据库提供了一种统一的途径，象ODBC一样，JDBC对开发者屏蔽了一些细节问题，另外，JDCB对数据库的访问也具有平台无关性。<br />JNDI(Java Name and Directory Interface):<br />JNDI API被用于执行名字和目录服务。它提供了一致的模型来存取和操作企业级的资源如DNS和LDAP，本地文件系统，或应用服务器中的对象。<br /><br />EJB(Enterprise JavaBean):<br />J2EE技术之所以赢得某体广泛重视的原因之一就是EJB。它们提供了一个框架来开发和实施分布式商务逻辑，由此很显著地简化了具有可伸缩性和高度复杂的企业级应用的开发。EJB规范定义了EJB组件在何时如何与它们的容器进行交互作用。容器负责提供公用的服务，例如目录服务、事务管理、安全性、资源缓冲池以及容错性。但这里值得注意的是，EJB并不是实现J2EE的唯一途径。正是由于J2EE的开放性，使得有的厂商能够以一种和EJB平行的方式来达到同样的目的。<br />RMI(Remote Method Invoke):<br />正如其名字所表示的那样，RMI协议调用远程对象上方法。它使用了序列化方式在客户端和服务器端传递数据。RMI是一种被EJB使用的更底层的协议。<br />Java IDL/CORBA:<br />在Java IDL的支持下，开发人员可以将Java和CORBA集成在一起。 他们可以创建Java对象并使之可在CORBA ORB中展开, 或者他们还可以创建Java类并作为和其它ORB一起展开的CORBA对象的客户。后一种方法提供了另外一种途径，通过它Java可以被用于将你的新的应用和旧的系统相集成。<br />JSP(Java Server Pages):<br />JSP页面由HTML代码和嵌入其中的Java代码所组成。服务器在页面被客户端所请求以后对这些Java代码进行处理，然后将生成的HTML页面返回给客户端的浏览器。<br />Java Servlet:<br />Servlet是一种小型的Java程序，它扩展了Web服务器的功能。作为一种服务器端的应用，当被请求时开始执行，这和CGI Perl脚本很相似。Servlet提供的功能大多与JSP类似，不过实现的方式不同。JSP通常是大多数HTML代码中嵌入少量的Java代码，而servlets全部由Java写成并且生成HTML。<br />XML(Extensible Markup Language):<br />XML是一种可以用来定义其它标记语言的语言。它被用来在不同的商务过程中共享数据。<br />XML的发展和Java是相互独立的，但是，它和Java具有的相同目标正是平台独立性。通过将Java和XML的组合，您可以得到一个完美的具有平台独立性的解决方案。<br />JMS(Java Message Service):<br />MS是用于和面向消息的中间件相互通信的应用程序接口(API)。它既支持点对点的域，有支持发布/订阅(publish/subscribe)类型的域，并且提供对下列类型的支持：经认可的消息传递,事务型消息的传递，一致性消息和具有持久性的订阅者支持。JMS还提供了另一种方式来对您的应用与旧的后台系统相集成。<br />JTA(Java Transaction Architecture):<br />JTA定义了一种标准的API，应用系统由此可以访问各种事务监控。<br />JTS(Java Transaction Service):<br />JTS是CORBA OTS事务监控的基本的实现。JTS规定了事务管理器的实现方式。该事务管理器是在高层支持Java Transaction API (JTA)规范，并且在较底层实现OMG OTS specification的Java映像。JTS事务管理器为应用服务器、资源管理器、独立的应用以及通信资源管理器提供了事务服务。<br />JavaMail:<br />JavaMail是用于存取邮件服务器的API，它提供了一套邮件服务器的抽象类。不仅支持SMTP服务器，也支持IMAP服务器。<br />JTA(JavaBeans Activation Framework):<br />JavaMail利用JAF来处理MIME编码的邮件附件。MIME的字节流可以被转换成Java对象</p>
																		<p>
																				<br />参考资料：<br />《Develop n-tier application using J2EE》- Steven Gould<br />《The Business Benefits of EJB and J2EE Technologies over COM+ and Windows D<br />NA》<br />《The J2EE Tutorial》chapter overview - Monica Pawlan</p>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
<img src ="http://www.blogjava.net/xixidabao/aggbug/69038.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-09-11 21:22 <a href="http://www.blogjava.net/xixidabao/archive/2006/09/11/69038.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>J2EE宠物商店</title><link>http://www.blogjava.net/xixidabao/archive/2006/09/11/69037.html</link><dc:creator>JAVA之路</dc:creator><author>JAVA之路</author><pubDate>Mon, 11 Sep 2006 13:17:00 GMT</pubDate><guid>http://www.blogjava.net/xixidabao/archive/2006/09/11/69037.html</guid><description><![CDATA[
		<table cellspacing="0" cellpadding="0" width="760" align="center" border="0">
				<tbody>
						<tr>
								<td class="title" valign="center" align="middle" height="56">
										<b>J2EE宠物商店</b>
								</td>
						</tr>
						<tr>
								<td class="formtitle" align="middle" height="40">
										<font size="2">
												<!-- #BeginEditable "2" -->
												<font color="#000080">作者：◇ 谷和启</font>
												<span class="myp11">
														<font id="zoom" color="#000080">  来源：CSDN</font>
												</span>
												<!-- #EndEditable -->
										</font>
								</td>
						</tr>
				</tbody>
		</table>
		<table height="65" cellspacing="0" cellpadding="0" width="760" align="center" border="0">
				<tbody>
						<tr>
								<td class="content" height="65">
										<!-- #BeginEditable "3" -->
										<table width="85%" align="center" border="0">
												<tbody>
														<tr>
																<td class="content">
																		<span class="myp11">
																				<font id="zoom">　</font>
																		</span>
																		<p>　<font color="#000000">J2EE 是Java技术在企业运算上的应用，它包含多种运算标准，如EJB组件架构、JDBC数据库运算、JMS信息传递、Java Servlets/JSP等Web组件