﻿<?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-franlk-文章分类-SPRING</title><link>http://www.blogjava.net/franlk/category/10336.html</link><description /><language>zh-cn</language><lastBuildDate>Fri, 02 Mar 2007 02:55:33 GMT</lastBuildDate><pubDate>Fri, 02 Mar 2007 02:55:33 GMT</pubDate><ttl>60</ttl><item><title>[摘录]Spring入门</title><link>http://www.blogjava.net/franlk/articles/42283.html</link><dc:creator>FRANLK 的个人空间</dc:creator><author>FRANLK 的个人空间</author><pubDate>Fri, 21 Apr 2006 02:41:00 GMT</pubDate><guid>http://www.blogjava.net/franlk/articles/42283.html</guid><wfw:comment>http://www.blogjava.net/franlk/comments/42283.html</wfw:comment><comments>http://www.blogjava.net/franlk/articles/42283.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/franlk/comments/commentRss/42283.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/franlk/services/trackbacks/42283.html</trackback:ping><description><![CDATA[摘录地址：<a href="http://www.codechina.net/resource/html/2006-04/07/150546.html">http://www.codechina.net/resource/html/2006-04/07/150546.html</a><br /><table cellspacing="1" cellpadding="4" width="100%" border="0"><tbody><tr><td valign="top"><div class="subhead"><b>Spring入门</b></div></td></tr><tr><td class="content" valign="top"><table width="200" align="right" border="0"><tbody><tr><td></td></tr></tbody></table><p>Spring是一个非常优秀的轻量级框架，通过Spring的IoC容器，我们的关注点便放到了需要实现的业务逻辑上。对AOP的支持则能让我们动态增强业务方法。编写普通的业务逻辑Bean是非常容易而且易于测试的，因为它能脱离J2EE容器（如Servlet，JSP环境）单独进行单元测试。最后的一步便是在Spring框架中将这些业务Bean以XML配置文件的方式组织起来，它们就按照我们预定的目标正常工作了！非常容易！</p><p>本文将给出一个基本的Spring入门示例，并演示如何使用Spring的AOP将复杂的业务逻辑分离到每个方面中。</p><p>1．开发环境配置<br />2．编写Bean接口及其实现<br />3．在Spring中配置Bean并获得Bean的实例<br />4．编写Advisor以增强ServiceBean<br />5．总结</p><h3>1．开发环境配置</h3><p>首先，需要正确配置Java环境。推荐安装JDK1.4.2，并正确配置环境变量：</p><p>JAVA_HOME=&lt;JDK安装目录&gt;<br />CLASSPATH=.<br />Path=%JAVA_HOME%\\bin;……</p><p>我们将使用免费的Eclipse 3.1作为IDE。新建一个Java Project，将Spring的发布包spring.jar以及commons-logging-1.0.4.jar复制到Project目录下，并在Project &gt; Properties中配置好Java Build Path：</p><p><img onmousewheel="return" alt="src=uppic/20060407/1405270.jpg" onload="javascript:resizepic(this)" border="undefined" bbimg(this)="" /></p><h3>2．编写Bean接口及其实现</h3><p>我们实现一个管理用户的业务Bean。首先定义一个ServiceBean接口，声明一些业务方法：</p><pre><font color="#0066ff">/**<br /> * Copyright_2006, Liao Xuefeng<br /> * Created on 2006-3-9<br /> * For more information, please visit: </font><a href="http://www.crackj2ee.com/"><font color="#0066ff">http://www.crackj2ee.com</font></a><br /><font color="#0066ff"> */<br />package com.crackj2ee.example.spring;</font></pre><pre><font color="#0066ff">/**<br /> * Interface of service facade.<br /> * <br /> * @author Xuefeng<br /> */<br />public interface ServiceBean {<br />    void addUser(String username, String password);<br />    void deleteUser(String username);<br />    boolean findUser(String username);<br />    String getPassword(String username);<br />}</font></pre><p>然后在MyServiceBean中实现接口：</p><pre><font color="#0066ff">/**<br /> * Copyright_2006, Liao Xuefeng<br /> * Created on 2006-3-9<br /> * <br /> * For more information, please visit: </font><a href="http://www.crackj2ee.com/"><font color="#0066ff">http://www.crackj2ee.com</font></a><br /><font color="#0066ff"> */<br />package com.crackj2ee.example.spring;</font></pre><pre><font color="#0066ff">import java.util.*;</font></pre><pre><font color="#0066ff">public class MyServiceBean implements ServiceBean {</font></pre><pre><font color="#0066ff">    private String dir;<br />    private Map map = new HashMap();</font></pre><pre><font color="#0066ff">    public void setUserDir(String dir) {<br />        this.dir = dir;<br />        System.out.println(Set user dir to:  + dir);<br />    }</font></pre><pre><font color="#0066ff">    public void addUser(String username, String password) {<br />        if(!map.containsKey(username))<br />            map.put(username, password);<br />        else<br />            throw new RuntimeException(User already exist.);<br />    }</font></pre><pre><font color="#0066ff">    public void deleteUser(String username) {<br />        if(map.remove(username)==null)<br />            throw new RuntimeException(User not exist.);<br />    }</font></pre><pre><font color="#0066ff">    public boolean findUser(String username) {<br />        return map.containsKey(username);<br />    }</font></pre><pre><font color="#0066ff">    public String getPassword(String username) {<br />        return (String)map.get(username);<br />    }<br />}</font></pre><p>为了简化逻辑，我们使用一个Map保存用户名和口令。</p><p>现在，我们已经有了一个业务Bean。要测试它非常容易，因为到目前为止，我们还没有涉及到Spring容器，也没有涉及到任何Web容器（假定这是一个Web应用程序关于用户管理的业务Bean）。完全可以直接进行Unit测试，或者，简单地写个main方法测试：</p><pre><font color="#0066ff">/**<br /> * Copyright_2006, Liao Xuefeng<br /> * Created on 2006-3-9<br /> * For more information, please visit: </font><a href="http://www.crackj2ee.com/"><font color="#0066ff">http://www.crackj2ee.com</font></a><br /><font color="#0066ff"> */<br />package com.crackj2ee.example.spring;</font></pre><pre><font color="#0066ff">public class Main {</font></pre><pre><font color="#0066ff">    public static void main(String[] args) throws Exception {<br />        ServiceBean service = new MyServiceBean();<br />        service.addUser("bill", "hello");<br />        service.addUser("tom", "goodbye");<br />        service.addUser("tracy", "morning");<br />        System.out.println("tom\'s password is: " + service.getPassword("tom"));<br />        if(service.findUser("tom")) {<br />            service.deleteUser("tom");<br />        }<br />    }<br />}</font></pre><p>执行结果：<br /><img onmousewheel="return" alt="src=uppic/20060407/1405271.jpg" onload="javascript:resizepic(this)" border="undefined" bbimg(this)="" /></p><h3>3．在Spring中配置Bean并获得Bean的实例</h3><p>我们已经在一个main方法中实现了业务，不过，将对象的生命周期交给容器管理是更好的办法，我们就不必为初始化对象和销毁对象进行硬编码，从而获得更大的灵活性和可测试性。</p><p>想要把ServiceBean交给Spring来管理，我们需要一个XML配置文件。新建一个beans.xml，放到src目录下，确保在classpath中能找到此配置文件，输入以下内容：</p><pre><font color="#0066ff">&lt;?xml version=1.0 encoding=UTF-8?&gt;<br />&lt;!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" <br /></font><a href="http://www.springframework.org/dtd/spring-beans.dtd"><font color="#0066ff">"http://www.springframework.org/dtd/spring-beans.dtd</font></a><font color="#0066ff">"&gt;<br />&lt;beans&gt;<br />    &lt;bean id="service" class="com.crackj2ee.example.spring.MyServiceBean" /&gt;<br />&lt;/beans&gt;</font></pre><p>以上XML声明了一个id为service的Bean，默认地，Spring为每个声明的Bean仅创建一个实例，并通过id来引用这个Bean。下面，我们修改main方法，让Spring来管理业务Bean：</p><pre><font color="#0066ff">/**<br /> * Copyright_2006, Liao Xuefeng<br /> * Created on 2006-3-9<br /> * For more information, please visit: </font><a href="http://www.crackj2ee.com/"><font color="#0066ff">http://www.crackj2ee.com</font></a><br /><font color="#0066ff"> */<br />package com.crackj2ee.example.spring;</font></pre><pre><font color="#0066ff">import org.springframework.beans.factory.xml.XmlBeanFactory;<br />import org.springframework.core.io.ClassPathResource;</font></pre><pre><font color="#0066ff">public class Main {</font></pre><pre><font color="#0066ff">    public static void main(String[] args) throws Exception {<br />        // init factory:<br />        <font color="#ff0000">XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource(<font color="#0066ff">"</font>beans.xml<font color="#0066ff">"</font>));</font><br />        // use service bean:<br />        ServiceBean service = (ServiceBean)factory.getBean("service");<br />        service.addUser("bill", "hello");<br />        service.addUser("tom", "goodbye");<br />        service.addUser("tracy", "morning");<br />        System.out.println("tom\'s password is \\" + service.getPassword("tom") + "\\");<br />        if(service.findUser("tom")) {<br />            service.deleteUser("tom");<br />        }<br />        // close factory:<br />        <font color="#ff0000">factory.destroySingletons();</font><br />    }<br />}</font></pre><p>执行结果：<br /> <img onmousewheel="return" alt="src=uppic/20060407/1405272.jpg" onload="javascript:resizepic(this)" border="undefined" bbimg(this)="" /></p><p>由于我们要通过main方法启动Spring环境，因此，首先需要初始化一个BeanFactory。红色部分是初始化Spring的BeanFactory的典型代码，只需要保证beans.xml文件位于classpath中。</p><p>然后，在BeanFactory中通过id查找，即可获得相应的Bean的实例，并将其适当转型为合适的接口。</p><p>接着，实现一系列业务操作，在应用程序结束前，让Spring销毁所有的Bean实例。</p><p>对比上一个版本的Main，可以看出，最大的变化是不需要自己管理Bean的生命周期。另一个好处是在不更改实现类的前提下，动态地为应用程序增加功能。</p><h3>4．编写Advisor以增强ServiceBean</h3><p>所谓AOP即是将分散在各个方法处的公共代码提取到一处，并通过类似拦截器的机制实现代码的动态织入。可以简单地想象成，在某个方法的调用前、返回前、调用后和抛出异常时，动态插入自己的代码。在弄清楚Pointcut、Advice之类的术语前，不如编写一个最简单的AOP应用来体验一下。</p><p>考虑一下通常的Web应用程序都会有日志记录，我们来编写一个LogAdvisor，对每个业务方法调用前都作一个记录：</p><pre><font color="#0066ff">/**<br /> * Copyright_2006, Liao Xuefeng<br /> * Created on 2006-3-9<br /> * For more information, please visit: </font><a href="http://www.crackj2ee.com/"><font color="#0066ff">http://www.crackj2ee.com</font></a><br /><font color="#0066ff"> */<br />package com.crackj2ee.example.spring;</font></pre><pre><font color="#0066ff">import java.lang.reflect.Method;<br />import org.springframework.aop.MethodBeforeAdvice;</font></pre><pre><font color="#0066ff">public class LogAdvisor implements MethodBeforeAdvice {<br />    public void before(Method m, Object[] args, Object target) throws Throwable {<br />        System.out.println("[Log] " + target.getClass().getName() + ". "+ m.getName() + "()");<br />    }<br />}</font></pre><p>然后，修改beans.xml：</p><pre><font color="#0066ff">&lt;?xml version=1.0 encoding=UTF-8?&gt;<br />&lt;!DOCTYPE beans PUBLIC -//SPRING//DTD BEAN//EN <br /></font><a href="http://www.springframework.org/dtd/spring-beans.dtd"><font color="#0066ff">http://www.springframework.org/dtd/spring-beans.dtd</font></a><font color="#0066ff">&gt;</font></pre><pre><font color="#0066ff">&lt;beans&gt;<br />    &lt;bean id="serviceTarget" class="com.crackj2ee.example.spring.MyServiceBean" /&gt;</font></pre><pre><font color="#0066ff">    &lt;bean id="logAdvisor" class="com.crackj2ee.example.spring.LogAdvisor" /&gt;</font></pre><pre><font color="#0066ff">    &lt;bean id="service" class="org.springframework.aop.framework.ProxyFactoryBean"&gt;<br />        &lt;property name="proxyInterfaces"&gt;&lt;value&gt;com.crackj2ee.example.spring.ServiceBean&lt;/value&gt;&lt;/property&gt;<br />        &lt;property name="target"&gt;&lt;ref local="serviceTarget/&gt;&lt;/property&gt;<br />        &lt;property name="interceptorNames"&gt;<br />            &lt;list&gt;<br />                &lt;value&gt;logAdvisor&lt;/value&gt;<br />            &lt;/list&gt;<br />        &lt;/property&gt;<br />    &lt;/bean&gt;<br />&lt;/beans&gt;</font></pre><p>注意观察修改后的配置文件，我们使用了一个ProxyFactoryBean作为service来与客户端打交道，而真正的业务Bean即MyServiceBean被声明为serviceTarget并作为参数对象传递给ProxyFactoryBean，proxyInterfaces指定了返回的接口类型。对于客户端而言，将感觉不出任何变化，但却动态加入了LogAdvisor，关系如下：<br /> <img onmousewheel="return" alt="src=uppic/20060407/1405273.jpg" onload="javascript:resizepic(this)" border="undefined" bbimg(this)="" /></p><p>运行结果如下，可以很容易看到调用了哪些方法：<br /> <img onmousewheel="return" alt="src=uppic/20060407/1405274.jpg" onload="javascript:resizepic(this)" border="undefined" bbimg(this)="" /></p><p>要截获指定的某些方法也是可以的。下面的例子将修改getPassword()方法的返回值：</p><pre><font color="#0066ff">/**<br /> * Copyright_2006, Liao Xuefeng<br /> * Created on 2006-3-9<br /> * For more information, please visit: </font><a href="http://www.crackj2ee.com/"><font color="#0066ff">http://www.crackj2ee.com</font></a><br /><font color="#0066ff"> */<br />package com.crackj2ee.example.spring;</font></pre><pre><font color="#0066ff">import org.aopalliance.intercept.MethodInterceptor;<br />import org.aopalliance.intercept.MethodInvocation;</font></pre><pre><font color="#0066ff">public class PasswordAdvisor implements MethodInterceptor {<br />    public Object invoke(MethodInvocation invocation) throws Throwable {<br />        Object ret = invocation.proceed();<br />        if(ret==null)<br />            return null;<br />        String password = (String)ret;<br />        StringBuffer encrypt = new StringBuffer(password.length());<br />        for(int i=0; i&lt;password.length(); i++)<br />            encrypt.append("\'*\'");<br />        return encrypt.toString();<br />    }<br />}</font></pre><p>这个PasswordAdvisor将截获ServiceBean的getPassword()方法的返回值，并将其改为***。继续修改beans.xml：</p><pre><font color="#0066ff">&lt;?xml version=1.0 encoding=UTF-8?&gt;<br />&lt;!DOCTYPE beans PUBLIC -//SPRING//DTD BEAN//EN <br /></font><a href="http://www.springframework.org/dtd/spring-beans.dtd"><font color="#0066ff">http://www.springframework.org/dtd/spring-beans.dtd</font></a><font color="#0066ff">&gt;<br />&lt;beans&gt;<br />    &lt;bean id="serviceTarget" class="com.crackj2ee.example.spring.MyServiceBean" /&gt;</font></pre><pre><font color="#0066ff">    &lt;bean id="logAdvisor" class="com.crackj2ee.example.spring.LogAdvisor" /&gt;</font></pre><pre><font color="#0066ff">    &lt;bean id="passwordAdvisorTarget" class="com.crackj2ee.example.spring.PasswordAdvisor" /&gt;</font></pre><pre><font color="#0066ff">    &lt;bean id="passwordAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"&gt;<br />        &lt;property name="advice"&gt;<br />            &lt;ref local="passwordAdvisorTarget"/&gt;<br />        &lt;/property&gt;<br />        &lt;property name="patterns"&gt;<br />            &lt;list&gt;<br />                &lt;value&gt;.*getPassword&lt;/value&gt;<br />            &lt;/list&gt;<br />        &lt;/property&gt;<br />    &lt;/bean&gt;</font></pre><pre><font color="#0066ff">    &lt;bean id="service" class="org.springframework.aop.framework.ProxyFactoryBean"&gt;<br />        &lt;property name="proxyInterfaces"&gt;&lt;value&gt;com.crackj2ee.example.spring.ServiceBean&lt;/value&gt;&lt;/property&gt;<br />        &lt;property name="target"&gt;&lt;ref local="serviceTarget"/&gt;&lt;/property&gt;<br />        &lt;property name="interceptorNames"&gt;<br />            &lt;list&gt;<br />                &lt;value&gt;logAdvisor&lt;/value&gt;<br />                &lt;value&gt;passwordAdvisor&lt;/value&gt;<br />            &lt;/list&gt;<br />        &lt;/property&gt;<br />    &lt;/bean&gt;<br />&lt;/beans&gt;</font></pre><p>利用Spring提供的一个RegexMethodPointcutAdvisor可以非常容易地指定要截获的方法。运行结果如下，可以看到返回结果变为******：<br /> <img onmousewheel="return" alt="src=uppic/20060407/1405275.jpg" onload="javascript:resizepic(this)" border="undefined" bbimg(this)="" /></p><p>还需要继续增强ServiceBean？我们编写一个ExceptionAdvisor，在业务方法抛出异常时能做一些处理：</p><pre><font color="#0066ff">/**<br /> * Copyright_2006, Liao Xuefeng<br /> * Created on 2006-3-9<br /> * For more information, please visit: </font><a href="http://www.crackj2ee.com/"><font color="#0066ff">http://www.crackj2ee.com</font></a><br /><font color="#0066ff"> */<br />package com.crackj2ee.example.spring;</font></pre><pre><font color="#0066ff">import org.springframework.aop.ThrowsAdvice;</font></pre><pre><font color="#0066ff">public class ExceptionAdvisor implements ThrowsAdvice {<br />    public void afterThrowing(RuntimeException re) throws Throwable {<br />        System.out.println("[Exception]"  + re.getMessage());<br />    }<br />}</font></pre><p>将此Advice添加到beans.xml中，然后在业务Bean中删除一个不存在的用户，故意抛出异常：</p><pre><font color="#0066ff">service.deleteUser("not-exist");</font></pre><p>再次运行，注意到ExceptionAdvisor记录下了异常：<br /> <img onmousewheel="return" alt="src=uppic/20060407/1405276.jpg" onload="javascript:resizepic(this)" border="undefined" bbimg(this)="" /></p><h3>5．总结</h3><p>利用Spring非常强大的IoC容器和AOP功能，我们能实现非常灵活的应用，让Spring容器管理业务对象的生命周期，利用AOP增强功能，却不影响业务接口，从而避免更改客户端代码。</p><p>为了实现这一目标，必须始终牢记：面向接口编程。而Spring默认的AOP代理也是通过Java的代理接口实现的。虽然Spring也可以用CGLIB实现对普通类的代理，但是，业务对象只要没有接口，就会变得难以扩展、维护和测试。</p></td></tr></tbody></table><img src ="http://www.blogjava.net/franlk/aggbug/42283.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/franlk/" target="_blank">FRANLK 的个人空间</a> 2006-04-21 10:41 <a href="http://www.blogjava.net/franlk/articles/42283.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[摘录]Learn Spring in spring(四) </title><link>http://www.blogjava.net/franlk/articles/42279.html</link><dc:creator>FRANLK 的个人空间</dc:creator><author>FRANLK 的个人空间</author><pubDate>Fri, 21 Apr 2006 02:35:00 GMT</pubDate><guid>http://www.blogjava.net/franlk/articles/42279.html</guid><wfw:comment>http://www.blogjava.net/franlk/comments/42279.html</wfw:comment><comments>http://www.blogjava.net/franlk/articles/42279.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/franlk/comments/commentRss/42279.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/franlk/services/trackbacks/42279.html</trackback:ping><description><![CDATA[摘录地址：<a href="http://www.codechina.net/resource/html/2005-04/10/16122.html">http://www.codechina.net/resource/html/2005-04/10/16122.html</a><br /><table cellspacing="1" cellpadding="4" width="100%" border="0"><tbody><tr><td valign="top"><div class="subhead"><b>Learn Spring in spring(四)</b></div></td></tr><tr><td class="content" valign="top"><table width="200" align="right" border="0"><tbody><tr><td></td></tr></tbody></table>四、Spring中的事务控制<br /><br />Bromon原创　请尊重版权<br /><br />　　Spring和EJB一样，提供了两种事务管理方式：编程式和声明式。在考试系统中我们将使用声明式的事务管理，这是spring推荐的做法。使用这种方式可以体验到spring的强大便捷，而且我们无须在Dao类中编写任何特殊的代码，只需要通过配置文件就可以让普通的java类加载到事务管理中，这个意义是很重大的。<br /><br />　　Spring中进行事务管理的通常方式是利用AOP（面向切片编程）的方式，为普通java类封装事务控制，它是通过动态代理实现的，由于接口是延迟实例化的，spring在这段时间内通过拦截器，加载事务切片。原理就是这样，具体细节请参考jdk中有关动态代理的文档。本文主要讲解如何在spring中进行事务控制。<br /><br />　　动态代理的一个重要特征是，它是针对接口的，所以我们的dao要通过动态代理来让spring接管事务，就必须在dao前面抽象出一个接口，当然如果没有这样的接口，那么spring会使用CGLIB来解决问题，但这不是spring推荐的方式，我们也不做讨论。<br /><br />　　参照前面的例子，我们为StudentManager.java定义一个接口，它的内容如下：<br /><br /><div class="codeStyle"><ol><li><i><font color="#339900">/*</font></i></li><li><i><font color="#339900"> * 创建日期 2005-3-25</font></i></li><li><i><font color="#339900"> */</font></i></li><li><b><font color="#0000ff">package</font></b> org.bromon.spring.examer.student; 
</li><li></li><li><b><font color="#0000ff">import</font></b> java.util.<b><a href="http://www.codechina.net/source/jdk142/java/util/List.java.html" target="_blank"><font class="classLink" color="#0066cc"><u>List</u></font></a></b>; 
</li><li></li><li><b><font color="#0000ff">import</font></b> org.bromon.spring.examer.pojo.Student; 
</li><li></li><li><i><font color="#339900">/**</font></i></li><li><i><font color="#339900"> * @author Bromon</font></i></li><li><i><font color="#339900"> */</font></i></li><li><b><font color="#0000ff">public</font></b> <b><font color="#0000ff">interface</font></b> StudentManagerInterface 
</li><li>{ 
</li><li>    <b><font color="#0000ff">public</font></b> <b><font color="#0000ff">void</font></b> add(Student s); 
</li><li>    <b><font color="#0000ff">public</font></b> <b><font color="#0000ff">void</font></b> del(Student s); 
</li><li>    <b><font color="#0000ff">public</font></b> <b><font color="#0000ff">void</font></b> update(Student s); 
</li><li>     
</li><li>    <b><font color="#0000ff">public</font></b> <b><a href="http://www.codechina.net/source/jdk142/java/util/List.java.html" target="_blank"><font class="classLink" color="#0066cc"><u>List</u></font></a></b> loadAll(); 
</li><li>    <b><font color="#0000ff">public</font></b> Student loadById(<b><font color="#0000ff">int</font></b> id); 
</li><li>}</li></ol></div><br /><br />　　StudentManager也应该做出修改，实现该接口：<br /><br /><div class="codeStyle"><ol><li><b><font color="#0000ff">public</font></b> <b><font color="#0000ff">class</font></b> StudentManager <b><font color="#0000ff">extends</font></b> HibernateDaoSupport <b><font color="#0000ff">implements</font></b> StudentManagerInterface</li></ol></div><br />　　现在需要修改配置文件，用于定义Hibrenate适用的事务管理器，并且把sessionFactory注入进去，同时还需要通过注册一个DefaultTransactionAttribute对象，来指出事务策略。其中sessionFactory的定义已经在本文的第三章中说明。<br /><br />　　首先定义一个Hibernate的事务管理器，让它来管理sessionFactory：<br /><div class="codeStyle"><ol><li>&lt;bean id=<font color="#ff33ff">"transactionManager"</font> <b><font color="#0000ff">class</font></b>=<font color="#ff33ff">"org.springframework.orm.hibernate.HibernateTransactionManager"</font>&gt; 
</li><li>　&lt;property name=<font color="#ff33ff">"sessionFactory"</font>&gt; 
</li><li>　　&lt;ref bean=<font color="#ff33ff">"sessionFactory"</font>/&gt; 
</li><li>　&lt;/property&gt; 
</li><li>&lt;/bean&gt;</li></ol></div><br /><br />　　下面定义事务管理策略，我们希望把策略定义在方法这个级别上，提供最大的灵活性，本例中将add方法定义为：PROPAGATION_REQUIRES_NEW，这可以保证它将始终运行在一个事务中。<br /><br /><div class="codeStyle"><ol><li>&lt;bean id=<font color="#ff33ff">"transactionAttributeSource"</font> <b><font color="#0000ff">class</font></b>=<font color="#ff33ff">"org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource"</font>&gt; 
</li><li>　&lt;property name=<font color="#ff33ff">"properties"</font>&gt; 
</li><li>　　&lt;props&gt; 
</li><li>　　　&lt;prop key=<font color="#ff33ff">"add"</font>&gt; 
</li><li>　　　　PROPAGATION_REQUIRES_NEW 
</li><li>　　　&lt;/prop&gt; 
</li><li>　　&lt;/props&gt; 
</li><li>　&lt;/property&gt; 
</li><li>&lt;/bean&gt;</li></ol></div><br /><br />　　我们不仅可以为add方法定义事务策略,还可以定义事务隔离程度和回滚策略,他们以逗号隔开,比如我们的add事务可以定义为:<br /><br /><div class="codeStyle"><ol><li>&lt;prop key=<font color="#ff33ff">"add"</font>&gt; 
</li><li>    PROPAGATION_REQUIRES_NEW,-ExamerException 
</li><li>&lt;/prop&gt;</li></ol></div><br /><br />　　这个事务策略表示add方法将会独占一个事务，当事务过程中产生ExamerException异常，事务会回滚。<br /><br />　　Add/update/del都是写入方法，对于select（读取）方法，我们可以指定较为复杂的事务策略，比如对于loadAll()方法：<br /><br />　 
<div class="codeStyle"><ol><li>&lt;prop key=”loadAll”&gt; 
</li><li>　　PROPAGATION_SUPPORTS,ISOLATION_READ_COMMITED,readOnly 
</li><li>　&lt;/prop&gt;</li></ol></div><br /><br />　　该事务的含义为，loadAll方法支持事务，不会读取未提交的数据，它的数据为只读（可提高执行速度）。<br /><br />　　如你所见，我们的StudentManagerInterface接口中还有一个loadById(int id)方法，也许我们将来还会有很多的loadByXXXX的方法，难道要一一为他们指定事务策略？太烦人了，他们应该和loadAll()一样，所以我们可以使用通配符，定义所有的loadXXXX方法：<br /><br />     
<div class="codeStyle"><ol><li>&lt;prop key=”load*”&gt; 
</li><li>        PROPAGATION_SUPPORTS,ISOLATION_READ_COMMITED,readOnly 
</li><li>    &lt;/prop&gt;</li></ol></div><br /><br />　现在可以定义事务管理器：<br /><div class="codeStyle"><ol><li>&lt;bean id=<font color="#ff33ff">"studentManager"</font> <b><font color="#0000ff">class</font></b>=<font color="#ff33ff">"org.springframework.transaction.interceptor.TransactionProxyFactoryBean"</font>&gt; 
</li><li>　&lt;property name=<font color="#ff33ff">"target"</font>&gt; 
</li><li>　　&lt;ref bean=<font color="#ff33ff">"studentManager"</font>/&gt; 
</li><li>　&lt;/property&gt; 
</li><li>　&lt;property name=<font color="#ff33ff">"transactionManager"</font>&gt; 
</li><li>　　&lt;ref bean=<font color="#ff33ff">"transactionManager"</font>/&gt; 
</li><li>　&lt;/property&gt; 
</li><li>　&lt;property name=<font color="#ff33ff">"transactionAttributeSource"</font>&gt; 
</li><li>　　&lt;ref bean=<font color="#ff33ff">"transactionAttributeSource"</font>/&gt; 
</li><li>　&lt;/property&gt; 
</li><li>&lt;/bean&gt;</li></ol></div><br />　　这个bean的外观是一个接口(StudentManagerInterface)，我们指出了它的具体实现(studentManager)，而且为它绑定了事务策略。在客户端使用的时候，获得对象是StudentManagerInterface，所有的操作都是针对这个接口的。测试代码并没有改变，我们虽然修改了很多地方，加入了事务控制，但是客户端并没有受到影响，这也体现了spring的一些优势。测试代码如下：<br /><br />　　 
<div class="codeStyle"><ol><li><b><font color="#0000ff">public</font></b> <b><font color="#0000ff">void</font></b> testAdd()  
</li><li>    { 
</li><li>        ApplicationContext ctx=<b><font color="#0000ff">new</font></b> ClassPathXmlApplicationContext(<font color="#ff33ff">"springConfig.xml"</font>); 
</li><li>        StudentManager sm=(StudentManager)ctx.getBean(<font color="#ff33ff">"studentManager"</font>); 
</li><li>         
</li><li>        Student s=<b><font color="#0000ff">new</font></b> Student(); 
</li><li>        s.setId(1); 
</li><li>        s.setName(<font color="#ff33ff">"bromon"</font>); 
</li><li>        s.setPassword(<font color="#ff33ff">"123"</font>); 
</li><li>        s.setGrade(1); 
</li><li>        s.setSex(0); 
</li><li>         
</li><li>        sm.add(s); 
</li><li>}</li></ol></div><br />  通过以上的代码可以看出，spring可以简单的把普通的java class纳入事务管理，声明性的事务操作起来也很容易。有了spring之后，声明性事务不再是EJB独有，我们不必为了获得声明性事务的功能而去忍受EJB带来的种种不便。<br /><br />  我所使用的mysql是不支持事务的，你可以更换使用PostgreSQL，有了spring+hibernate，更换db并不像以前那样恐怖了，步骤很简单：<br /><br />1、    添加PostgreSQL的jdbc驱动<br />2、    修改dataSource配置，包括驱动名称、url、帐号、密码<br />3、    修改sessionFactory的数据库dailet为net.sf.hibernate.dialect.PostgreSQLDialect<br />4、    修改hbm.xml中的主键生成策略为increment<br /><br />所有的修改都在配置文件中完成，业务代码不需要任何修改，我很满意，How about u?<br /><br />附A　　pring中的所有事务策略<br /><br />　　　　PROPAGATION_MANDATORY<br />　　　　PROPAGATION_NESTED            <br />　　　　PROPAGATION_NEVER            <br />　　　　PROPAGATION_NOT_SUPPORTED<br />　　　　PROPAGATION_REQUIRED<br />　　　　PROPAGATION_REQUIRED_NEW<br />　　　　PROPAGATION_SUPPORTS<br /><br />附B　　Spring中所有的隔离策略：<br /><br />　　　　ISOLATION_DEFAULT<br />　　　　ISOLATION_READ_UNCOMMITED<br />　　　　ISOLATION_COMMITED<br />　　　　ISOLATION_REPEATABLE_READ<br />　　　　ISOLATION_SERIALIZABLE<br /></td></tr></tbody></table><img src ="http://www.blogjava.net/franlk/aggbug/42279.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/franlk/" target="_blank">FRANLK 的个人空间</a> 2006-04-21 10:35 <a href="http://www.blogjava.net/franlk/articles/42279.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[摘录]Learn Spring in spring(三) </title><link>http://www.blogjava.net/franlk/articles/42278.html</link><dc:creator>FRANLK 的个人空间</dc:creator><author>FRANLK 的个人空间</author><pubDate>Fri, 21 Apr 2006 02:34:00 GMT</pubDate><guid>http://www.blogjava.net/franlk/articles/42278.html</guid><wfw:comment>http://www.blogjava.net/franlk/comments/42278.html</wfw:comment><comments>http://www.blogjava.net/franlk/articles/42278.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/franlk/comments/commentRss/42278.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/franlk/services/trackbacks/42278.html</trackback:ping><description><![CDATA[摘录地址：<a href="http://www.codechina.net/resource/html/2005-04/10/16123.html">http://www.codechina.net/resource/html/2005-04/10/16123.html</a><br /><table cellspacing="1" cellpadding="4" width="100%" border="0"><tbody><tr><td valign="top"><div class="subhead"><b>Learn Spring in spring(三)</b></div></td></tr><tr><td class="content" valign="top"><table width="200" align="right" border="0"><tbody><tr><td></td></tr></tbody></table>三、spring中的hibernate开发<br /><br />Bromon原创 请尊重版权<br /><br />　　spring中对hibernate的支持是非常强大的，从一个简单的例子就看得出来，从这个例子中我们还将对所谓的轻量级容器做一些讨论。<br /><br />　　首先需要配置数据源，通常我们有两种方式获得Connection，一是自己编写代码获得连接，二是从JNDI环境中得到DataSource，然后产生一个Connection。无论怎样，既然是spring下面的对象，就应该注册到配置文件中。假设我们需要一个连接mysql下面一个叫做examer的数据库，手动方式的配置是：<br /><br /><div class="codeStyle"><ol><li>&lt;bean id=<font color="#ff33ff">"dataSource"</font> <b><font color="#0000ff">class</font></b>=<font color="#ff33ff">"org.apache.commons.dbcp.BasicDataSource"</font> destroy-method=<font color="#ff33ff">"close"</font>&gt; 
</li><li>　　&lt;property name=<font color="#ff33ff">"driverClassName"</font>&gt; 
</li><li>　　　　&lt;value&gt;com.mysql.jdbc.<font color="#ff0000">Driver</font>&lt;/value&gt; 
</li><li>　　&lt;/property&gt; 
</li><li>　　&lt;property name=<font color="#ff33ff">"url"</font>&gt; 
</li><li>　　　　&lt;value&gt;jdbc:mysql:<i><font color="#339900">//localhost/examer&lt;/value&gt;</font></i></li><li>　　&lt;/property&gt; 
</li><li>　　&lt;property name=<font color="#ff33ff">"username"</font>&gt; 
</li><li>　　　　&lt;value&gt;root&lt;/value&gt; 
</li><li>　　&lt;/property&gt; 
</li><li>　　&lt;property name=<font color="#ff33ff">"password"</font>&gt; 
</li><li>　　　　&lt;value&gt;&lt;/value&gt; 
</li><li>　　&lt;/property&gt; 
</li><li>&lt;/bean&gt;</li></ol></div><br /><br />　　很好读是不是？假如我们使用JNDI数据源，那么dataSource的声明就应该是：<br /><br /><div class="codeStyle"><ol><li>&lt;bean id=<font color="#ff33ff">"dataSource"</font> <b><font color="#0000ff">class</font></b>=<font color="#ff33ff">"org.springframework.jndi.JndiObjectFactoryBean"</font>&gt; 
</li><li>　　&lt;property name=<font color="#ff33ff">"jndiName"</font>&gt; 
</li><li>　　　　&lt;value&gt;java:compenvjdbcspringExamer&lt;/value&gt; 
</li><li>　　&lt;/property&gt; 
</li><li>&lt;/bean&gt;</li></ol></div><br />　　你需要在JNDI环境中绑定一个名为jdbc/springExamer的东西，这段代码才有实际意义。另外需要提醒的是，所有的bean声明，它的id必须是唯一的。<br /><br />　　在本系统中，数据库操作是被hibernate封装起来的，所以dataSource是不需要注入到具体的逻辑类中，它只会被注给hibernate的sessionFactory。<br /><br />　　按照常规思路，我们需要在spring中注册hibernate的sessionFactory，它应该是我们自己编写的一个类，获得dataSource，返回sessionFactory，其他的逻辑类通过这个sessionFactory获得session进行数据库操作。<br /><br />　　但是我们有另外一种选择，spring直接提供了对sessionFactory的封装，你只需要注册一个spring自己的类，给它提供必须的属性，它会返回一个org.springframework.orm.hibernate.HibernateTemplate，这个类封装了add、del等操作，它的封装程度相当高，通过它来编写hibernate应用非常简单。但是问题出来了，我们该如何选择？<br /><br />　　表面上看，使用spring自己的库无疑更加简单，但是请注意，spring是一个轻量级的框架，所谓轻量级，一个重要特征就是无侵入性，也就是你使用这套框架，不会被它绑定，被spring管理的类，应该不需要使用它的接口和抽象类，这样你的系统不会对spring产生依赖。但是如果你使用了spring封装的方式去操作hibernate，就必须继承org.springframework.orm.hibernate.support.HibernateDaoSupport类，这导致了绑定。所以做这样的选择是有点痛苦的，如果有一天spring框架不存在了，你的代码怎么升级维护？具体问题只能具体分析，在我们的应用中，完全使用了spring封装的HibernateTemplate，它太好用了，所以容易上瘾。<br /><br />　　假设我们有一张student表，结构很简单：<br /><br />　　 
<div class="codeStyle"><ol><li>id　　　　　　自动增长 
</li><li>　　name　　　　　varchar(40) 
</li><li>　　password　　　varchar(32) 
</li><li>　　grade    　　　　<b><font color="#0000ff">int</font></b>(4)　　　　　　年级 
</li><li>　　sex　　　　　<b><a href="http://www.codechina.net/source/jdk142/java/lang/Boolean.java.html" target="_blank"><font class="classLink" color="#0066cc"><u>Boolean</u></font></a></b>　　　　　　性别(true为男，false为女)</li></ol></div><br />　　设计一个Student类来映射这张表：<br /><br /><div class="codeStyle"><ol><li><i><font color="#339900">/*</font></i></li><li><i><font color="#339900"> * 创建日期 2005-3-17</font></i></li><li><i><font color="#339900"> */</font></i></li><li><b><font color="#0000ff">package</font></b> net.bromon.spring.examer.pojo; 
</li><li></li><li><i><font color="#339900">/**</font></i></li><li><i><font color="#339900"> * @author Bromon</font></i></li><li><i><font color="#339900"> */</font></i></li><li><b><font color="#0000ff">public</font></b> <b><font color="#0000ff">class</font></b> Student  
</li><li>{ 
</li><li>    <b><font color="#0000ff">private</font></b> <b><font color="#0000ff">int</font></b> id; 
</li><li>    <b><font color="#0000ff">private</font></b> <b><a href="http://www.codechina.net/source/jdk142/java/lang/String.java.html" target="_blank"><font class="classLink" color="#0066cc"><u>String</u></font></a></b> name; 
</li><li>    <b><font color="#0000ff">private</font></b> <b><a href="http://www.codechina.net/source/jdk142/java/lang/String.java.html" target="_blank"><font class="classLink" color="#0066cc"><u>String</u></font></a></b> password; 
</li><li>    <b><font color="#0000ff">private</font></b> <b><font color="#0000ff">int</font></b> grade;<i><font color="#339900">//年级</font></i></li><li>    <b><font color="#0000ff">private</font></b> <b><font color="#0000ff">boolean</font></b> sex; 
</li><li>     
</li><li>    getset方法………. 
</li><li>}</li></ol></div><br />　　编写Student.hbm.xml，让hibernate知道如何去关联student表和Student类，该文件和Student.java在同一目录：<br /><br /><div class="codeStyle"><ol><li>&lt;hibernate-mapping&gt; 
</li><li>　　&lt;<b><font color="#0000ff">class</font></b> name=<font color="#ff33ff">"net.bromon.spring.examer.pojo.Student"</font> table=<font color="#ff33ff">"student"</font>&gt; 
</li><li>　　　　&lt;id name=<font color="#ff33ff">"id"</font> column=<font color="#ff33ff">"id"</font>&gt; 
</li><li>　　　　　　&lt;generator <b><font color="#0000ff">class</font></b>=<font color="#ff33ff">"identity"</font>/&gt; 
</li><li>　　　　&lt;/id&gt; 
</li><li>         
</li><li>　　　　&lt;property name=<font color="#ff33ff">"name"</font> column=<font color="#ff33ff">"name"</font> /&gt; 
</li><li>　　　　&lt;property name=<font color="#ff33ff">"password"</font> column=<font color="#ff33ff">"password"</font> /&gt; 
</li><li>　　　　&lt;property name=<font color="#ff33ff">"grade"</font> column=<font color="#ff33ff">"grade"</font> /&gt; 
</li><li>　　　　&lt;property name=<font color="#ff33ff">"sex"</font> column=<font color="#ff33ff">"sex"</font> /&gt; 
</li><li>　　&lt;/<b><font color="#0000ff">class</font></b>&gt; 
</li><li>&lt;/hibernate-mapping&gt;</li></ol></div><br />　　然后我们可以在spring中配置sessionFactory：<br /><br /><div class="codeStyle"><ol><li>&lt;bean id=<font color="#ff33ff">"sessionFactory"</font>　<b><font color="#0000ff">class</font></b>=<font color="#ff33ff">"org.springframework.orm.hibernate.LocalSessionFactoryBean"</font>&gt; 
</li><li>　　&lt;property name=<font color="#ff33ff">"dataSource"</font>&gt; 
</li><li>　　　　&lt;ref bean=<font color="#ff33ff">"dataSource"</font>/&gt; 
</li><li>　　&lt;/property&gt; 
</li><li>         
</li><li>　　&lt;property name=<font color="#ff33ff">"hibernateProperties"</font>&gt; 
</li><li>　　　　&lt;props&gt; 
</li><li>　　　　　　&lt;prop key=<font color="#ff33ff">"hibernate.dialect"</font>&gt;net.sf.hibernate.dialect.MySQLDialect&lt;/prop&gt; 
</li><li>　　　　&lt;/props&gt; 
</li><li>　　&lt;/property&gt; 
</li><li>         
</li><li>　　&lt;property name=<font color="#ff33ff">"mappingDirectoryLocations"</font>&gt; 
</li><li>　　　　&lt;list&gt; 
</li><li>　　　　　　&lt;value&gt;classpath:/netbromonspringexamerpojo&lt;/value&gt; 
</li><li>　　　　&lt;/list&gt; 
</li><li>　　&lt;/property&gt; 
</li><li>&lt;/bean&gt;</li></ol></div><br />　　其中引用了我们之前注册过的dataSource，mappingDirectoryLocations属性指明了.hbm.xml文件在哪里路径，该文件夹下面的.hbm.xml文件会被全部加载。<br /><br />　　一切都准备就绪，现在我们要加入一个StudentManager类，来进行增删查改的操作：<br /><div class="codeStyle"><ol><li><i><font color="#339900">/*</font></i></li><li><i><font color="#339900"> * 创建日期 2005-3-17</font></i></li><li><i><font color="#339900"> */</font></i></li><li><b><font color="#0000ff">package</font></b> net.bromon.spring.examer.student; 
</li><li></li><li><b><font color="#0000ff">import</font></b> net.bromon.spring.examer.pojo.Student; 
</li><li></li><li><b><font color="#0000ff">import</font></b> org.springframework.orm.hibernate.HibernateTemplate; 
</li><li><b><font color="#0000ff">import</font></b> org.springframework.orm.hibernate.LocalSessionFactoryBean; 
</li><li><b><font color="#0000ff">import</font></b> org.springframework.orm.hibernate.support.HibernateDaoSupport; 
</li><li></li><li><i><font color="#339900">/**</font></i></li><li><i><font color="#339900"> * @author Bromon</font></i></li><li><i><font color="#339900"> */</font></i></li><li><b><font color="#0000ff">public</font></b> <b><font color="#0000ff">class</font></b> StudentManager <b><font color="#0000ff">extends</font></b> HibernateDaoSupport 
</li><li>{ 
</li><li>    <b><font color="#0000ff">private</font></b> LocalSessionFactoryBean sessionFactory; 
</li><li>    <b><font color="#0000ff">private</font></b> HibernateTemplate ht; 
</li><li>    <b><font color="#0000ff">public</font></b> StudentManager() 
</li><li>    { 
</li><li>        <b><font color="#0000ff">this</font></b>.ht=<b><font color="#0000ff">super</font></b>.getHibernateTemplate(); 
</li><li>    } 
</li><li>     
</li><li>    <b><font color="#0000ff">public</font></b> <b><font color="#0000ff">void</font></b> add(Student s) 
</li><li>    {    
</li><li>        ht.save(s);<i><font color="#339900">//插入一条数据只需要这一行代码</font></i></li><li>    } 
</li><li>}</li></ol></div><br />　　该类只演示了如何增加一个Student，HibernateTemplate还封装了很多有用的方法，请查阅spring文档。StudentManager中的sessionFactory是由spring注入的，但是StudentManager并没有对sessionFactory做任何的处理，这是因为所有的处理都被HibernateDaoSupport.getHibernateTemplate()封装。整个StudentManager中也看不到任何的异常处理，他们也都被基类封装了。<br /><br />　　最后一个步骤就是在spring中注册StudentManger，然后向它注入sessionFactory：<br /><br /><div class="codeStyle"><ol><li>&lt;bean id=<font color="#ff33ff">"studentManager"</font> <b><font color="#0000ff">class</font></b>=<font color="#ff33ff">"net.bromon.spring.examer.student.StudentManager"</font>&gt; 
</li><li>　　&lt;property name=<font color="#ff33ff">"sessionFactory"</font>&gt; 
</li><li>　　　　&lt;ref bean=<font color="#ff33ff">"sessionFactory"</font>/&gt; 
</li><li>　　&lt;/property&gt; 
</li><li>&lt;/bean&gt;</li></ol></div><br /><br />　　所有的配置都完成了，下面做单元测试：<br /><br /><div class="codeStyle"><ol><li><i><font color="#339900">/*</font></i></li><li><i><font color="#339900"> * 创建日期 2005-3-17</font></i></li><li><i><font color="#339900"> */</font></i></li><li><b><font color="#0000ff">package</font></b> net.bromon.spring.examer.student.test; 
</li><li></li><li><b><font color="#0000ff">import</font></b> java.io.<b><a href="http://www.codechina.net/source/jdk142/java/io/FileInputStream.java.html" target="_blank"><font class="classLink" color="#0066cc"><u>FileInputStream</u></font></a></b>; 
</li><li></li><li><b><font color="#0000ff">import</font></b> org.springframework.beans.factory.xml.XmlBeanFactory; 
</li><li><b><font color="#0000ff">import</font></b> org.springframework.context.ApplicationContext; 
</li><li><b><font color="#0000ff">import</font></b> org.springframework.context.support.ClassPathXmlApplicationContext; 
</li><li></li><li><b><font color="#0000ff">import</font></b> net.bromon.spring.examer.pojo.Student; 
</li><li><b><font color="#0000ff">import</font></b> net.bromon.spring.examer.student.StudentManager; 
</li><li><b><font color="#0000ff">import</font></b> junit.framework.<a href="http://www.codechina.net/source/junit3.8.1/junit/framework/TestCase.java.html" target="_blank"><font class="classLink" color="#0066cc"><u>TestCase</u></font></a>; 
</li><li></li><li><i><font color="#339900">/**</font></i></li><li><i><font color="#339900"> * @author Bromon</font></i></li><li><i><font color="#339900"> */</font></i></li><li><b><font color="#0000ff">public</font></b> <b><font color="#0000ff">class</font></b> TestStudentManager <b><font color="#0000ff">extends</font></b> <a href="http://www.codechina.net/source/junit3.8.1/junit/framework/TestCase.java.html" target="_blank"><font class="classLink" color="#0066cc"><u>TestCase</u></font></a> { 
</li><li></li><li>    <b><font color="#0000ff">public</font></b> <b><font color="#0000ff">void</font></b> testAdd()  
</li><li>    { 
</li><li>        <b><font color="#0000ff">try</font></b></li><li>        { 
</li><li>            ApplicationContext context =<b><font color="#0000ff">new</font></b> ClassPathXmlApplicationContext(<font color="#ff33ff">"springConfig.xml"</font>); 
</li><li>             
</li><li>            Student s=<b><font color="#0000ff">new</font></b> Student(); 
</li><li>            s.setName(<font color="#ff33ff">"bromon"</font>); 
</li><li>            s.setPassword(<font color="#ff33ff">"123"</font>); 
</li><li>            s.setGrade(3); 
</li><li>            s.setSex(<b><font color="#0000ff">true</font></b>); 
</li><li>             
</li><li>            ((StudentManager)context.getBean(<font color="#ff33ff">"studentManager"</font>)).add(s); 
</li><li>        }<b><font color="#0000ff">catch</font></b>(<b><a href="http://www.codechina.net/source/jdk142/java/lang/Exception.java.html" target="_blank"><font class="classLink" color="#0066cc"><u>Exception</u></font></a></b> e) 
</li><li>        { 
</li><li>            e.printStackTrace(); 
</li><li>        } 
</li><li>    } 
</li><li></li><li>}</li></ol></div><br />　　Spring已经将hibernate的操作简化到了非常高的程度，最关键的是整个开发可以由设计来驱动，如果一个团队对spring有足够的熟悉，那么完全可以由设计师规划所有的类，整理清楚类之间的关系，写成配置文件，然后编写hibernate映射文件，将数据表与pojo关联，成员就可以完全在设计方案内工作，利用spring封装好的hibernate模版，开发起来速度非常快，调试也很容易。它能够解决如何在团队内贯彻设计方案的问题。<br /><br />　　由于本文不讲解hibernate的使用，所以相关内容请查阅hibernate文档。<br /><br />下一篇：spring中的事务控制<br /></td></tr></tbody></table><img src ="http://www.blogjava.net/franlk/aggbug/42278.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/franlk/" target="_blank">FRANLK 的个人空间</a> 2006-04-21 10:34 <a href="http://www.blogjava.net/franlk/articles/42278.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[摘录]Learn Spring in spring(二)</title><link>http://www.blogjava.net/franlk/articles/42277.html</link><dc:creator>FRANLK 的个人空间</dc:creator><author>FRANLK 的个人空间</author><pubDate>Fri, 21 Apr 2006 02:33:00 GMT</pubDate><guid>http://www.blogjava.net/franlk/articles/42277.html</guid><wfw:comment>http://www.blogjava.net/franlk/comments/42277.html</wfw:comment><comments>http://www.blogjava.net/franlk/articles/42277.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/franlk/comments/commentRss/42277.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/franlk/services/trackbacks/42277.html</trackback:ping><description><![CDATA[摘录地址：<a href="http://www.codechina.net/resource/html/2005-04/10/16124.html">http://www.codechina.net/resource/html/2005-04/10/16124.html</a><br /><table cellspacing="1" cellpadding="4" width="100%" border="0"><tbody><tr><td valign="top"><div class="subhead"><b>Learn Spring in spring(二)</b></div></td></tr><tr><td class="content" valign="top"><table width="200" align="right" border="0"><tbody><tr><td></td></tr></tbody></table>二、spring管理对象的简单例子<br /><br />Bromon原创　请尊重版权<br /><br />　　任何需要交给spring管理的对象，都必须在配置文件中注册，这个过程被称为wiring，下面做一个最简单的Hello world演示，我们将要注册的类如下：<br /><br /><div class="codeStyle"><ol><li><i><font color="#339900">/*</font></i></li><li><i><font color="#339900"> * 创建日期 2005-3-22</font></i></li><li><i><font color="#339900"> */</font></i></li><li><b><font color="#0000ff">package</font></b> org.bromon.spring.test; 
</li><li></li><li><i><font color="#339900">/**</font></i></li><li><i><font color="#339900"> * @author Bromon</font></i></li><li><i><font color="#339900"> */</font></i></li><li><b><font color="#0000ff">public</font></b> <b><font color="#0000ff">class</font></b> HelloTalker  
</li><li>{ 
</li><li>    <b><font color="#0000ff">public</font></b> <b><a href="http://www.codechina.net/source/jdk142/java/lang/String.java.html" target="_blank"><font class="classLink" color="#0066cc"><u>String</u></font></a></b> greeting() 
</li><li>    { 
</li><li>        <b><font color="#0000ff">return</font></b> <font color="#ff33ff">"hello world"</font>; 
</li><li>    } 
</li><li>}</li></ol></div><br />　　然后我们来编写一个spring配置文件，文件名任意，在我这里它是springConfig.xml，需要注意的是这个文件应该存放在classpath所包含的路径中：<br /><br /><div class="codeStyle"><ol><li>&lt;?xml version=<font color="#ff33ff">"1.0"</font> encoding=<font color="#ff33ff">"UTF-8"</font>?&gt; 
</li><li>&lt;!DOCTYPE beans PUBLIC <font color="#ff33ff">"-//SPRING//DTD BEAN//EN"</font> <font color="#ff33ff">"http://www.springframework.org/dtd/spring-beans.dtd"</font>&gt; 
</li><li>&lt;beans&gt; 
</li><li>　&lt;bean id=”helloTalker” <b><font color="#0000ff">class</font></b>=” org.bromon.spring.test.HelloTalker”&gt; 
</li><li>　&lt;/bean&gt; 
</li><li>&lt;/beans&gt;</li></ol></div><br />　　通过使用bean标签，注册了一个HelloTalker对象，它的名字叫做helloTalker。然后我们编写一个测试类，它的工作是利用spring框架提供的接口，加载配置文件，通过指定对象的id，获得一个对象。它的代码如下：<br /><div class="codeStyle"><ol><li><i><font color="#339900">/*</font></i></li><li><i><font color="#339900"> * 创建日期 2005-3-17</font></i></li><li><i><font color="#339900"> */</font></i></li><li><b><font color="#0000ff">package</font></b> org.bromon.spring.test.junit; 
</li><li></li><li><b><font color="#0000ff">import</font></b> java.io.<b><a href="http://www.codechina.net/source/jdk142/java/io/FileInputStream.java.html" target="_blank"><font class="classLink" color="#0066cc"><u>FileInputStream</u></font></a></b>; 
</li><li></li><li><b><font color="#0000ff">import</font></b> org.springframework.beans.factory.xml.XmlBeanFactory; 
</li><li><b><font color="#0000ff">import</font></b> org.springframework.context.ApplicationContext; 
</li><li><b><font color="#0000ff">import</font></b> org.springframework.context.support.ClassPathXmlApplicationContext; 
</li><li></li><li><b><font color="#0000ff">import</font></b> org.bromon.spring.test; 
</li><li></li><li><i><font color="#339900">/**</font></i></li><li><i><font color="#339900"> * @author Bromon</font></i></li><li><i><font color="#339900"> */</font></i></li><li><b><font color="#0000ff">public</font></b> <b><font color="#0000ff">class</font></b> TestStudentManager <b><font color="#0000ff">extends</font></b> TestCase { 
</li><li></li><li>    <b><font color="#0000ff">public</font></b> <b><font color="#0000ff">void</font></b> testHelloTalker()  
</li><li>    { 
</li><li>        <b><font color="#0000ff">try</font></b></li><li>        { 
</li><li>            ApplicationContext context =<b><font color="#0000ff">new</font></b> ClassPathXmlApplicationContext(<font color="#ff33ff">"springConfig.xml"</font>); 
</li><li>             
</li><li>HelloTalker ht=(HelloTalker)context.getBean(“helloTalker”); 
</li><li><b><a href="http://www.codechina.net/source/jdk142/java/lang/System.java.html" target="_blank"><font class="classLink" color="#0066cc"><u>System</u></font></a></b>.out.println(ht.greeting()); 
</li><li>        }<b><font color="#0000ff">catch</font></b>(<b><a href="http://www.codechina.net/source/jdk142/java/lang/Exception.java.html" target="_blank"><font class="classLink" color="#0066cc"><u>Exception</u></font></a></b> e) 
</li><li>        { 
</li><li>            e.printStackTrace(); 
</li><li>        } 
</li><li>    } 
</li><li></li><li>}</li></ol></div><br />　　这个程序就完成了，因为只有一个对象HelloTalker被注册到了spring中，所以不存在对象间的依赖，当然也就不涉及依赖注入。下面演示一个简单的依赖注入：<br /><br />　　第一步是修改HelloTalker，增加一个String name属性：<br /><div class="codeStyle"><ol><li><b><font color="#0000ff">public</font></b> <b><a href="http://www.codechina.net/source/jdk142/java/lang/String.java.html" target="_blank"><font class="classLink" color="#0066cc"><u>String</u></font></a></b> name;</li></ol></div><br /><br />　　为该属性编写set方法，该方法必须严格遵守javabean的命名规则：<br /><div class="codeStyle"><ol><li><b><font color="#0000ff">public</font></b> <b><font color="#0000ff">void</font></b> setName(<b><a href="http://www.codechina.net/source/jdk142/java/lang/String.java.html" target="_blank"><font class="classLink" color="#0066cc"><u>String</u></font></a></b> name) 
</li><li>{ 
</li><li>　　<b><font color="#0000ff">this</font></b>.name=name; 
</li><li>}</li></ol></div><br />　　修改greeting方法：<br /><br /><div class="codeStyle"><ol><li><b><font color="#0000ff">public</font></b> <b><a href="http://www.codechina.net/source/jdk142/java/lang/String.java.html" target="_blank"><font class="classLink" color="#0066cc"><u>String</u></font></a></b> greeting() 
</li><li>{ 
</li><li>　　<b><font color="#0000ff">return</font></b> <font color="#ff33ff">"hello "</font>+name; 
</li><li>}</li></ol></div><br />　　如你所见，name属性没有初试化，因为它的值将在运行过程中被spring动态注射入。<br /><br />　　第二步，修改springConfig.xml中唯一的这个bean配置：<br /><br /><div class="codeStyle"><ol><li>&lt;bean id=”helloTalker” <b><font color="#0000ff">class</font></b>=” org.bromon.spring.test.HelloTalker”&gt; 
</li><li>　&lt;property name=”name”&gt; 
</li><li>　　&lt;value&gt;bromon&lt;/value&gt; 
</li><li>　&lt;/property&gt; 
</li><li>&lt;/bean&gt;</li></ol></div><br /><br />　　修改完成。我们将一个名字”bromon”写死在springConfig.xml中，它会被动态的注入到HelloTalker的name属性中，greeting方法将会把它打印出来。重新运行刚才的junit类，可以看到结果。<br /><br />　　我们只演示了如何注入一个最简单的String，实际上我们可以注入任何值类型，也可以注入任何类的实例，也可以注入List、Map、Properties。配置文件管理了所有的对象和对象间的关系，而对象则只负责执行自己的功能，他们的职责越少，藕合度越低，系统就越容易测试，管理维护也更容易。<br /><br />　　&lt;bean&gt;标签还有很多属性，用于指定对象如何被实例化，它也有很多子标签用于配置对象的属性，请大家参考相关的DTD和文档，能够很快的掌握。本系列文章不是spring手册，spring的基础知识请参考spring in action，足够详细准确。后面的章节更多的讨论系统设计、开发的一些细节和高级特性。<br /><br />下一篇：在spring中进行hibernate开发<br /></td></tr></tbody></table><img src ="http://www.blogjava.net/franlk/aggbug/42277.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/franlk/" target="_blank">FRANLK 的个人空间</a> 2006-04-21 10:33 <a href="http://www.blogjava.net/franlk/articles/42277.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[摘录]Learn Spring in spring(一)</title><link>http://www.blogjava.net/franlk/articles/42276.html</link><dc:creator>FRANLK 的个人空间</dc:creator><author>FRANLK 的个人空间</author><pubDate>Fri, 21 Apr 2006 02:32:00 GMT</pubDate><guid>http://www.blogjava.net/franlk/articles/42276.html</guid><wfw:comment>http://www.blogjava.net/franlk/comments/42276.html</wfw:comment><comments>http://www.blogjava.net/franlk/articles/42276.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/franlk/comments/commentRss/42276.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/franlk/services/trackbacks/42276.html</trackback:ping><description><![CDATA[摘录地址：<a href="http://www.codechina.net/resource/html/2005-04/10/16126.html">http://www.codechina.net/resource/html/2005-04/10/16126.html</a><br />Bromon原创 请尊重版权<br /><br />　　当前的形势是，非常多的Java程序员言必称Spring，如此大面积的程序员集体叫”春”，体现了Spring框架的威力。春天正是叫春的好时候，你我一起来叫春吧。^_^<br /><br />　　Spring的设计目的是简化J2EE开发，所以如果我们学习、使用它的时候还需要抓破头皮口吐白沫的话，岂不是个笑话？就我的经验来说，Spring在这方面做得很好，的确是一个很牛叉易用的框架。<br /><br />　　之前我曾经设计过一个J2EE的考试系统，大量使用了EJB（详见<a href="http://blog.csdn.net/bromon/archive/2004/08/27/86291.aspx"><font color="#0066cc">http://blog.csdn.net/bromon/archive/2004/08/27/86291.aspx</font></a>），我打算同样使用一个考试系统做例子，便于比较。两个系统的大致结构都差不多，不过新的版本采用了轻量级的方案，使用Hibernate作为ORM框架，所有的对象都交给spring来管理。<br /><br />一、IoC与DI<br /><br />　　首先想说说IoC（Inversion of Control，控制倒转）。这是spring的核心，贯穿始终。所谓IoC，对于spring框架来说，就是由spring来负责控制对象的生命周期和对象间的关系。这是什么意思呢，举个简单的例子，我们是如何找女朋友的？常见的情况是，我们到处去看哪里有长得漂亮身材又好的mm，然后打听她们的兴趣爱好、qq号、电话号、ip号、iq号………，想办法认识她们，投其所好送其所要，然后嘿嘿……这个过程是复杂深奥的，我们必须自己设计和面对每个环节。传统的程序开发也是如此，在一个对象中，如果要使用另外的对象，就必须得到它（自己new一个，或者从JNDI中查询一个），使用完之后还要将对象销毁（比如Connection等），对象始终会和其他的接口或类藕合起来。<br /><br />　　那么IoC是如何做的呢？有点像通过婚介找女朋友，在我和女朋友之间引入了一个第三者：婚姻介绍所。婚介管理了很多男男女女的资料，我可以向婚介提出一个列表，告诉它我想找个什么样的女朋友，比如长得像李嘉欣，身材像林熙雷，唱歌像周杰伦，速度像卡洛斯，技术像齐达内之类的，然后婚介就会按照我们的要求，提供一个mm，我们只需要去和她谈恋爱、结婚就行了。简单明了，如果婚介给我们的人选不符合要求，我们就会抛出异常。整个过程不再由我自己控制，而是有婚介这样一个类似容器的机构来控制。Spring所倡导的开发方式就是如此，所有的类都会在spring容器中登记，告诉spring你是个什么东西，你需要什么东西，然后spring会在系统运行到适当的时候，把你要的东西主动给你，同时也把你交给其他需要你的东西。所有的类的创建、销毁都由spring来控制，也就是说控制对象生存周期的不再是引用它的对象，而是spring。对于某个具体的对象而言，以前是它控制其他对象，现在是所有对象都被spring控制，所以这叫控制反转。如果你还不明白的话，我决定放弃。<br /><br />　　IoC的一个重点是在系统运行中，动态的向某个对象提供它所需要的其他对象。这一点是通过DI（Dependency Injection，依赖注入）来实现的。比如对象A需要操作数据库，以前我们总是要在A中自己编写代码来获得一个Connection对象，有了spring我们就只需要告诉spring，A中需要一个Connection，至于这个Connection怎么构造，何时构造，A不需要知道。在系统运行时，spring会在适当的时候制造一个Connection，然后像打针一样，注射到A当中，这样就完成了对各个对象之间关系的控制。A需要依赖Connection才能正常运行，而这个Connection是由spring注入到A中的，依赖注入的名字就这么来的。那么DI是如何实现的呢？Java 1.3之后一个重要特征是反射（reflection），它允许程序在运行的时候动态的生成对象、执行对象的方法、改变对象的属性，spring就是通过反射来实现注入的。关于反射的相关资料请查阅java doc。<br /><br />　　理解了IoC和DI的概念后，一切都将变得简单明了，剩下的工作只是在spring的框架中堆积木而已。<br /><br />下一篇：spring管理对象的简单例子<br /><img src ="http://www.blogjava.net/franlk/aggbug/42276.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/franlk/" target="_blank">FRANLK 的个人空间</a> 2006-04-21 10:32 <a href="http://www.blogjava.net/franlk/articles/42276.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[摘录]Jive论坛与Spring框架</title><link>http://www.blogjava.net/franlk/articles/42275.html</link><dc:creator>FRANLK 的个人空间</dc:creator><author>FRANLK 的个人空间</author><pubDate>Fri, 21 Apr 2006 02:30:00 GMT</pubDate><guid>http://www.blogjava.net/franlk/articles/42275.html</guid><wfw:comment>http://www.blogjava.net/franlk/comments/42275.html</wfw:comment><comments>http://www.blogjava.net/franlk/articles/42275.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/franlk/comments/commentRss/42275.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/franlk/services/trackbacks/42275.html</trackback:ping><description><![CDATA[
		<font size="2">摘录地址：</font>
		<a href="http://www.codechina.net/resource/html/2006-04/07/150546.html">
				<font size="2">http://www.codechina.net/resource/html/2006-04/07/150546.html</font>
		</a>
		<br />
		<font size="2">Jive论坛与Spring框架<br />　　没有一种新技术是凭空诞生的，它的萌芽或胚胎总是或多或少显现于以前的技术中，Jive论坛是大家潜心研究的设计型应用程序，其相关解析可见本栏的GoF设计模式专栏。<br /><br />　　Jive和Spring同为由JavaBeans组成的J2EE Web系统，Jive作为早期成功设计案例，其主要架构成为大多数纯JavaBeans系统的流行架构，Spring也不例外。<br /><br />　　Spring框架除了是一种Web层应用框架，还提供了访问EJB层的接口，也有JDBC/ORM的直接操作。Spring框架主要魅力是使用IoC模式和AOP实现了Jive系统的通用功能，从而使得Jive这样的纯JavaBeans架构设计可以重用在其它系统中。<br /><br />　　如果你感慨于Jive的设计理念，但是又苦于无法重用其设计时，Spring框架已经帮你实现了。<br /><br />　　同时也要注意到：Spring框架类似“杂烩”，它包含了很多J2EE应用的工具，类如对EJB的调用，它的MVC与Struts JSF也是相竞争的，以纯Ioc和AOP设计来说，Spring框架也是一种很重的(Heavy、Weight)框架。Spring框架是复杂的，如果想以Spring替代EJB，那么无疑按了葫芦浮起瓢。<br /><br />　　将Jive论坛和Spring框架联系起来，会帮助更多理解设计模式的程序员迅速掌握最新的设计思潮，而不是一种跳跃式的强迫接受。如果你对Jive有很好的研究，将会发现Spring框架是Jive设计的更加通用的提升。<br /><br />　　在Jive中,ForumFactory是整个系统的入口和突破点，Jive通过ForumFactory将整个系统掌控在一个工厂模式下，这样做的好处是：便于控制系统的JavaBeans，例如，客户端通过ForumFactory可创建一个Forum或访问一个Forum，但是是否有权限访问呢？如下图：<br /><br /><br />　　<br />　　 Jive通过ForumFactory将这种访问引导到相应的Proxy类去，如ForumFactoryProxy类等，通过代理模式对这些类进行权限控制访问。这是代理模式的一个主要用处，但是研读Jive的代理模式会发现，要为每个类实现一个Proxy类，非常琐碎，有没有更优雅的方式呢？ 当然使用动态代理。<br /><br />　　Spring框架基本是抽象上述设计，Spring框架对所有JavaBeans的管理也是基于一个总入口Bean Factory机制，不同的是，BeanFactory可以 管理所有应用的JavaBeans，使用者只要将自己的JavaBeans通过配置文件告诉BeanFactory，那么BeanFactory将会加载这些JavaBeans，例如：<br /><br />　　&lt;beans&gt;<br />　　　　&lt;bean id="exampleBean" class="eg.ExampleBean"/&gt;<br />　　　　&lt;bean id="anotherExample" class="eg.ExampleBeanTwo"/&gt;<br />　　&lt;/beans&gt;<br /><br />　　在Jive中，ForumFactory加载Jive自己的JavaBeans是通过工厂实现DbForumFactory实现的，如下代码，DbForumFactory引发了后台一系列功能实现，这是纵向，而return new ForumFactoryProxy这个语句则类似引来一个切面，从一个横向方面实现了权限访问等功能：<br /><br />private static String className = "com.jivesoftware.forum.database.DbForumFactory"; <br /><br />public static ForumFactory getInstance(Authorization authorization) { <br />　　　　 //If no valid authorization passed in, return null. <br />　　　　 if (authorization == null) { <br />　　　　　　 return null; <br />　　　　 } <br />　　　　 //以下使用了Singleton 单态模式 <br />　　　　 if (factory == null) { <br />　　　　　　 synchronized(initLock) { <br />　　　　　　　　 if (factory == null) { <br />　　　　　　　　　　　　 ...... <br /><br />　　　　 　　　　 try { <br />　　　　　　　　　　　　　　 //动态转载类 <br />　　　　　　　　　　　　　　 Class c = Class.forName(className); <br />　　　　　　　　　　　　　　 factory = (ForumFactory)c.newInstance(); <br />　　　　　　　　　　 } <br />　　　　　　　　　　 catch (Exception e) { <br />　　　　　　　　　　　　　　 return null; <br />　　　　　　　　　　 } <br />　　　　　　　　 } <br />　　　　　　 } <br />　　　　 } <br /><br />　　　　 //Now, 返回 proxy.用来限制授权对forum的访问 <br />　　　　 return new ForumFactoryProxy(authorization, factory, 　　　　　　　　　　　　　　　　　　　 factory.getPermissions(authorization)); <br />　　 } <br /> <br /><br />　　既然Spring框架也是通过一个Bean Factory加载所有的类，那么它是如何加载的？通过IoC模式，也就是依赖性注射模式。在我以前文章“IoC模式”中，我比较了Factory工厂模式创建对象和Ioc模式的注射对象实现之间的异同，Ioc相比工厂模式则更加解耦了调用者和被调用者之间关系，使用Ioc模式，无需在调用者代码中涉及被调用者的具体实现。<br /><br />　　Spring框架不但可以向自己容器中注射应用者自己定义的JavaBeans（也就是创建它们），而且也可以向这些JavaBeans通过set方法实现数据赋值。<br /><br />　　一旦Bean Factory运行时刻掌管这些激活的对象，Spring通过AOP方式，从一个横切面为这些JavaBeans提供了权限访问、事务锁等通用功能的实现，这种实现是基于动态代理模式，而动态代理是AOP实现的一种方式。<br /><br />　　前面提到，Jive中使用代理模式实现权限访问，比代理模式更加简洁和抽象的是动态代理，使用动态代理将使得调用者无需指定被调用者的代理类，这是动态代理区别代理模式的本质。<br /><br />　　动态代理这一优势，又可以体现在另外一句话语上：动态代理拦截了调用者对被调用者的调用，正是这一功能符合了AOP的拦截器功能，为AOP实现提供了可能。<br /><br />　　Spring框架使用了动态代理实现的AOP，正是通过动态代理机制拦截了外界对Bean Factory管理下的对象的调用。如下图：<br /><br /><br /><br /> <br /><br />　　以上只是大体解构了Spring的架构，Spring框架在这个架构下，还顺带了很多其它功能，如Web MVC、 DAO JDBC、 DAO ORM 、以及remote，后者类似我设计的EJB方法调用框架。<br /><br />　　总之，Spring确实是Ioc和AOP的完美应用，Ioc用来装载JavaBeans，创建这些对象；AOP用来拦截这些对象的使用，这才是框架设计的必然经典方式。<br /></font>
<img src ="http://www.blogjava.net/franlk/aggbug/42275.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/franlk/" target="_blank">FRANLK 的个人空间</a> 2006-04-21 10:30 <a href="http://www.blogjava.net/franlk/articles/42275.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>