<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>shijian0306</title>
    <description></description>
    <link>http://shijian0306.javaeye.com</link>
    <language>UTF-8</language>
    <copyright>Copyright 2003-2008, JavaEye.com</copyright>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <generator>JavaEye - 做最棒的软件开发交流社区</generator>
      <item>
        <title>MySql 查询语句性能问题</title>
        <author>shijian0306</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://shijian0306.javaeye.com">shijian0306</a>&nbsp;
          链接：<a href="http://shijian0306.javaeye.com/blog/190917" style="color:red;">http://shijian0306.javaeye.com/blog/190917</a>&nbsp;
          发表时间: 2008年05月08日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          01010
          <br/>
          <span style="color:red;">
            <a href="http://shijian0306.javaeye.com/blog/190917#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 08 May 2008 10:00:54 +0800</pubDate>
        <link>http://shijian0306.javaeye.com/blog/190917</link>
        <guid>http://shijian0306.javaeye.com/blog/190917</guid>
      </item>
      <item>
        <title>POI 导出excel数据量大的时候的解决方案</title>
        <author>shijian0306</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://shijian0306.javaeye.com">shijian0306</a>&nbsp;
          链接：<a href="http://shijian0306.javaeye.com/blog/188444" style="color:red;">http://shijian0306.javaeye.com/blog/188444</a>&nbsp;
          发表时间: 2008年04月30日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          POI 在导出大量数据到response中的时候报socket错误（其实文件已经导出来了,数据量在21000左右，4列），请问大家是怎么解决的。<br />当数据量小的时候没有问题！错误信息如下。<br /><span style="color: red"><br />workBook.write(outputStream);<br />outputStream.flush();<br />outputStream.close();</span><br /><br />ClientAbortException:  java.net.SocketException: Software caused connection abort: socket write error<br />2008-04-30 15:41:07,625 ERROR (org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manage].[default]:253) - Servlet.service() for servlet default threw exception<br />java.net.SocketException: Software caused connection abort: socket write error<br />	at java.net.SocketOutputStream.socketWrite0(Native Method)<br />	at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:92)<br />	at java.net.SocketOutputStream.write(SocketOutputStream.java:136)<br />	at org.apache.coyote.http11.InternalOutputBuffer.realWriteBytes(InternalOutputBuffer.java:747)<br />	at org.apache.tomcat.util.buf.ByteChunk.flushBuffer(ByteChunk.java:432)<br />	at org.apache.tomcat.util.buf.ByteChunk.append(ByteChunk.java:347)<br />	at org.apache.coyote.http11.InternalOutputBuffer$OutputStreamOutputBuffer.doWrite(InternalOutputBuffer.java:770)<br />	at org.apache.coyote.http11.filters.IdentityOutputFilter.doWrite(IdentityOutputFilter.java:127)<br />	at org.apache.coyote.http11.InternalOutputBuffer.doWrite(InternalOutputBuffer.java:580)<br />	at org.apache.coyote.Response.doWrite(Response.java:560)<br />	at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:361)<br />	at org.apache.tomcat.util.buf.ByteChunk.flushBuffer(ByteChunk.java:432)<br />	at org.apache.catalina.connector.OutputBuffer.doFlush(OutputBuffer.java:314)<br />	at org.apache.catalina.connector.OutputBuffer.flush(OutputBuffer.java:293)<br />	at org.apache.catalina.connector.CoyoteOutputStream.flush(CoyoteOutputStream.java:98)<br />	at com.winkee.keyword.util.KeywordDownloadExcel.downloadKeyWord(KeywordDownloadExcel.java:97)<br />	at com.winkee.keyword.web.KeywordAction.list(KeywordAction.java:190)<br />	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)<br />	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)<br />	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)<br />	at java.lang.reflect.Method.invoke(Method.java:597)<br />	at com.opensymphony.xwork2.DefaultActionInvocation.invokeAction(DefaultActionInvocation.java:404)
          <br/>
          <span style="color:red;">
            <a href="http://shijian0306.javaeye.com/blog/188444#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 30 Apr 2008 15:44:33 +0800</pubDate>
        <link>http://shijian0306.javaeye.com/blog/188444</link>
        <guid>http://shijian0306.javaeye.com/blog/188444</guid>
      </item>
      <item>
        <title>观察者模式</title>
        <author>shijian0306</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://shijian0306.javaeye.com">shijian0306</a>&nbsp;
          链接：<a href="http://shijian0306.javaeye.com/blog/187108" style="color:red;">http://shijian0306.javaeye.com/blog/187108</a>&nbsp;
          发表时间: 2008年04月26日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          观察者模式<br />关键字: 观察者模式 <br />观察者模式定义了一种一对多的依赖关系，让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时，会通知所有观察者对象，让他们能够自动更新自己 <br /><br />观察者模式的组成 <br /><br />1.抽象主题角色:把所有对观察者对象的引用保存在一个集合中，每个抽象主题角色都可以有任意数量的观察者。抽象主题提供一个接口，可以增加和删除观察者角色。一般用一个抽象类或接口来实现 <br />2.抽象观察者角色:为所有具体的观察者定义一个接口，在得到主题的通知时更新自己。 <br />3.具体主题角色(Watched):把所有对观察者对象的引用保存在一个集合中，每个抽象主题角色都可以有任意数量的观察者。抽象主题提供一个接口，可以增加和删除观察者角色。一般用一个抽象类或接口来实现。 <br />4.具体观察者角色(Watcher):为所有具体的观察者定义一个接口，在得到主题的通知时更新自己 <br /><br />A.自定义观察者模式 <br /><br />例如： <br />1.抽象主题角色类 <br />Java代码 <br />package com.observe;   <br />  <br />public interface AbstractWatched {   <br />       <br />    //增加一个观察者   <br />    public void addAbstactWatcher(AbstractWatcher watcher);   <br />       <br />    //移除一个观察者   <br />    public void removeAbstactWatcher(AbstractWatcher watcher);   <br />       <br />    //移除所有的观察着   <br />    public void removeAll();   <br />       <br />    //通知所有的观察者   <br />    public void notifyWatchers();   <br />  <br />}  <br /><br />package com.observe;<br /><br />public interface AbstractWatched {<br />	<br />	//增加一个观察者<br />	public void addAbstactWatcher(AbstractWatcher watcher);<br />	<br />	//移除一个观察者<br />	public void removeAbstactWatcher(AbstractWatcher watcher);<br />	<br />	//移除所有的观察着<br />	public void removeAll();<br />	<br />	//通知所有的观察者<br />	public void notifyWatchers();<br /><br />}<br /><br />2.抽象观察者角色 <br />Java代码 <br />package com.observe;   <br />  <br />public interface AbstractWatcher {   <br />       <br />    public void update();   <br />  <br />}  <br /><br />package com.observe;<br /><br />public interface AbstractWatcher {<br />	<br />	public void update();<br /><br />}<br /><br />3.具体主题角色(Watched) <br />Java代码 <br />package com.observe;   <br />  <br />import java.util.ArrayList;   <br />import java.util.List;   <br />  <br />public class ConcreteWatched implements AbstractWatched {   <br />  <br />    //list:存放观察者的一个集合对象   <br />    List&lt;AbstractWatcher> list = new ArrayList&lt;AbstractWatcher>();   <br />       <br />    //增加一个观察者   <br />    public void addAbstactWatcher(AbstractWatcher watcher) {   <br />        list.add(watcher);   <br />  <br />    }   <br />  <br />    //移除一个观察者   <br />    public void removeAbstactWatcher(AbstractWatcher watcher) {   <br />        list.remove(watcher);   <br />  <br />    }   <br />  <br />    //移除所有的观察着   <br />    public void removeAll() {   <br />        list.clear();   <br />  <br />    }   <br />       <br />    //通知所有的观察者   <br />    public void notifyWatchers() {   <br />        for(AbstractWatcher watcher : list){   <br />            watcher.update();   <br />        }   <br />  <br />    }   <br />  <br />}  <br /><br />package com.observe;<br /><br />import java.util.ArrayList;<br />import java.util.List;<br /><br />public class ConcreteWatched implements AbstractWatched {<br /><br />	//list:存放观察者的一个集合对象<br />	List&lt;AbstractWatcher> list = new ArrayList&lt;AbstractWatcher>();<br />	<br />	//增加一个观察者<br />	public void addAbstactWatcher(AbstractWatcher watcher) {<br />		list.add(watcher);<br /><br />	}<br /><br />	//移除一个观察者<br />	public void removeAbstactWatcher(AbstractWatcher watcher) {<br />		list.remove(watcher);<br /><br />	}<br /><br />	//移除所有的观察着<br />	public void removeAll() {<br />		list.clear();<br /><br />	}<br />	<br />	//通知所有的观察者<br />	public void notifyWatchers() {<br />		for(AbstractWatcher watcher : list){<br />			watcher.update();<br />		}<br /><br />	}<br /><br />}<br /><br />4.具体观察者角色(Watcher) <br /><br />Java代码 <br />package com.observe;   <br />  <br />  <br />public class ConcreteWatcher implements AbstractWatcher {   <br />  <br />    //观察到被观察者发生变化时，执行的方法   <br />    public void update() {   <br />        System.out.println("update.....");   <br />           <br />    }   <br />       <br />       <br />  <br />}  <br /><br />package com.observe;<br /><br /><br />public class ConcreteWatcher implements AbstractWatcher {<br /><br />	//观察到被观察者发生变化时，执行的方法<br />	public void update() {<br />		System.out.println("update.....");<br />		<br />	}<br />	<br />	<br /><br />}<br /><br />5.客户端调用： <br /><br />Java代码 <br />package com.observe;   <br />  <br />public class ClientTest {   <br />  <br />    public static void main(String[] args){   <br />        //定义一个被观察者对象   <br />        AbstractWatched watched = new ConcreteWatched();   <br />           <br />        //定义三个观察者对象   <br />        AbstractWatcher watcher1 = new ConcreteWatcher();   <br />        AbstractWatcher watcher2 = new ConcreteWatcher();   <br />        AbstractWatcher watcher3 = new ConcreteWatcher();   <br />           <br />        //被观察者添加观察者. 被观察者和观察者之间关系是一对多关系   <br />        watched.addAbstactWatcher(watcher1);   <br />        watched.addAbstactWatcher(watcher2);   <br />        watched.addAbstactWatcher(watcher3);   <br />           <br />        System.out.println("第1次...");   <br />        //被观察者发生改变时，通知观察者执行相应方法   <br />        watched.notifyWatchers();   <br />           <br />        //移除一个观察者   <br />        watched.removeAbstactWatcher(watcher2);   <br />           <br />        System.out.println("第2次...");   <br />        //被观察者发生改变时，通知观察者执行相应方法   <br />        watched.notifyWatchers();   <br />           <br />        //移除一个所有观察者   <br />        watched.removeAll();   <br />           <br />        System.out.println("第3次...");   <br />        //被观察者发生改变时，通知观察者执行相应方法   <br />        watched.notifyWatchers();   <br />           <br />    }   <br />}  <br /><br />package com.observe;<br /><br />public class ClientTest {<br /><br />	public static void main(String[] args){<br />		//定义一个被观察者对象<br />		AbstractWatched watched = new ConcreteWatched();<br />		<br />		//定义三个观察者对象<br />		AbstractWatcher watcher1 = new ConcreteWatcher();<br />		AbstractWatcher watcher2 = new ConcreteWatcher();<br />		AbstractWatcher watcher3 = new ConcreteWatcher();<br />		<br />		//被观察者添加观察者. 被观察者和观察者之间关系是一对多关系<br />		watched.addAbstactWatcher(watcher1);<br />		watched.addAbstactWatcher(watcher2);<br />		watched.addAbstactWatcher(watcher3);<br />		<br />		System.out.println("第1次...");<br />		//被观察者发生改变时，通知观察者执行相应方法<br />		watched.notifyWatchers();<br />		<br />		//移除一个观察者<br />		watched.removeAbstactWatcher(watcher2);<br />		<br />		System.out.println("第2次...");<br />		//被观察者发生改变时，通知观察者执行相应方法<br />		watched.notifyWatchers();<br />		<br />		//移除一个所有观察者<br />		watched.removeAll();<br />		<br />		System.out.println("第3次...");<br />		//被观察者发生改变时，通知观察者执行相应方法<br />		watched.notifyWatchers();<br />		<br />	}<br />}<br /><br />执行结果为： <br />第1次... <br />update..... <br />update..... <br />update..... <br />第2次... <br />update..... <br />update..... <br />第3次... <br /><br /><br /><br />B:对于java的观察者模式框架 <br /><br />从AWT1.1开始图形系统的事件模型采用观察者模式，因此观察者模式在Java语言中的地位极其重要 <br />在xml解析中的SAX也采用了观察者模式来实现 <br />Java也提供了对观察者模式的内置支持 <br /><br />内置观察者模式主要有2个类，一个是类Observable,一个是接口类Observer <br /><br />Observable类是被观察者，子类只要继承它即可。而且添加观察者等方法已经都实现了. <br />Observer是观察者，只有一个接口方法public void update(Observable arg0, Object arg1)，需要其子类来实现.这里，observOb是被观测的对象，而arg是由notifyObservers( )方法传递的值。当被观测对象发生了改变，调用update( )方法 <br /><br /><br />1. 被观察者要继承Observable类 <br /><br />2. 被观察者通知观察者时，也就是调用notifyObservers方法时，一定要先调用setChanged()方法(该方法的作用就是将对象里面的changed这个boolean变量设定为true，因为notifyObservers要首先检查该变量是否为true，如果为false就不执行而直接返回了) <br /><br />3. Observable类的两个重载的notifyObservers方法，带参数的那个方法，里面的参数就是Observer接口中的update方法中的第二个参数 <br /><br /><br />一个被观测的对象必须服从下面的两个简单规则。第一，如果它被改变了，它必须调用setChanged( )方法。第二，当它准备通知观测程序它的改变时，它必须调用notifyObservers( )方法。这导致了在观测对象中对update( )方法的调用。注意——当对象在调用notifyObservers( )方法之前，没有调用setChanged( )方法，就不会有什么动作发生。在update( )被调用之前，被观测对象必须调用setChanged( )和notifyObservers( )两种方法 <br /><br /><br />例如： <br />被观察者： <br />Java代码 <br />package com.observe2;   <br />  <br />import java.util.Observable;   <br />  <br />public class Watched extends Observable{   <br />       <br />    public void count(int number){   <br />        for( ; number >=0 ; number-- ){   <br />            setChanged();   <br />               <br />            //注意notifyObservers()有两种形式：一种带有参数而另一种没有。当用参数调用notifyObservers( )方法时，该对象被传给观测程序的update( )方法作为其第二个参数。否则，将给update( )方法传递一个null。可以使用第二个参数传递适合于你的应用程序的任何类型的对象。    <br />            //也就是说notifyObservers()内部实际调用的是notifyObservers(null);   <br />            notifyObservers(number);   <br />        }   <br />    }   <br />  <br />}  <br /><br />package com.observe2;<br /><br />import java.util.Observable;<br /><br />public class Watched extends Observable{<br />	<br />	public void count(int number){<br />		for( ; number >=0 ; number-- ){<br />			setChanged();<br />			<br />			//注意notifyObservers()有两种形式：一种带有参数而另一种没有。当用参数调用notifyObservers( )方法时，该对象被传给观测程序的update( )方法作为其第二个参数。否则，将给update( )方法传递一个null。可以使用第二个参数传递适合于你的应用程序的任何类型的对象。 <br />			//也就是说notifyObservers()内部实际调用的是notifyObservers(null);<br />			notifyObservers(number);<br />		}<br />	}<br /><br />}<br /><br />第一个观察者 <br />Java代码 <br />package com.observe2;   <br />  <br />import java.util.Observable;   <br />import java.util.Observer;   <br />  <br />public class Watcher implements Observer{   <br />  <br />    public void update(Observable arg0, Object arg1) {   <br />        System.out.println((Integer)arg1);   <br />           <br />    }   <br />  <br />       <br />}  <br /><br />package com.observe2;<br /><br />import java.util.Observable;<br />import java.util.Observer;<br /><br />public class Watcher implements Observer{<br /><br />	public void update(Observable arg0, Object arg1) {<br />		System.out.println((Integer)arg1);<br />		<br />	}<br /><br />	<br />}<br /><br />第二个观察者： <br />Java代码 <br />package com.observe2;   <br />  <br />import java.util.Observable;   <br />import java.util.Observer;   <br />  <br />public class Watcher2 implements Observer{   <br />  <br />    public void update(Observable arg0, Object arg1) {   <br />        if((Integer)arg1 == 0){   <br />            System.out.println("done");   <br />        }   <br />           <br />    }   <br />  <br />       <br />}  <br /><br />package com.observe2;<br /><br />import java.util.Observable;<br />import java.util.Observer;<br /><br />public class Watcher2 implements Observer{<br /><br />	public void update(Observable arg0, Object arg1) {<br />		if((Integer)arg1 == 0){<br />			System.out.println("done");<br />		}<br />		<br />	}<br /><br />	<br />}<br /><br />客户端调用： <br />Java代码 <br />package com.observe2;   <br />  <br />public class Client {   <br />       <br />    public static void main(String[] args){   <br />        //定义一个被观察者   <br />        Watched watched = new Watched();   <br />           <br />        //定义2个观察者   <br />        Watcher watcher = new Watcher();   <br />        Watcher2 watcher2 = new Watcher2();   <br />           <br />        //给被观察者添加观察者   <br />        watched.addObserver(watcher);   <br />        watched.addObserver(watcher2);   <br />           <br />        watched.count(10);   <br />    }   <br />  <br />}  <br /><br />package com.observe2;<br /><br />public class Client {<br />	<br />	public static void main(String[] args){<br />		//定义一个被观察者<br />		Watched watched = new Watched();<br />		<br />		//定义2个观察者<br />		Watcher watcher = new Watcher();<br />		Watcher2 watcher2 = new Watcher2();<br />		<br />		//给被观察者添加观察者<br />		watched.addObserver(watcher);<br />		watched.addObserver(watcher2);<br />		<br />		watched.count(10);<br />	}<br /><br />}<br /><br />输出结果为： <br />10 <br />9 <br />8 <br />7 <br />6 <br />5 <br />4 <br />3 <br />2 <br />1 <br />done <br />0
          <br/>
          <span style="color:red;">
            <a href="http://shijian0306.javaeye.com/blog/187108#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sat, 26 Apr 2008 16:33:38 +0800</pubDate>
        <link>http://shijian0306.javaeye.com/blog/187108</link>
        <guid>http://shijian0306.javaeye.com/blog/187108</guid>
      </item>
      <item>
        <title>            ajax实现无刷新下载!!!</title>
        <author>shijian0306</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://shijian0306.javaeye.com">shijian0306</a>&nbsp;
          链接：<a href="http://shijian0306.javaeye.com/blog/186122" style="color:red;">http://shijian0306.javaeye.com/blog/186122</a>&nbsp;
          发表时间: 2008年04月24日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          想在页面上通过AJAX提交方式下载一个附件，从而不刷新页面，能否实现？<br /><br />主要是想实现无刷新页面下载?<br />大家讨论下,如何实现???
          <br/>
          <span style="color:red;">
            <a href="http://shijian0306.javaeye.com/blog/186122#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 24 Apr 2008 01:23:23 +0800</pubDate>
        <link>http://shijian0306.javaeye.com/blog/186122</link>
        <guid>http://shijian0306.javaeye.com/blog/186122</guid>
      </item>
      <item>
        <title>ajax 无刷新下载</title>
        <author>shijian0306</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://shijian0306.javaeye.com">shijian0306</a>&nbsp;
          链接：<a href="http://shijian0306.javaeye.com/blog/186121" style="color:red;">http://shijian0306.javaeye.com/blog/186121</a>&nbsp;
          发表时间: 2008年04月24日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          想在页面上通过AJAX提交方式下载一个附件，从而不刷新页面，能否实现？(java实现的是文件下载)<br /><br />主要是想实现无刷新页面下载?<br />大家讨论下,如何实现???
          <br/>
          <span style="color:red;">
            <a href="http://shijian0306.javaeye.com/blog/186121#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 24 Apr 2008 01:21:09 +0800</pubDate>
        <link>http://shijian0306.javaeye.com/blog/186121</link>
        <guid>http://shijian0306.javaeye.com/blog/186121</guid>
      </item>
      <item>
        <title>acegi的配置</title>
        <author>shijian0306</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://shijian0306.javaeye.com">shijian0306</a>&nbsp;
          链接：<a href="http://shijian0306.javaeye.com/blog/182209" style="color:red;">http://shijian0306.javaeye.com/blog/182209</a>&nbsp;
          发表时间: 2008年04月13日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          applicationContext-acegi-security.xml<br />1.<span style="color: darkred">filterChainProxy</span>配置<br />&lt;bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy"><br />  &lt;property name="filterInvocationDefinitionSource"><br />   &lt;value><br />    CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON<br />    PATTERN_TYPE_APACHE_ANT<br />    /**=httpSessionContextIntegrationFilter,logoutFilter,authenticationProcessingFilter,securityContextHolderAwareRequestFilter,rememberMeProcessingFilter,anonymousProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor<br />   &lt;/value><br />  &lt;/property><br /> &lt;/bean><br /><br />2.<span style="color: darkred">httpSessionContextIntegrationFilter</span>配置<br />&lt;bean id="httpSessionContextIntegrationFilter" class="org.acegisecurity.context.HttpSessionContextIntegrationFilter"/><br /><br />3.<span style="color: darkred">logoutFilter</span>配置<br />&lt;bean id="logoutFilter" class="org.acegisecurity.ui.logout.LogoutFilter"><br />  &lt;constructor-arg value="/index.jsp"/> &lt;!-- URL redirected to after logout --><br />  &lt;constructor-arg><br />   &lt;list><br />    &lt;ref bean="rememberMeServices"/><br />    &lt;bean class="org.acegisecurity.ui.logout.SecurityContextLogoutHandler"/><br />   &lt;/list><br />  &lt;/constructor-arg><br /> &lt;/bean><br /><br />4.<span style="color: darkred">authenticationProcessingFilter</span>配置<br />&lt;bean id="authenticationProcessingFilter" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter"><br />  &lt;property name="authenticationManager" ref="authenticationManager"/><br />  &lt;property name="authenticationFailureUrl" value="/login.jsp?login_error=1"/><br />  &lt;property name="defaultTargetUrl" value="/"/><br />  &lt;property name="filterProcessesUrl" value="/j_acegi_security_check"/><br />  &lt;property name="rememberMeServices" ref="rememberMeServices"/><br /> &lt;/bean><br /><br />5.<span style="color: darkred">securityContextHolderAwareRequestFilter</span>配置<br />&lt;bean id="securityContextHolderAwareRequestFilter" class="org.acegisecurity.wrapper.SecurityContextHolderAwareRequestFilter"/><br /><br />6.<span style="color: darkred">rememberMeProcessingFilter</span>配置<br />&lt;bean id="rememberMeProcessingFilter" class="org.acegisecurity.ui.rememberme.RememberMeProcessingFilter"><br />  &lt;property name="authenticationManager" ref="authenticationManager"/><br />  &lt;property name="rememberMeServices" ref="rememberMeServices"/><br /> &lt;/bean><br /><br />7.<span style="color: darkred">anonymousProcessingFilter</span>配置<br />&lt;bean id="anonymousProcessingFilter" class="org.acegisecurity.providers.anonymous.AnonymousProcessingFilter"><br />  &lt;property name="key" value="changeThis"/><br />  &lt;property name="userAttribute" value="anonymousUser,ROLE_ANONYMOUS"/><br /> &lt;/bean><br /><br />8.<span style="color: darkred">exceptionTranslationFilter</span>配置<br />&lt;bean id="exceptionTranslationFilter" class="org.acegisecurity.ui.ExceptionTranslationFilter"><br />  &lt;property name="authenticationEntryPoint"><br />   &lt;bean class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint"><br />    &lt;property name="loginFormUrl" value="/login.jsp"/><br />    &lt;property name="forceHttps" value="false"/><br />   &lt;/bean><br />  &lt;/property><br />  &lt;property name="accessDeniedHandler"><br />   &lt;bean class="org.acegisecurity.ui.AccessDeniedHandlerImpl"><br />    &lt;property name="errorPage" value="/accessDenied.jsp"/><br />   &lt;/bean><br />  &lt;/property><br /> &lt;/bean><br /><br />9.<span style="color: darkred">filterInvocationInterceptor</span>配置<br />&lt;bean id="filterInvocationInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor"><br />  &lt;property name="authenticationManager" ref="authenticationManager"/><br />  &lt;property name="accessDecisionManager" ref="accessDecisionManager"/><br />  &lt;property name="objectDefinitionSource"><br />   &lt;value><br />    PATTERN_TYPE_APACHE_ANT<br />    /mainFrame.html=admin,user<br />    /文件夹1/*.html*=admin,user<br />    /文件夹2/*.html*=admin,user<br />    /文件夹3/*.html*=admin<br />    /accessDenied.jsp*=ROLE_ANONYMOUS<br />   &lt;/value><br />  &lt;/property><br /> &lt;/bean><br /><br />10.<span style="color: darkred">accessDecisionManager</span>配置<br />&lt;bean id="accessDecisionManager" class="org.acegisecurity.vote.AffirmativeBased"><br />  &lt;property name="allowIfAllAbstainDecisions" value="false"/><br />  &lt;property name="decisionVoters"><br />   &lt;list><br />    &lt;bean class="org.acegisecurity.vote.RoleVoter"><br />     &lt;property name="rolePrefix" value=""/><br />    &lt;/bean><br />    &lt;bean class="org.acegisecurity.vote.AuthenticatedVoter"/><br />   &lt;/list><br />  &lt;/property><br /> &lt;/bean><br /><br />11.<span style="color: darkred">rememberMeServices</span>配置<br /><br /> &lt;bean id="rememberMeServices" class="org.acegisecurity.ui.rememberme.TokenBasedRememberMeServices"><br />  &lt;property name="userDetailsService" ref="userDetailsService"/><br />  &lt;property name="key" value="changeThis"/><br /> &lt;/bean><br /><br />12.<span style="color: darkred">authenticationManager</span>配置<br /><br /> &lt;bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager"><br />  &lt;property name="providers"><br />   &lt;list><br />    &lt;ref local="daoAuthenticationProvider"/><br />    &lt;bean class="org.acegisecurity.providers.anonymous.AnonymousAuthenticationProvider"><br />     &lt;property name="key" value="changeThis"/><br />    &lt;/bean><br />    &lt;bean class="org.acegisecurity.providers.rememberme.RememberMeAuthenticationProvider"><br />     &lt;property name="key" value="changeThis"/><br />    &lt;/bean><br />   &lt;/list><br />  &lt;/property><br /> &lt;/bean><br /><br />13.<span style="color: darkred">daoAuthenticationProvider</span>配置<br /><br /> &lt;bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider"><br />  &lt;property name="userDetailsService" ref="userDetailsService"/><br />  &lt;property name="userCache"><br />   &lt;bean class="org.acegisecurity.providers.dao.cache.EhCacheBasedUserCache"><br />    &lt;property name="cache"><br />     &lt;bean class="org.springframework.cache.ehcache.EhCacheFactoryBean"><br />      &lt;property name="cacheManager"><br />       &lt;bean class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"><br />        &lt;property name="configLocation" value="classpath:ehcache.xml"/><br />       &lt;/bean><br />      &lt;/property><br />      &lt;property name="cacheName" value="userCache"/><br />     &lt;/bean><br />    &lt;/property><br />   &lt;/bean><br />  &lt;/property><br /> &lt;/bean><br /><br />14.<span style="color: darkred">methodSecurityInterceptor</span>配置<br /> <br /> &lt;bean id="methodSecurityInterceptor" class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor"><br />  &lt;property name="authenticationManager" ref="authenticationManager"/><br />  &lt;property name="accessDecisionManager" ref="accessDecisionManager"/><br />  &lt;property name="objectDefinitionSource"><br />    &lt;value><br />     com.rain.wsh.service.IUserService.get*=IS_AUTHENTICATED_ANONYMOUSLY <br />      com.rain.wsh.service.IUserService.create*=IS_AUTHENTICATED_ANONYMOUSLY <br />      com.rain.wsh.service.IUserService.update*=IS_AUTHENTICATED_ANONYMOUSLY <br />      com.rain.wsh.service.IUserService.delete*=IS_AUTHENTICATED_ANONYMOUSLY <br />   &lt;/value><br />  &lt;/property><br /> &lt;/bean><br /><br />15.<span style="color: darkred">loggerListener</span>配置<br /><br /> &lt;!-- This bean is optional; it isn't used by any other bean as it only listens and logs --><br /> &lt;bean id="loggerListener" class="org.acegisecurity.event.authentication.LoggerListener"/><br /><br />注:<span style="color: darkred">userDetailsService</span>定义为:<br />&lt;bean id="userDetailsService" class="com.rain.wsh.service.impl.UserDetailsServiceImpl"/><br /><br />package com.rain.wsh.service.impl;<br /><br />import org.acegisecurity.userdetails.UserDetails;<br />import org.acegisecurity.userdetails.<span style="color: darkred">UserDetailsService</span>;<br />import org.acegisecurity.userdetails.UsernameNotFoundException;<br />import org.springframework.dao.DataAccessException;<br /><br />import com.rain.wsh.dao.IUserDAO;<br /><br />public class UserDetailsServiceImpl implements <span style="color: darkred">UserDetailsService </span>{<br /> private final Logger log = Logger.getLogger(getClass());<br /> <br /> private IUserDAO userDAO;<br /> <br /> /**<br />  * @return the userDAO<br />  */<br /> public IUserDAO getUserDAO() {<br />  return userDAO;<br /> }<br /><br /> /**<br />  * @param userDAO the userDAO to set<br />  */<br /> public void setUserDAO(IUserDAO userDAO) {<br />  this.userDAO = userDAO;<br /> }<br /> <br /> /*<br />  * (non-Javadoc)<br />  * @see org.acegisecurity.userdetails.UserDetailsService#loadUserByUsername(java.lang.String)<br />  */<br /> public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException, DataAccessException {<br />  <br />  UserDetails user = userDAO.getUserByName(userName);<br />  if (user == null) {<br />   log.error("The user was not found:" + userName);<br />   throw new UsernameNotFoundException("The user was not found:" + userName);<br />  }<br />  return user;<br /> }<br /><br />}<br /><br />注意user必须实现Serializable, UserDetails<br /><br /><span style="color: darkred">二.配置顺序</span><br />在web.xml中定义的filter的顺序是非常重要的。不管你实际用到哪个filter，&lt;filter-mapping>的顺序应该是如下所示的：<br /><br />1．ChannelProcessingFilter，因为可能要重定向到另一种协议。<br /><br />2．ConcurrentSessionFilter 因为不使用任何SecurityContextHolder的功能，但是需要更新SessionRegistry来表示当前的发送请求的principal。<br /><br />3． HttpSessionContextIntegrationFilter, 这样当一个web请求开始的时候就可以在SecurityContextHolder中设置一个SecurityContext，当web请求结束的时候任何对SecurityContext的改动都会被copy到HttpSession（以备下一个web请求使用）。<br /><br />4．Authentication processing mechanisms - AuthenticationProcessingFilter, CasProcessingFilter, BasicProcessingFilter, HttpRequestIntegrationFilter, JbossIntegrationFilter 等 - 修改SecurityContextHolder，使其中包含一个有效的认证请求令牌（token）。<br /><br />5．SecurityContextHolderAwareRequestFilter, 如果你使用它来在你的servlet容器中安装一个Acegi Security aware HttpServletRequestWrapper。<br /><br />6．RememberMeProcessingFilter, 如果早期的认证处理过程没有更新SecurityContextHolder，并且请求（request）提供了一个cookie启用remember-me服务，一个合适的被记住的Authentication对象会被放到SecurityContextHolder那里。<br /><br />7．AnonymousProcessingFilter, 如果早期的认证处理过程没有更新SecurityContextHolder，, 一个匿名Authentication 对象会被放到SecurityContextHolder那里。<br /><br />8．ExceptionTranslationFilter, 捕获所有的Acegi Security 异常，这样要么返回一个HTTP错误响应或者加载一个对应的AuthenticationEntryPoint。<br /><br />9．FilterSecurityInterceptor, 保护 web URIs<br /><br />所有上述的filter使用FilterToBeanProxy或FilterChainProxy。建议在一个应用中使用一个单个的FilterToBeanProxy代理到一个单个的FilterChainProxy。，在FilterChainProxy中定义所有的Acegi Security Filters。如果你使用SiteMesh，确保Acegi Security filters 在 SiteMesh filters调用前调用。这样使SecurityContextHolder在SiteMesh decorator使用前能够及时被装配。
          <br/>
          <span style="color:red;">
            <a href="http://shijian0306.javaeye.com/blog/182209#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 13 Apr 2008 00:01:31 +0800</pubDate>
        <link>http://shijian0306.javaeye.com/blog/182209</link>
        <guid>http://shijian0306.javaeye.com/blog/182209</guid>
      </item>
      <item>
        <title>Spring web应用下怎么方便的获得bean?</title>
        <author>shijian0306</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://shijian0306.javaeye.com">shijian0306</a>&nbsp;
          链接：<a href="http://shijian0306.javaeye.com/blog/174045" style="color:red;">http://shijian0306.javaeye.com/blog/174045</a>&nbsp;
          发表时间: 2008年03月20日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          Spring web应用下怎么方便的获得bean？     <br />如果我们的系统不是分布式的（在分布式里，我一般自己加载spring的配置文件)，不是一般的application，通过自己加载Spring的配置文件的方式。而是一般的web应用，我们通过在web.xml里配置spring的配置文件。我们怎么方便的得到一个Bean的实例呢？当然，web应用启动后，它已经创建好一个WebApplicationContext（这个是接口，其实也是ApplicationContext类型的，因为WebApplicationContext继承自ApplictionContext这个接口）类型的实例对象，通过org.springframework.web.context.support.WebApplicationContextUtils里的<br />getWebApplicationContext(ServletContext sc)可以得到这个对象的引用（这个就像我们一般的java application下得到ApplicationContext类型的引用一样），我们就可以通过它的getBean方法得到我们的bean实例了。但是这里有个问题getWebApplicationContext(ServletContext sc)这个方法的参数ServletContext代表的是你web应用的环境，也就是说，也就是说web应用环境下特有的。这个时候如果你想得到一个bean的话，必须要有这个ServletContext对象存在，如果你每个类里都写一个方法来接受ServletContext对象，从而得到WebApplicationContext类型实例的引用，之后再得到bean，进行你要的操作，这个是不是很麻烦？这个不是要写很多代码么？我觉得可以把获得bean的这个操作的功能代码放在一个Servlet里，让这个Servlet在web应用启动的时候加载，我们之后把这个Servlet当作普通类使用，调用里面的getBean方法就可以了。这个servlet的代码如下：<br /><br /> <br /><br />package jimmee.cn.edu.zju.pdm.framework.server;<br /><br /><br />import javax.servlet.ServletException;<br />import javax.servlet.http.HttpServlet;<br /><br />import org.springframework.web.context.WebApplicationContext;<br />import org.springframework.web.context.support.WebApplicationContextUtils;<br /><br />public class GetBeanServlet extends HttpServlet<br />...{<br /><br />    private static WebApplicationContext context;<br />    <br />    public void init() throws ServletException<br />    ...{<br />        context=WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());<br />    }<br />    <br />    public static Object getBean(String id)<br />    ...{<br />        Object bean = context.getBean(id);<br />        <br />        return bean;<br />    }<br />}<br /><br /><br /><br />.Spring在web应用<br /><br /> <br /><br />&lt;?xml version="1.0" encoding="UTF-8"?><br />&lt;web-app version="2.5" <br />    xmlns="http://java.sun.com/xml/ns/javaee" <br />    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <br />    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee <br />    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"><br /> &lt;!-- Spring的配置 --><br />  &lt;context-param><br />        &lt;param-name>contextConfigLocation&lt;/param-name><br />        &lt;param-value>/WEB-INF/beans.xml&lt;/param-value><br />    &lt;/context-param><br />    &lt;context-param><br />        &lt;param-name>log4jConfigLocation&lt;/param-name><br />        &lt;param-value>/WEB-INF/log4j.properties&lt;/param-value><br />    &lt;/context-param><br />    &lt;servlet><br />        &lt;servlet-name>springInitServlet&lt;/servlet-name><br />        &lt;servlet-class><br />            org.springframework.web.context.ContextLoaderServlet<br />        &lt;/servlet-class><br />        &lt;load-on-startup>1&lt;/load-on-startup><br />    &lt;/servlet><br />    &lt;servlet><br />        &lt;servlet-name>log4jInitServlet&lt;/servlet-name><br />        &lt;servlet-class><br />            org.springframework.web.util.Log4jConfigServlet<br />        &lt;/servlet-class><br />        &lt;load-on-startup>2&lt;/load-on-startup><br />    &lt;/servlet><br />  &lt;servlet><br />    &lt;servlet-name>GetBeanServlet&lt;/servlet-name><br />    &lt;servlet-class>jimmee.cn.edu.zju.pdm.framework.server.GetBeanServlet&lt;/servlet-class><br />      &lt;load-on-startup>3&lt;/load-on-startup><br />  &lt;/servlet><br />   &lt;!--Spring配置结束  --><br />  &lt;servlet-mapping><br />    &lt;servlet-name>GetBeanServlet&lt;/servlet-name><br />    &lt;url-pattern>/servlet/GetBeanServlet&lt;/url-pattern><br />  &lt;/servlet-mapping><br /> <br />  &lt;welcome-file-list><br />    &lt;welcome-file>index.jsp&lt;/welcome-file><br />  &lt;/welcome-file-list><br />&lt;/web-app><br /> <br /><br />使用示例：<br /><br />假使我有一个Person的类，属性有name和age，在spring配置文件里配置的id为“person”<br /><br />你在你的servlet或者jsp想得到这个实例的时候，直接这么做就可以了：<br /><br />Person person=(Person)GetBeanServlet.getBean("person");
          <br/>
          <span style="color:red;">
            <a href="http://shijian0306.javaeye.com/blog/174045#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 20 Mar 2008 12:03:04 +0800</pubDate>
        <link>http://shijian0306.javaeye.com/blog/174045</link>
        <guid>http://shijian0306.javaeye.com/blog/174045</guid>
      </item>
      <item>
        <title>Spring中IoC的入门实例详解</title>
        <author>shijian0306</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://shijian0306.javaeye.com">shijian0306</a>&nbsp;
          链接：<a href="http://shijian0306.javaeye.com/blog/166040" style="color:red;">http://shijian0306.javaeye.com/blog/166040</a>&nbsp;
          发表时间: 2008年02月29日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <pre name="code" class="java">Spring的模块化是很强的，各个功能模块都是独立的，我们可以选择的使用。这一章先从Spring的IoC开始。所谓IoC就是一个用XML来定义生成对象的模式，我们看看如果来使用的。

　　数据模型

　　1、如下图所示有三个类，Human（人类）是接口，Chinese（中国人）是一个子类，American（美国人）是另外一个子类。

　　

　　源代码如下：

package cn.com.chengang.spring;public interface Human {void eat();void walk();}package cn.com.chengang.spring;public class Chinese implements Human {/* （非 Javadoc）* @see cn.com.chengang.spring.Human#eat()*/public void eat() {System.out.println(&quot;中国人对吃很有一套&quot;);}/* （非 Javadoc）* @see cn.com.chengang.spring.Human#walk()*/public void walk() {System.out.println(&quot;中国人行如飞&quot;);}}package cn.com.chengang.spring;public class American implements Human {/* （非 Javadoc）* @see cn.com.chengang.spring.Human#eat()*/public void eat() {System.out.println(&quot;美国人主要以面包为主&quot;);}/* （非 Javadoc）* @see cn.com.chengang.spring.Human#walk()*/public void walk() {System.out.println(&quot;美国人以车代步，有四肢退化的趋势&quot;);}} 


　　2、对以上对象采用工厂模式的用法如下

　　创建一个工厂类Factory，如下。这个工厂类里定义了两个字符串常量，所标识不同的人种。getHuman方法根据传入参数的字串，来判断要生成什么样的人种。

package cn.com.chengang.spring;public class Factory {public final static String CHINESE = &quot;Chinese&quot;;public final static String AMERICAN = &quot;American&quot;;public Human getHuman(String ethnic) {if (ethnic.equals(CHINESE))return new Chinese();else if (ethnic.equals(AMERICAN))return new American();elsethrow new IllegalArgumentException(&quot;参数(人种)错误&quot;);}} 

　　下面是一个测试的程序，使用工厂方法来得到了不同的&ldquo;人种对象&rdquo;，并执行相应的方法。

package cn.com.chengang.spring;public class ClientTest {public static void main(String[] args) {Human human = null;human = new Factory().getHuman(Factory.CHINESE);human.eat();human.walk();human = new Factory().getHuman(Factory.AMERICAN);human.eat();human.walk();}} 


　　控制台的打印结果如下：

        

　　3、采用Spring的IoC的用法如下：

　　在项目根目录下创建一个bean.xml文件

＜?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?＞
＜!DOCTYPE beans PUBLIC &quot;-//SPRING//DTD BEAN//EN&quot; &quot;http://www.springframework.org/dtd/spring-beans.dtd&quot;＞
＜beans＞
＜bean id=&quot;Chinese&quot; class=&quot;cn.com.chengang.spring.Chinese&quot;/＞
＜bean id=&quot;American&quot; class=&quot;cn.com.chengang.spring.American&quot;/＞
＜/beans＞ 


　　bean.xml的位置如下图，注意不要看花眼把它看成是lib目录下的了，它是在myspring目录下的。

        

　　修改ClientTest程序如下：

package cn.com.chengang.spring;import org.springframework.context.ApplicationContext;import org.springframework.context.support.FileSystemXmlApplicationContext;public class ClientTest {public final static String CHINESE = &quot;Chinese&quot;;public final static String AMERICAN = &quot;American&quot;;public static void main(String[] args) {// Human human = null;// human = new Factory().getHuman(Factory.CHINESE);// human.eat();// human.walk();// human = new Factory().getHuman(Factory.AMERICAN);// human.eat();// human.walk();ApplicationContext ctx = new FileSystemXmlApplicationContext(&quot;bean.xml&quot;);Human human = null;human = (Human) ctx.getBean(CHINESE);human.eat();human.walk();human = (Human) ctx.getBean(AMERICAN);human.eat();human.walk();}} 

　　从这个程序可以看到，ctx就相当于原来的Factory工厂，原来的Factory就可以删除掉了。然后又把Factory里的两个常量移到了ClientTest类里，整个程序结构基本一样。

　　再回头看原来的bean.xml文件的这一句：

　　＜bean id=&quot;Chinese&quot; class=&quot;cn.com.chengang.spring.Chinese&quot;/＞

　　id就是ctx.getBean的参数值，一个字符串。class就是一个类（包名＋类名）。然后在ClientTest类里获得Chinese对象就是这么一句

　　human = （Human） ctx.getBean（CHINESE）；

　　因为getBean方法返回的是Object类型，所以前面要加一个类型转换。

　　总结

　　（1）也许有人说，IoC和工厂模式不是一样的作用吗，用IoC好象还麻烦一点。

　　举个例子，如果用户需求发生变化，要把Chinese类修改一下。那么前一种工厂模式，就要更改Factory类的方法，并且重新编译布署。而IoC只需要将class属性改变一下，并且由于IoC利用了Java反射机制，这些对象是动态生成的，这时我们就可以热插拨Chinese对象（不必把原程序停止下来重新编译布署）

　　（2）也许有人说，即然IoC这么好，那么我把系统所有对象都用IoC方式来生成。

　　注意，IoC的灵活性是有代价的：设置步骤麻烦、生成对象的方式不直观、反射比正常生成对象在效率上慢一点。因此使用IoC要看有没有必要，我认为比较通用的判断方式是：用到工厂模式的地方都可以考虑用IoC模式。

　　（3）在上面的IoC的方式里，还有一些可以变化的地方。比如，bean.xml不一定要放在项目录下，也可以放在其他地方，比如cn.com.chengang.spring包里。不过在使用时也要变化一下，如下所示：

　　new FileSystemXmlApplicationContext（&quot;src/cn/com/chengang/spring/bean.xml&quot;）；

　　另外，bean.xml也可以改成其他名字。这样我们在系统中就可以分门别类的设置不同的bean.xml.

　　（4）关于IoC的低侵入性。

　　什么是低侵入性？如果你用过Struts或EJB就会发现，要继承一些接口或类，才能利用它们的框架开发。这样，系统就被绑定在Struts、EJB上了，对系统的可移植性产生不利的影响。如果代码中很少涉及某一个框架的代码，那么这个框架就可以称做是一个低侵入性的框架。

　　Spring的侵入性很低，Humen.java、Chinese.java等几个类都不必继承什么接口或类。但在ClientTest里还是有一些Spring的影子：FileSystemXmlApplicationContext类和ctx.getBean方式等。

　　现在，低侵入性似乎也成了判定一个框架的实现技术好坏的标准之一。

　　（5）关于bean.xml的用法

　　bean.xml的用法还有很多，其中内容是相当丰富的。假设Chinese类里有一个humenName属性（姓名），那么原的bean.xml修改如下。此后生成Chinese对象时，&ldquo;陈刚&rdquo;这个值将自动设置到Chinese类的humenName属性中。而且由于singleton为true这时生成Chinese对象将采用单例模式，系统仅存在一个Chinese对象实例。

＜?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?＞＜!DOCTYPE beans PUBLIC &quot;-//SPRING//DTD BEAN//EN&quot;     &quot;http://www.springframework.org/dtd/spring-beans.dtd&quot;＞＜beans＞＜bean id=&quot;Chinese&quot; class=&quot;cn.com.chengang.spring.Chinese&quot; singleton=&quot;true&quot;＞＜property name=&quot;humenName&quot;＞＜value＞陈刚＜/value＞＜/property＞＜/bean＞＜bean id=&quot;American&quot; class=&quot;cn.com.chengang.spring.American&quot;/＞＜/beans＞ 


　　关于bean.xml的其它用法，不再详细介绍了，大家自己拿Spring的文档一看就明白了。
</pre>&nbsp;
          <br/>
          <span style="color:red;">
            <a href="http://shijian0306.javaeye.com/blog/166040#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 29 Feb 2008 10:18:18 +0800</pubDate>
        <link>http://shijian0306.javaeye.com/blog/166040</link>
        <guid>http://shijian0306.javaeye.com/blog/166040</guid>
      </item>
      <item>
        <title>Spring的AOP实现</title>
        <author>shijian0306</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://shijian0306.javaeye.com">shijian0306</a>&nbsp;
          链接：<a href="http://shijian0306.javaeye.com/blog/166037" style="color:red;">http://shijian0306.javaeye.com/blog/166037</a>&nbsp;
          发表时间: 2008年02月29日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <pre name="code" class="java">我们来分析一下这个Demo，它的业务逻辑是求图形的面积，如果把日志服务的代码直接写在业务逻辑中，那么业务逻辑就不是纯净的，而服务也不能被其他业务逻辑共享，所以我们需要把日志服务单独写成一个类，然后通过Spring的AOP实现，动态的把服务插入到业务逻辑中。理解了这点我们再来看IOC，其实IOC的核心思想就是面向接口编程；在这里求圆的面积和求正方形的面积是不一样的，那么为了减弱对象与对象的之间的依赖关系，我们需要对业务逻辑进行抽象，即定义圆形和正方形的接口－－几何图形。 
//定义业务逻辑的抽象－－Figure接口
package mypack;
public interface Figure {
 
 void computeArea();
}
 
//定义业务逻辑的实现－－圆形
package mypack;
public class Round implements Figure{
 public void computeArea() {
  System.out.println(&quot;计算圆形面积&quot;);
 }
}
//定义业务逻辑的实现－－正方形
package mypack;
public class Square implements Figure{
 public void computeArea() {
  System.out.println(&quot;计算正方形面积&quot;);
 }
}
 //对业务逻辑封装的抽象
package mypack;
public interface ComputeInterface {
 public abstract void compute();
}
//对业务逻辑进行封装，并采用set注入方式来实现依赖注入
package mypack;
public class Compute implements ComputeInterface {
 private Figure figure;
 public Figure getFigure() {
  return figure;
 }
 public void setFigure(Figure figure) {       //set注入
  this.figure = figure;
 }
 
 public void compute(){      //业务逻辑封装
  figure.computeArea();
 }
}
 
//将日志服务从业务逻辑中剥离出来产生一个Advice，这个Advice从而可以为其他业务逻辑反复使用
package mypack;
import java.lang.reflect.*;
import java.util.logging.*;
import org.springframework.aop.*;
public class LogBeforeAdvice implements MethodBeforeAdvice{
 private Logger loger = Logger.getLogger(this.getClass().getName());
 
 public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
  loger.log(Level.INFO, &quot;方法开始启动 &quot; + arg0);  
 }
  
}
 
//applicationContext.xml在后面做了很多事情，如实现依赖注入和产生动态代理对象将Advice织入到业务逻辑中
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;!DOCTYPE beans PUBLIC &quot;-//SPRING//DTD BEAN//EN&quot; &quot;http://www.springframework.org/dtd/spring-beans.dtd&quot;&gt;
&lt;beans&gt;
 &lt;bean id=&quot;round&quot; class=&quot;mypack.Round&quot;&gt;
 &lt;/bean&gt;
 
 &lt;bean id=&quot;square&quot; class=&quot;mypack.Square&quot;&gt;
 &lt;/bean&gt;
 
 &lt;bean id=&quot;compute&quot; class=&quot;mypack.Compute&quot;&gt;
  &lt;property name=&quot;figure&quot;&gt;
   &lt;ref bean=&quot;round&quot;/&gt;
  &lt;/property&gt;
 &lt;/bean&gt;
 
 &lt;bean id=&quot;logBeforeAdvice&quot; class=&quot;mypack.LogBeforeAdvice&quot;&gt;
 &lt;/bean&gt;
 
 &lt;bean id=&quot;proxy&quot; class=&quot;org.springframework.aop.framework.ProxyFactoryBean&quot;&gt;
  
  &lt;property name=&quot;proxyInterfaces&quot;&gt;
   &lt;value&gt;mypack.ComputeInterface&lt;/value&gt;
  &lt;/property&gt; 
  
  &lt;property name=&quot;target&quot;&gt;
   &lt;ref bean=&quot;compute&quot;/&gt;
  &lt;/property&gt;
  
  &lt;property name=&quot;interceptorNames&quot;&gt;
   &lt;list&gt;
    &lt;value&gt;logBeforeAdvice&lt;/value&gt;
   &lt;/list&gt;
  &lt;/property&gt;
 &lt;/bean&gt;
&lt;/beans&gt;
 
//最后来写一段测试代码来测试上面的代码
package mypack;
import org.springframework.context.*;
import org.springframework.context.support.*;
public class TestDemo {
 
 public static void main(String[] args) {
  ApplicationContext context = new FileSystemXmlApplicationContext(&quot;applicationContext.xml&quot;);
  
  ComputeInterface comp = (ComputeInterface)context.getBean(&quot;proxy&quot;);
  comp.compute();
 }
 
}</pre>&nbsp;
          <br/>
          <span style="color:red;">
            <a href="http://shijian0306.javaeye.com/blog/166037#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 29 Feb 2008 10:15:30 +0800</pubDate>
        <link>http://shijian0306.javaeye.com/blog/166037</link>
        <guid>http://shijian0306.javaeye.com/blog/166037</guid>
      </item>
      <item>
        <title>Spring的优秀工具类盘点</title>
        <author>shijian0306</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://shijian0306.javaeye.com">shijian0306</a>&nbsp;
          链接：<a href="http://shijian0306.javaeye.com/blog/166036" style="color:red;">http://shijian0306.javaeye.com/blog/166036</a>&nbsp;
          发表时间: 2008年02月29日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <pre name="code" class="java">Spring 所提供的过滤器和监听器
Spring 为 Web 应用提供了几个过滤器和监听器，在适合的时间使用它们，可以解决一些常见的 Web 应用问题。
延迟加载过滤器 
Hibernate 允许对关联对象、属性进行延迟加载，但是必须保证延迟加载的操作限于同一个 Hibernate Session 范围之内进行。如果 Service 层返回一个启用了延迟加载功能的领域对象给 Web 层，当 Web 层访问到那些需要延迟加载的数据时，由于加载领域对象的 Hibernate Session 已经关闭，这些导致延迟加载数据的访问异常。
Spring 为此专门提供了一个 OpenSessionInViewFilter 过滤器，它的主要功能是使每个请求过程绑定一个 Hibernate Session，即使最初的事务已经完成了，也可以在 Web 层进行延迟加载的操作。
OpenSessionInViewFilter 过滤器将 Hibernate Session 绑定到请求线程中，它将自动被 Spring 的事务管理器探测到。所以 OpenSessionInViewFilter 适用于 Service 层使用HibernateTransactionManager 或 JtaTransactionManager 进行事务管理的环境，也可以用于非事务只读的数据操作中。
要启用这个过滤器，必须在 web.xml 中对此进行配置：
&hellip;
&lt;filter&gt;
    &lt;filter-name&gt;hibernateFilter&lt;/filter-name&gt;
    &lt;filter-class&gt;
    org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
    &lt;/filter-class&gt;
&lt;/filter&gt;
&lt;filter-mapping&gt;
    &lt;filter-name&gt;hibernateFilter&lt;/filter-name&gt;
    &lt;url-pattern&gt;*.html&lt;/url-pattern&gt;
&lt;/filter-mapping&gt;
&hellip;

上面的配置，我们假设使用 .html 的后缀作为 Web 框架的 URL 匹配模式，如果您使用 Struts 等 Web 框架，可以将其改为对应的&ldquo;*.do&rdquo;模型。 
中文乱码过滤器 
在您通过表单向服务器提交数据时，一个经典的问题就是中文乱码问题。虽然我们所有的 JSP 文件和页面编码格式都采用 UTF-8，但这个问题还是会出现。解决的办法很简单，我们只需要在 web.xml 中配置一个 Spring 的编码转换过滤器就可以了：
&lt;web-app&gt;
&lt;!---listener的配置--&gt;
&lt;filter&gt;
    &lt;filter-name&gt;encodingFilter&lt;/filter-name&gt;
    &lt;filter-class&gt;
        org.springframework.web.filter.CharacterEncodingFilter ① Spring 编辑过滤器
    &lt;/filter-class&gt;
    &lt;init-param&gt; ② 编码方式
        &lt;param-name&gt;encoding&lt;/param-name&gt;
        &lt;param-value&gt;UTF-8&lt;/param-value&gt;
    &lt;/init-param&gt;
    &lt;init-param&gt; ③ 强制进行编码转换
        &lt;param-name&gt;forceEncoding&lt;/param-name&gt;
        &lt;param-value&gt;true&lt;/param-value&gt;
    &lt;/init-param&gt;
    &lt;/filter&gt;
    &lt;filter-mapping&gt; ② 过滤器的匹配 URL
        &lt;filter-name&gt;encodingFilter&lt;/filter-name&gt;
        &lt;url-pattern&gt;*.html&lt;/url-pattern&gt;
    &lt;/filter-mapping&gt;

&lt;!---servlet的配置--&gt;
&lt;/web-app&gt;

这样所有以 .html 为后缀的 URL 请求的数据都会被转码为 UTF-8 编码格式，表单中文乱码的问题就可以解决了。
请求跟踪日志过滤器 
除了以上两个常用的过滤器外，还有两个在程序调试时可能会用到的请求日志跟踪过滤器，它们会将请求的一些重要信息记录到日志中，方便程序的调试。这两个日志过滤器只有在日志级别为 DEBUG 时才会起作用：
方法 说明
org.springframework.web.filter.ServletContextRequestLoggingFilter  该过滤器将请求的 URI 记录到 Common 日志中（如通过 Log4J 指定的日志文件）；
org.springframework.web.filter.ServletContextRequestLoggingFilter  该过滤器将请求的 URI 记录到 ServletContext 日志中。
以下是日志过滤器记录的请求跟踪日志的片断：
(JspServlet.java:224) -     JspEngine --&gt; /htmlTest.jsp
(JspServlet.java:225) -       ServletPath: /htmlTest.jsp
(JspServlet.java:226) -          PathInfo: null
(JspServlet.java:227) -          RealPath: D:\masterSpring\chapter23\webapp\htmlTest.jsp
(JspServlet.java:228) -        RequestURI: /baobaotao/htmlTest.jsp
&hellip;

通过这个请求跟踪日志，程度调试者可以详细地查看到有哪些请求被调用，请求的参数是什么，请求是否正确返回等信息。虽然这两个请求跟踪日志过滤器一般在程序调试时使用，但是即使程序部署不将其从 web.xml 中移除也不会有大碍，因为只要将日志级别设置为 DEBUG 以上级别，它们就不会输出请求跟踪日志信息了。
转存 Web 应用根目录监听器和 Log4J 监听器 
Spring 在 org.springframework.web.util 包中提供了几个特殊用途的 Servlet 监听器，正确地使用它们可以完成一些特定需求的功能。比如某些第三方工具支持通过 ${key} 的方式引用系统参数（即可以通过 System.getProperty() 获取的属性），WebAppRootListener 可以将 Web 应用根目录添加到系统参数中，对应的属性名可以通过名为&ldquo;webAppRootKey&rdquo;的 Servlet 上下文参数指定，默认为&ldquo;webapp.root&rdquo;。下面是该监听器的具体的配置：

清单 6. WebAppRootListener 监听器配置
&hellip;
&lt;context-param&gt;
    &lt;param-name&gt;webAppRootKey&lt;/param-name&gt;
    &lt;param-value&gt;baobaotao.root&lt;/param-value&gt; ① Web 应用根目录以该属性名添加到系统参数中
&lt;/context-param&gt;
&hellip;
② 负责将 Web 应用根目录以 webAppRootKey 上下文参数指定的属性名添加到系统参数中
&lt;listener&gt;
    &lt;listener-class&gt; 
    org.springframework.web.util.WebAppRootListener
    &lt;/listener-class&gt;
&lt;/listener&gt;
&hellip;

这样，您就可以在程序中通过 System.getProperty(&quot;baobaotao.root&quot;) 获取 Web 应用的根目录了。不过更常见的使用场景是在第三方工具的配置文件中通过${baobaotao.root} 引用 Web 应用的根目录。比如以下的 log4j.properties 配置文件就通过 ${baobaotao.root} 设置了日志文件的地址：
log4j.rootLogger=INFO,R
log4j.appender.R=org.apache.log4j.RollingFileAppender
log4j.appender.R.File=${baobaotao.root}/WEB-INF/logs/log4j.log ① 指定日志文件的地址
log4j.appender.R.MaxFileSize=100KB
log4j.appender.R.MaxBackupIndex=1
log4j.appender.R.layout.ConversionPattern=%d %5p [%t] (%F:%L) - %m%n

另一个专门用于 Log4J 的监听器是 Log4jConfigListener。一般情况下，您必须将 Log4J 日志配置文件以 log4j.properties 为文件名并保存在类路径下。Log4jConfigListener 允许您通过 log4jConfigLocation Servlet 上下文参数显式指定 Log4J 配置文件的地址，如下所示：
① 指定 Log4J 配置文件的地址
&lt;context-param&gt;
    &lt;param-name&gt;log4jConfigLocation&lt;/param-name&gt;
    &lt;param-value&gt;/WEB-INF/log4j.properties&lt;/param-value&gt;
&lt;/context-param&gt;
&hellip;
② 使用该监听器初始化 Log4J 日志引擎
&lt;listener&gt;
    &lt;listener-class&gt;
    org.springframework.web.util.Log4jConfigListener
    &lt;/listener-class&gt;
&lt;/listener&gt;
&hellip;


提示
一些Web应用服务器（如 Tomcat）不会为不同的Web应用使用独立的系统参数，也就是说，应用服务器上所有的 Web 应用都共享同一个系统参数对象。这时，您必须通过webAppRootKey 上下文参数为不同Web应用指定不同的属性名：如第一个 Web 应用使用 webapp1.root 而第二个 Web 应用使用 webapp2.root 等，这样才不会发生后者覆盖前者的问题。此外，WebAppRootListener 和 Log4jConfigListener 都只能应用在 Web 应用部署后 WAR 文件会解包的 Web 应用服务器上。一些 Web 应用服务器不会将Web 应用的 WAR 文件解包，整个 Web 应用以一个 WAR 包的方式存在（如 Weblogic），此时因为无法指定对应文件系统的 Web 应用根目录，使用这两个监听器将会发生问题。

Log4jConfigListener 监听器包括了 WebAppRootListener 的功能，也就是说，Log4jConfigListener 会自动完成将 Web 应用根目录以 webAppRootKey 上下文参数指定的属性名添加到系统参数中，所以当您使用 Log4jConfigListener 后，就没有必须再使用 WebAppRootListener了。
Introspector 缓存清除监听器 
Spring 还提供了一个名为 org.springframework.web.util.IntrospectorCleanupListener 的监听器。它主要负责处理由 JavaBean Introspector 功能而引起的缓存泄露。IntrospectorCleanupListener 监听器在 Web 应用关闭的时会负责清除 JavaBean Introspector 的缓存，在 web.xml 中注册这个监听器可以保证在 Web 应用关闭的时候释放与其相关的 ClassLoader 的缓存和类引用。如果您使用了 JavaBean Introspector 分析应用中的类，Introspector 缓存会保留这些类的引用，结果在应用关闭的时候，这些类以及Web 应用相关的 ClassLoader 不能被垃圾回收。不幸的是，清除 Introspector 的唯一方式是刷新整个缓存，这是因为没法准确判断哪些是属于本 Web 应用的引用对象，哪些是属于其它 Web 应用的引用对象。所以删除被缓存的 Introspection 会导致将整个 JVM 所有应用的 Introspection 都删掉。需要注意的是，Spring 托管的 Bean 不需要使用这个监听器，因为 Spring 的 Introspection 所使用的缓存在分析完一个类之后会马上从 javaBean Introspector 缓存中清除掉，并将缓存保存在应用程序特定的 ClassLoader 中，所以它们一般不会导致内存资源泄露。但是一些类库和框架往往会产生这个问题。例如 Struts 和 Quartz 的 Introspector 的内存泄漏会导致整个的 Web 应用的 ClassLoader 不能进行垃圾回收。在 Web 应用关闭之后，您还会看到此应用的所有静态类引用，这个错误当然不是由这个类自身引起的。解决这个问题的方法很简单，您仅需在 web.xml 中配置 IntrospectorCleanupListener 监听器就可以了：
&lt;listener&gt;
    &lt;listener-class&gt;
    org.springframework.web.util.IntrospectorCleanupListener
    &lt;/listener-class&gt;
&lt;/listener&gt;
</pre>&nbsp;
          <br/>
          <span style="color:red;">
            <a href="http://shijian0306.javaeye.com/blog/166036#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 29 Feb 2008 10:13:36 +0800</pubDate>
        <link>http://shijian0306.javaeye.com/blog/166036</link>
        <guid>http://shijian0306.javaeye.com/blog/166036</guid>
      </item>
      <item>
        <title>Assert</title>
        <author>shijian0306</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://shijian0306.javaeye.com">shijian0306</a>&nbsp;
          链接：<a href="http://shijian0306.javaeye.com/blog/166030" style="color:red;">http://shijian0306.javaeye.com/blog/166030</a>&nbsp;
          发表时间: 2008年02月29日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <pre name="code" class="java">Spring 不但提供了一个功能全面的应用开发框架，本身还拥有众多可以在程序编写时直接使用的工具类，您不但可以在 Spring 应用中使用这些工具类，也可以在其它的应用中使用，这些工具类中的大部分是可以在脱离 Spring 框架时使用的。了解 Spring 中有哪些好用的工具类并在程序编写时适当使用，将有助于提高开发效率、增强代码质量。

在这个分为两部分的文章中，我们将从众多的 Spring 工具类中遴选出那些好用的工具类介绍给大家。第 1 部分 介绍了与文件资源操作和 Web 相关的工具类。在第 2 部分中将介绍特殊字符转义和方法入参检测工具类。

特殊字符转义

由于 Web 应用程序需要联合使用到多种语言，每种语言都包含一些特殊的字符，对于动态语言或标签式的语言而言，如果需要动态构造语言的内容时，一个我们经常会碰到的问题就是特殊字符转义的问题。下面是 Web 开发者最常面对需要转义的特殊字符类型：

HTML 特殊字符； 
JavaScript 特殊字符； 
SQL 特殊字符； 
如果不对这些特殊字符进行转义处理，则不但可能破坏文档结构，还可以引发潜在的安全问题。Spring 为 HTML 和 JavaScript 特殊字符提供了转义操作工具类，它们分别是 HtmlUtils 和 JavaScriptUtils。

HTML 特殊字符转义

HTML 中 &lt;，&gt;，&amp; 等字符有特殊含义，它们是 HTML 语言的保留字，因此不能直接使用。使用这些个字符时，应使用它们的转义序列：

&amp;：&amp; 
&quot; ：&quot; 
&lt; ：&lt; 
&gt; ：&gt; 
由于 HTML 网页本身就是一个文本型结构化文档，如果直接将这些包含了 HTML 特殊字符的内容输出到网页中，极有可能破坏整个 HTML 文档的结构。所以，一般情况下需要对动态数据进行转义处理，使用转义序列表示 HTML 特殊字符。下面的 JSP 网页将一些变量动态输出到 HTML 网页中：


清单 1. 未进行 HTML 特殊字符转义处理网页
                
&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=utf-8&quot;%&gt;
&lt;%!
   String userName = &quot;&lt;/td&gt;&lt;tr&gt;&lt;/table&gt;&quot;;
   String address = &quot; \&quot; type=\&quot;button&quot;;
 %&gt;
&lt;table border=&quot;1&quot;&gt;
   &lt;tr&gt;
     &lt;td&gt;姓名：&lt;/td&gt;&lt;td&gt;&lt;%=userName%&gt;&lt;/td&gt; ①
   &lt;/tr&gt;
   &lt;tr&gt;
     &lt;td&gt;年龄：&lt;/td&gt;&lt;td&gt;28&lt;/td&gt;
   &lt;/tr&gt;
&lt;/table&gt;
 &lt;input value=&quot;&lt;%=address%&gt;&quot;  type=&quot;text&quot; /&gt; ②
 


在 ① 和 ② 处，我们未经任何转义处理就直接将变量输出到 HTML 网页中，由于这些变量可能包含一些特殊的 HTML 的字符，它们将可能破坏整个 HTML 文档的结构。我们可以从以上 JSP 页面的一个具体输出中了解这一问题：

&lt;table border=&quot;1&quot;&gt;
   &lt;tr&gt;
     &lt;td&gt;姓名：&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;tr&gt;&lt;/table&gt;&lt;/td&gt; 
     ① 破坏了 &lt;table&gt; 的结构
   &lt;/tr&gt;
   &lt;tr&gt;
     &lt;td&gt;年龄：&lt;/td&gt;&lt;td&gt;28&lt;/td&gt;
   &lt;/tr&gt;
&lt;/table&gt;
 &lt;input value=&quot; &quot; type=&quot;button&quot;  type=&quot;text&quot; /&gt; 
 ② 将本来是输入框组件偷梁换柱为按钮组件
 


融合动态数据后的 HTML 网页已经面目全非，首先 ① 处的 &lt;table&gt; 结构被包含 HTML 特殊字符的 userName 变量截断了，造成其后的 &lt;table&gt; 代码变成无效的内容；其次，② 处 &lt;input&gt; 被动态数据改换为按钮类型的组件（type=&quot;button&quot;）。为了避免这一问题，我们需要事先对可能破坏 HTML 文档结构的动态数据进行转义处理。Spring 为我们提供了一个简单适用的 HTML 特殊字符转义工具类，它就是 HtmlUtils。下面，我们通过一个简单的例子了解 HtmlUtils 的具体用法：


清单 2. HtmpEscapeExample
                
package com.baobaotao.escape;
import org.springframework.web.util.HtmlUtils;
public class HtmpEscapeExample {
    public static void main(String[] args) {
        String specialStr = &quot;&lt;div id=\&quot;testDiv\&quot;&gt;test1;test2&lt;/div&gt;&quot;;
        String str1 = HtmlUtils.htmlEscape(specialStr); ①转换为HTML转义字符表示
        System.out.println(str1);
       
        String str2 = HtmlUtils.htmlEscapeDecimal(specialStr); ②转换为数据转义表示
        System.out.println(str2);
       
        String str3 = HtmlUtils.htmlEscapeHex(specialStr); ③转换为十六进制数据转义表示
        System.out.println(str3);
       
        ④下面对转义后字符串进行反向操作
        System.out.println(HtmlUtils.htmlUnescape(str1));
        System.out.println(HtmlUtils.htmlUnescape(str2));
        System.out.println(HtmlUtils.htmlUnescape(str3));
    }
}
 


HTML 不但可以使用通用的转义序列表示 HTML 特殊字符，还可以使用以 # 为前缀的数字序列表示 HTML 特殊字符，它们在最终的显示效果上是一样的。HtmlUtils 提供了三个转义方法：

方法 说明 
static String htmlEscape(String input)  将 HTML 特殊字符转义为 HTML 通用转义序列； 
static String htmlEscapeDecimal(String input)  将 HTML 特殊字符转义为带 # 的十进制数据转义序列； 
static String htmlEscapeHex(String input)  将 HTML 特殊字符转义为带 # 的十六进制数据转义序列； 

此外，HtmlUtils 还提供了一个能够将经过转义内容还原的方法：htmlUnescape(String input)，它可以还原以上三种转义序列的内容。运行以上代码，您将可以看到以下的输出：

str1:&lt;div id=&quot;testDiv&quot;&gt;test1;test2&lt;/div&gt;
str2:&lt;div id=&quot;testDiv&quot;&gt;test1;test2&lt;/div&gt;
str3:&lt;div id=&quot;testDiv&quot;&gt;test1;test2&lt;/div&gt;
&lt;div id=&quot;testDiv&quot;&gt;test1;test2&lt;/div&gt;
&lt;div id=&quot;testDiv&quot;&gt;test1;test2&lt;/div&gt;
&lt;div id=&quot;testDiv&quot;&gt;test1;test2&lt;/div&gt;
 


您只要使用 HtmlUtils 对代码 清单 1 的 userName 和 address 进行转义处理，最终输出的 HTML 页面就不会遭受破坏了。

JavaScript 特殊字符转义

JavaScript 中也有一些需要特殊处理的字符，如果直接将它们嵌入 JavaScript 代码中，JavaScript 程序结构将会遭受破坏，甚至被嵌入一些恶意的程序。下面列出了需要转义的特殊 JavaScript 字符：

' ：\' 
&quot; ：\&quot; 
\ ：\\ 
走纸换页： \f 
换行：\n 
换栏符：\t 
回车：\r 
回退符：\b 
 
我们通过一个具体例子演示动态变量是如何对 JavaScript 程序进行破坏的。假设我们有一个 JavaScript 数组变量，其元素值通过一个 Java List 对象提供，下面是完成这一操作的 JSP 代码片断：


清单 3. jsTest.jsp：未对 JavaScript 特殊字符进行处理
                
&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=utf-8&quot;%&gt;
&lt;jsp:directive.page import=&quot;java.util.*&quot;/&gt;
&lt;%
  List textList = new ArrayList();
  textList.add(&quot;\&quot;;alert();j=\&quot;&quot;);
%&gt;
&lt;script&gt;
  var txtList = new Array();
   &lt;% for ( int i = 0 ; i &lt; textList.size() ; i++) { %&gt;
     txtList[&lt;%=i%&gt;] = &quot;&lt;%=textList.get(i)%&gt;&quot;; 
	 ① 未对可能包含特殊 JavaScript 字符的变量进行处理
   &lt;% } %&gt;
&lt;/script&gt;
 


当客户端调用这个 JSP 页面后，将得到以下的 HTML 输出页面：

&lt;script&gt;
  var txtList = new Array();
   txtList[0] = &quot;&quot;;alert();j=&quot;&quot;; ① 本来是希望接受一个字符串，结果被植入了一段JavaScript代码
&lt;/script&gt;
 


由于包含 JavaScript 特殊字符的 Java 变量直接合并到 JavaScript 代码中，我们本来期望 ① 处所示部分是一个普通的字符串，但结果变成了一段 JavaScript 代码，网页将弹出一个 alert 窗口。想像一下如果粗体部分的字符串是&ldquo;&quot;;while(true)alert();j=&quot;&rdquo;时会产生什么后果呢？

因此，如果网页中的 JavaScript 代码需要通过拼接 Java 变量动态产生时，一般需要对变量的内容进行转义处理，可以通过 Spring 的 JavaScriptUtils 完成这件工作。下面，我们使用 JavaScriptUtils 对以上代码进行改造：

&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=utf-8&quot;%&gt;
&lt;jsp:directive.page import=&quot;java.util.*&quot;/&gt;
&lt;jsp:directive.page import=&quot;org.springframework.web.util.JavaScriptUtils&quot;/&gt;
&lt;%
  List textList = new ArrayList();
  textList.add(&quot;\&quot;;alert();j=\&quot;&quot;);
%&gt;
&lt;script&gt;
   var txtList = new Array();
   &lt;% for ( int i = 0 ; i &lt; textList.size() ; i++) { %&gt;
   ① 在输出动态内容前事先进行转义处理
   txtList[&lt;%=i%&gt;] = &quot;&lt;%=JavaScriptUtils.javaScriptEscape(&quot;&quot;+textList.get(i))%&gt;&quot;;
   &lt;% } %&gt;
&lt;/script&gt;
 


通过转义处理后，这个 JSP 页面输出的结果网页的 JavaScript 代码就不会产生问题了：

&lt;script&gt;
   var txtList = new Array();
   txtList[0] = &quot;\&quot;;alert();j=\&quot;&quot;;
   ① 粗体部分仅是一个普通的字符串，而非一段 JavaScript 的语句了
&lt;/script&gt;
 


SQL特殊字符转义

应该说，您即使没有处理 HTML 或 JavaScript 的特殊字符，也不会带来灾难性的后果，但是如果不在动态构造 SQL 语句时对变量中特殊字符进行处理，将可能导致程序漏洞、数据盗取、数据破坏等严重的安全问题。网络中有大量讲解 SQL 注入的文章，感兴趣的读者可以搜索相关的资料深入研究。

虽然 SQL 注入的后果很严重，但是只要对动态构造的 SQL 语句的变量进行特殊字符转义处理，就可以避免这一问题的发生了。来看一个存在安全漏洞的经典例子：

SELECT COUNT(userId) 
FROM t_user 
WHERE userName='&quot;+userName+&quot;' AND password ='&quot;+password+&quot;';
 


以上 SQL 语句根据返回的结果数判断用户提供的登录信息是否正确，如果 userName 变量不经过特殊字符转义处理就直接合并到 SQL 语句中，黑客就可以通过将 userName 设置为 &ldquo;1' or '1'='1&rdquo;绕过用户名/密码的检查直接进入系统了。

所以除非必要，一般建议通过 PreparedStatement 参数绑定的方式构造动态 SQL 语句，因为这种方式可以避免 SQL 注入的潜在安全问题。但是往往很难在应用中完全避免通过拼接字符串构造动态 SQL 语句的方式。为了防止他人使用特殊 SQL 字符破坏 SQL 的语句结构或植入恶意操作，必须在变量拼接到 SQL 语句之前对其中的特殊字符进行转义处理。Spring 并没有提供相应的工具类，您可以通过 jakarta commons lang 通用类包中（spring/lib/jakarta-commons/commons-lang.jar）的 StringEscapeUtils 完成这一工作：


清单 4. SqlEscapeExample
                
package com.baobaotao.escape;
import org.apache.commons.lang.StringEscapeUtils;
public class SqlEscapeExample {
    public static void main(String[] args) {
        String userName = &quot;1' or '1'='1&quot;;
        String password = &quot;123456&quot;;
        userName = StringEscapeUtils.escapeSql(userName);
        password = StringEscapeUtils.escapeSql(password);
        String sql = &quot;SELECT COUNT(userId) FROM t_user WHERE userName='&quot;
            + userName + &quot;' AND password ='&quot; + password + &quot;'&quot;;
        System.out.println(sql);
    }
}
 


事实上，StringEscapeUtils 不但提供了 SQL 特殊字符转义处理的功能，还提供了 HTML、XML、JavaScript、Java 特殊字符的转义和还原的方法。如果您不介意引入 jakarta commons lang 类包，我们更推荐您使用 StringEscapeUtils 工具类完成特殊字符转义处理的工作。



 


 回页首 
 



方法入参检测工具类

Web 应用在接受表单提交的数据后都需要对其进行合法性检查，如果表单数据不合法，请求将被驳回。类似的，当我们在编写类的方法时，也常常需要对方法入参进行合法性检查，如果入参不符合要求，方法将通过抛出异常的方式拒绝后续处理。举一个例子：有一个根据文件名获取输入流的方法：InputStream getData(String file)，为了使方法能够成功执行，必须保证 file 入参不能为 null 或空白字符，否则根本无须进行后继的处理。这时方法的编写者通常会在方法体的最前面编写一段对入参进行检测的代码，如下所示：

public InputStream getData(String file) {
    if (file == null || file.length() == 0|| file.replaceAll(&quot;\\s&quot;, &quot;&quot;).length() == 0) {
        throw new IllegalArgumentException(&quot;file入参不是有效的文件地址&quot;);
    }
&hellip;
}
 


类似以上检测方法入参的代码是非常常见，但是在每个方法中都使用手工编写检测逻辑的方式并不是一个好主意。阅读 Spring 源码，您会发现 Spring 采用一个 org.springframework.util.Assert 通用类完成这一任务。

Assert 翻译为中文为&ldquo;断言&rdquo;，使用过 JUnit 的读者都熟知这个概念，它断定某一个实际的运行值和预期想一样，否则就抛出异常。Spring 对方法入参的检测借用了这个概念，其提供的 Assert 类拥有众多按规则对方法入参进行断言的方法，可以满足大部分方法入参检测的要求。这些断言方法在入参不满足要求时就会抛出 IllegalArgumentException。下面，我们来认识一下 Assert 类中的常用断言方法：

断言方法 说明 
notNull(Object object)  当 object 不为 null 时抛出异常，notNull(Object object, String message) 方法允许您通过 message 定制异常信息。和 notNull() 方法断言规则相反的方法是 isNull(Object object)/isNull(Object object, String message)，它要求入参一定是 null； 
isTrue(boolean expression) / isTrue(boolean expression, String message)  当 expression 不为 true 抛出异常； 
notEmpty(Collection collection) / notEmpty(Collection collection, String message)  当集合未包含元素时抛出异常。notEmpty(Map map) / notEmpty(Map map, String message) 和 notEmpty(Object[] array, String message) / notEmpty(Object[] array, String message) 分别对 Map 和 Object[] 类型的入参进行判断； 
hasLength(String text) / hasLength(String text, String message)  当 text 为 null 或长度为 0 时抛出异常； 
hasText(String text) / hasText(String text, String message)  text 不能为 null 且必须至少包含一个非空格的字符，否则抛出异常； 
isInstanceOf(Class clazz, Object obj) / isInstanceOf(Class type, Object obj, String message)  如果 obj 不能被正确造型为 clazz 指定的类将抛出异常； 
isAssignable(Class superType, Class subType) / isAssignable(Class superType, Class subType, String message)  subType 必须可以按类型匹配于 superType，否则将抛出异常； 

使用 Assert 断言类可以简化方法入参检测的代码，如 InputStream getData(String file) 在应用 Assert 断言类后，其代码可以简化为以下的形式：

public InputStream getData(String file){
    Assert.hasText(file,&quot;file入参不是有效的文件地址&quot;); 
    ① 使用 Spring 断言类进行方法入参检测
&hellip;
}
 


可见使用 Spring 的 Assert 替代自编码实现的入参检测逻辑后，方法的简洁性得到了不少的提高。Assert 不依赖于 Spring 容器，您可以大胆地在自己的应用中使用这个工具类
</pre>&nbsp;
          <br/>
          <span style="color:red;">
            <a href="http://shijian0306.javaeye.com/blog/166030#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 29 Feb 2008 10:00:08 +0800</pubDate>
        <link>http://shijian0306.javaeye.com/blog/166030</link>
        <guid>http://shijian0306.javaeye.com/blog/166030</guid>
      </item>
      <item>
        <title>Jakarta CollectionUtils</title>
        <author>shijian0306</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://shijian0306.javaeye.com">shijian0306</a>&nbsp;
          链接：<a href="http://shijian0306.javaeye.com/blog/166024" style="color:red;">http://shijian0306.javaeye.com/blog/166024</a>&nbsp;
          发表时间: 2008年02月29日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <pre name="code" class="java">★ 数组转Collection

使用Apache Jakarta Commons Collections：


import org.apache.commons.collections.CollectionUtils;    
   
String[] strArray = {&quot;aaa&quot;, &quot;bbb&quot;, &quot;ccc&quot;};    
List strList = new ArrayList();    
Set strSet = new HashSet();    
CollectionUtils.addAll(strList, strArray);    
CollectionUtils.addAll(strSet, strArray);   

CollectionUtils.addAll()方法的实现很简单，只是循环使用了Collection的add()方法而已。

如果只是想将数组转换成List，可以用JDK中的java.util.Arrays类：


import java.util.Arrays;    
   
String[] strArray = {&quot;aaa&quot;, &quot;bbb&quot;, &quot;ccc&quot;};    
List strList = Arrays.asList(strArray);   

不过Arrays.asList()方法返回的List不能add对象，因为该方法的实现是使用参数引用的数组的大小来new的一个ArrayList。


★ Collection转数组

直接使用Collection的toArray()方法，该方法有两个重载版本：

Object[] toArray();    
   
T[] toArray(T[] a);   


★ Map转Collection

直接使用Map的values()方法。


★ List和Set转换

List list = new ArrayList(new Hashset());// Fixed-size list 
List list = Arrays.asList(array);// Growable 
list list = new LinkedList(Arrays.asList(array));// Duplicate elements are discarded 
Set set = new HashSet(Arrays.asList(array));
</pre>&nbsp;
          <br/>
          <span style="color:red;">
            <a href="http://shijian0306.javaeye.com/blog/166024#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 29 Feb 2008 09:52:57 +0800</pubDate>
        <link>http://shijian0306.javaeye.com/blog/166024</link>
        <guid>http://shijian0306.javaeye.com/blog/166024</guid>
      </item>
      <item>
        <title>Jakarta-Common-BeanUtils</title>
        <author>shijian0306</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://shijian0306.javaeye.com">shijian0306</a>&nbsp;
          链接：<a href="http://shijian0306.javaeye.com/blog/166023" style="color:red;">http://shijian0306.javaeye.com/blog/166023</a>&nbsp;
          发表时间: 2008年02月29日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <pre name="code" class="java">1.   概述

       第一次接触BeanUtils是在学习Struts的过程中，在Struts中它被大量用于处理FormBean。

BeanUtils主要提供了对于JavaBean进行各种操作，

       BeanUtils一共分4个包：

&Oslash;         org.apache.commons.beanutils

&Oslash;         org.apache.commons.beanutils.converters

&Oslash;         org.apache.commons.beanutils.locale

&Oslash;         org.apache.commons.beanutils.locale.converters

其中上面两个是BeanUtils的默认实现，它没有针对本地化的任何处理，这个可以提高执行效率。但是若你的程序对于本地化有要求的话，那还是使用下面2个包比较安全。

 

2.   org.apache.commons.beanutils

       这个包主要提供用于操作JavaBean的工具类，Jakarta-Common-BeanUtils的主要功能都在这个包里实现。

    下面分别介绍几个主要的工具类：

2.1.BeanUtil

1、首先，我先定义一个JavaBean作为之后例子的操作对象。

    public class Company

    {

      private String name;

      private HashMap address = new HashMap();

      private String[] otherInfo;

      private ArrayList product;

      private ArrayList employee;

      private HashMap telephone;

 

      public Company(){}

 

      public String getName()

      {

        return name;

      }

      public void setName(String name)

      {

        this.name = name;

      }

 

      public String getAddress(String type)

      {

        return address.get(type).toString();

      }

      public void setAddress(String type, String address)

      {

        this.address.put(type,address);

      }

 

      public String[] getOtherInfo()

      {

        return otherInfo;

      }

      public void setOtherInfo(String[] otherInfo)

      {

        this.otherInfo = otherInfo;

      }

 

      public ArrayList getProduct()

      {

        return product;

      }

      public void setProduct(ArrayList product)

      {

        this.product = product;

      }

 

      public ArrayList getEmployee()

      {

        return employee;

      }

      public void setEmployee(ArrayList employee)

      {

        this.employee = employee;

      }

 

      public HashMap getTelephone()

      {

        return telephone;

      }

      public void setTelephone(HashMap telephone)

      {

        this.telephone = telephone;

      }

    }

2、BeanUtils可以直接get和set一个属性的值。它将property分成3种类型：

       Simple&mdash;&mdash;简单类型，如Stirng、Int&hellip;&hellip;

       Indexed&mdash;&mdash;索引类型，如数组、arrayList&hellip;&hellip;

       Maped&mdash;&mdash;这个不用说也该知道，就是指Map啦，比如HashMap&hellip;&hellip;

       访问不同类型的数据可以直接调用函数getProperty和setProperty。它们都只有2个参数，第一个是JavaBean对象，第二个是要操作的属性名。

Company c = new Company();

c.setName(&quot;Simple&quot;);

 

对于Simple类型，参数二直接是属性名即可

//Simple

    System.out.println(BeanUtils.getProperty(c, &quot;name&quot;));

    对于Map类型，则需要以&ldquo;属性名（key值）&rdquo;的形式

//Map

    System.out.println(BeanUtils.getProperty(c, &quot;address (A2)&quot;));

    HashMap am = new HashMap();

    am.put(&quot;1&quot;,&quot;234-222-1222211&quot;);

    am.put(&quot;2&quot;,&quot;021-086-1232323&quot;);

    BeanUtils.setProperty(c,&quot;telephone&quot;,am);

    System.out.println(BeanUtils.getProperty(c, &quot;telephone (2)&quot;));

    对于Indexed，则为&ldquo;属性名[索引值]&rdquo;，注意这里对于ArrayList和数组都可以用一样的方式进行操作。

//index

    System.out.println(BeanUtils.getProperty(c, &quot;otherInfo[2]&quot;));

    BeanUtils.setProperty(c, &quot;product[1]&quot;, &quot;NOTES SERVER&quot;);

    System.out.println(BeanUtils.getProperty(c, &quot;product[1]&quot;));

 

       当然这3种类也可以组合使用啦！

    //nest

    System.out.println(BeanUtils.getProperty(c, &quot;employee[1].name&quot;));

 

3、此外，还有一个很重要的方法copyProperty，可以直接进行Bean之间的clone。

       Company c2 = new Company();

        BeanUtils.copyProperties(c2, c);

       但是这种copy都是浅拷贝，复制后的2个Bean的同一个属性可能拥有同一个对象的ref，这个在使用时要小心，特别是对于属性为自定义类的情况。

4、最后还有populate，它用于将一个map的值填充到一个bean中，其函数原型如下：

public void populate(java.lang.Object bean,

                java.util.Map properties)

              throws java.lang.IllegalAccessException,

                     java.lang.reflect.InvocationTargetException

在struts中这个函数被用于从http request中取得参数添加到FormBean，目前好像我也没有看到这个函数还有什么其他的用途？！以后想到再说吧：P

 

2.2.LazyDynaBean

       它实现一个动态的Bean，可以直接往里面加入属性，作为一个JavaBean一样使用，也可以用上面的BeanUtils或get/set方法进行操作，而不用事先定义一个标准的JavaBean类啦：）

记得在J2ee设计模式中有一种Value Object的模式，用于在MVC各层之间传递数据，避免直接传递大业务对象引起的性能问题，为了避免在项目中出现很多Bean类，在书中提供了一个动态Value Object的实现（通过扩展Map）。这里LazyDynaBean则可以作为一种更加成熟、稳定的实现来使用。呵呵，原来曾打算自己写一个类似的value object类的，现在看来可以直接用这个啦：P

       言归正传，LazyBean的确提供了一个很不错的DynaBean的实现。而且就像它的名字中表述的那样，它的确是为我这样的懒人考虑的很周到，用起来几乎不需要写什么多余的代码^_^，下面就看看使用的例子吧！

         //这里使用LazyDynaMap，它是LazyBean的一个轻量级实现

      LazyDynaMap dynaBean1 = new LazyDynaMap();

 

      dynaBean1.set(&quot;foo&quot;, &quot;bar&quot;);                  // simple

      dynaBean1.set(&quot;customer&quot;, &quot;title&quot;, &quot;Mr&quot;);        // mapped

      dynaBean1.set(&quot;address&quot;, 0, &quot;address1&quot;);         // indexed

      System.out.println(dynaBean1.get(&quot;address&quot;,0));

 

      Map myMap = dynaBean1.getMap();           // retrieve the Map

      System.out.println(myMap.toString());

       上面的例子可以看到，它可以在set时自动增加bean的property（既赋值的同时增加Bean中的property），同时也支持3中类型的property，并且LazyDynaMap还可以导出为map。

       对于这个类还有两个重要的Field要注意：

       returnnull&mdash;&mdash;指定在get方法使用了一个没有定义过的property时，DynaBean的行为。

         //取的字段的信息

      dynaBean1.setReturnNull(true);//设为ture。若Bean中没有此字段，返回null

                                //默认为false。若Bean中没有此字段，自动增加一个：）

      System.out.println(dynaBean1.get(&quot;aaa&quot;));//此时返回null

       Restricted&mdash;&mdash;指定是否允许改变这个bean的property。

//MutableDynaClass.setRestricted设为true后，字段不可再增删和修改.

      //默认为false，允许增删和修改

      dynaBean1.setRestricted(true);

      dynaBean1.set(&quot;test&quot;,&quot;error&quot;);//这里会出错！

       通过设置这两个属性，可以防止意外修改DynaBean的property。在设计架构时，你可以在后台从数据表或xml文件自动产生DynaBean，在传到控制层和表示层之前设置上述属性使其Bean结构不允许修改，如此就不可能无意中修改Bean包含的属性&hellip;&hellip;这样既可以享用它的便利，有可以防止由此引入的错误可能，设计者实在深得偷懒的精髓啊！！！！！

 

3.   其他

3.1.BeanUtils和PropertyUtils

       这两个类几乎有一摸一样的功能，唯一的区别是：BeanUtils在对Bean赋值是会进行类型转化。举例来说也就是在copyProperty时只要属性名相同，就算类型不同，BeanUtils也可以进行copy；而PropertyBean则可能会报错！！

       针对上面的例子，新建一个Company2的类，其中代码与Company一样，只是将otherinfo从String[]改为String。

      Company c = init();

      Company2 c2 = new Company2();

      

      BeanUtils.copyProperties(c2,c);

//      PropertyUtils.copyProperties(c2,c); 这句会报错！！

      System.out.println(c2.getOtherInfo());

    当然2个Bean之间的同名属性的类型必须是可以转化的，否则用BeanUtils一样会报错。

       若实现了org.apache.commons.beanutils.Converter接口则可以自定义类型之间的转化。

由于不做类型转化，用PropertyUtils在速度上会有很大提高！

此外，不作类型转化还有一个好处，如下面的代码：

      //test data type convert

//      ArrayList a1 = BeanUtils.getProperty(c,&quot;product&quot;); //BeanUtils返回的是String

      System.out.println(&quot;--&quot; + BeanUtils.getProperty(c,&quot;product&quot;));     //取出后直接被转为String

      ArrayList a = (ArrayList)PropertyUtils.getProperty(c,&quot;product&quot;);//PropertyUtils返回的是Object

      System.out.println(&quot;--&quot; + a.get(1));

用BeanUtils无法返回一个对象（除非自己写一个Converter），它会自动进行类型转化，然后返回String。对于想返回java类或自定义类的话，还是不要老它大驾转化了。

 

3.2.Utils类

       所有的XXXUtils类都提供的是静态方法，可以直接调用，其主要实现都在相应的XXXUtilsBean中：

BeanUtils     &mdash;&mdash;&gt; BeanUtilsBean

       ConvertUtils  &mdash;&mdash;&gt; ConvertUtilsBean

    PropertyUtils &mdash;&mdash;&gt; PropertyUtilsBean

 

其意思看类名也应该知道的差不多了，我就不再废话啦！当然你也可以直接调用那些XXXUtilsBean，功能都一样！
</pre><p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://shijian0306.javaeye.com/blog/166023#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 29 Feb 2008 09:40:57 +0800</pubDate>
        <link>http://shijian0306.javaeye.com/blog/166023</link>
        <guid>http://shijian0306.javaeye.com/blog/166023</guid>
      </item>
      <item>
        <title>1.Jakarta StringUtils </title>
        <author>shijian0306</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://shijian0306.javaeye.com">shijian0306</a>&nbsp;
          链接：<a href="http://shijian0306.javaeye.com/blog/166021" style="color:red;">http://shijian0306.javaeye.com/blog/166021</a>&nbsp;
          发表时间: 2008年02月29日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><span style="color: #ff0000"><strong><span style="font-size: small">1.Jakarta StringUtils</span></strong> </span></p><p>&nbsp;</p><p>标准的JAVA应用编程接口能够支持字符串操作，但是更多的时候，仅仅支持是不够的。Commons Lang的StringUtils包加入到类路径中。StringUtils类中有不计其数的有用的方法。 </p><div><p>如果你需要使一个字符串居中（在输出的时候），可以使用居中方法：<span style="color: #0066ff">log(StringUtils.center(&quot;to be centered&quot;, 50, &quot;*&quot;));</span><br /><span style="color: #006600">// ******************to be centered******************</span></p><p>如果你需要重复的书写同一个数字，你可以这么写：</p><p><span style="color: #0066ff">log(StringUtils.leftPad(&quot;34&quot;, 8, &quot;0&quot;));</span><br /><span style="color: #006600">// 00000034</span><br />又或者你需要在一个数组中加入一个元素，你可以这么做：</p><p><span style="color: #0066ff">log(StringUtils.join(new String[]{&quot;cat&quot;,&quot;dog&quot;,&quot;carrot&quot;,&quot;leaf&quot;,&quot;door&quot;}, &quot;:&quot;)</span></p><p><span style="color: #006600">// cat:dog:carrot:leaf:door</span></p><p>如果你需要一个大写字母或者是需要一个字符串中的每个单词第一个字母大写，你可以这么做：</p><p><span style="color: #0066ff">log(StringUtils.capitaliseAllWords(&quot;a sentenced to be capitalised&quot;));</span><br /><span style="color: #006600">// A Sentenced To Be Capitalised</span></p><p>如果你需要计算一个字母在字符串中出现的个数，你可以使用countMatches方法：<span style="color: #0066ff">log(StringUtils.countMatches(&quot;Bethany plays with army men&quot;, &quot;e&quot;));</span><br /><span style="color: #006600">// 2</span></p><p>甚至还有计算两字符串之间的Levenshtein-Distance</p><p><span style="color: #0066ff">log(StringUtils.getLevenshteinDistance(&quot;David&quot;, &quot;Jakob&quot;));</span><br /><span style="color: #006600">// 4</span></p><p><strong>检查字符串是否为空或null或仅仅包含空格<br /></strong>&nbsp; String test = &quot;&quot;;<br />&nbsp; String test1=&quot; &quot;;<br />&nbsp; String test2 = &quot;\n\n\t&quot;;<br />&nbsp; String test3 = null;<br />&nbsp; System.out.println( &quot;test blank? &quot; + StringUtils.isBlank( test ) );<br />&nbsp; System.out.println( &quot;test1 blank? &quot; + StringUtils.isBlank( test1 ) );<br />&nbsp; System.out.println( &quot;test2 blank? &quot; + StringUtils.isBlank( test2 ) );<br />&nbsp; System.out.println( &quot;test3 blank? &quot; + StringUtils.isBlank( test3 ) );<br />&nbsp; 运行结果：<br />&nbsp; test blank? true<br />&nbsp; test1 blank? true<br />&nbsp; test2 blank? true<br />&nbsp; test3 blank? true<br />&nbsp; 相对应的还有一个StringUtils.isNotBlank(String str)<br />&nbsp; StringUtils.isEmpty(String str)则检查字符串是否为空或null（不检查是否仅仅包含空格）<br />&nbsp;<br />&nbsp; <strong>分解字符串</strong><br />&nbsp; StringUtils.split(null, *, *)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = null<br />&nbsp; StringUtils.split(&quot;&quot;, *, *)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = []<br />&nbsp; StringUtils.split(&quot;ab de fg&quot;, null, 0)&nbsp;&nbsp; = [&quot;ab&quot;, &quot;cd&quot;, &quot;ef&quot;]<br />&nbsp; StringUtils.split(&quot;ab&nbsp;&nbsp; de fg&quot;, null, 0) = [&quot;ab&quot;, &quot;cd&quot;, &quot;ef&quot;]<br />&nbsp; StringUtils.split(&quot;ab:cd:ef&quot;, &quot;:&quot;, 0)&nbsp;&nbsp;&nbsp; = [&quot;ab&quot;, &quot;cd&quot;, &quot;ef&quot;]<br />&nbsp; StringUtils.split(&quot;ab:cd:ef&quot;, &quot;:&quot;, 1)&nbsp;&nbsp;&nbsp; = [&quot;ab:cd:ef&quot;]<br />&nbsp; StringUtils.split(&quot;ab:cd:ef&quot;, &quot;:&quot;, 2)&nbsp;&nbsp;&nbsp; = [&quot;ab&quot;, &quot;cd:ef&quot;]<br />&nbsp; StringUtils.split(String str,String separatorChars,int max) str为null时返回null<br />&nbsp; separatorChars为null时默认为按空格分解，max为0或负数时分解没有限制，max为1时返回整个字符串，max为分解成的个数（大于实际则无效）<br />&nbsp;<br />&nbsp; <strong>去除字符串前后指定的字符</strong><br />&nbsp; StringUtils.strip(null, *)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = null<br />&nbsp; StringUtils.strip(&quot;&quot;, *)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = &quot;&quot;<br />&nbsp; StringUtils.strip(&quot;abc&quot;, null)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = &quot;abc&quot;<br />&nbsp; StringUtils.strip(&quot; abc &quot;, null)&nbsp;&nbsp;&nbsp; = &quot;abc&quot;<br />&nbsp; StringUtils.strip(&quot;&nbsp; abcyx&quot;, &quot;xyz&quot;) = &quot;&nbsp; abc&quot;<br />&nbsp; StringUtils.strip(String str,String stripChars) str为null时返回null,stripChars为null时默认为空格</p><p>&nbsp; <strong>创建醒目的Header（调试时用）</strong><br />&nbsp; public String createHeader( String title ) {<br />&nbsp;&nbsp;&nbsp; int width = 30;<br />&nbsp;&nbsp;&nbsp; String stars = StringUtils.repeat( &quot;*&quot;, width);<br />&nbsp;&nbsp;&nbsp; String centered = StringUtils.center( title, width, &quot;*&quot; );<br />&nbsp;&nbsp;&nbsp; String heading = StringUtils.join(new Object[]{stars, centered, stars}, &quot;\n&quot;);<br />&nbsp;&nbsp;&nbsp; return heading;<br />&nbsp; }<br />&nbsp; 调用createHeader(&quot;TEST&quot;)的输出结果:<br />&nbsp; ******************************<br />&nbsp; ************ TEST ************<br />&nbsp; ******************************</p><p>&nbsp; <strong>字符的全部反转及以单个词为单位的反转<br /></strong>&nbsp; String original = &quot;In time, I grew tired of his babbling nonsense.&quot;;<br />&nbsp; StringUtils.reverse( original )&nbsp;&nbsp; = &quot;.esnesnon gnilbbab sih fo derit werg I ,emit nI&quot;<br />&nbsp; 以单个词为单位的反转<br />&nbsp; public Sentence reverseSentence(String sentence) {<br />&nbsp;&nbsp;&nbsp; String reversed = StringUtils.chomp( sentence, &quot;.&quot; );<br />&nbsp;&nbsp;&nbsp; reversed = StringUtils.reverseDelimited( reversed, ' ' );<br />&nbsp;&nbsp;&nbsp; reversed = reversed + &quot;.&quot;;<br />&nbsp;&nbsp;&nbsp; return reversed;<br />&nbsp; }<br />&nbsp; String sentence = &quot;I am Susan.&quot;<br />&nbsp; reverseSentence( sentence ) )&nbsp;&nbsp; = &quot;Susan am I.&quot;</p><p><strong>检查字符串是否仅仅包含数字、字母或数字和字母的混合<br /></strong>&nbsp; String test1 = &quot;ORANGE&quot;;<br />&nbsp; String test2 = &quot;ICE9&quot;;<br />&nbsp; String test3 = &quot;ICE CREAM&quot;;<br />&nbsp; String test4 = &quot;820B Judson Avenue&quot;;<br />&nbsp; String test5 = &quot;1976&quot;;<br />&nbsp; 结果：<br />&nbsp; boolean t1val = StringUtils.isAlpha( test1 ); // returns true<br />&nbsp; boolean t2val = StringUtils.isAlphanumeric( test2 ); // returns true<br />&nbsp; boolean t3val = StringUtils.isAlphaSpace( test3 ); // returns true<br />&nbsp; boolean t4val = StringUtils.isAlphanumericSpace( test4 ); // returns true<br />&nbsp; boolean t5val = StringUtils.isNumeric( test5 ); // returns true</p></div>
          <br/>
          <span style="color:red;">
            <a href="http://shijian0306.javaeye.com/blog/166021#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 29 Feb 2008 09:37:41 +0800</pubDate>
        <link>http://shijian0306.javaeye.com/blog/166021</link>
        <guid>http://shijian0306.javaeye.com/blog/166021</guid>
      </item>
      <item>
        <title>Spring 使用Properties配置文件</title>
        <author>shijian0306</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://shijian0306.javaeye.com">shijian0306</a>&nbsp;
          链接：<a href="http://shijian0306.javaeye.com/blog/160587" style="color:red;">http://shijian0306.javaeye.com/blog/160587</a>&nbsp;
          发表时间: 2008年01月30日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <span style="color: red">1. jdbc.properties</span><br /><br /><span style="color: darkred">database.url=jdbc:mysql://localhost/smaple<br />database.driver=org.gjt.mm.mysql.Driver<br />database.user=root<br />database.password=star1xing</span><br /><br /><span style="color: red">2.conf.xml</span><br /><br />&lt;?xml version="1.0" encoding="UTF-8"?><br />&lt;!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"><br /><br />&lt;beans><br />    &lt;bean id="propertyConfigurer"<br />        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"><br />        &lt;property name="location"><br />            &lt;value>com/starxing/test/jdbc.properties&lt;/value><br />        &lt;/property><br />    &lt;/bean><br />    &lt;bean id="dataSource"<br />        class="org.springframework.jdbc.datasource.DriverManagerDataSource"><br />        &lt;property name="url"><br />            &lt;value>${database.url}&lt;/value><br />        &lt;/property><br />        &lt;property name="driverClassName"><br />            &lt;value>${database.driver}&lt;/value><br />        &lt;/property><br />        &lt;property name="username"><br />            &lt;value>${database.user}&lt;/value><br />        &lt;/property><br />        &lt;property name="password"><br />            &lt;value>${database.password}&lt;/value><br />        &lt;/property><br /><br />    &lt;/bean><br />&lt;/beans><br /><br /><span style="color: red">3.Config.java</span><br />package com.starxing.test;<br /><br />import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;<br />import org.springframework.beans.factory.xml.XmlBeanFactory;<br />import org.springframework.context.ApplicationContext;<br />import org.springframework.context.support.ClassPathXmlApplicationContext;<br />import org.springframework.core.io.FileSystemResource;<br />import org.springframework.jdbc.datasource.DriverManagerDataSource;<br /><br />public class Config {<br /><br />    public static void main(String[] args) {<br />        XmlBeanFactory factory = new XmlBeanFactory(new FileSystemResource(<br />                "com/starxing/test/conf.xml"));<br /><br />        // 如果要在BeanFactory中使用，bean factory post-processor必须手动运行:<br />        PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer();<br />        cfg.setLocation(new FileSystemResource(<br />                "com/starxing/test/jdbc.properties"));<br />        cfg.postProcessBeanFactory(factory);<br /><br />        DriverManagerDataSource dataSource = (DriverManagerDataSource) factory<br />                .getBean("dataSource");<br />        System.out.println(dataSource.getDriverClassName());<br /><br />        // 注意，ApplicationContext能够自动辨认和应用在其上部署的实现了BeanFactoryPostProcessor的bean。这就意味着，当使用ApplicationContext的时候应用PropertyPlaceholderConfigurer会非常的方便。由于这个原因，建议想要使用这个或者其他bean<br />        // factory postprocessor的用户使用ApplicationContext代替BeanFactroy。<br />        ApplicationContext context = new ClassPathXmlApplicationContext(<br />                "com/starxing/test/conf.xml");<br />        DriverManagerDataSource dataSource2 = (DriverManagerDataSource) context<br />                .getBean("dataSource");<br />        System.out.println(dataSource2.getDriverClassName());<br />    }<br /><br />}<br /><br />相关文档:<br /><br />--------------------------------------------------------------------------------<br /><br />　使用这一解决方案，我们可以生成如下的属性文件（/WEB-INF/jdbc.properties）： <br />jdbc.driver=org.postgresql.Driverjdbc.url=jdbc:postgresql://localhost/testjdbc.user=postgresjdbc.password=<br />　　我们的Bean配置如下：<br /><br />&lt;bean id="propertyConfigurer"  class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">    &lt;property name="location">       &lt;value>/WEB-INF/jdbc.properties&lt;/value>    &lt;/property>&lt;/bean>&lt;bean id="dataSource"  class="org.springframework.jdbc.datasource.DriverManagerDataSource">    &lt;property name="driverClassName">         &lt;value>${jdbc.driver}&lt;/value>    &lt;/property>    &lt;property name="url">         &lt;value>${jdbc.url}&lt;/value>    &lt;/property>    &lt;property name="username">         &lt;value>${jdbc.user}&lt;/value>    &lt;/property>    &lt;property name="password">         &lt;value>${jdbc.password}&lt;/value>    &lt;/property>&lt;/bean><br />　　如上所述，我们定义了一个PropertyPlaceholderConfigurer类的实例，并将其位置属性设置为我们的属性文件。该类被实现为Bean工厂的后处理器，并将使用定义在文件中的属性来代替所有的占位符（${...}value）。<br /><br />　　利用这种技术，我们可以从applicationContext.xml中移除所有特定于主机的配置属性。通过这种方式，我们可以自由地为该文件添加新的Bean，而不必担心特定于主机属性的同步性。这样可以简化生产部署和维护。<br /><br /><br /><br /><br /><br /><br /><br />--------------------------------------------------------------------------------<br /><br />PropertyPlaceholderConfigurer作为一个bean factory post-processor实现，可以用来将BeanFactory定义中的属性值放置到另一个单独的Java Properties格式的文件中。这使得用户不用对BeanFactory的主XML定义文件进行复杂和危险的修改，就可以定制一些基本的属性（比如说数据库的urls,用户名和密码）。 <br /><br />考虑一个BeanFactory定义的片断，里面用占位符定义了DataSource： <br /><br />在下面这个例子中，定义了一个datasource，并且我们会在一个外部Porperties文件中配置一些相关属性。 在运行时，我们为BeanFactory提供一个PropertyPlaceholderConfigurer，它将用Properties文件中的值替换掉这个datasource的属性值： <br /><br />&lt;bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">    &lt;property name="driverClassName">&lt;value>${jdbc.driverClassName}&lt;/value>&lt;/property>    &lt;property name="url">&lt;value>${jdbc.url}&lt;/value>&lt;/property>    &lt;property name="username">&lt;value>${jdbc.username}&lt;/value>&lt;/property>    &lt;property name="password">&lt;value>${jdbc.password}&lt;/value>&lt;/property>&lt;/bean><br />真正的值来自于另一个Properties格式的文件:<br /><br />jdbc.driverClassName=org.hsqldb.jdbcDriverjdbc.url=jdbc:hsqldb:hsql://production:9002jdbc.username=sajdbc.password=root<br />如果要在BeanFactory中使用，bean factory post-processor必须手动运行:<br /><br />XmlBeanFactory factory = new XmlBeanFactory(new FileSystemResource("beans.xml"));PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer();cfg.setLocation(new FileSystemResource("jdbc.properties"));cfg.postProcessBeanFactory(factory);<br />注意，ApplicationContext能够自动辨认和应用在其上部署的实现了BeanFactoryPostProcessor的bean。这就意味着，当使用ApplicationContext的时候应用PropertyPlaceholderConfigurer会非常的方便。由于这个原因，建议想要使用这个或者其他bean factory postprocessor的用户使用ApplicationContext代替BeanFactroy。 <br /><br />PropertyPlaceHolderConfigurer不仅仅在你指定的Porperties文件中查找属性， 如果它在其中没有找到你想使用的属性，它还会在Java的系统properties中查找。 这个行为能够通过设置配置中的systemPropertiesMode 属性来定制。这个属性有三个值， 一个让配置总是覆盖，一个让它永不覆盖，一个让它仅在properties文件中找不到的时候覆盖。 请参考 PropertiesPlaceholderConfigurer的JavaDoc获得更多信息。
          <br/>
          <span style="color:red;">
            <a href="http://shijian0306.javaeye.com/blog/160587#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 30 Jan 2008 18:25:10 +0800</pubDate>
        <link>http://shijian0306.javaeye.com/blog/160587</link>
        <guid>http://shijian0306.javaeye.com/blog/160587</guid>
      </item>
  </channel>
</rss>