﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-Energy of Love-随笔分类-Java</title><link>http://www.blogjava.net/titanaly/category/39905.html</link><description /><language>zh-cn</language><lastBuildDate>Wed, 18 Sep 2013 01:59:16 GMT</lastBuildDate><pubDate>Wed, 18 Sep 2013 01:59:16 GMT</pubDate><ttl>60</ttl><item><title>JAVA的文件操作【转】</title><link>http://www.blogjava.net/titanaly/archive/2013/09/17/404191.html</link><dc:creator>不高兴</dc:creator><author>不高兴</author><pubDate>Tue, 17 Sep 2013 09:51:00 GMT</pubDate><guid>http://www.blogjava.net/titanaly/archive/2013/09/17/404191.html</guid><wfw:comment>http://www.blogjava.net/titanaly/comments/404191.html</wfw:comment><comments>http://www.blogjava.net/titanaly/archive/2013/09/17/404191.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/titanaly/comments/commentRss/404191.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/titanaly/services/trackbacks/404191.html</trackback:ping><description><![CDATA[<h2><span style="font-size: large;"><span style="font-family: Cambria;"></span></span></h2><div>11.3 I/O类使用</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;由于在IO操作中，需要使用的数据源有很多，作为一个IO技术的初学者，从读写文件开始学习IO技术是一个比较好的选择。因为文件是一种常见的数据源，而且读写文件也是程序员进行IO编程的一个基本能力。本章IO类的使用就从读写文件开始。</div><div></div><div>11.3.1 文件操作</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;文件(File)是 最常见的数据源之一，在程序中经常需要将数据存储到文件中，例如图片文件、声音文件等数据文件，也经常需要根据需要从指定的文件中进行数据的读取。当然， 在实际使用时，文件都包含一个的格式，这个格式需要程序员根据需要进行设计，读取已有的文件时也需要熟悉对应的文件格式，才能把数据从文件中正确的读取出 来。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;文件的存储介质有很多，例如硬盘、光盘和U盘等，由于IO类设计时，从数据源转换为流对象的操作由API实现了，所以存储介质的不同对于程序员来说是透明的，和实际编写代码无关。</div><div></div><div>11.3.1.1 文件的概念</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;文件是计算机中一种基本的数据存储形式，在实际存储数据时，如果对于数据的读写速度要求不是很高，存储的数据量不是很大时，使用文件作为一种持久数据存储的方式是比较好的选择。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;存储在文件内部的数据和内存中的数据不同，存储在文件中的数据是一种&#8220;持久存储&#8221;，也就是当程序退出或计算机关机以后，数据还是存在的，而内存内部的数据在程序退出或计算机关机以后，数据就丢失了。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;在不同的存储介质中，文件中的数据都是以一定的顺序依次存储起来，在实际读取时由硬件以及操作系统完成对于数据的控制，保证程序读取到的数据和存储的顺序保持一致。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;每个文件以一个文件路径和文件名称进行表示，在需要访问该文件的时，只需要知道该文件的路径以及文件的全名即可。在不同的操作系统环境下，文件路径的表示形式是不一样的，例如在Windows操作系统中一般的表示形式为C:\windows\system，而Unix上的表示形式为/user/my。所以如果需要让Java程序能够在不同的操作系统下运行，书写文件路径时还需要比较注意。</div><div></div><div>11.3.1.1.1 绝对路径和相对路径</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;绝对路径是指书写文件的完整路径，例如d:\java\Hello.java，该路径中包含文件的完整路径d:\java以及文件的全名Hello.java。使用该路径可以唯一的找到一个文件，不会产生歧义。但是使用绝对路径在表示文件时，受到的限制很大，且不能在不同的操作系统下运行，因为不同操作系统下绝对路径的表达形式存在不同。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;相对路径是指书写文件的部分路径，例如\test\Hello.java，该路径中只包含文件的部分路径\test和文件的全名Hello.java，部分路径是指当前路径下的子路径，例如当前程序在d:\abc下运行，则该文件的完整路径就是d:\abc\test。使用这种形式，可以更加通用的代表文件的位置，使得文件路径产生一定的灵活性。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;在Eclipse项目中运行程序时，当前路径是项目的根目录，例如工作空间存储在d:\javaproject，当前项目名称是Test，则当前路径是：d:\javaproject\Test。在控制台下面运行程序时，当前路径是class文件所在的目录，如果class文件包含包名，则以该class文件最顶层的包名作为当前路径。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;另外在Java语言的代码内部书写文件路径时，需要注意大小写，大小写需要保持一致，路径中的文件夹名称区分大小写。由于&#8217;\&#8217;是Java语言中的特殊字符，所以在代码内部书写文件路径时，例如代表&#8220;c:\test\java\Hello.java&#8221;时，需要书写成&#8220;c:\\test\\java\\Hello.java&#8221;或&#8220;c:/test/java/Hello.java&#8221;，这些都需要在代码中注意。</div><div></div><div>11.3.1.1.2 文件名称</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;文件名称一般采用&#8220;文件名.后缀名&#8221;的形式进行命名，其中&#8220;文件名&#8221;用来表示文件的作用，而使用后缀名来表示文件的类型，这是当前操作系统中常见的一种形式，例如&#8220;readme.txt&#8221;文件，其中readme代表该文件时说明文件，而txt后缀名代表文件时文本文件类型，在操作系统中，还会自动将特定格式的后缀名和对应的程序关联，在双击该文件时使用特定的程序打开。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;其实在文件名称只是一个标示，和实际存储的文件内容没有必然的联系，只是使用这种方式方便文件的使用。在程序中需要存储数据时，如果自己设计了特定的文件格式，则可以自定义文件的后缀名，来标示自己的文件类型。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;和文件路径一样，在Java代码内部书写文件名称时也区分大小写，文件名称的大小写必须和操作系统中的大小写保持一致。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;另外，在书写文件名称时不要忘记书写文件的后缀名。</div><div></div><div>11.3.1.2 File类</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;为了很方便的代表文件的概念，以及存储一些对于文件的基本操作，在java.io包中设计了一个专门的类&#8212;&#8212;File类。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;在File类中包含了大部分和文件操作的功能方法，该类的对象可以代表一个具体的文件或文件夹，所以以前曾有人建议将该类的类名修改成FilePath，因为该类也可以代表一个文件夹，更准确的说是可以代表一个文件路径。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;下面介绍一下File类的基本使用。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;1、File对象代表文件路径</div><div></div><div>File类的对象可以代表一个具体的文件路径，在实际代表时，可以使用绝对路径也可以使用相对路径。</div><div>下面是创建的文件对象示例。</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;public File(String pathname)</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;该示例中使用一个文件路径表示一个File类的对象，例如：</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;File f1 = new File(&#8220;d:\\test\\1.txt&#8221;);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;File f2 = new File(&#8220;1.txt&#8221;);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; File f3 = new File(&#8220;e:\\abc&#8221;);</div><div>这里的f1和f2对象分别代表一个文件，f1是绝对路径，而f2是相对路径，f3则代表一个文件夹，文件夹也是文件路径的一种。</div><div>public File(String parent, String child)</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 也可以使用父路径和子路径结合，实现代表文件路径，例如：</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;File f4 = new File(&#8220;d:\\test\\&#8221;,&#8221;1.txt&#8221;);</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 这样代表的文件路径是：d:\test\1.txt。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;2、File类常用方法</div><div></div><div>File类中包含了很多获得文件或文件夹属性的方法，使用起来比较方便，下面将常见的方法介绍如下：</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;a、createNewFile方法</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;public boolean createNewFile() throws IOException</div><div></div><div>该方法的作用是创建指定的文件。该方法只能用于创建文件，不能用于创建文件夹，且文件路径中包含的文件夹必须存在。</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;b、delect方法</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;public boolean delete()</div><div></div><div>该方法的作用是删除当前文件或文件夹。如果删除的是文件夹，则该文件夹必须为空。如果需要删除一个非空的文件夹，则需要首先删除该文件夹内部的每个文件和文件夹，然后在可以删除，这个需要书写一定的逻辑代码实现。</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;c、exists方法</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;public boolean exists()</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 该方法的作用是判断当前文件或文件夹是否存在。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;d、getAbsolutePath方法</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;public String getAbsolutePath()</div><div></div><div>该方法的作用是获得当前文件或文件夹的绝对路径。例如c:\test\1.t则返回c:\test\1.t。</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;e、getName方法</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;public String getName()</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 该方法的作用是获得当前文件或文件夹的名称。例如c:\test\1.t，则返回1.t。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;f、getParent方法</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;public String getParent()</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 该方法的作用是获得当前路径中的父路径。例如c:\test\1.t则返回c:\test。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;g、isDirectory方法</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;public boolean isDirectory()</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 该方法的作用是判断当前File对象是否是目录。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;h、isFile方法</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;public boolean isFile()</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 该方法的作用是判断当前File对象是否是文件。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;i、length方法</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;public long length()</div><div></div><div>该方法的作用是返回文件存储时占用的字节数。该数值获得的是文件的实际大小，而不是文件在存储时占用的空间数。</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;j、list方法</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;public String[] list()</div><div></div><div>该方法的作用是返回当前文件夹下所有的文件名和文件夹名称。说明，该名称不是绝对路径。</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;k、listFiles方法</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;public File[] listFiles()</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 该方法的作用是返回当前文件夹下所有的文件对象。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;l、mkdir方法</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;public boolean mkdir()</div><div></div><div>该方法的作用是创建当前文件文件夹，而不创建该路径中的其它文件夹。假设d盘下只有一个test文件夹，则创建d:\test\abc文件夹则成功，如果创建d:\a\b文件夹则创建失败，因为该路径中d:\a文件夹不存在。如果创建成功则返回true，否则返回false。</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;m、mkdirs方法</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;public boolean mkdirs()</div><div></div><div>该方法的作用是创建文件夹，如果当前路径中包含的父目录不存在时，也会自动根据需要创建。</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;n、renameTo方法</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;public boolean renameTo(File dest)</div><div></div><div>该方法的作用是修改文件名。在修改文件名时不能改变文件路径，如果该路径下已有该文件，则会修改失败。</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;o、setReadOnly方法</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;public boolean setReadOnly()</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 该方法的作用是设置当前文件或文件夹为只读。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;3、File类基本示例</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;以上各方法实现的测试代码如下：</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; import java.io.File;</div><div></div><div>/**</div><div>&nbsp;* File类使用示例</div><div>&nbsp;*/</div><div>public class FileDemo {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;public static void main(String[] args) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//创建File对象</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;File f1 = new File("d:\\test");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;File f2 = new File("1.txt");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;File f3 = new File("e:\\file.txt");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;File f4 = new File("d:\\","1.txt");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//创建文件</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;try{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; boolean b = f3.createNewFile();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}catch(Exception e){</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e.printStackTrace();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//判断文件是否存在</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;System.out.println(f4.exists());</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//获得文件的绝对路径</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;System.out.println(f3.getAbsolutePath());</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//获得文件名</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;System.out.println(f3.getName());</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//获得父路径</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;System.out.println(f3.getParent());</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//判断是否是目录</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;System.out.println(f1.isDirectory());</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//判断是否是文件</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;System.out.println(f3.isFile());</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//获得文件长度</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;System.out.println(f3.length());</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//获得当前文件夹下所有文件和文件夹名称</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;String[] s = f1.list();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;for(int i = 0;i &lt; s.length;i++){</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println(s[i]);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//获得文件对象</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;File[] f5 = f1.listFiles();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;for(int i = 0;i &lt; f5.length;i++){</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println(f5[i]);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//创建文件夹</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;File f6 = new File("e:\\test\\abc");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;boolean b1 = f6.mkdir();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;System.out.println(b1);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;b1 = f6.mkdirs();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;System.out.println(b1);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//修改文件名</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;File f7 = new File("e:\\a.txt");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;boolean b2 = f3.renameTo(f7);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;System.out.println(b2);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//设置文件为只读</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;f7.setReadOnly(); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</div><div>}</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;4、File类综合示例</div><div></div><div>下面以两个示例演示File类的综合使用。第一个示例是显示某个文件夹下的所有文件和文件夹，原理是输出当前名称，然后判断当前File对 象是文件还是文件夹，如果则获得该文件夹下的所有子文件和子文件夹，并递归调用该方法实现。第二个示例是删除某个文件夹下的所有文件和文件夹，原理是判断 是否是文件，如果是文件则直接删除，如果是文件夹，则获得该文件夹下所有的子文件和子文件夹，然后递归调用该方法处理所有子文件和子文件夹，然后将空文件 夹删除。则测试时谨慎使用第二个方法，以免删除自己有用的数据文件。示例代码如下：</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; import java.io.File;</div><div></div><div>/**</div><div>&nbsp;* 文件综合使用示例</div><div>&nbsp;*/</div><div>public class AdvanceFileDemo {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;public static void main(String[] args) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;File f = new File("e:\\Book");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;printAllFile(f);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;File f1 = new File("e:\\test");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;deleteAll(f1);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</div><div>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;/**</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; * 打印f路径下所有的文件和文件夹</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; * @param f 文件对象</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; */</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;public static void printAllFile(File f){</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//打印当前文件名</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;System.out.println(f.getName());</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//是否是文件夹</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if(f.isDirectory()){</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //获得该文件夹下所有子文件和子文件夹</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; File[] f1 = f.listFiles();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //循环处理每个对象</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; int len = f1.length;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for(int i = 0;i &lt; len;i++){</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//递归调用，处理每个文件对象</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;printAllFile(f1[i]);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</div><div>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;/**</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; * 删除对象f下的所有文件和文件夹</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; * @param f 文件路径</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; */</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;public static void deleteAll(File f){</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//文件</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if(f.isFile()){</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; f.delete();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}else{ //文件夹</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //获得当前文件夹下的所有子文件和子文件夹</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; File f1[] = f.listFiles();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //循环处理每个对象</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; int len = f1.length;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for(int i = 0;i &lt; len;i++){</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//递归调用，处理每个文件对象</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;deleteAll(f1[i]);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //删除当前文件夹</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; f.delete();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</div><div>}</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;关于File类的使用就介绍这么多，其它的方法和使用时需要注意的问题还需要多进行练习和实际使用。</div><div></div><div>11.3.1.3 读取文件</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;虽然前面介绍了流的概念，但是这个概念对于初学者来说，还是比较抽象的，下面以实际的读取文件为例子，介绍流的概念，以及输入流的基本使用。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;按照前面介绍的知识，将文件中的数据读入程序，是将程序外部的数据传入程序中，应该使用输入流&#8212;&#8212;InputStream或Reader。而由于读取的是特定的数据源&#8212;&#8212;文件，则可以使用输入对应的子类FileInputStream或FileReader实现。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;在实际书写代码时，需要首先熟悉读取文件在程序中实现的过程。在Java语言的IO编程中，读取文件是分两个步骤：1、将文件中的数据转换为流，2、读取流内部的数据。其中第一个步骤由系统完成，只需要创建对应的流对象即可，对象创建完成以后步骤1就完成了，第二个步骤使用输入流对象中的read方法即可实现了。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;使用输入流进行编程时，代码一般分为3个部分：1、创建流对象，2、读取流对象内部的数据，3、关闭流对象。下面以读取文件的代码示例：</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;import java.io.*;</div><div></div><div>/**</div><div>&nbsp;* 使用FileInputStream读取文件</div><div>&nbsp;*/</div><div>public class ReadFile1 {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;public static void main(String[] args) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//声明流对象</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;FileInputStream fis = null; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;try{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //创建流对象</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fis = new FileInputStream("e:\\a.txt");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //读取数据，并将读取到的数据存储到数组中</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; byte[] data = new byte[1024]; //数据存储的数组</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; int i = 0; //当前下标</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //读取流中的第一个字节数据</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; int n = fis.read();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //依次读取后续的数据</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; while(n != -1){ //未到达流的末尾</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//将有效数据存储到数组中</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;data[i] = (byte)n;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//下标增加</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;i++;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//读取下一个字节的数据</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; n = fis.read();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //解析数据</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; String s = new String(data,0,i);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //输出字符串</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println(s);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}catch(Exception e){</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e.printStackTrace();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}finally{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; try{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//关闭流，释放资源</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;fis.close();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }catch(Exception e){}</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</div><div>}</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;在该示例代码中，首先创建一个FileInputStream类型的对象fis：</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;fis = new FileInputStream("e:\\a.txt");</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;这样建立了一个连接到数据源e:\a.txt的流，并将该数据源中的数据转换为流对象fis，以后程序读取数据源中的数据，只需要从流对象fis中读取即可。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;读取流fis中的数据，需要使用read方法，该方法是从InputStream类中继承过来的方法，该方法的作用是每次读取流中的一个字节，如果需要读取流中的所有数据，需要使用循环读取，当到达流的末尾时，read方法的返回值是-1。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;在该示例中，首先读取流中的第一个字节：</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;int n = fis.read();</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;并将读取的值赋值给int值n，如果流fis为空，则n的值是-1，否则n中的最后一个字节包含的时流fis中的第一个字节，该字节被读取以后，将被从流fis中删除。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;然后循环读取流中的其它数据，如果读取到的数据不是-1，则将已经读取到的数据n强制转换为byte，即取n中的有效数据&#8212;&#8212;最后一个字节，并存储到数组data中，然后调用流对象fis中的read方法继续读取流中的下一个字节的数据。一直这样循环下去，直到读取到的数据是-1，也就是读取到流的末尾则循环结束。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;这里的数组长度是1024，所以要求流中的数据长度不能超过1024，所以该示例代码在这里具有一定的局限性。如果流的数据个数比较多，则可以将1024扩大到合适的个数即可。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;经过上面的循环以后，就可以将流中的数据依次存储到data数组中，存储到data数组中有效数据的个数是i个，即循环次数。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;其实截至到这里，IO操作中的读取数据已经完成，然后再按照数据源中的数据格式，这里是文件的格式，解析读取出的byte数组即可。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;该示例代码中的解析，只是将从流对象中读取到的有效的数据，也就是data数组中的前n个数据，转换为字符串，然后进行输出。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;在该示例代码中，只是在catch语句中输出异常的信息，便于代码的调试，在实际的程序中，需要根据情况进行一定的逻辑处理，例如给出提示信息等。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;最后在finally语句块中，关闭流对象fis，释放流对象占用的资源，关闭数据源，实现流操作的结束工作。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;上面详细介绍了读取文件的过程，其实在实际读取流数据时，还可以使用其它的read方法，下面的示例代码是使用另外一个read方法实现读取的代码：</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;import java.io.FileInputStream;</div><div></div><div>/**</div><div>&nbsp;* 使用FileInputStream读取文件</div><div>&nbsp;*/</div><div>public class ReadFile2 {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;public static void main(String[] args) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//声明流对象</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;FileInputStream fis = null; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;try{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //创建流对象</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fis = new FileInputStream("e:\\a.txt");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //读取数据，并将读取到的数据存储到数组中</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; byte[] data = new byte[1024]; //数据存储的数组</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; int i = fis.read(data);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //解析数据</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; String s = new String(data,0,i);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //输出字符串</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println(s);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}catch(Exception e){</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e.printStackTrace();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}finally{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; try{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//关闭流，释放资源</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;fis.close();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }catch(Exception e){}</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</div><div>}</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;该示例代码中，只使用一行代码：</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;int i = fis.read(data);</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;就实现了将流对象fis中的数据读取到字节数组data中。该行代码的作用是将fis流中的数据读取出来，并依次存储到数组data中，返回值为实际读取的有效数据的个数。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;使用该中方式在进行读取时，可以简化读取的代码。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;当然，在读取文件时，也可以使用Reader类的子类FileReader进行实现，在编写代码时，只需要将上面示例代码中的byte数组替换成char数组即可。</div><div></div><div>使用FileReader读取文件时，是按照char为单位进行读取的，所以更适合于文本文件的读取，而对于二进制文件或自定义格式的文件来说，还是使用FileInputStream进行读取，方便对于读取到的数据进行解析和操作。</div><div></div><div>读取其它数据源的操作和读取文件类似，最大的区别在于建立流对象时选择的类不同，而流对象一旦建立，则基本的读取方法是一样，如果只使用最基本的read方法进行读取，则使用基本上是一致的。这也是IO类设计的初衷，使得对于流对象的操作保持一致，简化IO类使用的难度。</div><div></div><div>&nbsp;程。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;基本的输出流包含OutputStream和Writer两个，区别是OutputStream体系中的类(也就是OutputStream的子类)是按照字节写入的，而Writer体系中的类(也就是Writer的子类)是按照字符写入的。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;使用输出流进行编程的步骤是：</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;1、建立输出流</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 建立对应的输出流对象，也就是完成由流对象到外部数据源之间的转换。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;2、向流中写入数据</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 将需要输出的数据，调用对应的write方法写入到流对象中。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;3、关闭输出流</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 在写入完毕以后，调用流对象的close方法关闭输出流，释放资源。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;在使用输出流向外部输出数据时，程序员只需要将数据写入流对象即可，底层的API实现将流对象中的内容写入外部数据源，这个写入的过程对于程序员来说是透明的，不需要专门书写代码实现。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;在向文件中输出数据，也就是写文件时，使用对应的文件输出流，包括FileOutputStream和FileWriter两个类，下面以FileOutputStream为例子说明输出流的使用。示例代码如下：</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;import java.io.*;</div><div></div><div>/**</div><div>&nbsp;* 使用FileOutputStream写文件示例</div><div>&nbsp;*/</div><div>public class WriteFile1 {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;public static void main(String[] args) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;String s = "Java语言";</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;int n = 100;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//声明流对象</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;FileOutputStream fos = null;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;try{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //创建流对象</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fos = new FileOutputStream("e:\\out.txt");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //转换为byte数组</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; byte[] b1 = s.getBytes();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //换行符</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; byte[] b2 = "\r\n".getBytes();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; byte[] b3 = String.valueOf(n).getBytes();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //依次写入文件</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fos.write(b1);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fos.write(b2);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fos.write(b3);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;} catch (Exception e) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e.printStackTrace();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}finally{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; try{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;fos.close();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }catch(Exception e){}</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</div><div>}</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;该示例代码写入的文件使用记事本打开以后，内容为：</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Java语言</div><div></div><div>100</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;在该示例代码中，演示了将一个字符串和一个int类型的值依次写入到同一个文件中。在写入文件时，首先创建了一个文件输出流对象fos：</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;fos = new FileOutputStream("e:\\out.txt");</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;该对象创建以后，就实现了从流到外部数据源e:\out.txt的连接。说明：当外部文件不存在时，系统会自动创建该文件，但是如果文件路径中包含未创建的目录时将出现异常。这里书写的文件路径可以是绝对路径也可以是相对路径。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;在 实际写入文件时，有两种写入文件的方式：覆盖和追加。其中&#8220;覆盖&#8221;是指清除原文件的内容，写入新的内容，默认采用该种形式写文件，&#8220;追加&#8221;是指在已有文件 的末尾写入内容，保留原来的文件内容，例如写日志文件时，一般采用追加。在实际使用时可以根据需要采用适合的形式，可以使用：</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;public FileOutputStream(String name, boolean append) throws FileNotFoundException</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;只需要使用该构造方法在构造FileOutputStream对象时，将第二个参数append的值设置为true即可。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;流对象创建完成以后，就可以使用OutputStream中提供的wirte方法向流中依次写入数据了。最基本的写入方法只支持byte数组格式的数据，所以如果需要将内容写入文件，则需要把对应的内容首先转换为byte数组。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;这里以如下格式写入数据：首先写入字符串s，使用String类的getBytes方法将该字符串转换为byte数组，然后写入字符串&#8220;\r\n&#8221;，转换方式同上，该字符串的作用是实现文本文件的换行显示，最后写入int数据n，首先将n转换为字符串，再转换为byte数组。这种写入数据的顺序以及转换为byte数组的方式就是流的数据格式，也就是该文件的格式。因为这里写的都是文本文件，所以写入的内容以明文的形式显示出来，也可以根据自己需要存储的数据设定特定的文件格式。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;其实，所有的数据文件，包括图片文件、声音文件等等，都是以一定的数据格式存储数据的，在保存该文件时，将需要保存的数据按照该文件的数据格式依次写入即可，而在打开该文件时，将读取到的数据按照该文件的格式解析成对应的逻辑即可。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;最后，在数据写入到流内部以后，如果需要立即将写入流内部的数据强制输出到外部的数据源，则可以使用流对象的flush方法实现。如果不需要强制输出，则只需要在写入结束以后，关闭流对象即可。在关闭流对象时，系统首先将流中未输出到数据源中的数据强制输出，然后再释放该流对象占用的内存空间。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;使用FileWriter写入文件时，步骤和创建流对象的操作都和该示例代码一致，只是在转换数据时，需要将写入的数据转换为char数组，对于字符串来说，可以使用String中的toCharArray方法实现转换，然后按照文件格式写入数据即可。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;对于其它类型的字节输出流/字符输出流来说，只是在逻辑上连接不同的数据源，在创建对象的代码上会存在一定的不同，但是一旦流对象创建完成以后，基本的写入方法都是write方法，也需要首先将需要写入的数据按照一定的格式转换为对应的byte数组/char数组，然后依次写入即可。</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;所以IO类的这种设计形式，只需要熟悉该体系中的某一个类的使用以后，就可以触类旁通的学会其它相同类型的类的使用，从而简化程序员的学习，使得使用时保持统一。</div><p style="margin-top: 10px; margin-bottom: 10px; color: #4d4d4d; font-family: Tahoma, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 26px; background-color: #ffffff;"><span style="font-family: 宋体;"></span></p><img src ="http://www.blogjava.net/titanaly/aggbug/404191.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/titanaly/" target="_blank">不高兴</a> 2013-09-17 17:51 <a href="http://www.blogjava.net/titanaly/archive/2013/09/17/404191.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Netty 3.1 中文用户手册</title><link>http://www.blogjava.net/titanaly/archive/2013/06/07/400359.html</link><dc:creator>不高兴</dc:creator><author>不高兴</author><pubDate>Fri, 07 Jun 2013 08:11:00 GMT</pubDate><guid>http://www.blogjava.net/titanaly/archive/2013/06/07/400359.html</guid><wfw:comment>http://www.blogjava.net/titanaly/comments/400359.html</wfw:comment><comments>http://www.blogjava.net/titanaly/archive/2013/06/07/400359.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/titanaly/comments/commentRss/400359.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/titanaly/services/trackbacks/400359.html</trackback:ping><description><![CDATA[<img src="http://img.ph.126.net/BhwwU-20PIN0SGx3jYb5qQ==/3262294980077829420.png" alt="Netty 3.1 中文用户手册（一）-序言 - stone - stone 的博客" data-pinit="registered" /><br /><br />序言<br /><br /><br />本指南对Netty 进行了介绍并指出其意义所在。<br /><br /><br />1. 问题<br /><br /><br />现在，我们使用适合一般用途的应用或组件来和彼此通信。例如，我们常常使用一个HTTP客户端从远程服务器获取信息或者通过web services进行远程方法的调用。<br /><br />然而，一个适合普通目的的协议或其实现并不具备其规模上的扩展性。例如，我们无法使用一个普通的HTTP服务器进行大型文件，电邮信息的交互，或者处理金 融信息和多人游戏数据那种要求准实时消息传递的应用场景。因此，这些都要求使用一个适用于特殊目的并经过高度优化的协议实现。例如，你可能想要实现一个对 基于AJAX的聊天应用，媒体流或大文件传输进行过特殊优化的HTTP服务器。你甚至可能想去设计和实现一个全新的，特定于你的需求的通信协议。<br /><br />另一种无法避免的场景是你可能不得不使用一种专有的协议和原有系统交互。在这种情况下，你需要考虑的是如何能够快速的开发出这个协议的实现并且同时还没有牺牲最终应用的性能和稳定性。<br /><br /><br />2. 方案<br /><br /><br />Netty 是一个异步的，事件驱动的网络编程框架和工具，使用Netty 可以快速开发出可维护的，高性能、高扩展能力的协议服务及其客户端应用。<br /><br />也就是说，Netty 是一个基于NIO的客户，服务器端编程框架，使用Netty 可以确保你快速和简单的开发出一个网络应用，例如实现了某种协议的客户，服务端应用。Netty相当简化和流线化了网络应用的编程开发过程，例如，TCP和UDP的socket服务开发。<br /><br />&#8220;快速&#8221;和&#8220;简单&#8221;并不意味着会让你的最终应用产生维护性或性能上的问题。Netty 是一个吸收了多种协议的实现经验，这些协议包括FTP,SMPT,HTTP，各种二进制，文本协议，并经过相当精心设计的项目，最终，Netty 成功的找到了一种方式，在保证易于开发的同时还保证了其应用的性能，稳定性和伸缩性。<br /><br />一些用户可能找到了某些同样声称具有这些特性的编程框架，因此你们可能想问Netty 又有什么不一样的地方。这个问题的答案是Netty 项目的设计哲学。从创立之初，无论是在API还是在其实现上Netty 都致力于为你提供最为舒适的使用体验。虽然这并不是显而易见的，但你终将会认识到这种设计哲学将令你在阅读本指南和使用Netty 时变得更加得轻松和容易。<br /><br />第一章. 开始<br /><br /><br />这一章节将围绕Netty的核心结构展开，同时通过一些简单的例子可以让你更快的了解Netty的使用。当你读完本章，你将有能力使用Netty完成客户端和服务端的开发。<br /><br />如果你更喜欢自上而下式的学习方式，你可以首先完成 第二章：架构总览 的学习，然后再回到这里。<br /><br />1.1. 开始之前<br /><br /><br />运行本章示例程序的两个最低要求是：最新版本的Netty程序以及JDK 1.5或更高版本。最新版本的Netty程序可在项目下载页 下载。下载正确版本的JDK，请到你偏好的JDK站点下载。<br /><br />这就已经足够了吗？实际上你会发现，这两个条件已经足够你完成任何协议的开发了。如果不是这样，请联系Netty项目社区 ，让我们知道还缺少了什么。<br /><br />最终但不是至少，当你想了解本章所介绍的类的更多信息时请参考API手册。为方便你的使用，这篇文档中所有的类名均连接至在线API手册。此外，如果本篇文档中有任何错误信息，无论是语法错误，还是打印排版错误或者你有更好的建议，请不要顾虑，立即联系Netty项目社区 。<br /><br />1.2. 抛弃协议服务<br /><br /><br />在这个世界上最简化的协议不是&#8220;Hello,world!&#8221;而是抛弃协议 。这是一种丢弃接收到的任何数据并不做任何回应的协议。<br /><br />实现抛弃协议（DISCARD protocol），你仅需要忽略接受到的任何数据即可。让我们直接从处理器（handler）实现开始，这个处理器处理Netty的所有I/O事件。<br /><br />Java代码 <br />package org.jboss.netty.example.discard;  <br />  <br />@ChannelPipelineCoverage("all")1  <br />public class DiscardServerHandler extends SimpleChannelHandler {2  <br />  <br />    @Override  <br />    public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {3  <br />    }  <br />  <br />    @Override  <br />    public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {4  <br />        e.getCause().printStackTrace();  <br />         <br />        Channel ch = e.getChannel();  <br />        ch.close();  <br />    }  <br />}  <br /> <br /><br />     代码说明<br /><br />1)ChannelPipelineCoverage注解了一种处理器类型，这个注解标示了一个处理器是 否可被多个Channel通道共享（同时关联着ChannelPipeline）。DiscardServerHandler没有处理任何有状态的信息， 因此这里的注解是&#8220;all&#8221;。<br /><br />2)DiscardServerHandler继承了SimpleChannelHandler，这也是一个ChannelHandler 的实现。SimpleChannelHandler提供了多种你可以重写的事件处理方法。目前直接继承SimpleChannelHandler已经足够 了，并不需要你完成一个自己的处理器接口。<br /><br />3)我们这里重写了messageReceived事件处理方法。这个方法由一个接收了客户端传送数据的MessageEvent事件调用。在这个例子中，我们忽略接收到的任何数据，并以此来实现一个抛弃协议（DISCARD protocol）。<br /><br />4)exceptionCaught 事件处理方法由一个ExceptionEvent异常事件调用，这个异常事件起因于Netty的I/O异常或一个处理器实现的内部异常。多数情况下，捕捉 到的异常应当被记录下来，并在这个方法中关闭这个channel通道。当然处理这种异常情况的方法实现可能因你的实际需求而有所不同，例如，在关闭这个连 接之前你可能会发送一个包含了错误码的响应消息。<br /> <br />目前进展不错，我们已经完成了抛弃协议服务器的一半开发工作。下面要做的是完成一个可以启动这个包含DiscardServerHandler处理器服务的主方法。<br /><br /> <br /><br />Java代码 <br />package org.jboss.netty.example.discard;  <br />  <br />import java.net.InetSocketAddress;  <br />import java.util.concurrent.Executors;  <br />  <br />public class DiscardServer {  <br />  <br />    public static void main(String[] args) throws Exception {  <br />        ChannelFactory factory =  <br />            new NioServerSocketChannelFactory (  <br />                    Executors.newCachedThreadPool(),  <br />                    Executors.newCachedThreadPool());  <br />  <br />        ServerBootstrap bootstrap = new ServerBootstrap (factory);  <br />  <br />        DiscardServerHandler handler = new DiscardServerHandler();  <br />        ChannelPipeline pipeline = bootstrap.getPipeline();  <br />        pipeline.addLast("handler", handler);  <br />  <br />        bootstrap.setOption("child.tcpNoDelay", true);  <br />        bootstrap.setOption("child.keepAlive", true);  <br />  <br />        bootstrap.bind(new InetSocketAddress(8080));  <br />    }  <br />}  <br /> <br /><br />     代码说明<br /><br /><br />1)ChannelFactory 是一个创建和管理Channel通道及其相关资源的工厂接口，它处理所有的I/O请求并产生相应的I/O ChannelEvent通道事件。Netty 提供了多种 ChannelFactory 实现。这里我们需要实现一个服务端的例子，因此我们使用NioServerSocketChannelFactory实现。另一件需要注意的事情是这个工 厂并自己不负责创建I/O线程。你应当在其构造器中指定该工厂使用的线程池，这样做的好处是你获得了更高的控制力来管理你的应用环境中使用的线程，例如一 个包含了安全管理的应用服务。<br /><br />2)ServerBootstrap 是一个设置服务的帮助类。你甚至可以在这个服务中直接设置一个Channel通道。然而请注意，这是一个繁琐的过程，大多数情况下并不需要这样做。<br /><br />3)这里，我们将DiscardServerHandler处理器添加至默认的ChannelPipeline通道。任何时候当服务器接收到一个新的连 接，一个新的ChannelPipeline管道对象将被创建，并且所有在这里添加的ChannelHandler对象将被添加至这个新的 ChannelPipeline管道对象。这很像是一种浅拷贝操作（a shallow-copy operation）；所有的Channel通道以及其对应的ChannelPipeline实例将分享相同的DiscardServerHandler 实例。<br /><br />4)你也可以设置我们在这里指定的这个通道实现的配置参数。我们正在写的是一个TCP/IP服务，因此我们运行设定一些socket选项，例如 tcpNoDelay和keepAlive。请注意我们在配置选项里添加的"child."前缀。这意味着这个配置项仅适用于我们接收到的通道实例，而不 是ServerSocketChannel实例。因此，你可以这样给一个ServerSocketChannel设定参数：<br />bootstrap.setOption("reuseAddress", true); <br /><br />5)我们继续。剩下要做的是绑定这个服务使用的端口并且启动这个服务。这里，我们绑定本机所有网卡（NICs,network interface cards）上的8080端口。当然，你现在也可以对应不同的绑定地址多次调用绑定操作。<br /> <br />大功告成！现在你已经完成你的第一个基于Netty的服务端程序。<br /><br />1.3. 查看接收到的数据<br /><br /><br />现在你已经完成了你的第一个服务端程序，我们需要测试它是否可以真正的工作。最简单的方法是使用telnet 命令。例如，你可以在命令行中输入&#8220;telnet localhost 8080 &#8221;或其他类型参数。<br /><br />然而，我们可以认为服务器在正常工作吗？由于这是一个丢球协议服务，所以实际上我们无法真正的知道。你最终将收不到任何回应。为了证明它在真正的工作，让我们修改代码打印其接收到的数据。<br />我们已经知道当完成数据的接收后将产生MessageEvent消息事件，并且也会触发messageReceived处理方法。所以让我在DiscardServerHandler处理器的messageReceived方法内增加一些代码。<br /><br />Java代码 <br />@Override  <br />public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {  <br />    ChannelBuffer  buf = (ChannelBuffer) e.getMessage();  <br />    while(buf.readable()) {  <br />        System.out.println((char) buf.readByte());  <br />    }  <br />}  <br /> <br /><br />     代码说明<br /><br />1) 基本上我们可以假定在socket的传输中消息类型总是ChannelBuffer。ChannelBuffer是Netty的一个基本数据结构，这个数 据结构存储了一个字节序列。ChannelBuffer类似于NIO的ByteBuffer，但是前者却更加的灵活和易于使用。例如，Netty允许你创 建一个由多个ChannelBuffer构建的复合ChannelBuffer类型，这样就可以减少不必要的内存拷贝次数。<br /><br />2) 虽然ChannelBuffer有些类似于NIO的ByteBuffer，但强烈建议你参考Netty的API手册。学会如何正确的使用ChannelBuffer是无障碍使用Netty的关键一步。<br /> <br />如果你再次运行telnet命令，你将会看到你所接收到的数据。<br />抛弃协议服务的所有源代码均存放在在分发版的org.jboss.netty.example.discard包下。<br /><br /><br />1.4. 响应协议服务<br /><br /><br />目前，我们虽然使用了数据，但最终却未作任何回应。然而一般情况下，一个服务都需要回应一个请求。让我们实现ECHO协议 来学习如何完成一个客户请求的回应消息，ECHO协议规定要返回任何接收到的数据。<br /><br />与我们上一节实现的抛弃协议服务唯一不同的地方是，这里需要返回所有的接收数据而不是仅仅打印在控制台之上。因此我们再次修改messageReceived方法就足够了。<br /><br />Java代码 <br />@Override  <br />public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {  <br />    Channel  ch = e.getChannel();  <br />    ch.write(e.getMessage());  <br />}  <br />代码说明<br />1) 一个ChannelEvent通道事件对象自身存有一个和其关联的Channel对象引用。这个返回的Channel通道对象代表了这个接收 MessageEvent消息事件的连接（connection）。因此，我们可以通过调用这个Channel通道对象的write方法向远程节点写入返 回数据。<br /> <br />现在如果你再次运行telnet命令，你将会看到服务器返回的你所发送的任何数据。<br /><br />相应服务的所有源代码存放在分发版的org.jboss.netty.example.echo包下。<br /><br />1.5. 时间协议服务<br /><br /><br />这一节需要实现的协议是TIME协议 。这是一个与先前所介绍的不同的例子。这个例子里，服务端返回一个32位的整数消息，我们不接受请求中包含的任何数据并且当消息返回完毕后立即关闭连接。通过这个例子你将学会如何构建和发送消息，以及当完成处理后如何主动关闭连接。<br /><br />因为我们会忽略接收到的任何数据而只是返回消息，这应当在建立连接后就立即开始。因此这次我们不再使用messageReceived方法，取而代之的是使用channelConnected方法。下面是具体的实现：<br /><br /> <br /><br />Java代码 <br />package org.jboss.netty.example.time;  <br />  <br />@ChannelPipelineCoverage("all")  <br />public class TimeServerHandler extends SimpleChannelHandler {  <br />  <br />    @Override  <br />    public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) {  <br />        Channel ch = e.getChannel();  <br />         <br />        ChannelBuffer time = ChannelBuffers.buffer(4);  <br />        time.writeInt(System.currentTimeMillis() / 1000);  <br />         <br />        ChannelFuture f = ch.write(time);  <br />         <br />        f.addListener(new ChannelFutureListener() {  <br />            public void operationComplete(ChannelFuture future) {  <br />                Channel ch = future.getChannel();  <br />                ch.close();  <br />            }  <br />        });  <br />    }  <br />  <br />    @Override  <br />    public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {  <br />        e.getCause().printStackTrace();  <br />        e.getChannel().close();  <br />    }  <br />}  <br /> <br />代码说明<br />1) 正如我们解释过的，channelConnected方法将在一个连接建立后立即触发。因此让我们在这个方法里完成一个代表当前时间（秒）的32位整数消息的构建工作。<br /><br />2) 为了发送一个消息，我们需要分配一个包含了这个消息的buffer缓冲。因为我们将要写入一个32位的整数，因此我们需要一个4字节的 ChannelBuffer。ChannelBuffers是一个可以创建buffer缓冲的帮助类。除了这个buffer方 法，ChannelBuffers还提供了很多和ChannelBuffer相关的实用方法。更多信息请参考API手册。<br /><br />另外，一个很不错的方法是使用静态的导入方式：<br />import static org.jboss.netty.buffer.ChannelBuffers.*;<br />...<br />ChannelBuffer dynamicBuf = dynamicBuffer(256);<br />ChannelBuffer ordinaryBuf = buffer(1024);<br /><br />3) 像通常一样，我们需要自己构造消息。<br /><br />但是打住，flip在哪？过去我们在使用NIO发送消息时不是常常需要调用 ByteBuffer.flip()方法吗？实际上ChannelBuffer之所以不需要这个方法是因为 ChannelBuffer有两个指针；一个对应读操作，一个对应写操作。当你向一个 ChannelBuffer写入数据的时候写指针的索引值便会增加，但与此同时读指针的索引值不会有任何变化。读写指针的索引值分别代表了这个消息的开 始、结束位置。<br /><br />与之相应的是，NIO的buffer缓冲没有为我们提供如此简洁的一种方法，除非你调用它的flip方法。因此，当你忘记调用flip方法而引起发送错误 时，你便会陷入困境。这样的错误不会再Netty中发生，因为我们对应不同的操作类型有不同的指针。你会发现就像你已习惯的这样过程变得更加容易&#8212;一种没 有flippling的体验！<br /><br />另一点需要注意的是这个写方法返回了一个ChannelFuture对象。一个ChannelFuture 对象代表了一个尚未发生的I/O操作。这意味着，任何已请求的操作都可能是没有被立即执行的，因为在Netty内部所有的操作都是异步的。例如，下面的代 码可能会关闭一 个连接，这个操作甚至会发生在消息发送之前：<br /><br />Channel ch = ...;<br />ch.write(message);<br />ch.close();<br /><br />因此，你需要这个write方法返回的ChannelFuture对象，close方法需要等待写操作异步完成之后的ChannelFuture通知/监听触发。需要注意的是，关闭方法仍旧不是立即关闭一个连接，它同样也是返回了一个ChannelFuture对象。<br /><br />4) 在写操作完成之后我们又如何得到通知？这个只需要简单的为这个返回的ChannelFuture对象增加一个ChannelFutureListener 即可。在这里我们创建了一个匿名ChannelFutureListener对象，在这个ChannelFutureListener对象内部我们处理了 异步操作完成之后的关闭操作。<br /><br />另外，你也可以通过使用一个预定义的监听类来简化代码。<br />f.addListener(ChannelFutureListener.CLOSE);<br /> <br /><br />1.6. 时间协议服务客户端<br /><br /><br />不同于DISCARD和ECHO协议服务，我们需要一个时间协议服务的客户端，因为人们无法直接将一个32位的二进制数据转换一个日历时间。在这一节我们将学习如何确保服务器端工作正常，以及如何使用Netty完成客户端的开发。<br /><br />使用Netty开发服务器端和客户端代码最大的不同是要求使用不同的Bootstrap及ChannelFactory。请参照以下的代码：<br /><br />Java代码 <br />package org.jboss.netty.example.time;  <br />  <br />import java.net.InetSocketAddress;  <br />import java.util.concurrent.Executors;  <br />  <br />public class TimeClient {  <br />  <br />    public static void main(String[] args) throws Exception {  <br />        String host = args[0];  <br />        int port = Integer.parseInt(args[1]);  <br />  <br />        ChannelFactory factory =  <br />            new NioClientSocketChannelFactory (  <br />                    Executors.newCachedThreadPool(),  <br />                    Executors.newCachedThreadPool());  <br />  <br />        ClientBootstrap bootstrap = new ClientBootstrap (factory);  <br />  <br />        TimeClientHandler handler = new TimeClientHandler();  <br />        bootstrap.getPipeline().addLast("handler", handler);  <br />         <br />        bootstrap.setOption("tcpNoDelay" , true);  <br />        bootstrap.setOption("keepAlive", true);  <br />  <br />        bootstrap.connect (new InetSocketAddress(host, port));  <br />    }  <br />}  <br />代码说明<br />1) 使用NioClientSocketChannelFactory而不是NioServerSocketChannelFactory来创建客户端的Channel通道对象。<br /><br />2) 客户端的ClientBootstrap对应ServerBootstrap。<br /><br />3) 请注意，这里不存在使用&#8220;child.&#8221;前缀的配置项，客户端的SocketChannel实例不存在父级Channel对象。<br /><br />4) 我们应当调用connect连接方法，而不是之前的bind绑定方法。<br /> <br />正如你所看到的，这与服务端的启动过程是完全不一样的。ChannelHandler又该如何实现呢？它应当负责接收一个32位的整数，将其转换为可读的格式后，打印输出时间，并关闭这个连接。<br /><br /> <br /><br />Java代码 <br />package org.jboss.netty.example.time;  <br />  <br />import java.util.Date;  <br />  <br />@ChannelPipelineCoverage("all")  <br />public class TimeClientHandler extends SimpleChannelHandler {  <br />  <br />    @Override  <br />    public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {  <br />        ChannelBuffer buf = (ChannelBuffer) e.getMessage();  <br />        long currentTimeMillis = buf.readInt() * 1000L;  <br />        System.out.println(new Date(currentTimeMillis));  <br />        e.getChannel().close();  <br />    }  <br />  <br />    @Override  <br />    public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {  <br />        e.getCause().printStackTrace();  <br />        e.getChannel().close();  <br />    }  <br />}  <br /> <br />这看起来很是简单，与服务端的实现也并未有什么不同。然而，这个处理器却时常会因为抛出IndexOutOfBoundsException异常而拒绝工作。我们将在下一节讨论这个问题产生的原因。<br /><br />1.7. 流数据的传输处理<br /><br /> <br /><br />1.7.1. Socket Buffer的缺陷<br /><br /><br />对于例如TCP/IP这种基于流的传输协议实现，接收到的数据会被存储在socket的接受缓冲区内。不幸的是，这种基于流的传输缓冲区并不是一个包队 列，而是一个字节队列。这意味着，即使你以两个数据包的形式发送了两条消息，操作系统却不会把它们看成是两条消息，而仅仅是一个批次的字节序列。因此，在 这种情况下我们就无法保证收到的数据恰好就是远程节点所发送的数据。例如，让我们假设一个操作系统的TCP/IP堆栈收到了三个数据包：<br /><br /> <br /><br />+-----+-----+-----+<br />| ABC | DEF | GHI |<br />+-----+-----+-----+<br /> <br />由于这种流传输协议的普遍性质，在你的应用中有较高的可能会把这些数据读取为另外一种形式：<br /><br /> <br /><br />+----+-------+---+---+<br />| AB | CDEFG | H | I |<br />+----+-------+---+---+<br /> <br /><br />因此对于数据的接收方，不管是服务端还是客户端，应当重构这些接收到的数据，让其变成一种可让你的应用逻辑易于理解的更有意义的数据结构。在上面所述的这个例子中，接收到的数据应当重构为下面的形式：<br /><br /> <br /><br />+-----+-----+-----+<br />| ABC | DEF | GHI |<br />+-----+-----+-----+<br /> <br />1.7.2. 第一种方案<br /><br /><br />现在让我们回到时间协议服务客户端的例子中。我们在这里遇到了同样的问题。一个32位的整数是一个非常小的数据量，因此它常常不会被切分在不同的数据段内。然而，问题是它确实可以被切分在不同的数据段内，并且这种可能性随着流量的增加而提高。<br /><br />最简单的方案是在程序内部创建一个可准确接收4字节数据的累积性缓冲。下面的代码是修复了这个问题后的TimeClientHandler实现。<br /><br /> <br /><br />Java代码 <br />package org.jboss.netty.example.time;  <br />  <br />import static org.jboss.netty.buffer.ChannelBuffers.*;  <br />  <br />import java.util.Date;  <br />  <br />@ChannelPipelineCoverage("one")  <br />public class TimeClientHandler extends SimpleChannelHandler {  <br />  <br />    private final ChannelBuffer buf = dynamicBuffer();  <br />  <br />    @Override  <br />    public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {  <br />        ChannelBuffer m = (ChannelBuffer) e.getMessage();  <br />        buf.writeBytes(m);  <br />         <br />        if (buf.readableBytes() &gt;= 4) {  <br />            long currentTimeMillis = buf.readInt() * 1000L;  <br />            System.out.println(new Date(currentTimeMillis));  <br />            e.getChannel().close();  <br />        }  <br />    }  <br />  <br />    @Override  <br />    public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {  <br />        e.getCause().printStackTrace();  <br />        e.getChannel().close();  <br />    }  <br />}  <br /> <br /><br />     代码说明  <br /><br />1) 这一次我们使用&#8220;one&#8221;做为ChannelPipelineCoverage的注解值。这是由于这个修改后的TimeClientHandler不在不 在内部保持一个buffer缓冲，因此这个TimeClientHandler实例不可以再被多个Channel通道或ChannelPipeline共 享。否则这个内部的buffer缓冲将无法缓冲正确的数据内容。<br /><br />2) 动态的buffer缓冲也是ChannelBuffer的一种实现，其拥有动态增加缓冲容量的能力。当你无法预估消息的数据长度时，动态的buffer缓冲是一种很有用的缓冲结构。<br /><br />3) 首先，所有的数据将会被累积的缓冲至buf容器。<br /><br />4) 之后，这个处理器将会检查是否收到了足够的数据然后再进行真实的业务逻辑处理，在这个例子中需要接收4字节数据。否则，Netty将重复调用messageReceived方法，直至4字节数据接收完成。<br /> <br />这里还有另一个地方需要进行修改。你是否还记得我们把TimeClientHandler实例添加到了这个ClientBootstrap实例的默 认ChannelPipeline管道里？这意味着同一个TimeClientHandler实例将被多个Channel通道共享，因此接受的数据也将受 到破坏。为了给每一个Channel通道创建一个新的TimeClientHandler实例，我们需要实现一个 ChannelPipelineFactory管道工厂：<br /><br />Java代码 <br />package org.jboss.netty.example.time;  <br />  <br />public class TimeClientPipelineFactory implements ChannelPipelineFactory {  <br />  <br />    public ChannelPipeline getPipeline() {  <br />        ChannelPipeline pipeline = Channels.pipeline();  <br />        pipeline.addLast("handler", new TimeClientHandler());  <br />        return pipeline;  <br />    }  <br />}  <br /> <br />现在，我们需要把TimeClient下面的代码片段：<br /><br />Java代码 <br />TimeClientHandler handler = new TimeClientHandler();  <br />bootstrap.getPipeline().addLast("handler", handler);  <br /> <br />替换为：<br /><br />Java代码 <br />bootstrap.setPipelineFactory(new TimeClientPipelineFactory());  <br /> <br />虽然这看上去有些复杂，并且由于在TimeClient内部我们只创建了一个连接（connection），因此我们在这里确实没必要引入TimeClientPipelineFactory实例。<br /><br />然而，当你的应用变得越来越复杂，你就总会需要实现自己的ChannelPipelineFactory，这个管道工厂将会令你的管道配置变得更加具有灵活性。<br /><br />1.7.3. 第二种方案<br /><br /> <br /><br />虽然第二种方案解决了时间协议客户端遇到的问题，但是这个修改后的处理器实现看上去却不再那么简洁。设想一种更为复杂的，由多个可变长度字段组成的协议。你的ChannelHandler实现将变得越来越难以维护。<br /><br />正如你已注意到的，你可以为一个ChannelPipeline添加多个ChannelHandler，因此，为了减小应用的复杂性，你可以把这个臃肿的 ChannelHandler切分为多个独立的模块单元。例如，你可以把TimeClientHandler切分为两个独立的处理器：<br /><br />  TimeDecoder，解决数据分段的问题。<br />  TimeClientHandler，原始版本的实现。<br />幸运的是，Netty提供了一个可扩展的类，这个类可以直接拿过来使用帮你完成TimeDecoder的开发：<br /><br />Java代码 <br />package org.jboss.netty.example.time;  <br />  <br />  <br />public class TimeDecoder extends FrameDecoder {  <br />  <br />    @Override  <br />    protected Object decode(  <br />            ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer)  {  <br />             <br />        if (buffer.readableBytes() &lt; 4) {  <br />            return null;   <br />        }  <br />         <br />        return buffer.readBytes(4);  <br />    }  <br />}  <br /> <br /><br />代码说明<br />1) 这里不再需要使用ChannelPipelineCoverage的注解，因为FrameDecoder总是被注解为&#8220;one&#8221;。<br /><br />2) 当接收到新的数据后，FrameDecoder会调用decode方法，同时传入一个FrameDecoder内部持有的累积型buffer缓冲。<br /><br />3) 如果decode返回null值，这意味着还没有接收到足够的数据。当有足够数量的数据后FrameDecoder会再次调用decode方法。<br /><br />4) 如果decode方法返回一个非空值，这意味着decode方法已经成功完成一条信息的解码。FrameDecoder将丢弃这个内部的累计型缓冲。请注 意你不需要对多条消息进行解码，FrameDecoder将保持对decode方法的调用，直到decode方法返回非空对象。<br /> <br />如果你是一个勇于尝试的人，你或许应当使用ReplayingDecoder，ReplayingDecoder更加简化了解码的过程。为此你需要查看API手册获得更多的帮助信息。<br /><br />Java代码 <br />package org.jboss.netty.example.time;  <br />  <br />public class TimeDecoder extends ReplayingDecoder&lt;VoidEnum&gt; {  <br />  <br />    @Override  <br />    protected Object decode(  <br />            ChannelHandlerContext ctx, Channel channel,  <br />            ChannelBuffer buffer, VoidEnum state) {  <br />             <br />        return buffer.readBytes(4);  <br />    }  <br />}  <br /> <br />此外，Netty还为你提供了一些可以直接使用的decoder实现，这些decoder实现不仅可以让你非常容易的实现大多数协议，并且还会帮你避免某些臃肿、难以维护的处理器实现。请参考下面的代码包获得更加详细的实例：<br /><br />  org.jboss.netty.example.factorial for a binary protocol, and<br />  org.jboss.netty.example.telnet for a text line-based protocol<br />1.8. 使用POJO代替ChannelBuffer<br /><br /><br />目前为止所有的实例程序都是使用ChannelBuffer做为协议消息的原始数据结构。在这一节，我们将改进时间协议服务的客户/服务端实现，使用POJO 而不是ChannelBuffer做为协议消息的原始数据结构。<br /><br />在你的ChannelHandler实现中使用POJO的优势是很明显的；从你的ChannelHandler实现中分离从ChannelBuffer获 取数据的代码，将有助于提高你的ChannelHandler实现的可维护性和可重用性。在时间协议服务的客户/服务端代码中，直接使用 ChannelBuffer读取一个32位的整数并不是一个主要的问题。然而，你会发现，当你试图实现一个真实的协议的时候，这种代码上的分离是很有必要 的。<br /><br />首先，让我们定义一个称之为UnixTime的新类型。<br /><br />Java代码 <br />package org.jboss.netty.example.time;  <br />  <br />import java.util.Date;  <br />  <br />public class UnixTime {  <br />    private final int value;  <br />     <br />    public UnixTime(int value) {  <br />        this.value = value;  <br />    }  <br />     <br />    public int getValue() {  <br />        return value;  <br />    }  <br />     <br />    @Override  <br />    public String toString() {  <br />        return new Date(value * 1000L).toString();  <br />    }  <br />}  <br /> <br />现在让我们重新修改TimeDecoder实现，让其返回一个UnixTime，而不是一个ChannelBuffer。<br /><br />Java代码 <br />@Override  <br />protected Object decode(  <br />        ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) {  <br />    if (buffer.readableBytes() &lt; 4) {  <br />        return null;  <br />    }  <br />  <br />    return new UnixTime(buffer.readInt());  <br />}  <br /> <br />FrameDecoder和ReplayingDecoder允许你返回一个任何类型的对象。如果它们仅允许返回一个ChannelBuffer类 型的对象，我们将不得不插入另一个可以从ChannelBuffer对象转换 为UnixTime对象的ChannelHandler实现。<br /><br /><br />有了这个修改后的decoder实现，这个TimeClientHandler便不会再依赖ChannelBuffer。<br /><br />Java代码 <br />@Override  <br />public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {  <br />    UnixTime m = (UnixTime) e.getMessage();  <br />    System.out.println(m);  <br />    e.getChannel().close();  <br />}  <br /> <br />更加简单优雅了，不是吗？同样的技巧也可以应用在服务端，让我们现在更新TimeServerHandler的实现：<br /><br />Java代码 <br />@Override  <br />public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) {  <br />    UnixTime time = new UnixTime(System.currentTimeMillis() / 1000);  <br />    ChannelFuture f = e.getChannel().write(time);  <br />    f.addListener(ChannelFutureListener.CLOSE);  <br />}  <br /> <br />现在剩下的唯一需要修改的部分是这个ChannelHandler实现，这个ChannelHandler实现需要把一个UnixTime对象重新 转换为一个ChannelBuffer。但这却已是相当简单了，因为当你对消息进行编码的时候你不再需要处理数据包的拆分及组装。<br /><br />Java代码 <br />package org.jboss.netty.example.time;  <br />     <br />import static org.jboss.netty.buffer.ChannelBuffers.*;  <br />  <br />@ChannelPipelineCoverage("all")  <br />public class TimeEncoder extends SimpleChannelHandler {  <br />  <br />    public void writeRequested(ChannelHandlerContext ctx, MessageEvent  e) {  <br />        UnixTime time = (UnixTime) e.getMessage();  <br />         <br />        ChannelBuffer buf = buffer(4);  <br />        buf.writeInt(time.getValue());  <br />         <br />        Channels.write(ctx, e.getFuture(), buf);  <br />    }  <br />}  <br /> <br />     代码说明<br /><br />1) 因为这个encoder是无状态的，所以其使用的ChannelPipelineCoverage注解值是&#8220;all&#8221;。实际上，大多数encoder实现都是无状态的。<br /><br />2) 一个encoder通过重写writeRequested方法来实现对写操作请求的拦截。不过请注意虽然这个writeRequested方法使用了和 messageReceived方法一样的MessageEvent参数，但是它们却分别对应了不同的解释。一个ChannelEvent事件可以既是一 个上升流事件（upstream event）也可以是一个下降流事件（downstream event），这取决于事件流的方向。例如：一个MessageEvent消息事件可以作为一个上升流事件（upstream event）被messageReceived方法调用，也可以作为一个下降流事件（downstream event）被writeRequested方法调用。请参考API手册获得上升流事件（upstream event）和下降流事件（downstream event）的更多信息。<br /><br />3) 一旦完成了POJO和ChannelBuffer转换，你应当确保把这个新的buffer缓冲转发至先前的 ChannelDownstreamHandler处理，这个下降通道的处理器由某个ChannelPipeline管理。Channels提供了多个可 以创建和发送ChannelEvent事件的帮助方法。在这个例子中，Channels.write(...)方法创建了一个新的 MessageEvent事件，并把这个事件发送给了先前的处于某个ChannelPipeline内的 ChannelDownstreamHandler处理器。<br /><br />另外，一个很不错的方法是使用静态的方式导入Channels类：<br /><br />import static org.jboss.netty.channel.Channels.*;<br />...<br />ChannelPipeline pipeline = pipeline();<br />write(ctx, e.getFuture(), buf);<br />fireChannelDisconnected(ctx);<br /><br /> <br />最后的任务是把这个TimeEncoder插入服务端的ChannelPipeline，这是一个很简单的步骤。<br /><br />1.9. 关闭你的应用<br /><br /><br />如果你运行了TimeClient，你肯定可以注意到，这个应用并没有自动退出而只是在那里保持着无意义的运行。跟踪堆栈记录你可以发现，这里有一些运行 状态的I/O线程。为了关闭这些I/O线程并让应用优雅的退出，你需要释放这些由ChannelFactory分配的资源。<br /><br />一个典型的网络应用的关闭过程由以下三步组成：<br /><br />关闭负责接收所有请求的server socket。<br />关闭所有客户端socket或服务端为响应某个请求而创建的socket。<br />释放ChannelFactory使用的所有资源。<br />为了让TimeClient执行这三步，你需要在TimeClient.main()方法内关闭唯一的客户连接以及ChannelFactory使用的所有资源，这样做便可以优雅的关闭这个应用。<br /><br />Java代码 <br />package org.jboss.netty.example.time;  <br />  <br />public class TimeClient {  <br />    public static void main(String[] args) throws Exception {  <br />        ...  <br />        ChannelFactory factory = ...;  <br />        ClientBootstrap bootstrap = ...;  <br />        ...  <br />        ChannelFuture future  = bootstrap.connect(...);  <br />        future.awaitUninterruptible();  <br />        if (!future.isSuccess()) {  <br />            future.getCause().printStackTrace();  <br />        }  <br />        future.getChannel().getCloseFuture().awaitUninterruptibly();  <br />        factory.releaseExternalResources();  <br />    }  <br />}  <br />代码说明<br />1) ClientBootstrap对象的connect方法返回一个ChannelFuture对象，这个ChannelFuture对象将告知这个连接操 作的成功或失败状态。同时这个ChannelFuture对象也保存了一个代表这个连接操作的Channel对象引用。<br /><br />2) 阻塞式的等待，直到ChannelFuture对象返回这个连接操作的成功或失败状态。<br /><br />3) 如果连接失败，我们将打印连接失败的原因。如果连接操作没有成功或者被取消，ChannelFuture对象的getCause()方法将返回连接失败的原因。<br /><br />4) 现在，连接操作结束，我们需要等待并且一直到这个Channel通道返回的closeFuture关闭这个连接。每一个Channel都可获得自己的closeFuture对象，因此我们可以收到通知并在这个关闭时间点执行某种操作。<br /><br />并且即使这个连接操作失败，这个closeFuture仍旧会收到通知，因为这个代表连接的 Channel对象将会在连接操作失败后自动关闭。<br /><br />5) 在这个时间点，所有的连接已被关闭。剩下的唯一工作是释放ChannelFactory通道工厂使用的资源。这一步仅需要调用 releaseExternalResources()方法即可。包括NIO Secector和线程池在内的所有资源将被自动的关闭和终止。<br /> <br />关闭一个客户端应用是很简单的，但又该如何关闭一个服务端应用呢？你需要释放其绑定的端口并关闭所有接受和打开的连接。为了做到这一点，你需要使用一种数据结构记录所有的活动连接，但这却并不是一件容易的事。幸运的是，这里有一种解决方案，ChannelGroup。<br /><br />ChannelGroup是Java 集合 API的一个特有扩展，ChannelGroup内部持有所有打开状态的Channel通道。如果一个Channel通道对象被加入到 ChannelGroup，如果这个Channel通道被关闭，ChannelGroup将自动移除这个关闭的Channel通道对象。此外，你还可以对 一个ChannelGroup对象内部的所有Channel通道对象执行相同的操作。例如，当你关闭服务端应用时你可以关闭一个ChannelGroup 内部的所有Channel通道对象。<br /><br />为了记录所有打开的socket，你需要修改你的TimeServerHandler实现，将一个打开的Channel通道加入全局的ChannelGroup对象，TimeServer.allChannels:<br /><br />Java代码 <br />@Override  <br />public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) {  <br />    TimeServer.allChannels.add(e.getChannel());  <br />}  <br />代码说明<br />是的，ChannelGroup是线程安全的。<br /> <br />现在，所有活动的Channel通道将被自动的维护，关闭一个服务端应用有如关闭一个客户端应用一样简单。<br /><br />Java代码 <br />package org.jboss.netty.example.time;  <br />  <br />public class TimeServer {  <br />  <br />    static final ChannelGroup allChannels = new DefaultChannelGroup("time-server" );  <br />  <br />    public static void main(String[] args) throws Exception {  <br />        ...  <br />        ChannelFactory factory = ...;  <br />        ServerBootstrap bootstrap = ...;  <br />        ...  <br />        Channel channel  = bootstrap.bind(...);  <br />        allChannels.add(channel);  <br />        waitForShutdownCommand();  <br />        ChannelGroupFuture future = allChannels.close();  <br />        future.awaitUninterruptibly();  <br />        factory.releaseExternalResources();  <br />    }  <br />}  <br />代码说明<br />1) DefaultChannelGroup需要一个组名作为其构造器参数。这个组名仅是区分每个ChannelGroup的一个标示。<br /><br />2) ServerBootstrap对象的bind方法返回了一个绑定了本地地址的服务端Channel通道对象。调用这个Channel通道的close()方法将释放这个Channel通道绑定的本地地址。<br /><br />3) 不管这个Channel对象属于服务端，客户端，还是为响应某一个请求创建，任何一种类型的Channel对象都会被加入ChannelGroup。因此，你尽可在关闭服务时关闭所有的Channel对象。<br /><br />4) waitForShutdownCommand()是一个想象中等待关闭信号的方法。你可以在这里等待某个客户端的关闭信号或者JVM的关闭回调命令。<br /><br />5) 你可以对ChannelGroup管理的所有Channel对象执行相同的操作。在这个例子里，我们将关闭所有的通道，这意味着绑定在服务端特定地址的 Channel通道将解除绑定，所有已建立的连接也将异步关闭。为了获得成功关闭所有连接的通知，close()方法将返回一个 ChannelGroupFuture对象，这是一个类似ChannelFuture的对象。<br /> <br />1.10. 总述<br /><br /><br />在这一章节，我们快速浏览并示范了如何使用Netty开发网络应用。下一章节将涉及更多的问题。同时请记住，为了帮助你以及能够让Netty基于你的回馈得到持续的改进和提高，Netty社区 将永远欢迎你的问题及建议。<br /><br /><br /><br /> 第二章. 架构总览<br /> <br />在这个章节，我们将阐述Netty提供的核心功能以及在此基础之上如何构建一个完备的网络应用。<br /><br />2.1. 丰富的缓冲实现<br /><br /><br />Netty使用自建的buffer API，而不是使用NIO的ByteBuffer来代表一个连续的字节序列。与ByteBuffer相比这种方式拥有明显的优势。Netty使用新的 buffer类型ChannelBuffer，ChannelBuffer被设计为一个可从底层解决ByteBuffer问题，并可满足日常网络应用开发 需要的缓冲类型。这些很酷的特性包括：<br /><br /> <br /><br />如果需要，允许使用自定义的缓冲类型。<br />复合缓冲类型中内置的透明的零拷贝实现。<br />开箱即用的动态缓冲类型，具有像StringBuffer一样的动态缓冲能力。<br />不再需要调用的flip()方法。<br />正常情况下具有比ByteBuffer更快的响应速度。<br />更多信息请参考：org.jboss.netty.buffer package description<br /><br />2.2. 统一的异步 I/O API<br /><br /><br />传统的Java I/O API在应对不同的传输协议时需要使用不同的类型和方法。例如：java.net.Socket 和 java.net.DatagramSocket它们并不具有相同的超类型，因此，这就需要使用不同的调用方式执行socket操作。<br /><br />这种模式上的不匹配使得在更换一个网络应用的传输协议时变得繁杂和困难。由于（Java I/O API）缺乏协议间的移植性，当你试图在不修改网络传输层的前提下增加多种协议的支持，这时便会产生问题。并且理论上讲，多种应用层协议可运行在多种传输 层协议之上例如TCP/IP,UDP/IP,SCTP和串口通信。<br /><br />让这种情况变得更糟的是，Java新的I/O（NIO）API与原有的阻塞式的I/O（OIO）API并不兼容，NIO.2(AIO)也是如此。由于所有的API无论是在其设计上还是性能上的特性都与彼此不同，在进入开发阶段，你常常会被迫的选择一种你需要的API。<br /><br />例如，在用户数较小的时候你可能会选择使用传统的OIO(Old I/O) API，毕竟与NIO相比使用OIO将更加容易一些。然而，当你的业务呈指数增长并且服务器需要同时处理成千上万的客户连接时你便会遇到问题。这种情况下 你可能会尝试使用NIO，但是复杂的NIO Selector编程接口又会耗费你大量时间并最终会阻碍你的快速开发。<br /><br />Netty有一个叫做Channel的统一的异步I/O编程接口，这个编程接口抽象了所有点对点的通信操作。也就是说，如果你的应用是基于Netty的某 一种传输实现，那么同样的，你的应用也可以运行在Netty的另一种传输实现上。Netty提供了几种拥有相同编程接口的基本传输实现：<br /><br /> <br /><br />NIO-based TCP/IP transport (See org.jboss.netty.channel.socket.nio),<br />OIO-based TCP/IP transport (See org.jboss.netty.channel.socket.oio),<br />OIO-based UDP/IP transport, and<br />Local transport (See org.jboss.netty.channel.local).<br />切换不同的传输实现通常只需对代码进行几行的修改调整，例如选择一个不同的ChannelFactory实现。<br /><br />此外，你甚至可以利用新的传输实现没有写入的优势，只需替换一些构造器的调用方法即可，例如串口通信。而且由于核心API具有高度的可扩展性，你还可以完成自己的传输实现。<br /><br />2.3. 基于拦截链模式的事件模型<br /><br /><br />一个定义良好并具有扩展能力的事件模型是事件驱动开发的必要条件。Netty具有定义良好的I/O事件模型。由于严格的层次结构区分了不同的事件类型，因 此Netty也允许你在不破坏现有代码的情况下实现自己的事件类型。这是与其他框架相比另一个不同的地方。很多NIO框架没有或者仅有有限的事件模型概 念；在你试图添加一个新的事件类型的时候常常需要修改已有的代码，或者根本就不允许你进行这种扩展。<br /><br />在一个ChannelPipeline内部一个ChannelEvent被一组ChannelHandler处理。这个管道是拦截过滤器 模式的一种高级形式的实现，因此对于一个事件如何被处理以及管道内部处理器间的交互过程，你都将拥有绝对的控制力。例如，你可以定义一个从socket读取到数据后的操作：<br /><br />Java代码 <br />public class MyReadHandler implements SimpleChannelHandler {  <br />    public void messageReceived(ChannelHandlerContext ctx, MessageEvent evt) {  <br />        Object message = evt.getMessage();  <br />        // Do something with the received message.  <br />        ...  <br />  <br />        // And forward the event to the next handler.  <br />        ctx.sendUpstream(evt);  <br />    }  <br />}  <br /> <br />同时你也可以定义一种操作响应其他处理器的写操作请求：<br /><br />Java代码 <br />public class MyWriteHandler implements SimpleChannelHandler {  <br />    public void writeRequested(ChannelHandlerContext ctx, MessageEvent evt) {  <br />        Object message = evt.getMessage();  <br />        // Do something with the message to be written.  <br />        ...  <br />  <br />        // And forward the event to the next handler.  <br />        ctx.sendDownstream(evt);  <br />    }  <br />}  <br /> <br />有关事件模型的更多信息，请参考API文档ChannelEvent和ChannelPipeline部分。<br /><br />2.4. 适用快速开发的高级组件<br /><br /><br />上述所提及的核心组件已经足够实现各种类型的网络应用，除此之外，Netty也提供了一系列的高级组件来加速你的开发过程。<br /><br />2.4.1. Codec框架<br /><br /><br />就像&#8220;1.8. 使用POJO代替ChannelBuffer&#8221;一节所展示的那样，从业务逻辑代码中分离协议处理部分总是一个很不错的想法。然而如果一切从零开始便会遭遇 到实现上的复杂性。你不得不处理分段的消息。一些协议是多层的（例如构建在其他低层协议之上的协议）。一些协议过于复杂以致难以在一台主机（single state machine）上实现。<br /><br />因此，一个好的网络应用框架应该提供一种可扩展，可重用，可单元测试并且是多层的codec框架，为用户提供易维护的codec代码。<br /><br />Netty提供了一组构建在其核心模块之上的codec实现，这些简单的或者高级的codec实现帮你解决了大部分在你进行协议处理开发过程会遇到的问题，无论这些协议是简单的还是复杂的，二进制的或是简单文本的。<br /><br />2.4.2. SSL / TLS 支持<br /><br /><br />不同于传统阻塞式的I/O实现，在NIO模式下支持SSL功能是一个艰难的工作。你不能只是简单的包装一下流数据并进行加密或解密工作，你不得不借助于 javax.net.ssl.SSLEngine，SSLEngine是一个有状态的实现，其复杂性不亚于SSL自身。你必须管理所有可能的状态，例如密 码套件，密钥协商（或重新协商），证书交换以及认证等。此外，与通常期望情况相反的是SSLEngine甚至不是一个绝对的线程安全实现。<br /><br />在Netty内部，SslHandler封装了所有艰难的细节以及使用SSLEngine可能带来的陷阱。你所做的仅是配置并将该SslHandler插入到你的ChannelPipeline中。同样Netty也允许你实现像StartTlS 那样所拥有的高级特性，这很容易。<br /><br />2.4.3. HTTP实现<br /><br /><br />HTTP无疑是互联网上最受欢迎的协议，并且已经有了一些例如Servlet容器这样的HTTP实现。因此，为什么Netty还要在其核心模块之上构建一套HTTP实现？<br /><br />与现有的HTTP实现相比Netty的HTTP实现是相当与众不同的。在HTTP消息的低层交互过程中你将拥有绝对的控制力。这是因为Netty的 HTTP实现只是一些HTTP codec和HTTP消息类的简单组合，这里不存在任何限制&#8212;&#8212;例如那种被迫选择的线程模型。你可以随心所欲的编写那种可以完全按照你期望的工作方式工作 的客户端或服务器端代码。这包括线程模型，连接生命期，快编码，以及所有HTTP协议允许你做的，所有的一切，你都将拥有绝对的控制力。<br /><br />由于这种高度可定制化的特性，你可以开发一个非常高效的HTTP服务器，例如：<br /><br />要求持久化链接以及服务器端推送技术的聊天服务（e.g. Comet ）<br />需要保持链接直至整个文件下载完成的媒体流服务（e.g. 2小时长的电影）<br />需要上传大文件并且没有内存压力的文件服务（e.g. 上传1GB文件的请求）<br />支持大规模mash-up应用以及数以万计连接的第三方web services异步处理平台<br />2.4.4. Google Protocol Buffer 整合<br /><br /><br />Google Protocol Buffers 是快速实现一个高效的二进制协议的理想方案。通过使用ProtobufEncoder和ProtobufDecoder，你可以把Google Protocol Buffers 编译器 (protoc)生成的消息类放入到Netty的codec实现中。请参考&#8220;LocalTime &#8221;实例，这个例子也同时显示出开发一个由简单协议定义 的客户及服务端是多么的容易。<br /><br />2.5. 总述 <br />在这一章节，我们从功能特性的角度回顾了Netty的整体架构。Netty有一个简单却不失强大的架构。这个架构由三部分组成&#8212;&#8212;缓冲（buffer）， 通道（channel），事件模型（event model）&#8212;&#8212;所有的高级特性都构建在这三个核心组件之上。一旦你理解了它们之间的工作原理，你便不难理解在本章简要提及的更多高级特性。<br /><br />你可能对Netty的整体架构以及每一部分的工作原理仍旧存有疑问。如果是这样，最好的方式是告诉我们 应该如何改进这份指南<img src ="http://www.blogjava.net/titanaly/aggbug/400359.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/titanaly/" target="_blank">不高兴</a> 2013-06-07 16:11 <a href="http://www.blogjava.net/titanaly/archive/2013/06/07/400359.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Eclipse调试Java的10个技巧(转)</title><link>http://www.blogjava.net/titanaly/archive/2012/10/19/389881.html</link><dc:creator>不高兴</dc:creator><author>不高兴</author><pubDate>Fri, 19 Oct 2012 08:54:00 GMT</pubDate><guid>http://www.blogjava.net/titanaly/archive/2012/10/19/389881.html</guid><wfw:comment>http://www.blogjava.net/titanaly/comments/389881.html</wfw:comment><comments>http://www.blogjava.net/titanaly/archive/2012/10/19/389881.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/titanaly/comments/commentRss/389881.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/titanaly/services/trackbacks/389881.html</trackback:ping><description><![CDATA[<p style="margin: 0px; padding: 0px; font-family: verdana, 'bitstream vera sans', sans-serif; font-size: 13px; ">在本教程中，我们将看到使用Eclipse调试Java应用程序。调试可以帮助我们识别和解决应用程序中的缺陷。我们将重点放在运行时间的问题，而不是编译时错误。有提供像gdb的命令行调试器。在本教程中，我们将集中在基于GUI的调试，我们把我们最喜爱的IDE Eclipse来运行，通过本教程。虽然我们说的Eclipse，点大多是通用的，适用于调试使用的IDE像NetBeans。</p>
<p style="margin: 0px; padding: 0px;font-family: verdana, 'bitstream vera sans', sans-serif; font-size: 13px; "><span style="padding: 0px; margin: 0px; font-family: 微软雅黑, Verdana, sans-serif, 宋体; line-height: 22px;  font-size: 14px; ">在看这篇文章前，我推荐你看一下</span><a href="http://javapapers.com/core-java/eclipse-shortcuts/" target="_blank" rel="nofollow" style="color: #4466bb; text-decoration: none; padding: 0px; margin: 0px; outline: 0px; font-family: 微软雅黑, Verdana, sans-serif, 宋体; line-height: 22px;  font-size: 14px; "><span style="padding: 0px; margin: 0px; ">Eclipse 快捷键手册</span></a><span style="padding: 0px; margin: 0px; font-family: 微软雅黑, Verdana, sans-serif, 宋体; line-height: 22px;  font-size: 14px; ">，你也可以到这儿：<a href="http://javapapers.com/wp-content/uploads/2012/02/Eclipse-Shortcuts.pdf" style="color: #ff9900; text-decoration: none; ">下载PDF文件</a>我的eclipse版本是4.2 Juno。</span></p>
<p style="margin: 0px; padding: 0px; font-family: verdana, 'bitstream vera sans', sans-serif; font-size: 13px; "></p>
<h2><a name="t0" style="color: #ff9900; "></a>0.三点特别提醒：</h2>
<ul style="padding: 0px; margin: 10px 0px 20px 20px; list-style-position: inside; line-height: 20px; font-family: 微软雅黑, Verdana, sans-serif, 宋体;  ">
     <li style="padding: 0px; margin: 0px; "><span style="padding: 0px; margin: 0px; ">不要使用System.out.println作为调试工具</span></li>
     <li style="padding: 0px; margin: 0px; "><span style="padding: 0px; margin: 0px; ">启用所有组件的详细的日志记录级别</span></li>
     <li style="padding: 0px; margin: 0px; "><span style="padding: 0px; margin: 0px; ">使用一个日志分析器来阅读日志</span></li>
</ul>
<p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; "><span style="color: #ff0000; "><strong>[</strong></span></p>
<blockquote style=" font-family: Arial; line-height: 26px; margin: 0px 0px 0px 40px; border: none; padding: 0px; ">
<p style="margin: 0px; padding: 0px; ">（System.out.println()对开发人员来说，有时候也许可以是一种调试手段，但是项目一旦完成他就没有什么用途了，就变成垃圾了，得必须注释或删除掉，这样会比较麻烦。启用所有组件的详细日志记录级别，运用日志分析器来记录详细系统运行状态,这对后期网站的优化和维护会有很多作用。）这仅仅是个人理解，仅供参考！</p>
</blockquote>
<p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; "><span style="color: #ff0000; "><strong>]</strong></span></p>
<p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; "><br />
</p>
<h2><a name="t1" style="color: #ff9900; "></a>1.条件断点</h2>
<p style="margin: 0px; padding: 0px; font-family: verdana, 'bitstream vera sans', sans-serif; font-size: 13px; "><span style="font-family: 微软雅黑, Verdana, sans-serif, 宋体; line-height: 22px;  font-size: 14px; ">想象一下我们平时如何添加断点，通常的做法是双击行号的左边。在debug视图中，BreakPoint View将所有断点都列出来，但是我们可以添加一个boolean类型的条件来决定断点是否被跳过。如果条件为真，在断点处程序将停止，否则断点被跳过，程序继续执行。</span></p>
<p style="margin: 0px; padding: 0px; font-family: verdana, 'bitstream vera sans', sans-serif; font-size: 13px; "><img size-full=""  wp-image-973"="" title="conditionaldebug" src="http://javapapers.com/wp-content/uploads/2012/08/conditionaldebug.png" alt="" width="404" height="290" style="border: none; " /></p>
<h2><a name="t2" style="color: #ff9900; "></a>2.异常断点</h2>
<p style="margin: 0px; padding: 0px; font-family: verdana, 'bitstream vera sans', sans-serif; font-size: 13px; "><span style="font-family: 微软雅黑, Verdana, sans-serif, 宋体; line-height: 22px;  font-size: 14px; ">在断点view中有一个看起来像J！的按钮，我们可以使用它添加一个基于异常的断点，例如我们希望当NullPointerException抛出的时候程序暂停，我们可以这样:</span></p>
<p style="margin: 0px; padding: 0px;font-family: verdana, 'bitstream vera sans', sans-serif; font-size: 13px; "><img size-full=""  wp-image-974"="" title="javaexceptionbreakpoint" src="http://javapapers.com/wp-content/uploads/2012/08/javaexceptionbreakpoint.png" alt="" width="399" height="318" style="border: none; " /></p>
<h2><a name="t3" style="color: #ff9900; "></a>3.观察点</h2>
<p style="margin: 0px; padding: 0px; font-family: verdana, 'bitstream vera sans', sans-serif; font-size: 13px; ">这是一个很好的功能，<span style="font-family: 微软雅黑, Verdana, sans-serif, 宋体; line-height: 22px;  font-size: 14px; ">他允许当一个选定的属性被访问或者被更改的时候程序执行暂停，并进行debug。最简单的办法是在类中声明成员变量的语句行号左边双击，就可以加入一个观察点。</span></p>
<p style="margin: 0px; padding: 0px; font-family: verdana, 'bitstream vera sans', sans-serif; font-size: 13px; "><img size-full=""  wp-image-975"="" title="观察点" src="http://javapapers.com/wp-content/uploads/2012/08/watchpoint.png" alt="" width="351" height="497" style="border: none; " /></p>
<h2><a name="t4" style="color: #ff9900; "></a>4.查看变量</h2>
<p style="margin: 0px; padding: 0px; font-family: verdana, 'bitstream vera sans', sans-serif; font-size: 13px; "><span style="font-family: 微软雅黑, Verdana, sans-serif, 宋体; line-height: 22px;  font-size: 14px; ">在选中的变量上使用Ctrl+Shift+d 或者 Ctrl+Shift+i可以查看变量值，另外我们还可以在Expressions View中添加监视。</span></p>
<p style="margin: 0px; padding: 0px; font-family: verdana, 'bitstream vera sans', sans-serif; font-size: 13px; "><img size-full=""  wp-image-976"="" title="看" src="http://javapapers.com/wp-content/uploads/2012/08/watch.png" alt="" width="351" height="321" style="border: none; " /></p>
<h2><a name="t5" style="color: #ff9900; "></a>5.更改变量的值</h2>
<p style="margin: 0px; padding: 0px; font-family: verdana, 'bitstream vera sans', sans-serif; font-size: 13px; "><span style="font-family: 微软雅黑, Verdana, sans-serif, 宋体; line-height: 22px;  font-size: 14px; ">我们可以在Debug的时候改变其中变量的值。在Variables View中可以按下图所示操作。</span></p>
<p style="margin: 0px; padding: 0px; font-family: verdana, 'bitstream vera sans', sans-serif; font-size: 13px; "><img size-full=""  wp-image-977"="" title="changevalue" src="http://javapapers.com/wp-content/uploads/2012/08/changevalue.png" alt="" width="351" height="319" style="border: none; " /></p>
<h2><a name="t6" style="color: #ff9900; "></a>6.在主方法停止</h2>
<p style="margin: 0px; padding: 0px; font-family: verdana, 'bitstream vera sans', sans-serif; font-size: 13px; "><span style="font-family: 微软雅黑, Verdana, sans-serif, 宋体; line-height: 22px;  font-size: 14px; ">在Run/Debug设置中，我们可以按如下图所示的启用这个特性。程序将会在main方法的第一行停住</span></p>
<p style="margin: 0px; padding: 0px; font-family: verdana, 'bitstream vera sans', sans-serif; font-size: 13px; "><img size-full=""  wp-image-978"="" title="Stopinmain" src="http://javapapers.com/wp-content/uploads/2012/08/Stopinmain.png" alt="" width="457" height="433" style="border: none; " /></p>
<h2><a name="t7" style="color: #ff9900; "></a>7.环境变量</h2>
<p style="margin: 0px; padding: 0px; font-family: verdana, 'bitstream vera sans', sans-serif; font-size: 13px; "><span style="font-family: 微软雅黑, Verdana, sans-serif, 宋体; line-height: 22px;  font-size: 14px; ">我们可以很方便的在Edit Conriguration对话框中添加环境变量</span></p>
<p style="margin: 0px; padding: 0px; font-family: verdana, 'bitstream vera sans', sans-serif; font-size: 13px; "><img size-full=""  wp-image-979"="" title="环境变量" src="http://javapapers.com/wp-content/uploads/2012/08/environment-variable.png" alt="" width="451" height="620" style="border: none; " /></p>
<h2><a name="t8" style="color: #ff9900; "></a>8.跳出函数到选定层</h2>
<p style="margin: 0px; padding: 0px; font-family: verdana, 'bitstream vera sans', sans-serif; font-size: 13px; "><span style="font-family: 微软雅黑, Verdana, sans-serif, 宋体; line-height: 22px;  font-size: 14px; ">这个功能非常酷，是我第二个非常喜欢的功能，Drop to frame就是说，可以重新跳到当前方法的开始处重新执行，并且所有上下文变量的值也回到那个时候。不一定是当前方法，可以点击当前调用栈中的任何一个frame跳到那里（除了最开始的那个frame）。主要用途是所有变量状态快速恢复到方法开始时候的样子重新执行一遍，即可以一遍又一遍地在那个你关注的上下文中进行多次调试（结合改变变量值等其它功能），而不用重来一遍调试到哪里了。当然，原来执行过程中产生的副作用是不可逆的（比如你往数据库中插入了一条记录）。</span></p>
<p style="margin: 0px; padding: 0px; font-family: verdana, 'bitstream vera sans', sans-serif; font-size: 13px; "><img size-full=""  wp-image-980"="" title="droptoframe" src="http://javapapers.com/wp-content/uploads/2012/08/droptoframe.png" alt="" width="521" height="402" style="border: none; " /></p>
<h2><a name="t9" style="color: #ff9900; "></a>9.分步过滤</h2>
<p style="margin: 0px; padding: 0px; font-family: verdana, 'bitstream vera sans', sans-serif; font-size: 13px; "><span style="font-family: 微软雅黑, Verdana, sans-serif, 宋体; line-height: 22px;  font-size: 14px; ">当我们在调试的时候摁F5将进入方法的内部，但这有个缺点有的时候可能会进入到一些库的内部（例如JDK），可能并不是我们想要的，我们可以在Preferences中添加一个过滤器，排除指定的包。</span></p>
<p style="margin: 0px; padding: 0px; font-family: verdana, 'bitstream vera sans', sans-serif; font-size: 13px; "><img size-full=""  wp-image-981"="" title="加强过滤器" src="http://javapapers.com/wp-content/uploads/2012/08/stepfilter.png" alt="" width="626" height="561" style="border: none; " /></p>
<h2><a name="t10" style="color: #ff9900; "></a>10.跳入，跳过和返回</h2>
<p style="margin: 0px; padding: 0px; font-family: verdana, 'bitstream vera sans', sans-serif; font-size: 13px; "></p>
<div style="margin: 0px; font-family: 微软雅黑, Verdana, sans-serif, 宋体; line-height: 22px;  "><span style="padding: 0px; margin: 0px; ">其实这个技巧是debug最基本的知识。</span></div>
<div style="margin: 0px; font-family: 微软雅黑, Verdana, sans-serif, 宋体; line-height: 22px;  ">
<ul style="padding: 0px; margin: 10px 0px 20px 20px; list-style-position: inside; line-height: 20px; ">
     <li style="padding: 0px; margin: 0px; "></li>
     <li style="padding: 0px; margin: 0px; "><span style="padding: 0px; margin: 0px; ">F5-Step Into：移动到下一步，如果当前的行是一个方法调用，将进入这个方法的第一行。（可以通过第九条来排除）</span></li>
     <li style="padding: 0px; margin: 0px; "></li>
     <li style="padding: 0px; margin: 0px; "><span style="padding: 0px; margin: 0px; ">F6-Step Over：移动到下一行。如果当前行有方法调用，这个方法将被执行完毕返回，然后到下一行。</span></li>
     <li style="padding: 0px; margin: 0px; "></li>
     <li style="padding: 0px; margin: 0px; "><span style="padding: 0px; margin: 0px; ">F7-Step Return：继续执行当前方法，当当前方法执行完毕的时候，控制将转到当前方法被调用的行。</span></li>
     <li style="padding: 0px; margin: 0px; "><span style="padding: 0px; margin: 0px; ">F8-移动到下一个断点处。</span></li>
</ul>
</div>
<div style="font-family: Arial; line-height: 26px; "><span style="font-family: verdana, 'bitstream vera sans', sans-serif; font-size: 12px; "><span style="line-height: 21px; "><img src="http://javapapers.com/wp-content/uploads/2012/08/steps.png" alt="" style="border: none; " /><br />
</span></span></div>
<div style="font-family: Arial; line-height: 26px; "><span style="line-height: 21px; font-family: verdana, 'bitstream vera sans', sans-serif; "><br />
</span></div>
<div style="font-family: Arial; line-height: 26px;"><span style="line-height: 21px; font-family: verdana, 'bitstream vera sans', sans-serif; ">原文出自:</span><a href="http://javapapers.com/core-java/top-10-java-debugging-tips-with-eclipse/" style="color: #ff9900; text-decoration: none; line-height: 21px; font-family: verdana, 'bitstream vera sans', sans-serif; ">http://javapapers.com/core-java/top-10-java-debugging-tips-with-eclipse/</a></div><img src ="http://www.blogjava.net/titanaly/aggbug/389881.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/titanaly/" target="_blank">不高兴</a> 2012-10-19 16:54 <a href="http://www.blogjava.net/titanaly/archive/2012/10/19/389881.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>hg clone abort: error:</title><link>http://www.blogjava.net/titanaly/archive/2012/05/30/379595.html</link><dc:creator>不高兴</dc:creator><author>不高兴</author><pubDate>Wed, 30 May 2012 14:25:00 GMT</pubDate><guid>http://www.blogjava.net/titanaly/archive/2012/05/30/379595.html</guid><wfw:comment>http://www.blogjava.net/titanaly/comments/379595.html</wfw:comment><comments>http://www.blogjava.net/titanaly/archive/2012/05/30/379595.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/titanaly/comments/commentRss/379595.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/titanaly/services/trackbacks/379595.html</trackback:ping><description><![CDATA[<div>用tortoisehg下载google code时报错abort：error<br />
解决方案:将https: 换成http 试一试</div><img src ="http://www.blogjava.net/titanaly/aggbug/379595.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/titanaly/" target="_blank">不高兴</a> 2012-05-30 22:25 <a href="http://www.blogjava.net/titanaly/archive/2012/05/30/379595.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>visualvm监控jvm及远程jvm监控方法</title><link>http://www.blogjava.net/titanaly/archive/2012/03/20/372318.html</link><dc:creator>不高兴</dc:creator><author>不高兴</author><pubDate>Tue, 20 Mar 2012 13:59:00 GMT</pubDate><guid>http://www.blogjava.net/titanaly/archive/2012/03/20/372318.html</guid><wfw:comment>http://www.blogjava.net/titanaly/comments/372318.html</wfw:comment><comments>http://www.blogjava.net/titanaly/archive/2012/03/20/372318.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/titanaly/comments/commentRss/372318.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/titanaly/services/trackbacks/372318.html</trackback:ping><description><![CDATA[<span style="color: #333333; font-family: 宋体; line-height: 28px; text-indent: 28px; ">&nbsp; &nbsp; VisualVM是Sun的一个OpenJDK项目，其目的在于为Java应用创建一个整套的问题解决工具。它集成了多个JDK命令工具的一个可视化工具，它主要用来监控JVM的运行情况，可以用它来查看和浏览Heap Dump、Thread Dump、内存对象实例情况、GC执行情况、CPU消耗以及类的装载情况。 Java开发人员可以使用 VisualVM创建必要信息的日志，系统管理人员可用来监控及控制Java应用程序在网络中的运行状况。</span>&nbsp;<br />
&nbsp; &nbsp;<span style="color: #333333; font-family: Arial; line-height: normal; ">下载页面 :&nbsp;</span><a href="https://visualvm.dev.java.net/download.html" style="font-family: Arial; line-height: normal; ">https://visualvm.dev.java.net/download.html</a>
<p style="line-height: normal; color: #333333; font-family: Arial; ">&nbsp;&nbsp;&nbsp;&nbsp;文档地址 :&nbsp;<a href="https://visualvm.dev.java.net/docindex.html">https://visualvm.dev.java.net/docindex.html</a></p>
<p style="line-height: normal; color: #333333; font-family: Arial; ">&nbsp;&nbsp;&nbsp;&nbsp;入门文档 :&nbsp;<a href="https://visualvm.dev.java.net/zh_CN/gettingstarted.html">https://visualvm.dev.java.net/zh_CN/gettingstarted.html<br />
<br />
</a>&nbsp; &nbsp;&nbsp;</p>
<hr />
&nbsp; &nbsp; <span style="color: #800000; ">安装插件</span><br />
&nbsp; &nbsp;&nbsp;通过安装 VisualVM 更新中心提供的插件，可以向 VisualVM 添加功能。<br />
&nbsp; &nbsp; 1.&nbsp;从主菜单中选择&#8220;工具&#8221;&gt;&#8220;插件&#8221;。<br />
&nbsp;&nbsp;&nbsp;&nbsp;2. 在&#8220;可用插件&#8221;标签中，选中该插件的&#8220;安装&#8221;复选框。单击&#8220;安装&#8221;。<br />
&nbsp; &nbsp; 3. 逐步完成插件安装程序。<br />
&nbsp; &nbsp;&nbsp;<img src="http://www.blogjava.net/images/blogjava_net/titanaly/vvm-plugins-window.png" width="751" height="487" alt="" /><br />
<br />
<hr />
&nbsp; &nbsp; <span style="color: #800000; ">功能</span>&nbsp; &nbsp;&nbsp;<br />
&nbsp; &nbsp; 1. 概述<br />
&nbsp; &nbsp; &nbsp; &nbsp; 查看jvm信息及系统配置<br />
&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/images/blogjava_net/titanaly/概况.png" width="1051" height="709" alt="" /><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;2. 监视<br />
&nbsp; &nbsp; &nbsp; &nbsp; 了解项目运动的概况<br />
&nbsp; &nbsp;&nbsp;<img src="http://www.blogjava.net/images/blogjava_net/titanaly/监视.png" width="1046" height="704" alt="" /><br />
<br />
&nbsp; &nbsp; 3. visual gc<br />
&nbsp; &nbsp; &nbsp; &nbsp; 可以看到内存gc的详细情况<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/images/blogjava_net/titanaly/visualgc.png" border="0" alt="" width="1051" height="709" /><br />
<br />
<hr />
&nbsp; &nbsp; <span style="color: #800000; ">远程监控</span>&nbsp; &nbsp;&nbsp;<br />
&nbsp; &nbsp; 1. 通过jstatd启动RMI服务<br />
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;配置java安全访问，将如下的代码存为文件 jstatd.all.policy，放到JAVA_HOME/bin中，其内容如下，<br />
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;grant codebase "file:${java.home}/../lib/tools.jar" {
<p style="margin-top: 0cm; margin-right: 0cm; margin-bottom: 0pt; margin-left: 0cm; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left;  "><span style="font-size: small; ">&nbsp;&nbsp;</span>&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;permission java.security.AllPermission;</p>
<p style="margin-top: 0cm; margin-right: 0cm; margin-bottom: 0pt; margin-left: 0cm; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; ">&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 执行命令jstatd -J-Djava.security.policy=jstatd.all.policy -J-Djava.rmi.server.hostname=192.168.1.8 &amp;(192.168.1.8 &nbsp;为你服务器的ip地址,&amp;表示用守护线程的方式运行)<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; jstatd命令详解 :<a href="http://hzl7652.iteye.com/blog/1183182">http://hzl7652.iteye.com/blog/1183182</a>&nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;打开jvisualvm, 右键Remort,选择 "Add Remort Host..."，在弹出框中输入你的远端IP,比如192.168.1.8. 连接成功.<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp; &nbsp; 2. 配置JMX管理tomcat<br />
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;打开Tomcat的bin/catalina.bat，<span style="color: #ff0000; ">如果为linux或unix系统，则为catalina.sh文件</span>&nbsp;。&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;无限制访问&nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</p>
<div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left;margin-left: 40px; ">&nbsp; set JAVA_OPTS=-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9008 -Dcom.sun.management.jmxremote.authenticate=false - &nbsp; &nbsp;Dcom.sun.management.jmxremote.ssl=false&nbsp;<br />
<br />
需要用户名和密码访问</div>
<div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; margin-left: 40px; "></div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;JAVA_OPTS='-Xms128m -Xmx256m -XX:MaxPermSize=128m</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-Djava.rmi.server.hostname=192.168.1.8</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-Dcom.sun.management.jmxremote.port=8088</div>
<div>&nbsp; &nbsp; &nbsp; &nbsp; -Dcom.sun.management.jmxremote.ssl=false</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-Dcom.sun.management.jmxremote.authenticate=true</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-Dcom.sun.management.jmxremote.password.file=/usr/java/default/jre/lib/management/jmxremote.password</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-Dcom.sun.management.jmxremote.access.file=/usr/java/default/jre/lib/management/jmxremote.access'</div>
<div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left;  margin-left: 40px; "></div>
<div style="margin-left: 40px; "></div>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (jmxremote.access 在JAVA_HOME\jre\lib\management下有模板)<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;jmxremote.access 中显示<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;monitorRole &nbsp; readonly
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;controlRole &nbsp; readwrite</div>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;jmxremote.password中显示<br />
&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;monitorRole &nbsp;QED &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(QED为密码)
<div>&nbsp; &nbsp; &nbsp; &nbsp; controlRole &nbsp; R&amp;D<br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; 重新在visualvm中打开远程tomcat就可以使用JMX带来的功能了</div>
<p>&nbsp;</p><img src ="http://www.blogjava.net/titanaly/aggbug/372318.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/titanaly/" target="_blank">不高兴</a> 2012-03-20 21:59 <a href="http://www.blogjava.net/titanaly/archive/2012/03/20/372318.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Eclipse快捷键大全(转载)</title><link>http://www.blogjava.net/titanaly/archive/2012/03/07/371407.html</link><dc:creator>不高兴</dc:creator><author>不高兴</author><pubDate>Wed, 07 Mar 2012 07:52:00 GMT</pubDate><guid>http://www.blogjava.net/titanaly/archive/2012/03/07/371407.html</guid><wfw:comment>http://www.blogjava.net/titanaly/comments/371407.html</wfw:comment><comments>http://www.blogjava.net/titanaly/archive/2012/03/07/371407.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/titanaly/comments/commentRss/371407.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/titanaly/services/trackbacks/371407.html</trackback:ping><description><![CDATA[<div style="font-size: 14.7px; font-weight: bold; margin-bottom: 10px; color: #4b4b4b; font-family: georgia, verdana, Arial, helvetica, sans-seriff; line-height: 20px; background-color: #ffffff; "><a id="viewpost1_TitleUrl" href="http://www.blogjava.net/action/articles/17339.html" style="text-decoration: none; color: #4371a6; ">Eclipse快捷键大全(转载)</a></div><div style="color: #4b4b4b; font-family: georgia, verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; ">Ctrl+1&nbsp;快速修复(最经典的快捷键,就不用多说了)<br />Ctrl+D:&nbsp;删除当前行&nbsp;<br />Ctrl+Alt+&#8595;&nbsp;复制当前行到下一行(复制增加)<br />Ctrl+Alt+&#8593;&nbsp;复制当前行到上一行(复制增加)<br />Alt+&#8595;&nbsp;当前行和下面一行交互位置(特别实用,可以省去先剪切,再粘贴了)<br />Alt+&#8593;&nbsp;当前行和上面一行交互位置(同上)<br />Alt+&#8592;&nbsp;前一个编辑的页面<br />Alt+&#8594;&nbsp;下一个编辑的页面(当然是针对上面那条来说了)<br />Alt+Enter&nbsp;显示当前选择资源(工程,or&nbsp;文件&nbsp;or文件)的属性<br />Shift+Enter&nbsp;在当前行的下一行插入空行(这时鼠标可以在当前行的任一位置,不一定是最后)<br />Shift+Ctrl+Enter&nbsp;在当前行插入空行(原理同上条)<br />Ctrl+Q&nbsp;定位到最后编辑的地方<br />Ctrl+L&nbsp;定位在某行&nbsp;(对于程序超过100的人就有福音了)<br />Ctrl+M&nbsp;最大化当前的Edit或View&nbsp;(再按则反之)<br />Ctrl+/&nbsp;注释当前行,再按则取消注释<br />Ctrl+O&nbsp;快速显示&nbsp;OutLine<br />Ctrl+T&nbsp;快速显示当前类的继承结构<br />Ctrl+W&nbsp;关闭当前Editer<br />Ctrl+K&nbsp;参照选中的Word快速定位到下一个<br />Ctrl+E&nbsp;快速显示当前Editer的下拉列表(如果当前页面没有显示的用黑体表示)<br />Ctrl+/(小键盘)&nbsp;折叠当前类中的所有代码<br />Ctrl+&#215;(小键盘)&nbsp;展开当前类中的所有代码<br />Ctrl+Space&nbsp;代码助手完成一些代码的插入(但一般和输入法有冲突,可以修改输入法的热键,也可以暂用Alt+/来代替)<br />Ctrl+Shift+E&nbsp;显示管理当前打开的所有的View的管理器(可以选择关闭,激活等操作)<br />Ctrl+J&nbsp;正向增量查找(按下Ctrl+J后,你所输入的每个字母编辑器都提供快速匹配定位到某个单词,如果没有,则在stutes&nbsp;line中显示没有找到了,查一个单词时,特别实用,这个功能Idea两年前就有了)<br />Ctrl+Shift+J&nbsp;反向增量查找(和上条相同,只不过是从后往前查)<br />Ctrl+Shift+F4&nbsp;关闭所有打开的Editer<br />Ctrl+Shift+X&nbsp;把当前选中的文本全部变味小写<br />Ctrl+Shift+Y&nbsp;把当前选中的文本全部变为小写<br />Ctrl+Shift+F&nbsp;格式化当前代码<br />Ctrl+Shift+P&nbsp;定位到对于的匹配符(譬如{})&nbsp;(从前面定位后面时,光标要在匹配符里面,后面到前面,则反之)<br /><br />下面的快捷键是重构里面常用的,本人就自己喜欢且常用的整理一下(注:一般重构的快捷键都是Alt+Shift开头的了)<br />Alt+Shift+R&nbsp;重命名&nbsp;(是我自己最爱用的一个了,尤其是变量和类的Rename,比手工方法能节省很多劳动力)<br />Alt+Shift+M&nbsp;抽取方法&nbsp;(这是重构里面最常用的方法之一了,尤其是对一大堆泥团代码有用)<br />Alt+Shift+C&nbsp;修改函数结构(比较实用,有N个函数调用了这个方法,修改一次搞定)<br />Alt+Shift+L&nbsp;抽取本地变量(&nbsp;可以直接把一些魔法数字和字符串抽取成一个变量,尤其是多处调用的时候)<br />Alt+Shift+F&nbsp;把Class中的local变量变为field变量&nbsp;(比较实用的功能)<br />Alt+Shift+I&nbsp;合并变量(可能这样说有点不妥Inline)<br />Alt+Shift+V&nbsp;移动函数和变量(不怎么常用)<br />Alt+Shift+Z&nbsp;重构的后悔药(Undo)<br /><br />编辑<br />作用域&nbsp;功能&nbsp;快捷键&nbsp;<br />全局&nbsp;查找并替换&nbsp;Ctrl+F&nbsp;<br />文本编辑器&nbsp;查找上一个&nbsp;Ctrl+Shift+K&nbsp;<br />文本编辑器&nbsp;查找下一个&nbsp;Ctrl+K&nbsp;<br />全局&nbsp;撤销&nbsp;Ctrl+Z&nbsp;<br />全局&nbsp;复制&nbsp;Ctrl+C&nbsp;<br />全局&nbsp;恢复上一个选择&nbsp;Alt+Shift+&#8595;&nbsp;<br />全局&nbsp;剪切&nbsp;Ctrl+X&nbsp;<br />全局&nbsp;快速修正&nbsp;Ctrl1+1&nbsp;<br />全局&nbsp;内容辅助&nbsp;Alt+/&nbsp;<br />全局&nbsp;全部选中&nbsp;Ctrl+A&nbsp;<br />全局&nbsp;删除&nbsp;Delete&nbsp;<br />全局&nbsp;上下文信息&nbsp;Alt+？<br />Alt+Shift+?<br />Ctrl+Shift+Space&nbsp;<br />Java编辑器&nbsp;显示工具提示描述&nbsp;F2&nbsp;<br />Java编辑器&nbsp;选择封装元素&nbsp;Alt+Shift+&#8593;&nbsp;<br />Java编辑器&nbsp;选择上一个元素&nbsp;Alt+Shift+&#8592;&nbsp;<br />Java编辑器&nbsp;选择下一个元素&nbsp;Alt+Shift+&#8594;&nbsp;<br />文本编辑器&nbsp;增量查找&nbsp;Ctrl+J&nbsp;<br />文本编辑器&nbsp;增量逆向查找&nbsp;Ctrl+Shift+J&nbsp;<br />全局&nbsp;粘贴&nbsp;Ctrl+V&nbsp;<br />全局&nbsp;重做&nbsp;Ctrl+Y&nbsp;<br /><br />&nbsp;<br />查看<br />作用域&nbsp;功能&nbsp;快捷键&nbsp;<br />全局&nbsp;放大&nbsp;Ctrl+=&nbsp;<br />全局&nbsp;缩小&nbsp;Ctrl+-&nbsp;<br /><br />&nbsp;<br />窗口<br />作用域&nbsp;功能&nbsp;快捷键&nbsp;<br />全局&nbsp;激活编辑器&nbsp;F12&nbsp;<br />全局&nbsp;切换编辑器&nbsp;Ctrl+Shift+W&nbsp;<br />全局&nbsp;上一个编辑器&nbsp;Ctrl+Shift+F6&nbsp;<br />全局&nbsp;上一个视图&nbsp;Ctrl+Shift+F7&nbsp;<br />全局&nbsp;上一个透视图&nbsp;Ctrl+Shift+F8&nbsp;<br />全局&nbsp;下一个编辑器&nbsp;Ctrl+F6&nbsp;<br />全局&nbsp;下一个视图&nbsp;Ctrl+F7&nbsp;<br />全局&nbsp;下一个透视图&nbsp;Ctrl+F8&nbsp;<br />文本编辑器&nbsp;显示标尺上下文菜单&nbsp;Ctrl+W&nbsp;<br />全局&nbsp;显示视图菜单&nbsp;Ctrl+F10&nbsp;<br />全局&nbsp;显示系统菜单&nbsp;Alt+-&nbsp;<br /><br />&nbsp;<br />导航<br />作用域&nbsp;功能&nbsp;快捷键&nbsp;<br />Java编辑器&nbsp;打开结构&nbsp;Ctrl+F3&nbsp;<br />全局&nbsp;打开类型&nbsp;Ctrl+Shift+T&nbsp;<br />全局&nbsp;打开类型层次结构&nbsp;F4&nbsp;<br />全局&nbsp;打开声明&nbsp;F3&nbsp;<br />全局&nbsp;打开外部javadoc&nbsp;Shift+F2&nbsp;<br />全局&nbsp;打开资源&nbsp;Ctrl+Shift+R&nbsp;<br />全局&nbsp;后退历史记录&nbsp;Alt+&#8592;&nbsp;<br />全局&nbsp;前进历史记录&nbsp;Alt+&#8594;&nbsp;<br />全局&nbsp;上一个&nbsp;Ctrl+,&nbsp;<br />全局&nbsp;下一个&nbsp;Ctrl+.&nbsp;<br />Java编辑器&nbsp;显示大纲&nbsp;Ctrl+O&nbsp;<br />全局&nbsp;在层次结构中打开类型&nbsp;Ctrl+Shift+H&nbsp;<br />全局&nbsp;转至匹配的括号&nbsp;Ctrl+Shift+P&nbsp;<br />全局&nbsp;转至上一个编辑位置&nbsp;Ctrl+Q&nbsp;<br />Java编辑器&nbsp;转至上一个成员&nbsp;Ctrl+Shift+&#8593;&nbsp;<br />Java编辑器&nbsp;转至下一个成员&nbsp;Ctrl+Shift+&#8595;&nbsp;<br />文本编辑器&nbsp;转至行&nbsp;Ctrl+L&nbsp;<br /><br />&nbsp;<br />搜索<br />作用域&nbsp;功能&nbsp;快捷键&nbsp;<br />全局&nbsp;出现在文件中&nbsp;Ctrl+Shift+U&nbsp;<br />全局&nbsp;打开搜索对话框&nbsp;Ctrl+H&nbsp;<br />全局&nbsp;工作区中的声明&nbsp;Ctrl+G&nbsp;<br />全局&nbsp;工作区中的引用&nbsp;Ctrl+Shift+G&nbsp;<br /><br />&nbsp;<br />文本编辑<br />作用域&nbsp;功能&nbsp;快捷键&nbsp;<br />文本编辑器&nbsp;改写切换&nbsp;Insert&nbsp;<br />文本编辑器&nbsp;上滚行&nbsp;Ctrl+&#8593;&nbsp;<br />文本编辑器&nbsp;下滚行&nbsp;Ctrl+&#8595;&nbsp;<br /><br />&nbsp;<br />文件<br />作用域&nbsp;功能&nbsp;快捷键&nbsp;<br />全局&nbsp;保存&nbsp;Ctrl+X&nbsp;<br />Ctrl+S&nbsp;<br />全局&nbsp;打印&nbsp;Ctrl+P&nbsp;<br />全局&nbsp;关闭&nbsp;Ctrl+F4&nbsp;<br />全局&nbsp;全部保存&nbsp;Ctrl+Shift+S&nbsp;<br />全局&nbsp;全部关闭&nbsp;Ctrl+Shift+F4&nbsp;<br />全局&nbsp;属性&nbsp;Alt+Enter&nbsp;<br />全局&nbsp;新建&nbsp;Ctrl+N&nbsp;<br /><br />&nbsp;<br />项目<br />作用域&nbsp;功能&nbsp;快捷键&nbsp;<br />全局&nbsp;全部构建&nbsp;Ctrl+B&nbsp;<br /><br />&nbsp;<br />源代码<br />作用域&nbsp;功能&nbsp;快捷键&nbsp;<br />Java编辑器&nbsp;格式化&nbsp;Ctrl+Shift+F&nbsp;<br />Java编辑器&nbsp;取消注释&nbsp;Ctrl+\&nbsp;<br />Java编辑器&nbsp;注释&nbsp;Ctrl+/&nbsp;<br />Java编辑器&nbsp;添加导入&nbsp;Ctrl+Shift+M&nbsp;<br />Java编辑器&nbsp;组织导入&nbsp;Ctrl+Shift+O&nbsp;<br />Java编辑器&nbsp;使用try/catch块来包围&nbsp;未设置，太常用了，所以在这里列出,建议自己设置。<br />也可以使用Ctrl+1自动修正。&nbsp;<br /><br />&nbsp;<br />运行<br />作用域&nbsp;功能&nbsp;快捷键&nbsp;<br />全局&nbsp;单步返回&nbsp;F7&nbsp;<br />全局&nbsp;单步跳过&nbsp;F6&nbsp;<br />全局&nbsp;单步跳入&nbsp;F5&nbsp;<br />全局&nbsp;单步跳入选择&nbsp;Ctrl+F5&nbsp;<br />全局&nbsp;调试上次启动&nbsp;F11&nbsp;<br />全局&nbsp;继续&nbsp;F8&nbsp;<br />全局&nbsp;使用过滤器单步执行&nbsp;Shift+F5&nbsp;<br />全局&nbsp;添加/去除断点&nbsp;Ctrl+Shift+B&nbsp;<br />全局&nbsp;显示&nbsp;Ctrl+D&nbsp;<br />全局&nbsp;运行上次启动&nbsp;Ctrl+F11&nbsp;<br />全局&nbsp;运行至行&nbsp;Ctrl+R&nbsp;<br />全局&nbsp;执行&nbsp;Ctrl+U&nbsp;<br /><br />&nbsp;<br />重构<br />作用域&nbsp;功能&nbsp;快捷键&nbsp;<br />全局&nbsp;撤销重构&nbsp;Alt+Shift+Z&nbsp;<br />全局&nbsp;抽取方法&nbsp;Alt+Shift+M&nbsp;<br />全局&nbsp;抽取局部变量&nbsp;Alt+Shift+L&nbsp;<br />全局&nbsp;内联&nbsp;Alt+Shift+I&nbsp;<br />全局&nbsp;移动&nbsp;Alt+Shift+V&nbsp;<br />全局&nbsp;重命名&nbsp;Alt+Shift+R&nbsp;<br />全局&nbsp;重做&nbsp;Alt+Shift+Y</div><img src ="http://www.blogjava.net/titanaly/aggbug/371407.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/titanaly/" target="_blank">不高兴</a> 2012-03-07 15:52 <a href="http://www.blogjava.net/titanaly/archive/2012/03/07/371407.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>btrace使用实例加注释</title><link>http://www.blogjava.net/titanaly/archive/2012/02/02/369252.html</link><dc:creator>不高兴</dc:creator><author>不高兴</author><pubDate>Thu, 02 Feb 2012 09:38:00 GMT</pubDate><guid>http://www.blogjava.net/titanaly/archive/2012/02/02/369252.html</guid><wfw:comment>http://www.blogjava.net/titanaly/comments/369252.html</wfw:comment><comments>http://www.blogjava.net/titanaly/archive/2012/02/02/369252.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/titanaly/comments/commentRss/369252.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/titanaly/services/trackbacks/369252.html</trackback:ping><description><![CDATA[<div><div>BTrace的技术分析,本人暂没有这个技术能力,大家可以看&nbsp;<a href="http://www.iteye.com/topic/1005918">http://www.iteye.com/topic/1005918,<br /></a><a href="http://mgoann.iteye.com/blog/1409667">http://mgoann.iteye.com/blog/1409667</a>&nbsp;<br />下面是个人写的一些简单实例,不过我一直没办法通过BTrace拿到局部变量的值,不知道哪位牛人帮帮解答下<br /><span style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">Linux下：</span><br style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; " /><span style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #ffffff; ">在http://kenai.com/projects/btrace下载btrace-bin.tar.gz，并解压，在/etc/profile设置环境变量：</span>&nbsp;<br /><ol start="1" style="font-size: 12px; line-height: 1.4em; margin-top: 0px; margin-right: 0px; margin-bottom: 1px; margin-left: 0px; padding-top: 2px; padding-right: 0px; padding-bottom: 2px; padding-left: 0px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: #d1d7dc; border-right-color: #d1d7dc; border-bottom-color: #d1d7dc; border-left-color: #d1d7dc; border-image: initial; list-style-position: initial; list-style-image: initial; background-color: #ffffff; color: #2b91af; font-family: Monaco, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', Consolas, 'Courier New', monospace; text-align: left; "><li style="font-size: 1em; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 38px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 10px; border-left-width: 1px; border-left-style: solid; border-left-color: #d1d7dc; background-color: #fafafa; line-height: 18px; "><span style="color: black; ">export&nbsp;BTRACE_HOME=/home/workspace/btrace/</span></li><li style="font-size: 1em; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 38px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 10px; border-left-width: 1px; border-left-style: solid; border-left-color: #d1d7dc; background-color: #fafafa; line-height: 18px; "><span style="color: black; ">export&nbsp;PATH=$BTRACE_HOME/bin:$PATH &nbsp;<br /></span></li></ol>设置完成后 source /etc/profile<br />给执行文件赋权限 chmod +x btrace<br /><br />/* BTrace Script Template */</div><div>import com.sun.btrace.annotations.*;</div><div>import static com.sun.btrace.BTraceUtils.*;</div><div>import java.lang.reflect.Field;</div><div></div><div>@BTrace</div><div>public class TracingScript {</div><div><span style="white-space:pre">	</span>/* put your code here */</div><div><span style="white-space:pre">	</span>//打印实例属性</div><div><span style="white-space:pre">	</span>@OnMethod(clazz = "com.gameplus.action.siteLobby.LobbyAction", method = "/.*bankPage/", location = @Location(value = Kind.ENTRY))</div><div><span style="white-space:pre">	</span>//clazz = "com.gameplus.action.siteLobby.LobbyAction" 表示监控的类,method = "/.*bankPage/"表示监控的方法 ,这两个参数都可以用正则匹配</div><div><span style="white-space:pre">	</span>//如果是接口用+号clazz = "+com.gameplus.action.siteLobby.LobbyAction"&nbsp;</div><div><span style="white-space:pre">	</span>public static void bufferMonitor(@Self Object self ){<span style="white-space:pre">				</span>// @Self 表示监控点实例&nbsp;</div><div><span style="white-space:pre">	</span> &nbsp; &nbsp;print(strcat(strcat(name(probeClass()), "."), probeMethod()));<span style="white-space:pre">		</span>//probeClass()监控的类,probeMethod()监控的方法</div><div>&nbsp; &nbsp; &nbsp; &nbsp; println(self);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; println(get(field(classOf(self), "money")));<span style="white-space:pre">									</span>//只能取值static变量</div><div><span style="white-space:pre">		</span>println(get(field(classOf(self), "money"),self));<span style="white-space:pre">							</span>//可以取值当前实例变量,static也可以取到</div><div><span style="white-space:pre">		</span>Field moneyField = field("com.gameplus.action.siteLobby.LobbyAction", "money");<span style="white-space:pre">	</span>//知道class的名称也可以取值</div><div><span style="white-space:pre">		</span>get(moneyField,self);<span style="white-space:pre">	</span></div><div><span style="white-space:pre">		</span>get(field("com.gameplus.action.siteLobby.LobbyAction", "money"), self);&nbsp;</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; Object montmp =get(field(getSuperclass(classOf(self)), "user"), self);<span style="white-space:pre">							</span>//获取父类变量的方法</div><div>&nbsp; &nbsp; &nbsp; &nbsp; println(str(montmp));</div><div><span style="white-space:pre">		</span>long userId = (Long)get(field(classOf(montmp),"userId"),montmp);<span style="white-space:pre">							</span>//获取superClass.Object.变量值</div><div>&nbsp; &nbsp; &nbsp; &nbsp; println(userId);</div><div></div><div>&nbsp; &nbsp; }</div><div><span style="white-space:pre">	</span></div><div><span style="white-space:pre">	</span>//打印运行时lineNumber</div><div>&nbsp; &nbsp; @OnMethod(clazz = "com.gameplus.action.siteLobby.LobbyAction", location=@Location(value=Kind.LINE, line=-1))</div><div>&nbsp; &nbsp; public static void online(@ProbeClassName String pcn, @ProbeMethodName String pmn, int line) {</div><div><span style="white-space:pre">		</span>print(Strings.strcat(pcn, "."));<span style="white-space:pre">						</span>//className</div><div><span style="white-space:pre">		</span>print(Strings.strcat(pmn, ":"));<span style="white-space:pre">					</span>//methodName</div><div><span style="white-space:pre">		</span>println(line);<span style="white-space:pre">												</span>//lineNumber</div><div><span style="white-space:pre">		</span>//结果为:com.gameplus.action.siteLobby.LobbyAction.bankPage:161</div><div><span style="white-space:pre">	</span>}</div><div></div><div><span style="white-space:pre">	</span>//打印传递的参数值</div><div><span style="white-space:pre">	</span>import com.sun.btrace.AnyType;</div><div><span style="white-space:pre">	</span>@OnMethod(clazz="com.gameplus.service.operateBankService.OperateBankService",method="/.*/")</div><div><span style="white-space:pre">	</span>public static void anyRead(@ProbeClassName String pcn, @ProbeMethodName String pmn, AnyType[] args) {</div><div><span style="white-space:pre">		</span>println(pcn);</div><div><span style="white-space:pre">		</span>println(pmn);</div><div><span style="white-space:pre">		</span>printArray(args);</div><div><span style="white-space:pre">	</span>}</div><div></div><div><span style="white-space:pre">	</span>//打印所有属性</div><div><span style="white-space:pre">	</span>@OnMethod(clazz = "com.gameplus.action.siteLobby.LobbyAction", method = "/.*bankPage/", location = @Location(value = Kind.RETURN))</div><div>&nbsp; &nbsp; public static void bufferMonitor(@Self Object self,@Return Object command ,@Duration long time){&nbsp;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; printFields(self);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; Object montmp =get(field(getSuperclass(classOf(self)), "user"), self);<span style="white-space:pre">	</span></div><div>&nbsp; &nbsp; &nbsp; &nbsp; printFields(montmp);</div><div><span style="white-space:pre">		</span>//{password=null, newPassword=null, rePassword=, bankPassword=, newBankPassword=, reBankPassword=, operateType=0, operateBankType=0, money=111, integral=0, dateStartQuery=, dateEndQuery=, isDefaultPasswd=0, }</div><div><span style="white-space:pre">		</span>//{userId=10918, username=titanaly11, realname=方法1, expTime=1146510, bankMoney=1317886229, bankPasswd=243b6503f2e3e83faccc89830aca1d91, ifAvailable=1, password=1bbd886460827015e5d605ed44252251, money=100000, }</div><div></div><div>&nbsp; &nbsp; }</div><div></div><div><span style="white-space:pre">	</span>//初始化时的变量参数</div><div><span style="white-space:pre">	</span>//public User(long userId,String playServerId) {</div><div><span style="white-space:pre">	</span>//<span style="white-space:pre">	</span>this.userId = userId;</div><div><span style="white-space:pre">	</span>//<span style="white-space:pre">	</span>this.playServerId = playServerId;</div><div><span style="white-space:pre">	</span>//}</div><div><span style="white-space:pre">	</span>@OnMethod(clazz = "com.gameplus.core.model.oracle.user.User", method="&lt;init&gt;")</div><div>&nbsp; &nbsp; &nbsp;public static void bufferMonitor(@Self Object self,long userId,String gameId){&nbsp;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; printFields(self);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; println(userId);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; println(gameId);</div><div><span style="white-space:pre">		</span>//结果</div><div><span style="white-space:pre">		</span>//{userId=0, username=null, realname=null, expTime=0, bankMoney=0, bankPasswd=null, ifAvailable=0, password=null, money=0, nickName=null, iconNum=0, tim=null, infullCount=0, userToken=null, onlineTime=0,}</div><div><span style="white-space:pre">		</span>//10918</div><div><span style="white-space:pre">		</span>//222</div><div>&nbsp; &nbsp; }</div><div></div><div><span style="white-space:pre">	</span>//打印系统参数</div><div><span style="white-space:pre">	</span>static {</div><div><span style="white-space:pre">		</span>println("System Properties:");</div><div><span style="white-space:pre">		</span>printProperties();</div><div><span style="white-space:pre">		</span>println("VM Flags:");</div><div><span style="white-space:pre">		</span>printVmArguments();</div><div><span style="white-space:pre">		</span>println("OS Enviroment:");</div><div><span style="white-space:pre">		</span>printEnv();</div><div><span style="white-space:pre">		</span>exit(0);</div><div><span style="white-space:pre">	</span>}</div><div></div><div><span style="white-space:pre">	</span>//打印程序执行关系</div><div><span style="white-space:pre">	</span>//LobbyAction中所有方法执行的执行顺序</div><div><span style="white-space:pre">	</span>@OnMethod(clazz="com.gameplus.action.siteLobby.LobbyAction", method="/.*/",</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; location=@Location(value=Kind.CALL, clazz="/.*/", method="/.*/"))</div><div>&nbsp; &nbsp; public static void n(@Self Object self, @ProbeClassName String pcm, @ProbeMethodName String pmn,</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;@TargetInstance Object instance, @TargetMethodOrField String method){ // all calls to the methods with signature "(String)"</div><div>&nbsp; &nbsp; &nbsp; &nbsp; println(Strings.strcat("Context: ", Strings.strcat(pcm, Strings.strcat("#", pmn))));</div><div>&nbsp; &nbsp; &nbsp; &nbsp; println(instance);<span style="white-space:pre">														</span>//被调用目标对象</div><div>&nbsp; &nbsp; &nbsp; &nbsp; println(Strings.strcat("",method));<span style="white-space:pre">								</span>//被调用方法</div><div></div><div><span style="white-space:pre">		</span></div><div><span style="white-space:pre">		</span>//Context: com/gameplus/action/siteLobby/LobbyAction#bankPage</div><div><span style="white-space:pre">		</span>//$Proxy18@807c31</div><div><span style="white-space:pre">		</span>//getBankPage</div><div><span style="white-space:pre">		</span>//Context: com/gameplus/action/siteLobby/LobbyAction#bankPage</div><div><span style="white-space:pre">		</span>//{userEx=10, leverRestriction=6, isDefaultPasswd=0, bankPassEqGamePass=0, moneyTransferMsg=S, isSimplePasswd=0, mobile=null}</div><div><span style="white-space:pre">		</span>//get</div><div><span style="white-space:pre">		</span>//Context: com/gameplus/action/siteLobby/LobbyAction#bankPage</div><div><span style="white-space:pre">		</span>//6</div><div><span style="white-space:pre">		</span>//intValue</div><div><span style="white-space:pre">		</span>//Context: com/gameplus/action/siteLobby/LobbyAction#bankPage</div><div><span style="white-space:pre">		</span>//{userEx=10, leverRestriction=6, isDefaultPasswd=0, bankPassEqGamePass=0, moneyTransferMsg=S, isSimplePasswd=0, mobile=null}</div><div><span style="white-space:pre">		</span>//get</div><div>}</div></div><img src ="http://www.blogjava.net/titanaly/aggbug/369252.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/titanaly/" target="_blank">不高兴</a> 2012-02-02 17:38 <a href="http://www.blogjava.net/titanaly/archive/2012/02/02/369252.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MyEclipse has detected that less than 5% of the 12MB of Par Survivor Space (Heap memory) space remains.</title><link>http://www.blogjava.net/titanaly/archive/2012/02/01/369131.html</link><dc:creator>不高兴</dc:creator><author>不高兴</author><pubDate>Wed, 01 Feb 2012 03:03:00 GMT</pubDate><guid>http://www.blogjava.net/titanaly/archive/2012/02/01/369131.html</guid><wfw:comment>http://www.blogjava.net/titanaly/comments/369131.html</wfw:comment><comments>http://www.blogjava.net/titanaly/archive/2012/02/01/369131.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/titanaly/comments/commentRss/369131.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/titanaly/services/trackbacks/369131.html</trackback:ping><description><![CDATA[<span style="font-size: 14pt; ">&nbsp; &nbsp; 最近在进行MyEclipse启动速度优化,优化发现MyEclipse报这个错误,关掉它的提示后不影响正常的使用.<br />
</span><br />
<span style="font-size: 14pt; ">&nbsp; &nbsp; 用visualvm监控发现heap memory正常运转,查看了下配置参数,发现这个参数-XX:+DisableExplicitGC(禁止system.gc()的调用,gc过程完全有jvm控制),怀疑他就是报错的原因,去掉后一切正常.估计是MyEclipse在发现heap memory不足是显示调用了gc方法,然后gc方法不被jvm接受,当内存达到MyEclipse的报警值时报错提醒&nbsp;<br /><br /><br /></span><img src ="http://www.blogjava.net/titanaly/aggbug/369131.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/titanaly/" target="_blank">不高兴</a> 2012-02-01 11:03 <a href="http://www.blogjava.net/titanaly/archive/2012/02/01/369131.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在Tomcat和Eclipse进行远程调试的配置</title><link>http://www.blogjava.net/titanaly/archive/2011/12/08/365914.html</link><dc:creator>不高兴</dc:creator><author>不高兴</author><pubDate>Thu, 08 Dec 2011 10:08:00 GMT</pubDate><guid>http://www.blogjava.net/titanaly/archive/2011/12/08/365914.html</guid><wfw:comment>http://www.blogjava.net/titanaly/comments/365914.html</wfw:comment><comments>http://www.blogjava.net/titanaly/archive/2011/12/08/365914.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/titanaly/comments/commentRss/365914.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/titanaly/services/trackbacks/365914.html</trackback:ping><description><![CDATA[<div><a href="http://avar.iteye.com/blog/163767">http://avar.iteye.com/blog/163767</a><br />
<br />
在做远程调试时，在windows系统和非windows系统下的配置，Tomcat中会有所差别,具体如下：&nbsp;<br />
<br />
第一步、配置tomcat&nbsp;<br />
一、在windows系统中：&nbsp;<br />
打开%CATALINE_HOME%/bin下的文件catalina.bat，加入下面这行：&nbsp;<br />
set CATALINA_OPTS=-server -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8787&nbsp;<br />
<br />
其中address=8787是没被使用的端口号。连接方式有两种，为dt_shmem和dt_socket，分别表示本机调试和远程调试。&nbsp;<br />
<br />
二、在非windows系统中：&nbsp;<br />
还需要把% CATALINE_HOME %/bin/startup.sh中的最后一行exec "$PRGDIR"/"$EXECUTABLE"&nbsp;start "$@" 中的start改成jpda&nbsp;start。由于默认的端口是8000，所以如果8000端口已有他用的话，还需在catalina.sh文件中设置：JPDA_ADDRESS=8787。&nbsp;<br />
输入命令sh catalina.sh jpda start就可启动tomcat。&nbsp;<br />
<br />
第二步、配置eclipse&nbsp;<br />
在Eclipse中选择RunDebug，在弹出的对话框中右击Remote Java Application新建一个远程调试项，如下如所示：&nbsp;<br />
<br />
<br />
<br />
在&#8220;Name&#8221;输入框中输入远程调试的名称，在&#8220;Project&#8221;中选择要调试的项目，在&#8220;Host&#8221;中输入需要远程调试项目的IP，也就是tomcat所在的IP，在&#8220;Port&#8221;中输入设置的端口号，比如上面设置的8787，然后钩选&#8220;Allow termination&nbsp;of remote VM&#8221;，点击&#8220;Apply&#8221;即可。&nbsp;<br />
设置完后就可以开始调试了，大概分一下几步：&nbsp;<br />
1、启动tomcat（远程），如在控制台输出&#8220;Listening for transport dt_socket at address: 8787&#8221;，即说明在tomcat中设置成功；&nbsp;<br />
2、在本机设置断点，即在需要监视的代码行前双击就会出现一个小圆点；&nbsp;<br />
3、进入上图界面，选择要调试的项，点击&#8220;Debug&#8221;即可进行远程调试；&nbsp;<br />
4、当运行到设置了断点的代码行处即可看到如下图所示的浅绿条。&nbsp;<br />
<br />
<br />
按键操作：&nbsp;<br />
1、F5键与F6键均为单步调试，F5是进入本行代码中执行，F6是执行本行代码，跳到下一行；&nbsp;<br />
2、F7是跳出函数；&nbsp;<br />
3、F8是执行到最后。&nbsp;<br />
<br />
<br />
当然，为了方便，可以新建一个批处理文件，假如取名为debug.bat，在这个文件中加入下面几行：&nbsp;<br />
<br />
cd %CATALINE_HOME%/bin&nbsp;<br />
set JPDA_ADDRESS=8787&nbsp;<br />
set JPDA_TRANSPORT=dt_socket&nbsp;<br />
set CATALINA_OPTS=-server -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8787&nbsp;<br />
startup&nbsp;<br />
<br />
这样需要远程调试时，运行debug.bat即可；不需要远程调试时，还是运行startup.bat文件。&nbsp;</div><img src ="http://www.blogjava.net/titanaly/aggbug/365914.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/titanaly/" target="_blank">不高兴</a> 2011-12-08 18:08 <a href="http://www.blogjava.net/titanaly/archive/2011/12/08/365914.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Tomcat 在IE中下载rar文件直接以乱码方式打开解决方案</title><link>http://www.blogjava.net/titanaly/archive/2011/12/06/365694.html</link><dc:creator>不高兴</dc:creator><author>不高兴</author><pubDate>Tue, 06 Dec 2011 10:53:00 GMT</pubDate><guid>http://www.blogjava.net/titanaly/archive/2011/12/06/365694.html</guid><wfw:comment>http://www.blogjava.net/titanaly/comments/365694.html</wfw:comment><comments>http://www.blogjava.net/titanaly/archive/2011/12/06/365694.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/titanaly/comments/commentRss/365694.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/titanaly/services/trackbacks/365694.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: http://hain.iteye.com/blog/150875web.xml文件中配置&lt;mime-mapping&gt;下载文件类型TOMCAT在默认情况下下载.rar的文件是把文件当作text打开,以至于IE打开RAR文件为乱码,如果遇到这种情况时不必认为是浏览器的问题,大多数浏览器应该不会死皮赖脸地把二进制文件当作文本打开,一般都是服务器给什么浏览器就开什么.解决方法:&nbsp;&...&nbsp;&nbsp;<a href='http://www.blogjava.net/titanaly/archive/2011/12/06/365694.html'>阅读全文</a><img src ="http://www.blogjava.net/titanaly/aggbug/365694.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/titanaly/" target="_blank">不高兴</a> 2011-12-06 18:53 <a href="http://www.blogjava.net/titanaly/archive/2011/12/06/365694.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>利用 JAVA 操作 EXCEL 文件</title><link>http://www.blogjava.net/titanaly/archive/2011/12/05/365599.html</link><dc:creator>不高兴</dc:creator><author>不高兴</author><pubDate>Mon, 05 Dec 2011 07:48:00 GMT</pubDate><guid>http://www.blogjava.net/titanaly/archive/2011/12/05/365599.html</guid><wfw:comment>http://www.blogjava.net/titanaly/comments/365599.html</wfw:comment><comments>http://www.blogjava.net/titanaly/archive/2011/12/05/365599.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/titanaly/comments/commentRss/365599.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/titanaly/services/trackbacks/365599.html</trackback:ping><description><![CDATA[<div><span style="font-family: Simsun; line-height: normal; font-size: medium; ">
<p style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; "><a name="1"><span style="font-size: 1.5em; font-weight: bold; "><div><a href="http://www.ibm.com/developerworks/cn/java/l-javaExcel/">http://www.ibm.com/developerworks/cn/java/l-javaExcel/<br /><br /><br /></a></div>JAVA EXCEL API 简介</span></a></p>
<p style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; ">Java Excel 是一开放源码项目，通过它 Java 开发人员可以读取 Excel 文件的内容、创建新的 Excel 文件、更新已经存在的 Excel 文件。使用该 API 非 Windows 操作系统也可以通过纯 Java 应用来处理 Excel 数据表。因为是使用 Java 编写的，所以我们在 Web 应用中可以通过 JSP、Servlet 来调用 API 实现对 Excel 数据表的访问。</p>
<p style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; ">现在发布的稳定版本是 V2.0，提供以下功能：</p>
<ul style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-right: 5px; padding-bottom: 5px; font-size: 0.76em; ">
     <li style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-right: 5px; padding-bottom: 3px; ">从 Excel 95、97、2000 等格式的文件中读取数据；</li>
     <li style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-right: 5px; padding-bottom: 3px; ">读取 Excel 公式（可以读取 Excel 97 以后的公式）；</li>
     <li style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-right: 5px; padding-bottom: 3px; ">生成 Excel 数据表（格式为 Excel 97）；</li>
     <li style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-right: 5px; padding-bottom: 3px; ">支持字体、数字、日期的格式化；</li>
     <li style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-right: 5px; padding-bottom: 3px; ">支持单元格的阴影操作，以及颜色操作；</li>
     <li style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-right: 5px; padding-bottom: 3px; ">修改已经存在的数据表；</li>
</ul>
<p style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; ">现在还不支持以下功能，但不久就会提供了：</p>
<ol style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-right: 5px; padding-bottom: 5px; font-size: 0.76em; ">
     <li style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-bottom: 0px; padding-top: 5px; padding-right: 5px; padding-bottom: 3px; ">不能够读取图表信息；</li>
     <li style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-bottom: 0px; padding-top: 5px; padding-right: 5px; padding-bottom: 3px; ">可以读，但是不能生成公式，任何类型公式最后的计算值都可以读出；</li>
</ol>
<div style="clear: both; background-image: url(http://1.www.s81c.com/i/solid.gif); background-attachment: initial; background-origin: initial; background-clip: initial; background-color: #ffffff; height: 1px; background-position: initial initial; background-repeat: repeat no-repeat; "></div>
<p ibm-back-to-top"="" style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 5px; padding-right: 5px; padding-bottom: 5px; padding-left: 5px; font-size: 0.76em; clear: both; text-align: right; height: 15px; "><a href="http://www.ibm.com/developerworks/cn/java/l-javaExcel/#ibm-pcon" style="color: #4c6e94; display: inline; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 18px; text-decoration: none; background-image: url(http://1.www.s81c.com/i/v16/icons/u_bold.gif); background-attachment: initial; background-origin: initial; background-clip: initial; background-color: initial; font-weight: bold; background-position: 0px -1px; background-repeat: no-repeat no-repeat; ">回页首</a></p>
<p style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; "><a name="2"><span style="font-size: 1.5em; font-weight: bold; ">应用示例</span></a></p>
<p style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; "><a name="N10079"><span style="font-size: 1.2em; font-weight: bold; ">1 从 Excel 文件读取数据表</span></a></p>
<p style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; ">Java Excel API 既可以从本地文件系统的一个文件 (.xls)，也可以从输入流中读取 Excel 数据表。读取 Excel 数据表的第一步是创建 Workbook( 术语：工作薄 )，下面的代码片段举例说明了应该如何操作：( 完整代码见 ExcelReading.java)</p>
<table width="100%" cellpadding="0" cellspacing="0" border="0" style="font-size: 0.8em; ">
     <tbody>
         <tr>
             <td style="font-family: arial, nsimsun, sans-serif; background-color: #f7f7f7 !important; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: #cccccc; border-right-color: #cccccc; border-bottom-color: #cccccc; border-left-color: #cccccc; padding-top: 2px; padding-right: 2px; padding-bottom: 5px; padding-left: 2px; ">
             <pre style="width: 694px; margin-top: 0px; margin-bottom: 0px; font-family: 'Andale Mono', 'Lucida Console', Monaco, Liberation, fixed, monospace; font-size: 11px; overflow-x: auto; overflow-y: auto; background-image: initial !important; background-attachment: initial !important; background-origin: initial !important; background-clip: initial !important; background-color: #f7f7f7 !important; color: #000000; background-position: initial initial !important; background-repeat: initial initial !important; "> import java.io.*; import jxl.*; &#8230; &#8230; &#8230; &#8230; try { // 构建 Workbook 对象 , 只读 Workbook 对象 // 直接从本地文件创建 Workbook // 从输入流创建 Workbook InputStream is = new FileInputStream(sourcefile); jxl.Workbook rwb = Workbook.getWorkbook(is); } catch (Exception e) { e.printStackTrace(); } </pre>
             </td>
         </tr>
     </tbody>
</table>
<br />
<p style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; ">一旦创建了 Workbook，我们就可以通过它来访问 Excel Sheet( 术语：工作表 )。参考下面的代码片段：</p>
<table width="100%" cellpadding="0" cellspacing="0" border="0" style="font-size: 0.8em; ">
     <tbody>
         <tr>
             <td style="font-family: arial, nsimsun, sans-serif; background-color: #f7f7f7 !important; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: #cccccc; border-right-color: #cccccc; border-bottom-color: #cccccc; border-left-color: #cccccc; padding-top: 2px; padding-right: 2px; padding-bottom: 5px; padding-left: 2px; ">
             <pre style="width: 694px; margin-top: 0px; margin-bottom: 0px; font-family: 'Andale Mono', 'Lucida Console', Monaco, Liberation, fixed, monospace; font-size: 11px; overflow-x: auto; overflow-y: auto; background-image: initial !important; background-attachment: initial !important; background-origin: initial !important; background-clip: initial !important; background-color: #f7f7f7 !important; color: #000000; background-position: initial initial !important; background-repeat: initial initial !important; "> // 获取第一张 Sheet 表 Sheet rs = rwb.getSheet(0); </pre>
             </td>
         </tr>
     </tbody>
</table>
<br />
<p style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; ">我们既可能通过 Sheet 的名称来访问它，也可以通过下标来访问它。如果通过下标来访问的话，要注意的一点是下标从 0 开始，就像数组一样。</p>
<p style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; ">一旦得到了 Sheet，我们就可以通过它来访问 Excel Cell( 术语：单元格 )。参考下面的代码片段：</p>
<table width="100%" cellpadding="0" cellspacing="0" border="0" style="font-size: 0.8em; ">
     <tbody>
         <tr>
             <td style="font-family: arial, nsimsun, sans-serif; background-color: #f7f7f7 !important; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: #cccccc; border-right-color: #cccccc; border-bottom-color: #cccccc; border-left-color: #cccccc; padding-top: 2px; padding-right: 2px; padding-bottom: 5px; padding-left: 2px; ">
             <pre style="width: 694px; margin-top: 0px; margin-bottom: 0px; font-family: 'Andale Mono', 'Lucida Console', Monaco, Liberation, fixed, monospace; font-size: 11px; overflow-x: auto; overflow-y: auto; background-image: initial !important; background-attachment: initial !important; background-origin: initial !important; background-clip: initial !important; background-color: #f7f7f7 !important; color: #000000; background-position: initial initial !important; background-repeat: initial initial !important; "> // 获取第一行，第一列的值 Cell c00 = rs.getCell(0, 0); String strc00 = c00.getContents(); // 获取第一行，第二列的值 Cell c10 = rs.getCell(1, 0); String strc10 = c10.getContents(); // 获取第二行，第二列的值 Cell c11 = rs.getCell(1, 1); String strc11 = c11.getContents(); System.out.println("Cell(0, 0)" + " value : " + strc00 + "; type : " + c00.getType()); System.out.println("Cell(1, 0)" + " value : " + strc10 + "; type : " + c10.getType()); System.out.println("Cell(1, 1)" + " value : " + strc11 + "; type : " + c11.getType()); </pre>
             </td>
         </tr>
     </tbody>
</table>
<br />
<p style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; ">如果仅仅是取得 Cell 的值，我们可以方便地通过 getContents() 方法，它可以将任何类型的 Cell 值都作为一个字符串返回。示例代码中 Cell(0, 0) 是文本型，Cell(1, 0) 是数字型，Cell(1,1) 是日期型，通过 getContents()，三种类型的返回值都是字符型。</p>
<p style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; ">如果有需要知道 Cell 内容的确切类型，API 也提供了一系列的方法。参考下面的代码片段：</p>
<table width="100%" cellpadding="0" cellspacing="0" border="0" style="font-size: 0.8em; ">
     <tbody>
         <tr>
             <td style="font-family: arial, nsimsun, sans-serif; background-color: #f7f7f7 !important; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: #cccccc; border-right-color: #cccccc; border-bottom-color: #cccccc; border-left-color: #cccccc; padding-top: 2px; padding-right: 2px; padding-bottom: 5px; padding-left: 2px; ">
             <pre style="width: 694px; margin-top: 0px; margin-bottom: 0px; font-family: 'Andale Mono', 'Lucida Console', Monaco, Liberation, fixed, monospace; font-size: 11px; overflow-x: auto; overflow-y: auto; background-image: initial !important; background-attachment: initial !important; background-origin: initial !important; background-clip: initial !important; background-color: #f7f7f7 !important; color: #000000; background-position: initial initial !important; background-repeat: initial initial !important; "> String strc00 = null; double strc10 = 0.00; Date strc11 = null; Cell c00 = rs.getCell(0, 0); Cell c10 = rs.getCell(1, 0); Cell c11 = rs.getCell(1, 1); if(c00.getType() == CellType.LABEL) { LabelCell labelc00 = (LabelCell)c00; strc00 = labelc00.getString(); } if(c10.getType() == CellType.NUMBER) { NmberCell numc10 = (NumberCell)c10; strc10 = numc10.getValue(); } if(c11.getType() == CellType.DATE) { DateCell datec11 = (DateCell)c11; strc11 = datec11.getDate(); } System.out.println("Cell(0, 0)" + " value : " + strc00 + "; type : " + c00.getType()); System.out.println("Cell(1, 0)" + " value : " + strc10 + "; type : " + c10.getType()); System.out.println("Cell(1, 1)" + " value : " + strc11 + "; type : " + c11.getType()); </pre>
             </td>
         </tr>
     </tbody>
</table>
<br />
<p style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; ">在得到 Cell 对象后，通过 getType() 方法可以获得该单元格的类型，然后与 API 提供的基本类型相匹配，强制转换成相应的类型，最后调用相应的取值方法 getXXX()，就可以得到确定类型的值。API 提供了以下基本类型，与 Excel 的数据格式相对应，如下图所示：</p>
<br />
<img alt="" height="218" src="http://www.ibm.com/developerworks/cn/java/l-javaExcel/image001.jpg" width="365" style="border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; " />&nbsp;<br />
<p style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; ">每种类型的具体意义，请参见 Java Excel API Document。</p>
<p style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; ">当你完成对 Excel 电子表格数据的处理后，一定要使用 close() 方法来关闭先前创建的对象，以释放读取数据表的过程中所占用的内存空间，在读取大量数据时显得尤为重要。参考如下代码片段：</p>
<table width="100%" cellpadding="0" cellspacing="0" border="0" style="font-size: 0.8em; ">
     <tbody>
         <tr>
             <td style="font-family: arial, nsimsun, sans-serif; background-color: #f7f7f7 !important; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: #cccccc; border-right-color: #cccccc; border-bottom-color: #cccccc; border-left-color: #cccccc; padding-top: 2px; padding-right: 2px; padding-bottom: 5px; padding-left: 2px; ">
             <pre style="width: 694px; margin-top: 0px; margin-bottom: 0px; font-family: 'Andale Mono', 'Lucida Console', Monaco, Liberation, fixed, monospace; font-size: 11px; overflow-x: auto; overflow-y: auto; background-image: initial !important; background-attachment: initial !important; background-origin: initial !important; background-clip: initial !important; background-color: #f7f7f7 !important; color: #000000; background-position: initial initial !important; background-repeat: initial initial !important; "> // 操作完成时，关闭对象，释放占用的内存空间 rwb.close(); </pre>
             </td>
         </tr>
     </tbody>
</table>
<br />
<p style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; ">Java Excel API 提供了许多访问 Excel 数据表的方法，在这里我只简要地介绍几个常用的方法，其它的方法请参考附录中的 Java Excel API Document。</p>
<p style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; "><strong>Workbook 类提供的方法</strong></p>
<p style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; ">1. int getNumberOfSheets()&nbsp;<br />
获得工作薄（Workbook）中工作表（Sheet）的个数，示例：</p>
<table width="100%" cellpadding="0" cellspacing="0" border="0" style="font-size: 0.8em; ">
     <tbody>
         <tr>
             <td style="font-family: arial, nsimsun, sans-serif; background-color: #f7f7f7 !important; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: #cccccc; border-right-color: #cccccc; border-bottom-color: #cccccc; border-left-color: #cccccc; padding-top: 2px; padding-right: 2px; padding-bottom: 5px; padding-left: 2px; ">
             <pre style="width: 694px; margin-top: 0px; margin-bottom: 0px; font-family: 'Andale Mono', 'Lucida Console', Monaco, Liberation, fixed, monospace; font-size: 11px; overflow-x: auto; overflow-y: auto; background-image: initial !important; background-attachment: initial !important; background-origin: initial !important; background-clip: initial !important; background-color: #f7f7f7 !important; color: #000000; background-position: initial initial !important; background-repeat: initial initial !important; "> jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile)); int sheets = rwb.getNumberOfSheets(); </pre>
             </td>
         </tr>
     </tbody>
</table>
<br />
<p style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; ">2. Sheet[] getSheets()&nbsp;<br />
返回工作薄（Workbook）中工作表（Sheet）对象数组，示例：</p>
<table width="100%" cellpadding="0" cellspacing="0" border="0" style="font-size: 0.8em; ">
     <tbody>
         <tr>
             <td style="font-family: arial, nsimsun, sans-serif; background-color: #f7f7f7 !important; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: #cccccc; border-right-color: #cccccc; border-bottom-color: #cccccc; border-left-color: #cccccc; padding-top: 2px; padding-right: 2px; padding-bottom: 5px; padding-left: 2px; ">
             <pre style="width: 694px; margin-top: 0px; margin-bottom: 0px; font-family: 'Andale Mono', 'Lucida Console', Monaco, Liberation, fixed, monospace; font-size: 11px; overflow-x: auto; overflow-y: auto; background-image: initial !important; background-attachment: initial !important; background-origin: initial !important; background-clip: initial !important; background-color: #f7f7f7 !important; color: #000000; background-position: initial initial !important; background-repeat: initial initial !important; "> jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile)); Sheet[] sheets = rwb.getSheets(); </pre>
             </td>
         </tr>
     </tbody>
</table>
<br />
<p style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; ">3. String getVersion()&nbsp;<br />
返回正在使用的 API 的版本号，好像是没什么太大的作用。</p>
<table width="100%" cellpadding="0" cellspacing="0" border="0" style="font-size: 0.8em; ">
     <tbody>
         <tr>
             <td style="font-family: arial, nsimsun, sans-serif; background-color: #f7f7f7 !important; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: #cccccc; border-right-color: #cccccc; border-bottom-color: #cccccc; border-left-color: #cccccc; padding-top: 2px; padding-right: 2px; padding-bottom: 5px; padding-left: 2px; ">
             <pre style="width: 694px; margin-top: 0px; margin-bottom: 0px; font-family: 'Andale Mono', 'Lucida Console', Monaco, Liberation, fixed, monospace; font-size: 11px; overflow-x: auto; overflow-y: auto; background-image: initial !important; background-attachment: initial !important; background-origin: initial !important; background-clip: initial !important; background-color: #f7f7f7 !important; color: #000000; background-position: initial initial !important; background-repeat: initial initial !important; "> jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile)); String apiVersion = rwb.getVersion(); </pre>
             </td>
         </tr>
     </tbody>
</table>
<br />
<p style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; "><strong>Sheet 接口提供的方法</strong></p>
<p style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; ">1) String getName()&nbsp;<br />
获取 Sheet 的名称，示例：</p>
<table width="100%" cellpadding="0" cellspacing="0" border="0" style="font-size: 0.8em; ">
     <tbody>
         <tr>
             <td style="font-family: arial, nsimsun, sans-serif; background-color: #f7f7f7 !important; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: #cccccc; border-right-color: #cccccc; border-bottom-color: #cccccc; border-left-color: #cccccc; padding-top: 2px; padding-right: 2px; padding-bottom: 5px; padding-left: 2px; ">
             <pre style="width: 694px; margin-top: 0px; margin-bottom: 0px; font-family: 'Andale Mono', 'Lucida Console', Monaco, Liberation, fixed, monospace; font-size: 11px; overflow-x: auto; overflow-y: auto; background-image: initial !important; background-attachment: initial !important; background-origin: initial !important; background-clip: initial !important; background-color: #f7f7f7 !important; color: #000000; background-position: initial initial !important; background-repeat: initial initial !important; "> jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile)); jxl.Sheet rs = rwb.getSheet(0); String sheetName = rs.getName(); </pre>
             </td>
         </tr>
     </tbody>
</table>
<br />
<p style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; ">2) int getColumns()&nbsp;<br />
获取 Sheet 表中所包含的总列数，示例：</p>
<table width="100%" cellpadding="0" cellspacing="0" border="0" style="font-size: 0.8em; ">
     <tbody>
         <tr>
             <td style="font-family: arial, nsimsun, sans-serif; background-color: #f7f7f7 !important; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: #cccccc; border-right-color: #cccccc; border-bottom-color: #cccccc; border-left-color: #cccccc; padding-top: 2px; padding-right: 2px; padding-bottom: 5px; padding-left: 2px; ">
             <pre style="width: 694px; margin-top: 0px; margin-bottom: 0px; font-family: 'Andale Mono', 'Lucida Console', Monaco, Liberation, fixed, monospace; font-size: 11px; overflow-x: auto; overflow-y: auto; background-image: initial !important; background-attachment: initial !important; background-origin: initial !important; background-clip: initial !important; background-color: #f7f7f7 !important; color: #000000; background-position: initial initial !important; background-repeat: initial initial !important; "> jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile)); jxl.Sheet rs = rwb.getSheet(0); int rsColumns = rs.getColumns(); </pre>
             </td>
         </tr>
     </tbody>
</table>
<br />
<p style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; ">3) Cell[] getColumn(int column)&nbsp;<br />
获取某一列的所有单元格，返回的是单元格对象数组，示例：</p>
<table width="100%" cellpadding="0" cellspacing="0" border="0" style="font-size: 0.8em; ">
     <tbody>
         <tr>
             <td style="font-family: arial, nsimsun, sans-serif; background-color: #f7f7f7 !important; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: #cccccc; border-right-color: #cccccc; border-bottom-color: #cccccc; border-left-color: #cccccc; padding-top: 2px; padding-right: 2px; padding-bottom: 5px; padding-left: 2px; ">
             <pre style="width: 694px; margin-top: 0px; margin-bottom: 0px; font-family: 'Andale Mono', 'Lucida Console', Monaco, Liberation, fixed, monospace; font-size: 11px; overflow-x: auto; overflow-y: auto; background-image: initial !important; background-attachment: initial !important; background-origin: initial !important; background-clip: initial !important; background-color: #f7f7f7 !important; color: #000000; background-position: initial initial !important; background-repeat: initial initial !important; "> jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile)); jxl.Sheet rs = rwb.getSheet(0); Cell[] cell = rs.getColumn(0); </pre>
             </td>
         </tr>
     </tbody>
</table>
<br />
<p style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; ">4) int getRows()&nbsp;<br />
获取 Sheet 表中所包含的总行数，示例：</p>
<table width="100%" cellpadding="0" cellspacing="0" border="0" style="font-size: 0.8em; ">
     <tbody>
         <tr>
             <td style="font-family: arial, nsimsun, sans-serif; background-color: #f7f7f7 !important; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: #cccccc; border-right-color: #cccccc; border-bottom-color: #cccccc; border-left-color: #cccccc; padding-top: 2px; padding-right: 2px; padding-bottom: 5px; padding-left: 2px; ">
             <pre style="width: 694px; margin-top: 0px; margin-bottom: 0px; font-family: 'Andale Mono', 'Lucida Console', Monaco, Liberation, fixed, monospace; font-size: 11px; overflow-x: auto; overflow-y: auto; background-image: initial !important; background-attachment: initial !important; background-origin: initial !important; background-clip: initial !important; background-color: #f7f7f7 !important; color: #000000; background-position: initial initial !important; background-repeat: initial initial !important; "> jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile)); jxl.Sheet rs = rwb.getSheet(0); int rsRows = rs.getRows(); </pre>
             </td>
         </tr>
     </tbody>
</table>
<br />
<p style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; ">5) Cell[] getRow(int row)&nbsp;<br />
获取某一行的所有单元格，返回的是单元格对象数组，示例子：</p>
<table width="100%" cellpadding="0" cellspacing="0" border="0" style="font-size: 0.8em; ">
     <tbody>
         <tr>
             <td style="font-family: arial, nsimsun, sans-serif; background-color: #f7f7f7 !important; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: #cccccc; border-right-color: #cccccc; border-bottom-color: #cccccc; border-left-color: #cccccc; padding-top: 2px; padding-right: 2px; padding-bottom: 5px; padding-left: 2px; ">
             <pre style="width: 694px; margin-top: 0px; margin-bottom: 0px; font-family: 'Andale Mono', 'Lucida Console', Monaco, Liberation, fixed, monospace; font-size: 11px; overflow-x: auto; overflow-y: auto; background-image: initial !important; background-attachment: initial !important; background-origin: initial !important; background-clip: initial !important; background-color: #f7f7f7 !important; color: #000000; background-position: initial initial !important; background-repeat: initial initial !important; "> jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile)); jxl.Sheet rs = rwb.getSheet(0); Cell[] cell = rs.getRow(0); </pre>
             </td>
         </tr>
     </tbody>
</table>
<br />
<p style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; ">6) Cell getCell(int column, int row)&nbsp;<br />
获取指定单元格的对象引用，需要注意的是它的两个参数，第一个是列数，第二个是行数，这与通常的行、列组合有些不同。</p>
<table width="100%" cellpadding="0" cellspacing="0" border="0" style="font-size: 0.8em; ">
     <tbody>
         <tr>
             <td style="font-family: arial, nsimsun, sans-serif; background-color: #f7f7f7 !important; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: #cccccc; border-right-color: #cccccc; border-bottom-color: #cccccc; border-left-color: #cccccc; padding-top: 2px; padding-right: 2px; padding-bottom: 5px; padding-left: 2px; ">
             <pre style="width: 694px; margin-top: 0px; margin-bottom: 0px; font-family: 'Andale Mono', 'Lucida Console', Monaco, Liberation, fixed, monospace; font-size: 11px; overflow-x: auto; overflow-y: auto; background-image: initial !important; background-attachment: initial !important; background-origin: initial !important; background-clip: initial !important; background-color: #f7f7f7 !important; color: #000000; background-position: initial initial !important; background-repeat: initial initial !important; "> jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile)); jxl.Sheet rs = rwb.getSheet(0); Cell cell = rs.getCell(0, 0); </pre>
             </td>
         </tr>
     </tbody>
</table>
<br />
<p style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; "><a name="N1011E"><span style="font-size: 1.2em; font-weight: bold; ">2 生成新的 Excel 工作薄</span></a></p>
<p style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; ">下面的代码主要是向大家介绍如何生成简单的 Excel 工作表，在这里单元格的内容是不带任何修饰的 ( 如：字体，颜色等等 )，所有的内容都作为字符串写入。( 完整代码见 ExcelWriting.java)</p>
<p style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; ">与读取 Excel 工作表相似，首先要使用 Workbook 类的工厂方法创建一个可写入的工作薄 (Workbook) 对象，这里要注意的是，只能通过 API 提供的工厂方法来创建 Workbook，而不能使用 WritableWorkbook 的构造函数，因为类 WritableWorkbook 的构造函数为 protected 类型。示例代码片段如下：</p>
<table width="100%" cellpadding="0" cellspacing="0" border="0" style="font-size: 0.8em; ">
     <tbody>
         <tr>
             <td style="font-family: arial, nsimsun, sans-serif; background-color: #f7f7f7 !important; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: #cccccc; border-right-color: #cccccc; border-bottom-color: #cccccc; border-left-color: #cccccc; padding-top: 2px; padding-right: 2px; padding-bottom: 5px; padding-left: 2px; ">
             <pre style="width: 694px; margin-top: 0px; margin-bottom: 0px; font-family: 'Andale Mono', 'Lucida Console', Monaco, Liberation, fixed, monospace; font-size: 11px; overflow-x: auto; overflow-y: auto; background-image: initial !important; background-attachment: initial !important; background-origin: initial !important; background-clip: initial !important; background-color: #f7f7f7 !important; color: #000000; background-position: initial initial !important; background-repeat: initial initial !important; "> import java.io.*; import jxl.*; import jxl.write.*; &#8230; &#8230; &#8230; &#8230; try { // 构建 Workbook 对象 , 只读 Workbook 对象 //Method 1：创建可写入的 Excel 工作薄 jxl.write.WritableWorkbook wwb = Workbook.createWorkbook(new File(targetfile)); //Method 2：将 WritableWorkbook 直接写入到输出流 /* OutputStream os = new FileOutputStream(targetfile); jxl.write.WritableWorkbook wwb = Workbook.createWorkbook(os); */ } catch (Exception e) { e.printStackTrace(); } </pre>
             </td>
         </tr>
     </tbody>
</table>
<br />
<p style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; ">API 提供了两种方式来处理可写入的输出流，一种是直接生成本地文件，如果文件名不带全路径的话，缺省的文件会定位在当前目录，如果文件名带有全路径的话，则生成的 Excel 文件则会定位在相应的目录；另外一种是将 Excel 对象直接写入到输出流，例如：用户通过浏览器来访问 Web 服务器，如果 HTTP 头设置正确的话，浏览器自动调用客户端的 Excel 应用程序，来显示动态生成的 Excel 电子表格。</p>
<p style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; ">接下来就是要创建工作表，创建工作表的方法与创建工作薄的方法几乎一样，同样是通过工厂模式方法获得相应的对象，该方法需要两个参数，一个是工作表的名称，另一个是工作表在工作薄中的位置，参考下面的代码片段：</p>
<table width="100%" cellpadding="0" cellspacing="0" border="0" style="font-size: 0.8em; ">
     <tbody>
         <tr>
             <td style="font-family: arial, nsimsun, sans-serif; background-color: #f7f7f7 !important; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: #cccccc; border-right-color: #cccccc; border-bottom-color: #cccccc; border-left-color: #cccccc; padding-top: 2px; padding-right: 2px; padding-bottom: 5px; padding-left: 2px; ">
             <pre style="width: 694px; margin-top: 0px; margin-bottom: 0px; font-family: 'Andale Mono', 'Lucida Console', Monaco, Liberation, fixed, monospace; font-size: 11px; overflow-x: auto; overflow-y: auto; background-image: initial !important; background-attachment: initial !important; background-origin: initial !important; background-clip: initial !important; background-color: #f7f7f7 !important; color: #000000; background-position: initial initial !important; background-repeat: initial initial !important; "> // 创建 Excel 工作表 jxl.write.WritableSheet ws = wwb.createSheet("Test Sheet 1", 0); </pre>
             </td>
         </tr>
     </tbody>
</table>
<br />
<p style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; ">"这锅也支好了，材料也准备齐全了，可以开始下锅了！"，现在要做的只是实例化 API 所提供的 Excel 基本数据类型，并将它们添加到工作表中就可以了，参考下面的代码片段：</p>
<table width="100%" cellpadding="0" cellspacing="0" border="0" style="font-size: 0.8em; ">
     <tbody>
         <tr>
             <td style="font-family: arial, nsimsun, sans-serif; background-color: #f7f7f7 !important; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: #cccccc; border-right-color: #cccccc; border-bottom-color: #cccccc; border-left-color: #cccccc; padding-top: 2px; padding-right: 2px; padding-bottom: 5px; padding-left: 2px; ">
             <pre style="width: 694px; margin-top: 0px; margin-bottom: 0px; font-family: 'Andale Mono', 'Lucida Console', Monaco, Liberation, fixed, monospace; font-size: 11px; overflow-x: auto; overflow-y: auto; background-image: initial !important; background-attachment: initial !important; background-origin: initial !important; background-clip: initial !important; background-color: #f7f7f7 !important; color: #000000; background-position: initial initial !important; background-repeat: initial initial !important; "> //1. 添加 Label 对象 jxl.write.Label labelC = new jxl.write.Label(0, 0, "This is a Label cell"); ws.addCell(labelC); // 添加带有字型 Formatting 的对象 jxl.write.WritableFont wf = new jxl.write.WritableFont(WritableFont.TIMES, 18, WritableFont.BOLD, true); jxl.write.WritableCellFormat wcfF = new jxl.write.WritableCellFormat(wf); jxl.write.Label labelCF = new jxl.write.Label(1, 0, "This is a Label Cell", wcfF); ws.addCell(labelCF); // 添加带有字体颜色 Formatting 的对象 jxl.write.WritableFont wfc = new jxl.write.WritableFont(WritableFont.ARIAL, 10, WritableFont.NO_BOLD, false, UnderlineStyle.NO_UNDERLINE, jxl.format.Colour.RED); jxl.write.WritableCellFormat wcfFC = new jxl.write.WritableCellFormat(wfc); jxl.write.Label labelCFC = new jxl.write.Label(1, 0, "This is a Label Cell", wcfFC); ws.addCell(labelCF); //2. 添加 Number 对象 jxl.write.Number labelN = new jxl.write.Number(0, 1, 3.1415926); ws.addCell(labelN); // 添加带有 formatting 的 Number 对象 jxl.write.NumberFormat nf = new jxl.write.NumberFormat("#.##"); jxl.write.WritableCellFormat wcfN = new jxl.write.WritableCellFormat(nf); jxl.write.Number labelNF = new jxl.write.Number(1, 1, 3.1415926, wcfN); ws.addCell(labelNF); //3. 添加 Boolean 对象 jxl.write.Boolean labelB = new jxl.write.Boolean(0, 2, false); ws.addCell(labelB); //4. 添加 DateTime 对象 jxl.write.DateTime labelDT = new jxl.write.DateTime(0, 3, new java.util.Date()); ws.addCell(labelDT); // 添加带有 formatting 的 DateFormat 对象 jxl.write.DateFormat df = new jxl.write.DateFormat("dd MM yyyy hh:mm:ss"); jxl.write.WritableCellFormat wcfDF = new jxl.write.WritableCellFormat(df); jxl.write.DateTime labelDTF = new jxl.write.DateTime(1, 3, new java.util.Date(), wcfDF); ws.addCell(labelDTF); </pre>
             </td>
         </tr>
     </tbody>
</table>
<br />
<p style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; ">这里有两点大家要引起大家的注意。第一点，在构造单元格时，单元格在工作表中的位置就已经确定了。一旦创建后，单元格的位置是不能够变更的，尽管单元格的内容是可以改变的。第二点，单元格的定位是按照下面这样的规律 (column, row)，而且下标都是从 0 开始，例如，A1 被存储在 (0, 0)，B1 被存储在 (1, 0)。</p>
<p style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; ">最后，不要忘记关闭打开的 Excel 工作薄对象，以释放占用的内存，参见下面的代码片段：</p>
<table width="100%" cellpadding="0" cellspacing="0" border="0" style="font-size: 0.8em; ">
     <tbody>
         <tr>
             <td style="font-family: arial, nsimsun, sans-serif; background-color: #f7f7f7 !important; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: #cccccc; border-right-color: #cccccc; border-bottom-color: #cccccc; border-left-color: #cccccc; padding-top: 2px; padding-right: 2px; padding-bottom: 5px; padding-left: 2px; ">
             <pre style="width: 694px; margin-top: 0px; margin-bottom: 0px; font-family: 'Andale Mono', 'Lucida Console', Monaco, Liberation, fixed, monospace; font-size: 11px; overflow-x: auto; overflow-y: auto; background-image: initial !important; background-attachment: initial !important; background-origin: initial !important; background-clip: initial !important; background-color: #f7f7f7 !important; color: #000000; background-position: initial initial !important; background-repeat: initial initial !important; "> // 写入 Exel 工作表 wwb.write(); // 关闭 Excel 工作薄对象 wwb.close(); </pre>
             </td>
         </tr>
     </tbody>
</table>
<br />
<p style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; ">这可能与读取 Excel 文件的操作有少少不同，在关闭 Excel 对象之前，你必须要先调用 write() 方法，因为先前的操作都是存储在缓存中的，所以要通过该方法将操作的内容保存在文件中。如果你先关闭了 Excel 对象，那么只能得到一张空的工作薄了。</p>
<p style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; "><a name="N1014E"><span style="font-size: 1.2em; font-weight: bold; ">3 拷贝、更新 Excel 工作薄</span></a></p>
<p style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; ">接下来简要介绍一下如何更新一个已经存在的工作薄，主要是下面二步操作，第一步是构造只读的 Excel 工作薄，第二步是利用已经创建的 Excel 工作薄创建新的可写入的 Excel 工作薄，参考下面的代码片段：( 完整代码见 ExcelModifying.java)</p>
<table width="100%" cellpadding="0" cellspacing="0" border="0" style="font-size: 0.8em; ">
     <tbody>
         <tr>
             <td style="font-family: arial, nsimsun, sans-serif; background-color: #f7f7f7 !important; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: #cccccc; border-right-color: #cccccc; border-bottom-color: #cccccc; border-left-color: #cccccc; padding-top: 2px; padding-right: 2px; padding-bottom: 5px; padding-left: 2px; ">
             <pre style="width: 694px; margin-top: 0px; margin-bottom: 0px; font-family: 'Andale Mono', 'Lucida Console', Monaco, Liberation, fixed, monospace; font-size: 11px; overflow-x: auto; overflow-y: auto; background-image: initial !important; background-attachment: initial !important; background-origin: initial !important; background-clip: initial !important; background-color: #f7f7f7 !important; color: #000000; background-position: initial initial !important; background-repeat: initial initial !important; "> // 创建只读的 Excel 工作薄的对象 jxl.Workbook rw = jxl.Workbook.getWorkbook(new File(sourcefile)); // 创建可写入的 Excel 工作薄对象 jxl.write.WritableWorkbook wwb = Workbook.createWorkbook(new File(targetfile), rw); // 读取第一张工作表 jxl.write.WritableSheet ws = wwb.getSheet(0); // 获得第一个单元格对象 jxl.write.WritableCell wc = ws.getWritableCell(0, 0); // 判断单元格的类型 , 做出相应的转化 if(wc.getType() == CellType.LABEL) { Label l = (Label)wc; l.setString("The value has been modified."); } // 写入 Excel 对象 wwb.write(); // 关闭可写入的 Excel 对象 wwb.close(); // 关闭只读的 Excel 对象 rw.close(); </pre>
             </td>
         </tr>
     </tbody>
</table>
<br />
<p style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; ">之所以使用这种方式构建 Excel 对象，完全是因为效率的原因，因为上面的示例才是 API 的主要应用。为了提高性能，在读取工作表时，与数据相关的一些输出信息，所有的格式信息，如：字体、颜色等等，是不被处理的，因为我们的目的是获得行数据的值，既使没有了修饰，也不会对行数据的值产生什么影响。唯一的不利之处就是，在内存中会同时保存两个同样的工作表，这样当工作表体积比较大时，会占用相当大的内存，但现在好像内存的大小并不是什么关键因素了。</p>
<p style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; ">一旦获得了可写入的工作表对象，我们就可以对单元格对象进行更新的操作了，在这里我们不必调用 API 提供的 add() 方法，因为单元格已经于工作表当中，所以我们只需要调用相应的 setXXX() 方法，就可以完成更新的操作了。</p>
<p style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; ">尽单元格原有的格式化修饰是不能去掉的，我们还是可以将新的单元格修饰加上去，以使单元格的内容以不同的形式表现。</p>
<p style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; ">新生成的工作表对象是可写入的，我们除了更新原有的单元格外，还可以添加新的单元格到工作表中，这与示例 2 的操作是完全一样的。</p>
<p style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; ">最后，不要忘记调用 write() 方法，将更新的内容写入到文件中，然后关闭工作薄对象，这里有两个工作薄对象要关闭，一个是只读的，另外一个是可写入的。</p>
<div style="clear: both; background-image: url(http://1.www.s81c.com/i/solid.gif); background-attachment: initial; background-origin: initial; background-clip: initial; background-color: #ffffff; height: 1px; background-position: initial initial; background-repeat: repeat no-repeat; "></div>
<p ibm-back-to-top"="" style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 5px; padding-right: 5px; padding-bottom: 5px; padding-left: 5px; font-size: 0.76em; clear: both; text-align: right; height: 15px; "><a href="http://www.ibm.com/developerworks/cn/java/l-javaExcel/#ibm-pcon" style="color: #4c6e94; display: inline; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 18px; text-decoration: none; background-image: url(http://1.www.s81c.com/i/v16/icons/u_bold.gif); background-attachment: initial; background-origin: initial; background-clip: initial; background-color: initial; font-weight: bold; background-position: 0px -1px; background-repeat: no-repeat no-repeat; ">回页首</a></p>
<p style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; "><a name="3"><span style="font-size: 1.5em; font-weight: bold; ">小结</span></a></p>
<p style="font-family: arial, nsimsun, sans-serif; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; ">本文只是对 Java Excel API 中常用的方法作了介绍，要想更详尽地了解 API，请大家参考 API 文档，或源代码。Java Excel API 是一个开放源码项目，请大家关注它的最新进展，有兴趣的朋友也可以申请加入这个项目，或者是提出宝贵的意见。</p>
</span></div><img src ="http://www.blogjava.net/titanaly/aggbug/365599.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/titanaly/" target="_blank">不高兴</a> 2011-12-05 15:48 <a href="http://www.blogjava.net/titanaly/archive/2011/12/05/365599.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用Spring+Junit4.4进行测试(使用注解)</title><link>http://www.blogjava.net/titanaly/archive/2011/11/30/365230.html</link><dc:creator>不高兴</dc:creator><author>不高兴</author><pubDate>Wed, 30 Nov 2011 11:38:00 GMT</pubDate><guid>http://www.blogjava.net/titanaly/archive/2011/11/30/365230.html</guid><wfw:comment>http://www.blogjava.net/titanaly/comments/365230.html</wfw:comment><comments>http://www.blogjava.net/titanaly/archive/2011/11/30/365230.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/titanaly/comments/commentRss/365230.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/titanaly/services/trackbacks/365230.html</trackback:ping><description><![CDATA[<div><span style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; "><div><div><div style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><a href="http://nottiansyf.iteye.com/blog/345819">http://nottiansyf.iteye.com/blog/345819</a></div>使用Junit4.4测试&nbsp;<br />在类上的配置Annotation&nbsp;<br />@RunWith(SpringJUnit4ClassRunner.class) 用于配置spring中测试的环境&nbsp;<br />@ContextConfiguration(Locations="../applicationContext.xml") 用于指定配置文件所在的位置&nbsp;<br />@Test标注在方法前，表示其是一个测试的方法 无需在其配置文件中额外设置属性.&nbsp;<br /><br />多个配置文件时{"/applic","/asas"} 可以导入多个配置文件&nbsp;<br /><br />测试中的事务配置 ，&nbsp;<br />AbstractTransactionalJUnit38SpringContextTests、 AbstractTransactionalJUnit4SpringContextTests&nbsp;<br />AbstractTransactionalTestNGSpringContextTests&nbsp;<br />已经在类级别预先配置了好了事物支持&nbsp;<br /><br />在普通spring的junit环境中配置事务&nbsp;<br />在类之前加入注解&nbsp;<br />@TransactionConfiguration(transactionManagert="txMgr",defaultRollback=false)&nbsp;<br />@Transactional&nbsp;<br />在方法中主要使用的Annotation包括&nbsp;<br />@TestExecutionListeners({})---用于禁用默认的监听器 否着需要通过@contextconfiguration配置一个ApplicationContext；&nbsp;<br /><br />@BeforeTransaction&nbsp;<br />@Before&nbsp;<br />@Rollback(true)&nbsp;<br />@AfterTransaction&nbsp;<br />@NotTransactional&nbsp;<br /><br />Junit4.4下支持类，方便基于junit4.4的测试&nbsp;<br />AbstractJUnit4SpringContextTests：&nbsp;<br /><br />AbstractTransactionalJUnit4SpringContextTests：&nbsp;<br />需要在applicationContext中定义一个datasource&nbsp;<br /><br />2009年3月9日&nbsp;<br />目前Spring2.5只支持4.4的Junit进行测试&nbsp;<br />下面是一个简单的测试Demo&nbsp;<br /><br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008080; ">&nbsp;1</span>&nbsp;<span style="color: #0000FF; ">package</span><span style="color: #000000; ">&nbsp;com.gameplus.service.webService;<br /></span><span style="color: #008080; ">&nbsp;2</span>&nbsp;<span style="color: #000000; "><br /></span><span style="color: #008080; ">&nbsp;3</span>&nbsp;<span style="color: #000000; "></span><span style="color: #0000FF; ">import</span><span style="color: #000000; ">&nbsp;javax.annotation.Resource;<br /></span><span style="color: #008080; ">&nbsp;4</span>&nbsp;<span style="color: #000000; "><br /></span><span style="color: #008080; ">&nbsp;5</span>&nbsp;<span style="color: #000000; "></span><span style="color: #0000FF; ">import</span><span style="color: #000000; ">&nbsp;org.junit.Test;<br /></span><span style="color: #008080; ">&nbsp;6</span>&nbsp;<span style="color: #000000; "></span><span style="color: #0000FF; ">import</span><span style="color: #000000; ">&nbsp;org.junit.runner.RunWith;<br /></span><span style="color: #008080; ">&nbsp;7</span>&nbsp;<span style="color: #000000; "></span><span style="color: #0000FF; ">import</span><span style="color: #000000; ">&nbsp;org.springframework.test.context.ContextConfiguration;<br /></span><span style="color: #008080; ">&nbsp;8</span>&nbsp;<span style="color: #000000; "></span><span style="color: #0000FF; ">import</span><span style="color: #000000; ">&nbsp;org.springframework.test.context.junit4.SpringJUnit4ClassRunner;<br /></span><span style="color: #008080; ">&nbsp;9</span>&nbsp;<span style="color: #000000; "><br /></span><span style="color: #008080; ">10</span>&nbsp;<span style="color: #000000; ">@RunWith(SpringJUnit4ClassRunner.</span><span style="color: #0000FF; ">class</span><span style="color: #000000; ">)<br /></span><span style="color: #008080; ">11</span>&nbsp;<span style="color: #000000; ">@ContextConfiguration(locations</span><span style="color: #000000; ">=</span><span style="color: #000000; ">{</span><span style="color: #000000; ">"</span><span style="color: #000000; ">../../../../applicationContext.xml</span><span style="color: #000000; ">"</span><span style="color: #000000; ">,</span><span style="color: #000000; ">"</span><span style="color: #000000; ">../../../../applicationDatasource.xml</span><span style="color: #000000; ">"</span><span style="color: #000000; ">})<br /></span><span style="color: #008080; ">12</span>&nbsp;<span style="color: #000000; "></span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">class</span><span style="color: #000000; ">&nbsp;UserServiceTest&nbsp;&nbsp;{<br /></span><span style="color: #008080; ">13</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;@Resource<br /></span><span style="color: #008080; ">14</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;IUserService&nbsp;userService;<br /></span><span style="color: #008080; ">15</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;<br /></span><span style="color: #008080; ">16</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;@Test<br /></span><span style="color: #008080; ">17</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;testAddOpinion1()&nbsp;{<br /></span><span style="color: #008080; ">18</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;userService.downloadCount(</span><span style="color: #000000; ">1</span><span style="color: #000000; ">);<br /></span><span style="color: #008080; ">19</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000; ">1</span><span style="color: #000000; ">);<br /></span><span style="color: #008080; ">20</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;}<br /></span><span style="color: #008080; ">21</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;@Test<br /></span><span style="color: #008080; ">22</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;testAddOpinion2()&nbsp;{<br /></span><span style="color: #008080; ">23</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;userService.downloadCount(</span><span style="color: #000000; ">2</span><span style="color: #000000; ">);<br /></span><span style="color: #008080; ">24</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000; ">2</span><span style="color: #000000; ">);<br /></span><span style="color: #008080; ">25</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;}<br /></span><span style="color: #008080; ">26</span>&nbsp;<span style="color: #000000; ">}<br /></span><span style="color: #008080; ">27</span>&nbsp;<span style="color: #000000; "></span></div></div></div><br />注意需要新的Jar包如下&nbsp;<br />javassist-3.4.GA.jar&nbsp;<br />hibernate3.jar&nbsp;<br />hibernate-annotations.jar&nbsp;<br />尤其注意用新版的,旧版会出现类未找到的异常&nbsp;</span></div><img src ="http://www.blogjava.net/titanaly/aggbug/365230.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/titanaly/" target="_blank">不高兴</a> 2011-11-30 19:38 <a href="http://www.blogjava.net/titanaly/archive/2011/11/30/365230.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用JUnit4来对Spring/Hibernate应用进行测试</title><link>http://www.blogjava.net/titanaly/archive/2011/11/30/365228.html</link><dc:creator>不高兴</dc:creator><author>不高兴</author><pubDate>Wed, 30 Nov 2011 11:19:00 GMT</pubDate><guid>http://www.blogjava.net/titanaly/archive/2011/11/30/365228.html</guid><wfw:comment>http://www.blogjava.net/titanaly/comments/365228.html</wfw:comment><comments>http://www.blogjava.net/titanaly/archive/2011/11/30/365228.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/titanaly/comments/commentRss/365228.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/titanaly/services/trackbacks/365228.html</trackback:ping><description><![CDATA[<div><span style="color: #444444; font-family: Verdana, Arial, sans-serif, 宋体; font-size: 12px; line-height: 19px; "><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 21px; "><a href="http://creativecommons.org/licenses/by/3.0/deed.zh" target="_blank" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-decoration: none; color: #f39700; ">版权声明</a>：转载时请以超链接形式标明文章原始出处和作者信息及<a href="http://bangzhuzhongxin.blogbus.com/logs/11205960.html" target="_blank" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-decoration: none; color: #f39700; ">本声明</a><br style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; " /><a href="http://ralf0131.blogbus.com/logs/55701639.html" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-decoration: none; color: #f39700; ">http://ralf0131.blogbus.com/logs/55701639.html</a><br style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; " /><br style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; " /></p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">参考：<a href="http://www.javaeye.com/topic/14631" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-decoration: none; color: #f39700; ">http://www.javaeye.com/topic/14631</a><br style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; " />关于JUnit4:&nbsp;<a href="http://www.ibm.com/developerworks/cn/java/j-junit4.html" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-decoration: none; color: #f39700; ">http://www.ibm.com/developerworks/cn/java/j-junit4.html</a></p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">背景：<br style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; " />如果在Hibernate层采用lazy=true的话，有的时候会抛出LazyInitializationException，这时一种解决办法是用OpenSessionInViewFilter,但是如果通过main方法来运行一些测试程序，那么上述方法就没有用武之地了。这里提供了一种方法，来达到实现和OpenSessionInViewFilter相同作用的目的。这里的应用场景是采用JUnit4来编写测试用例。</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">JUnit4的好处是：采用annotation来代替反射机制，不必写死方法名.<br style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; " />首先添加一个abstract class(AbstractBaseTestCase.class), 做一些准备性的工作：<br style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; " />(可以看到@Before和@After两个annotation的作用相当于setUp()和tearDown()方法，但是，显然更灵活)</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">package testcase;</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">import org.hibernate.FlushMode;</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">import org.hibernate.Session;</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">import org.hibernate.SessionFactory;</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">import org.junit.After;</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">import org.junit.Before;</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">import org.springframework.context.support.FileSystemXmlApplicationContext;</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">import org.springframework.orm.hibernate3.SessionFactoryUtils;</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">import org.springframework.orm.hibernate3.SessionHolder;</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">import org.springframework.transaction.support.TransactionSynchronizationManager;</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">&nbsp;</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">/***</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">&nbsp;* An abstract base class for TestCases.</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">&nbsp;* All test cases should extend this class.</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">&nbsp;*/</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">public class AbstractBaseTestCase&nbsp;{</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">&nbsp;</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">&nbsp;&nbsp; &nbsp;private SessionFactory sessionFactory; &nbsp;</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">&nbsp;&nbsp; &nbsp;private Session session; &nbsp;</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">&nbsp;&nbsp; &nbsp;protected FileSystemXmlApplicationContext dsContext;</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">&nbsp;&nbsp; &nbsp;private String []configStr = {"/WebRoot/WEB-INF/applicationContext.xml"}; &nbsp;</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; white-space: pre; ">	</span></p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; white-space: pre; ">	</span>@Before</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; white-space: pre; ">	</span>public void openSession() throws Exception {</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; white-space: pre; ">		</span>dsContext = new FileSystemXmlApplicationContext(configStr);</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;sessionFactory = (SessionFactory) dsContext.getBean("sessionFactory");&nbsp;&nbsp;</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;session = SessionFactoryUtils.getSession(sessionFactory, true);&nbsp;&nbsp;</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;session.setFlushMode(FlushMode.MANUAL); &nbsp;</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session));&nbsp;</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; white-space: pre; ">	</span>}</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">&nbsp;</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; white-space: pre; ">	</span>@After</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; white-space: pre; ">	</span>public void closeSession() throws Exception {</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; white-space: pre; ">		</span>TransactionSynchronizationManager.unbindResource(sessionFactory); &nbsp;</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;SessionFactoryUtils.releaseSession(session, sessionFactory); &nbsp;</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; white-space: pre; ">	</span>}</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">}</p><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">接下来继承上述基类，实现测试逻辑：</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">（注意import static用于引用某个类的静态方法)</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">（@Test注解表明该方法是一个测试方法）</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "></div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">package testcase;</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "></div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">import static org.junit.Assert.assertEquals;</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">import static org.junit.Assert.fail;</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "></div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">import org.junit.Before;</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">import org.junit.Test;</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "></div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">public class testCase1 extends AbstractBaseTestCase {</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "></div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; white-space: pre; ">	</span>private&nbsp;YourManager manager;</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; white-space: pre; ">	</span></div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; white-space: pre; ">	</span>@Before</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; white-space: pre; ">	</span>public void prepare(){</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; white-space: pre; ">		</span>manager = (YourManager)dsContext.getBean("YourManager");</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; white-space: pre; ">	</span>}</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; white-space: pre; ">	</span></div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; white-space: pre; ">	</span>@Test&nbsp;</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; white-space: pre; ">	</span>public void test1(){</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; white-space: pre; ">		</span>try {</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; white-space: pre; ">			</span>String result = manager.do_sth();</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; white-space: pre; ">			</span>System.out.println(result);</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; white-space: pre; ">			</span>assertEquals(result, EXPECTED_RESULT);</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; white-space: pre; ">		</span>} catch (Exception e) {</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; white-space: pre; ">			</span>e.printStackTrace();</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; white-space: pre; ">			</span>fail("Exception thrown.");</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; white-space: pre; ">		</span>}</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; white-space: pre; ">	</span>}</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">}</div></div></span></div><img src ="http://www.blogjava.net/titanaly/aggbug/365228.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/titanaly/" target="_blank">不高兴</a> 2011-11-30 19:19 <a href="http://www.blogjava.net/titanaly/archive/2011/11/30/365228.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>String.split() 结果数组中不包括结尾空字符串</title><link>http://www.blogjava.net/titanaly/archive/2011/08/25/357275.html</link><dc:creator>不高兴</dc:creator><author>不高兴</author><pubDate>Thu, 25 Aug 2011 07:37:00 GMT</pubDate><guid>http://www.blogjava.net/titanaly/archive/2011/08/25/357275.html</guid><wfw:comment>http://www.blogjava.net/titanaly/comments/357275.html</wfw:comment><comments>http://www.blogjava.net/titanaly/archive/2011/08/25/357275.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/titanaly/comments/commentRss/357275.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/titanaly/services/trackbacks/357275.html</trackback:ping><description><![CDATA[<div><span style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; "><div><div>String[] userData = "1######".split("#");</div><div>System.out.println(userData.length);<br />输出:userData.length =&nbsp;1</div></div>该方法的作用就像是使用给定的表达式和限制参数 0 来调用两参数 split 方法。因此，<span style="color: red; ">结果数组中不包括结尾空字符串。</span>&nbsp;<br /><br /><div id="" style="font-family: Monaco, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', Consolas, 'Courier New', monospace; font-size: 12px; background-color: transparent; width: 634px; overflow-x: auto; overflow-y: auto; margin-left: 9px; padding-top: 1px; padding-right: 1px; padding-bottom: 1px; padding-left: 1px; word-break: break-all; word-wrap: break-word; "><div><div style="padding-top: 3px; padding-right: 3px; padding-bottom: 3px; padding-left: 3px; text-align: left; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; color: black; font-weight: bold; ">Java代码&nbsp;<embed src="http://www.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf" width="14" height="15" flashvars="clipboard=%2F%2F%20Construct%20result%0A%20%20%20%20%20%20%20%20int%20resultSize%20%3D%20matchList.size()%3B%0A%20%20%20%20%20%20%20%20if%20(limit%20%3D%3D%200)%0A%20%20%20%20%20%20%20%20%20%20%20%20while%20(resultSize%20%3E%200%20%26%26%20matchList.get(resultSize-1).equals(%22%22))%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20resultSize--%3B%0A%20%20%20%20%20%20%20%20String%5B%5D%20result%20%3D%20new%20String%5BresultSize%5D%3B%0A%20%20%20%20%20%20%20%20return%20matchList.subList(0%2C%20resultSize).toArray(result)%3B" quality="high" allowscriptaccess="always" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer">&nbsp;<a href="http://www.iteye.com/problems/4876" title="收藏这段代码" style="color: #006699; text-decoration: none; "><img src="http://www.iteye.com/images/icon_star.png" alt="收藏代码" style="border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; " /></a></div></div><ol start="1" style="font-size: 1em; line-height: 1.4em; margin-top: 0px; margin-right: 0px; margin-bottom: 1px; margin-left: 0px; padding-top: 2px; padding-right: 0px; padding-bottom: 2px; padding-left: 0px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: #d1d7dc; border-right-color: #d1d7dc; border-bottom-color: #d1d7dc; border-left-color: #d1d7dc; list-style-type: decimal; list-style-position: initial; list-style-image: initial; background-color: #ffffff; color: #2b91af; "><li style="font-size: 1em; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 38px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 10px; border-left-width: 1px; border-left-style: solid; border-left-color: #d1d7dc; background-color: #fafafa; line-height: 18px; "><span style="color: black; "><span style="color: #008200; ">//&nbsp;Construct&nbsp;result</span><span style="color: black; ">&nbsp;&nbsp;</span></span></li><li style="font-size: 1em; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 38px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 10px; border-left-width: 1px; border-left-style: solid; border-left-color: #d1d7dc; background-color: #fafafa; line-height: 18px; "><span style="color: black; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #7f0055; font-weight: bold; ">int</span><span style="color: black; ">&nbsp;resultSize&nbsp;=&nbsp;matchList.size();&nbsp;&nbsp;</span></span></li><li style="font-size: 1em; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 38px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 10px; border-left-width: 1px; border-left-style: solid; border-left-color: #d1d7dc; background-color: #fafafa; line-height: 18px; "><span style="color: black; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #7f0055; font-weight: bold; ">if</span><span style="color: black; ">&nbsp;(limit&nbsp;==&nbsp;</span><span style="color: #c00000; ">0</span><span style="color: black; ">)&nbsp;&nbsp;</span></span></li><li style="font-size: 1em; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 38px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 10px; border-left-width: 1px; border-left-style: solid; border-left-color: #d1d7dc; background-color: #fafafa; line-height: 18px; "><span style="color: black; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #7f0055; font-weight: bold; ">while</span><span style="color: black; ">&nbsp;(resultSize&nbsp;&gt;&nbsp;</span><span style="color: #c00000; ">0</span><span style="color: black; ">&nbsp;&amp;&amp;&nbsp;matchList.get(resultSize-</span><span style="color: #c00000; ">1</span><span style="color: black; ">).equals(</span><span style="color: blue; ">""</span><span style="color: black; ">))&nbsp;&nbsp;</span></span></li><li style="font-size: 1em; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 38px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 10px; border-left-width: 1px; border-left-style: solid; border-left-color: #d1d7dc; background-color: #fafafa; line-height: 18px; "><span style="color: black; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;resultSize--;&nbsp;&nbsp;</span></li><li style="font-size: 1em; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 38px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 10px; border-left-width: 1px; border-left-style: solid; border-left-color: #d1d7dc; background-color: #fafafa; line-height: 18px; "><span style="color: black; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String[]&nbsp;result&nbsp;=&nbsp;<span style="color: #7f0055; font-weight: bold; ">new</span><span style="color: black; ">&nbsp;String[resultSize];&nbsp;&nbsp;</span></span></li><li style="font-size: 1em; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 38px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 10px; border-left-width: 1px; border-left-style: solid; border-left-color: #d1d7dc; background-color: #fafafa; line-height: 18px; "><span style="color: black; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #7f0055; font-weight: bold; ">return</span><span style="color: black; ">&nbsp;matchList.subList(</span><span style="color: #c00000; ">0</span><span style="color: black; ">,&nbsp;resultSize).toArray(result);&nbsp;&nbsp;</span></span></li></ol></div><br /><br /><br />split方法是调用Pattern的split实现的，看上面代码中的&nbsp;<br />while (resultSize &gt; 0 &amp;&amp; matchList.get(resultSize-1).equals(""))&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; resultSize--;&nbsp;<br />可见。字符串末尾的空字符串将从匹配结果中去除&nbsp;</span></div><img src ="http://www.blogjava.net/titanaly/aggbug/357275.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/titanaly/" target="_blank">不高兴</a> 2011-08-25 15:37 <a href="http://www.blogjava.net/titanaly/archive/2011/08/25/357275.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>log4j配置祥解</title><link>http://www.blogjava.net/titanaly/archive/2010/09/01/330578.html</link><dc:creator>不高兴</dc:creator><author>不高兴</author><pubDate>Wed, 01 Sep 2010 06:53:00 GMT</pubDate><guid>http://www.blogjava.net/titanaly/archive/2010/09/01/330578.html</guid><wfw:comment>http://www.blogjava.net/titanaly/comments/330578.html</wfw:comment><comments>http://www.blogjava.net/titanaly/archive/2010/09/01/330578.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/titanaly/comments/commentRss/330578.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/titanaly/services/trackbacks/330578.html</trackback:ping><description><![CDATA[<div class="postTitle"><span style="line-height: 1.3em; font-family: '宋体'">第一步：加入log4j-1.2.8.jar到lib下。</span><wbr><br />
<br />
<span style="line-height: 1.3em; font-family: '宋体'">第二步：在CLASSPATH下建立log4j.properties。内容如下：</span><wbr><br />
<br />
1 log4j.rootCategory=INFO, stdout , R<br />
<br />
2<br />
<br />
3 log4j.appender.stdout=org.apache.log4j.ConsoleAppender<br />
<br />
4 log4j.appender.stdout.layout=org.apache.log4j.PatternLayout<br />
<br />
5 log4j.appender.stdout.layout.ConversionPattern=[QC] %p [%t] %C.%M(%L) | %m%n<br />
<br />
6<br />
<br />
7 log4j.appender.R=org.apache.log4j.DailyRollingFileAppender<br />
<br />
8 log4j.appender.R.File=D:\Tomcat 5.5\logs\qc.log<br />
<br />
9 log4j.appender.R.layout=org.apache.log4j.PatternLayout<br />
<br />
10 log4j.appender.R.layout.ConversionPattern=%d-[TS] %p %t %c - %m%n<br />
<br />
11<br />
<br />
12 log4j.logger.com.neusoft=DEBUG<br />
<br />
13 log4j.logger.com.opensymphony.oscache=ERROR<br />
<br />
14 log4j.logger.net.sf.navigator=ERROR<br />
<br />
15 log4j.logger.org.apache.commons=ERROR<br />
<br />
16 log4j.logger.org.apache.struts=WARN<br />
<br />
17 log4j.logger.org.displaytag=ERROR<br />
<br />
18 log4j.logger.org.springframework=DEBUG<br />
<br />
19 log4j.logger.com.ibatis.db=WARN<br />
<br />
20 log4j.logger.org.apache.velocity=FATAL<br />
<br />
21<br />
<br />
22 log4j.logger.com.canoo.webtest=WARN<br />
<br />
23<br />
<br />
24 log4j.logger.org.hibernate.ps.PreparedStatementCache=WARN<br />
<br />
25 log4j.logger.org.hibernate=DEBUG<br />
<br />
26 log4j.logger.org.logicalcobwebs=WARN<br />
<br />
<span style="line-height: 1.3em; font-family: '宋体'">第三步：相应的修改其中属性，修改之前就必须知道这些都是干什么的，在第二部分讲解。</span><wbr><br />
<br />
<span style="line-height: 1.3em; font-family: '宋体'">第四步：在要输出日志的类中加入相关语句：</span><wbr><br />
<br />
<span style="line-height: 1.3em; font-family: '宋体'">定义属性：protected final Log log = LogFactory.getLog(getClass());</span><wbr><br />
<br />
<span style="line-height: 1.3em; font-family: '宋体'">在相应的方法中：</span><wbr><br />
<br />
if (log.isDebugEnabled())<br />
<br />
{<br />
<br />
log.debug(&#8220;System &#8230;..&#8221;);<br />
<br />
}<br />
<br />
<span style="line-height: 1.3em; font-family: '宋体'">二、Log4j说明</span><wbr><br />
<br />
1 log4j.rootCategory=INFO, stdout , R<br />
<br />
<span style="line-height: 1.3em; font-family: '宋体'">此句为将等级为INFO的日志信息输出到stdout和R这两个目的地，stdout和R的定义在下面的代码，可以任意起名。等级可分为OFF、 FATAL、ERROR、WARN、INFO、DEBUG、ALL，如果配置OFF则不打出任何信息，如果配置为INFO这样只显示INFO, WARN, ERROR的log信息，而DEBUG信息不会被显示，具体讲解可参照第三部分定义配置文件中的logger。</span><wbr><br />
<br />
3 log4j.appender.stdout=org.apache.log4j.ConsoleAppender<br />
<br />
<span style="line-height: 1.3em; font-family: '宋体'">此句为定义名为stdout的输出端是哪种类型，可以是</span><wbr><br />
<br />
org.apache.log4j.ConsoleAppender<span style="line-height: 1.3em; font-family: '宋体'">（控制台），</span><wbr><br />
<br />
org.apache.log4j.FileAppender<span style="line-height: 1.3em; font-family: '宋体'">（文件），</span><wbr><br />
<br />
org.apache.log4j.DailyRollingFileAppender<span style="line-height: 1.3em; font-family: '宋体'">（每天产生一个日志文件），</span><wbr><br />
<br />
org.apache.log4j.RollingFileAppender<span style="line-height: 1.3em; font-family: '宋体'">（文件大小到达指定尺寸的时候产生一个新的文件）</span><wbr><br />
<br />
org.apache.log4j.WriterAppender<span style="line-height: 1.3em; font-family: '宋体'">（将日志信息以流格式发送到任意指定的地方）</span><wbr><br />
<br />
<span style="line-height: 1.3em; font-family: '宋体'">具体讲解可参照第三部分定义配置文件中的Appender。</span><wbr><br />
<br />
4 log4j.appender.stdout.layout=org.apache.log4j.PatternLayout<br />
<br />
<span style="line-height: 1.3em; font-family: '宋体'">此句为定义名为stdout的输出端的layout是哪种类型，可以是</span><wbr><br />
<br />
org.apache.log4j.HTMLLayout<span style="line-height: 1.3em; font-family: '宋体'">（以HTML表格形式布局），</span><wbr><br />
<br />
org.apache.log4j.PatternLayout<span style="line-height: 1.3em; font-family: '宋体'">（可以灵活地指定布局模式），</span><wbr><br />
<br />
org.apache.log4j.SimpleLayout<span style="line-height: 1.3em; font-family: '宋体'">（包含日志信息的级别和信息字符串），</span><wbr><br />
<br />
org.apache.log4j.TTCCLayout<span style="line-height: 1.3em; font-family: '宋体'">（包含日志产生的时间、线程、类别等等信息）</span><wbr><br />
<br />
<span style="line-height: 1.3em; font-family: '宋体'">具体讲解可参照第三部分定义配置文件中的Layout。</span><wbr><br />
<br />
5 log4j.appender.stdout.layout.ConversionPattern= [QC] %p [%t] %C.%M(%L) | %m%n<br />
<br />
<span style="line-height: 1.3em; font-family: '宋体'">如果使用pattern布局就要指定的打印信息的具体格式ConversionPattern，打印参数如下：</span><wbr><br />
<br />
%m <span style="line-height: 1.3em; font-family: '宋体'">输出代码中指定的消息</span><wbr><br />
<br />
%p <span style="line-height: 1.3em; font-family: '宋体'">输出优先级，即DEBUG，INFO，WARN，ERROR，FATAL</span><wbr><br />
<br />
%r <span style="line-height: 1.3em; font-family: '宋体'">输出自应用启动到输出该log信息耗费的毫秒数</span><wbr><br />
<br />
%c <span style="line-height: 1.3em; font-family: '宋体'">输出所属的类目，通常就是所在类的全名</span><wbr><br />
<br />
%t <span style="line-height: 1.3em; font-family: '宋体'">输出产生该日志事件的线程名</span><wbr><br />
<br />
%n <span style="line-height: 1.3em; font-family: '宋体'">输出一个回车换行符，Windows平台为&#8220;rn&#8221;，Unix平台为&#8220;n&#8221;</span><wbr><br />
<br />
%d <span style="line-height: 1.3em; font-family: '宋体'">输出日志时间点的日期或时间，默认格式为ISO8601，也可以在其后指定格式，比如：%d{yyyy MMM dd HH:mm:ss,SSS}，输出类似：2002年10月18日 22：10：28，921</span><wbr><br />
<br />
%l <span style="line-height: 1.3em; font-family: '宋体'">输出日志事件的发生位置，包括类目名、发生的线程，以及在代码中的行数。</span><wbr><br />
<br />
[QC]<span style="line-height: 1.3em; font-family: '宋体'">是log信息的开头，可以为任意字符，一般为项目简称。</span><wbr><br />
<br />
<span style="line-height: 1.3em; font-family: '宋体'">输出的信息</span><wbr><br />
<br />
[TS] DEBUG [main] AbstractBeanFactory.getBean(189) | Returning cached instance of singleton bean 'MyAutoProxy'<br />
<br />
<span style="line-height: 1.3em; font-family: '宋体'">具体讲解可参照第三部分定义配置文件中的格式化日志信息。</span><wbr><br />
<br />
7 log4j.appender.R=org.apache.log4j.DailyRollingFileAppender<br />
<br />
<span style="line-height: 1.3em; font-family: '宋体'">此句与第3行一样。定义名为R的输出端的类型为每天产生一个日志文件。</span><wbr><br />
<br />
8 log4j.appender.R.File=D:\Tomcat 5.5\logs\qc.log<br />
<br />
<span style="line-height: 1.3em; font-family: '宋体'">此句为定义名为R的输出端的文件名为D:\Tomcat 5.5\logs\qc.log</span><wbr><br />
<br />
<span style="line-height: 1.3em; font-family: '宋体'">可以自行修改。</span><wbr><br />
<br />
9 log4j.appender.R.layout=org.apache.log4j.PatternLayout<br />
<br />
<span style="line-height: 1.3em; font-family: '宋体'">与第4行相同。</span><wbr><br />
<br />
10 log4j.appender.R.layout.ConversionPattern=%d-[TS] %p %t %c - %m%n<br />
<br />
<span style="line-height: 1.3em; font-family: '宋体'">与第5行相同。</span><wbr><br />
<br />
12 log4j.logger.com. neusoft =DEBUG<br />
<br />
<span style="line-height: 1.3em; font-family: '宋体'">指定com.neusoft包下的所有类的等级为DEBUG。</span><wbr><br />
<br />
<span style="line-height: 1.3em; font-family: '宋体'">可以把com.neusoft改为自己项目所用的包名。</span><wbr><br />
<br />
13 log4j.logger.com.opensymphony.oscache=ERROR<br />
<br />
14 log4j.logger.net.sf.navigator=ERROR<br />
<br />
<span style="line-height: 1.3em; font-family: '宋体'">这两句是把这两个包下出现的错误的等级设为ERROR，如果项目中没有配置EHCache，则不需要这两句。</span><wbr><br />
<br />
15 log4j.logger.org.apache.commons=ERROR<br />
<br />
16 log4j.logger.org.apache.struts=WARN<br />
<br />
<span style="line-height: 1.3em; font-family: '宋体'">这两句是struts的包。</span><wbr><br />
<br />
17 log4j.logger.org.displaytag=ERROR<br />
<br />
<span style="line-height: 1.3em; font-family: '宋体'">这句是displaytag的包。（QC问题列表页面所用）</span><wbr><br />
<br />
18 log4j.logger.org.springframework=DEBUG<br />
<br />
<span style="line-height: 1.3em; font-family: '宋体'">此句为Spring的包。</span><wbr><br />
<br />
24 log4j.logger.org.hibernate.ps.PreparedStatementCache=WARN<br />
<br />
25 log4j.logger.org.hibernate=DEBUG<br />
<br />
<span style="line-height: 1.3em; font-family: '宋体'">此两句是hibernate的包。</span><wbr><br />
<br />
<span style="line-height: 1.3em; font-family: '宋体'">以上这些包的设置可根据项目的实际情况而自行定制。</span><wbr><br />
<br />
<span style="line-height: 1.3em; font-family: '宋体'">三、log4j详解</span><wbr><br />
<br />
1<span style="line-height: 1.3em; font-family: '宋体'">、定义配置文件</span><wbr><br />
<br />
Log4j<span style="line-height: 1.3em; font-family: '宋体'">支持两种配置文件格式，一种是XML格式的文件，一种是Java特性文件log4j.properties（键=值）。下面将介绍使用log4j.properties文件作为配置文件的方法:</span><wbr><br />
<br />
①<span style="line-height: 1.3em; font-family: '宋体'">、配置根Logger</span><wbr><br />
<br />
Logger <span style="line-height: 1.3em; font-family: '宋体'">负责处理日志记录的大部分操作。</span><wbr><br />
<br />
<span style="line-height: 1.3em; font-family: '宋体'">其语法为：</span><wbr><br />
<br />
log4j.rootLogger = [ level ] , appenderName, appenderName, &#8230;<br />
<br />
<span style="line-height: 1.3em; font-family: '宋体'">其中，level 是日志记录的优先级，分为OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL或者自定义的级别。Log4j建议只使用四个级别，优 先级从高到低分别是ERROR、WARN、INFO、DEBUG。通过在这里定义的级别，您可以控制到应用程序中相应级别的日志信息的开关。比如在这里定 义了INFO级别，只有等于及高于这个级别的才进行处理，则应用程序中所有DEBUG级别的日志信息将不被打印出来。ALL:打印所有的日志，OFF：关 闭所有的日志输出。 appenderName就是指定日志信息输出到哪个地方。可同时指定多个输出目的地。</span><wbr><br />
<br />
②<span style="line-height: 1.3em; font-family: '宋体'">、配置日志信息输出目的地 Appender</span><wbr><br />
<br />
Appender <span style="line-height: 1.3em; font-family: '宋体'">负责控制日志记录操作的输出。</span><wbr><br />
<br />
<span style="line-height: 1.3em; font-family: '宋体'">其语法为：</span><wbr><br />
<br />
log4j.appender.appenderName = fully.qualified.name.of.appender.class<br />
<br />
log4j.appender.appenderName.option1 = value1<br />
<br />
&#8230;<br />
<br />
log4j.appender.appenderName.optionN = valueN<br />
<br />
<span style="line-height: 1.3em; font-family: '宋体'">这里的appenderName为在①里定义的，可任意起名。</span><wbr><br />
<br />
<span style="line-height: 1.3em; font-family: '宋体'">其中，Log4j提供的appender有以下几种：</span><wbr><br />
<br />
org.apache.log4j.ConsoleAppender<span style="line-height: 1.3em; font-family: '宋体'">（控制台），</span><wbr><br />
<br />
org.apache.log4j.FileAppender<span style="line-height: 1.3em; font-family: '宋体'">（文件），</span><wbr><br />
<br />
org.apache.log4j.DailyRollingFileAppender<span style="line-height: 1.3em; font-family: '宋体'">（每天产生一个日志文件），</span><wbr><br />
<br />
org.apache.log4j.RollingFileAppender<span style="line-height: 1.3em; font-family: '宋体'">（文件大小到达指定尺寸的时候产生一个新的文件），可通过 log4j.appender.R.MaxFileSize=100KB设置文件大小，还可通过 log4j.appender.R.MaxBackupIndex=1设置为保存一个备份文件。</span><wbr><br />
<br />
org.apache.log4j.WriterAppender<span style="line-height: 1.3em; font-family: '宋体'">（将日志信息以流格式发送到任意指定的地方）</span><wbr><br />
<br />
<span style="line-height: 1.3em; font-family: '宋体'">例如：log4j.appender.stdout=org.apache.log4j.ConsoleAppender</span><wbr><br />
<br />
<span style="line-height: 1.3em; font-family: '宋体'">定义一个名为stdout的输出目的地，ConsoleAppender为控制台。</span><wbr><br />
<br />
③<span style="line-height: 1.3em; font-family: '宋体'">、配置日志信息的格式（布局）Layout</span><wbr><br />
<br />
Layout <span style="line-height: 1.3em; font-family: '宋体'">负责格式化Appender的输出。</span><wbr><br />
<br />
<span style="line-height: 1.3em; font-family: '宋体'">其语法为：</span><wbr><br />
<br />
log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class<br />
<br />
log4j.appender.appenderName.layout.option1 = value1<br />
<br />
&#8230;<br />
<br />
log4j.appender.appenderName.layout.optionN = valueN<br />
<br />
<span style="line-height: 1.3em; font-family: '宋体'">其中，Log4j提供的layout有以下几种：</span><wbr><br />
<br />
org.apache.log4j.HTMLLayout<span style="line-height: 1.3em; font-family: '宋体'">（以HTML表格形式布局），</span><wbr><br />
<br />
org.apache.log4j.PatternLayout<span style="line-height: 1.3em; font-family: '宋体'">（可以灵活地指定布局模式），</span><wbr><br />
<br />
org.apache.log4j.SimpleLayout<span style="line-height: 1.3em; font-family: '宋体'">（包含日志信息的级别和信息字符串），</span><wbr><br />
<br />
org.apache.log4j.TTCCLayout<span style="line-height: 1.3em; font-family: '宋体'">（包含日志产生的时间、线程、类别等等信息）</span><wbr><br />
<br />
2<span style="line-height: 1.3em; font-family: '宋体'">、格式化日志信息</span><wbr><br />
<br />
Log4J<span style="line-height: 1.3em; font-family: '宋体'">采用类似C语言中的printf函数的打印格式格式化日志信息，打印参数如下：</span><wbr><br />
<br />
%m <span style="line-height: 1.3em; font-family: '宋体'">输出代码中指定的消息</span><wbr><br />
<br />
%p <span style="line-height: 1.3em; font-family: '宋体'">输出优先级，即DEBUG，INFO，WARN，ERROR，FATAL</span><wbr><br />
<br />
%r <span style="line-height: 1.3em; font-family: '宋体'">输出自应用启动到输出该log信息耗费的毫秒数</span><wbr><br />
<br />
%c <span style="line-height: 1.3em; font-family: '宋体'">输出所属的类目，通常就是所在类的全名</span><wbr><br />
<br />
%t <span style="line-height: 1.3em; font-family: '宋体'">输出产生该日志事件的线程名</span><wbr><br />
<br />
%n <span style="line-height: 1.3em; font-family: '宋体'">输出一个回车换行符，Windows平台为&#8220;rn&#8221;，Unix平台为&#8220;n&#8221;</span><wbr><br />
<br />
%d <span style="line-height: 1.3em; font-family: '宋体'">输出日志时间点的日期或时间，默认格式为ISO8601，也可以在其后指定格式，比如：%d{yyyy MMM dd HH:mm:ss,SSS}，输出类似：2002年10月18日 22：10：28，921</span><wbr><br />
<br />
%l <span style="line-height: 1.3em; font-family: '宋体'">输出日志事件的发生位置，包括类目名、发生的线程，以及在代码中的行数。</span><wbr><br />
<br />
3<span style="line-height: 1.3em; font-family: '宋体'">、在代码中使用Log4j</span><wbr><br />
<br />
<span style="line-height: 1.3em; font-family: '宋体'">我们在需要输出日志信息的类中做如下的三个工作：</span><wbr><br />
<br />
1<span style="line-height: 1.3em; font-family: '宋体'">、导入所有需的commongs-logging类：</span><wbr><br />
<br />
import org.apache.commons.logging.Log;<br />
<br />
import org.apache.commons.logging.LogFactory;<br />
<br />
2<span style="line-height: 1.3em; font-family: '宋体'">、在自己的类中定义一个org.apache.commons.logging.Log类的私有静态类成员：</span><wbr><br />
<br />
private final Log log = LogFactory.getLog(getClass());<br />
<br />
LogFactory.getLog()<span style="line-height: 1.3em; font-family: '宋体'">方法的参数使用的是当前类的class。</span><wbr><br />
<br />
3<span style="line-height: 1.3em; font-family: '宋体'">、使用org.apache.commons.logging.Log类的成员方法输出日志信息：</span><wbr><br />
<br />
if (log.isDebugEnabled())<br />
{<br />
log.debug("111");<br />
}<br />
if (log.isInfoEnabled())<br />
{<br />
log.info("222");<br />
}<br />
if (log.isWarnEnabled())<br />
{<br />
log.warn("333");<br />
}<br />
if (log.isErrorEnabled())<br />
{<br />
log.error("444");<br />
}<br />
if (log.isFatalEnabled())<br />
{<br />
log.fatal("555")<br />
} <br />
<br />
<br />
<br />
<a href="http://harbey.javaeye.com/blog/626170"></a><a href="http://harbey.javaeye.com/blog/626170"></a>log4j中关闭memcached日志<br />
log4j.logger.com.danga.MemCached.MemCachedClient=ERROR </div>
<img src ="http://www.blogjava.net/titanaly/aggbug/330578.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/titanaly/" target="_blank">不高兴</a> 2010-09-01 14:53 <a href="http://www.blogjava.net/titanaly/archive/2010/09/01/330578.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>spring配置详解-连接池配置（转载）</title><link>http://www.blogjava.net/titanaly/archive/2010/08/27/330039.html</link><dc:creator>不高兴</dc:creator><author>不高兴</author><pubDate>Fri, 27 Aug 2010 02:25:00 GMT</pubDate><guid>http://www.blogjava.net/titanaly/archive/2010/08/27/330039.html</guid><wfw:comment>http://www.blogjava.net/titanaly/comments/330039.html</wfw:comment><comments>http://www.blogjava.net/titanaly/archive/2010/08/27/330039.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/titanaly/comments/commentRss/330039.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/titanaly/services/trackbacks/330039.html</trackback:ping><description><![CDATA[一、连接池概述<br />
　数据库连接池概述：<br />
　　数据库连接是一种关键的有限的昂贵的资源，这一点在多用户的网页应用程序中体现得尤为突出。对数据库连接的管理能显著影响到整个<br />
应用程序的伸缩性和健壮性，影响到程序的性能指标。数据库连接池正是针对这个问题提出来的。<br />
　　数据库连接池负责分配、管理和释放数据库连接，它允许应用程序重复使用一个现有的数据库连接，而再不是重新建立一个；释放空闲时<br />
间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏。这项技术能明显提高对数据库操作的性能。<br />
　　数据库连接池在初始化时将创建一定数量的数据库连接放到连接池中，这些数据库连接的数量是由最小数据库连接数来设定的。无论这些<br />
数据库连接是否被使用，连接池都将一直保证至少拥有这么多的连接数量。连接池的最大数据库连接数量限定了这个连接池能占有的最大连接<br />
数，当应用程序向连接池请求的连接数超过最大连接数量时，这些请求将被加入到等待队列中。数据库连接池的最小连接数和最大连接数的设<br />
置要考虑到下列几个因素：<br />
　　1) 最小连接数是连接池一直保持的数据库连接，所以如果应用程序对数据库连接的使用量不大，将会有大量的数据库连接资源被浪费；<br />
　　2) 最大连接数是连接池能申请的最大连接数，如果数据库连接请求超过此数，后面的数据库连接请求将被加入到等待队列中，这会影响之<br />
后的数据库操作。<br />
　　3) 如果最小连接数与最大连接数相差太大，那么最先的连接请求将会获利，之后超过最小连接数量的连接请求等价于建立一个新的数据库<br />
连接。不过，这些大于最小连接数的数据库连接在使用完不会马上被释放，它将被放到连接池中等待重复使用或是空闲超时后被释放。<br />
目前常用的连接池有：C3P0、DBCP、Proxool<br />
网上的评价是：<br />
C3P0比较耗费资源，效率方面可能要低一点。<br />
DBCP在实践中存在BUG，在某些种情会产生很多空连接不能释放，Hibernate3.0已经放弃了对其的支持。<br />
Proxool的负面评价较少，现在比较推荐它，而且它还提供即时监控连接池状态的功能，便于发现连接泄漏的情况。<br />
配置如下：<br />
1、在spring配置文件中，一般在applicationContext.xml中<br />
&nbsp;&nbsp;&nbsp;&nbsp; &lt;bean id="proxoolDataSource" class="org.logicalcobwebs.proxool.ProxoolDataSource"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="driver" value="${jdbc.connection.driverClassName}"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="driverUrl" value="${jdbc.connection.url}"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="user" value="${jdbc.connection.username}"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="password" value="${jdbc.connection.password}"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;!-- 测试的SQL执行语句 --&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="houseKeepingTestSql" value="${proxool.houseKeepingTestSql}"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;!-- 最少保持的空闲连接数 （默认2个） --&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="prototypeCount" value="${proxool.prototypeCount}"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;!-- proxool自动侦察各个连接状态的时间间隔(毫秒),侦察到空闲的连接就马上回收,超时的销毁 默认30秒） --&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="houseKeepingSleepTime" value="${proxool.hourseKeepingSleepTime}"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;!-- 最大活动时间(超过此时间线程将被kill,默认为5分钟) --&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="maximumActiveTime" value="${proxool.maximumActiveTime}"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;!-- 连接最长时间(默认为4个小时) --&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="maximumConnectionLifetime" value="${proxool.maximumConnectionLifetime}"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;!-- 最小连接数 （默认2个） --&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="minimumConnectionCount" value="${proxool.minimumConnectionCount}"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;!-- 最大连接数 （默认5个） --&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="maximumConnectionCount" value="${proxool.maximumConnectionCount}"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;!-- --&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="statistics" value="${proxool.statistics}"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;!-- 别名 --&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="alias" value="${proxool.alias}"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;!-- --&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="simultaneousBuildThrottle" value="${proxool.simultaneous-build-throttle}"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; &lt;/bean&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; 然后注入到sessionFactory中<br />
&nbsp;&nbsp;&nbsp;&nbsp; &lt;bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="dataSource" ref="proxoolDataSource"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; &lt;/bean&gt;<br />
&nbsp;<br />
Porxool 配置文件 <br />
--==--==--==--==--==&lt;proxool.xml&gt;==--==--==--==--==--==--== <br />
&lt;?xml version="1.0" encoding="UTF-8"?&gt; <br />
&lt;proxool&gt; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;alias&gt;WMS&lt;/alias&gt; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;driver-url&gt;jdbc:postgresql://192.168.210.184:5432/wms&lt;/driver-url&gt; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;driver-class&gt;org.postgresql.Driver&lt;/driver-class&gt; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;driver-properties&gt; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="user" value="wms_user" /&gt; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="password" value="wms" /&gt; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/driver-properties&gt; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;minimum-connection-count&gt;2&lt;/minimum-connection-count&gt; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;maximum-connection-count&gt;40&lt;/maximum-connection-count&gt; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;simultaneous-build-throttle&gt;20&lt;/simultaneous-build-throttle&gt; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;prototype-count&gt;2&lt;/prototype-count&gt; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;house-keeping-test-sql&gt;select CURRENT_DATE&lt;/house-keeping-test-sql&gt; <br />
&lt;/proxool&gt; <br />
--==--==--==--==--==&lt;proxool.xml&gt;==--==--==--==--==--==--== <br />
&nbsp; <br />
配置说明： <br />
alias&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -〉数据库连接别名（程序中需要使用的名称） <br />
driver-url&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -〉数据库驱动 <br />
driver-class&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -〉驱动程序类 <br />
driver-properties&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -〉联机数据库的用户和密码 <br />
minimum-connection-count&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -〉最小连接数量，建议设置0以上，保证第一次连接时间 <br />
maximum-connection-count&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -〉最大连接数量，如果超过最大连接数量则会抛出异常。连接数设置过多，服务器CPU和内存性能消耗很<br />
大。 <br />
simultaneous-build-throttle&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -〉同时最大连接数 <br />
prototype-count&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -〉一次产生连接的数量。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 例：如果现在prototype-count设置为4个，但是现在已经有2个可以获得的连接，那么<br />
将会试图再创建2个连接。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 但不能超过最大连接数。 <br />
maximum-active-time&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -〉连接最大时间活动 默认5分钟 <br />
maximum-connection-lifetime&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -〉连接最大生命时间 默认4小时 
<img src ="http://www.blogjava.net/titanaly/aggbug/330039.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/titanaly/" target="_blank">不高兴</a> 2010-08-27 10:25 <a href="http://www.blogjava.net/titanaly/archive/2010/08/27/330039.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>可用Jamon来监测你的Spring应用,sql执行效率(转)</title><link>http://www.blogjava.net/titanaly/archive/2010/07/28/327330.html</link><dc:creator>不高兴</dc:creator><author>不高兴</author><pubDate>Wed, 28 Jul 2010 08:06:00 GMT</pubDate><guid>http://www.blogjava.net/titanaly/archive/2010/07/28/327330.html</guid><wfw:comment>http://www.blogjava.net/titanaly/comments/327330.html</wfw:comment><comments>http://www.blogjava.net/titanaly/archive/2010/07/28/327330.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/titanaly/comments/commentRss/327330.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/titanaly/services/trackbacks/327330.html</trackback:ping><description><![CDATA[/** <br />
*作者：张荣华(ahuaxuan) <br />
*2007-8-15 <br />
*转载请注明出处及作者 <br />
*/ <br />
<br />
前两天在看Spring内置的拦截器的时候，发现了一个之前没有注意的类：org.springframework.aop.interceptor.JamonPerformanceMonitorInterceptor，好奇心促使我上网查了一下这个jamon。大概看了一下之后发现这个玩意还真挺好用的而且挺重要的，而且现在国内对它的介绍也很少，所以写了一篇文章和大家分享。 <br />
<br />
一，Jamon简介： <br />
Jamon的全名是：Java Application Monitor。它是一个小巧的，免费的，高性能的，线程安全的性能监测工具。它可以用来测定系统的性能瓶颈，也可以用来监视用户和应用程序之间的交互情况。 Jamon主要是用来检测jee的应用程序。它最新的版本是2.1，可以用在1.4以上的jdk上。 <br />
<br />
二，将jamon导入到你的应用程序中去 <br />
首先下载jamon的开发包，见我的附件，同时你也可以去Sourceforge上自己下载。Sourceforge的下载地址为http://jamonapi.sourceforge.net。解压之后可以得到一个jar包和一个war包。jar包是自己会用到的，而war包是一个例子（不要小看这个例子，待会也要把它导入到项目中）。把war包之间丢到服务器上，访问：localhost:8080/jamon就可以看到这个例子了，这个例子是一个简单的性能监控系统。 <br />
<br />
接着把例子中的所有的包都导入到项目中，并把war包中的jsp和images还有css都考到项目中，比如新建一个目录叫monitor（它和WEB-INF是同级目录）。 <br />
<br />
三，正确配置自己的应用 <br />
我们在性能监测的时候最监测的就是页面的访问率和类中方法的访问率。所以在这一部分主要讲解一下如何监测自己的页面和类中方法的访问。 <br />
<br />
1， 检测自己的页面访问率 <br />
首先我们需要在web.xml中添加一个filter，这个filter就是用来判断哪些页面需要被监视的，如下所示： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://www.javaeye.com/topic/112172#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span>&lt;filter&gt; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;filter-name&gt;JAMonFilter&lt;/filter-name&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;filter-</span><span class="keyword">class</span><span>&gt;com.easywebwork.filter.EasyPageMonFilter&lt;/filter-</span><span class="keyword">class</span><span>&gt; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/filter&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&lt;filter-mapping&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;filter-name&gt;JAMonFilter&lt;/filter-name&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;url-pattern&gt;/*&lt;/url-pattern&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/filter-mapping&gt;&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">&lt;filter&gt;
&lt;filter-name&gt;JAMonFilter&lt;/filter-name&gt;
&lt;filter-class&gt;com.easywebwork.filter.EasyPageMonFilter&lt;/filter-class&gt;
&lt;/filter&gt;
&lt;filter-mapping&gt;
&lt;filter-name&gt;JAMonFilter&lt;/filter-name&gt;
&lt;url-pattern&gt;/*&lt;/url-pattern&gt;
&lt;/filter-mapping&gt;
</pre>
接下来我们看看这个filter的写法： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://www.javaeye.com/topic/112172#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span class="comment">/** </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;@author&nbsp;张荣华（ahuaxuan） </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;* </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;@since&nbsp;2007-8-13 </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*/</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;PageMonFilter&nbsp;</span><span class="keyword">extends</span><span>&nbsp;JAMonFilter{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">private</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;</span><span class="keyword">final</span><span>&nbsp;</span><span class="keyword">long</span><span>&nbsp;serialVersionUID&nbsp;=&nbsp;5746197114960908454L; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;doFilter(ServletRequest&nbsp;request,&nbsp;ServletResponse&nbsp;response,&nbsp;FilterChain&nbsp;filterChain)&nbsp;</span><span class="keyword">throws</span><span>&nbsp;IOException,&nbsp;ServletException&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Monitor&nbsp;allPages&nbsp;=&nbsp;MonitorFactory.start(</span><span class="keyword">new</span><span>&nbsp;MonKeyImp(</span><span class="string">"org.easywebwork.allPages"</span><span>,getURI(request),</span><span class="string">"ms."</span><span>)); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//这里就是我们要监视的所有的页面的配置 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Monitor&nbsp;monitor&nbsp;=&nbsp;MonitorFactory.start(getURI(request)); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//这里就是我们要监视的某个页面的配置 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">try</span><span>&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;filterChain.doFilter(request,&nbsp;response); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span class="keyword">finally</span><span>&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;monitor.stop(); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;allPages.stop(); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">protected</span><span>&nbsp;String&nbsp;getURI(ServletRequest&nbsp;request)&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span>&nbsp;(request&nbsp;</span><span class="keyword">instanceof</span><span>&nbsp;HttpServletRequest)&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;((HttpServletRequest)&nbsp;request).getRequestURI(); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span><span class="keyword">else</span><span>&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;</span><span class="string">"Not&nbsp;an&nbsp;HttpServletRequest"</span><span>; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">private</span><span>&nbsp;FilterConfig&nbsp;filterConfig&nbsp;=&nbsp;</span><span class="keyword">null</span><span>; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>}}&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">/**
* @author 张荣华（ahuaxuan）
*
* @since 2007-8-13
*/
public class PageMonFilter extends JAMonFilter{
private static final long serialVersionUID = 5746197114960908454L;
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
Monitor allPages = MonitorFactory.start(new MonKeyImp("org.easywebwork.allPages",getURI(request),"ms."));
//这里就是我们要监视的所有的页面的配置
Monitor monitor = MonitorFactory.start(getURI(request));
//这里就是我们要监视的某个页面的配置
try {
filterChain.doFilter(request, response);
} finally {
monitor.stop();
allPages.stop();
}
}
protected String getURI(ServletRequest request) {
if (request instanceof HttpServletRequest) {
return ((HttpServletRequest) request).getRequestURI();
} 	else {
return "Not an HttpServletRequest";
}
}
private FilterConfig filterConfig = null;
}}
</pre>
<br />
这个类看上去很简单，其实也挺简单的，就是得到uri，然后把它注册到MonitorFactory类中。这样只要我们去访问刚才创建的monitor目录下的jsp就可以看到性能监测页面了。 <br />
<br />
2， ，接下来我们看看在使用spring的情况下如何监测一个bean的方法调用。Spring也提供了对Jamon的支持(spring支持的东西还真多啊)，也就是文章开头提出的那个拦截器，为了给我们的bean加上拦截器，我们在spring的applicationcontext配置文件中加入如下语句： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://www.javaeye.com/topic/112172#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span>&lt;bean&nbsp;</span><span class="keyword">class</span><span>=</span><span class="string">"org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"</span><span>&gt; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property&nbsp;name=</span><span class="string">"beanNames"</span><span>&gt; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;list&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;value&gt;userService&lt;/value&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/list&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/property&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property&nbsp;name=</span><span class="string">"interceptorNames"</span><span>&gt; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;list&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;value&gt;jamonInterceptor&lt;/value&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/list&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/property&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/bean&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&lt;bean&nbsp;id=</span><span class="string">"jamonInterceptor"</span><span>&nbsp;</span><span class="keyword">class</span><span>=</span><span class="string">"org.springframework.aop.interceptor.JamonPerformanceMonitorInterceptor"</span><span>&gt; &nbsp;&nbsp;</span></span></li>
    <li><span>&lt;/bean&gt;&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">&lt;bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"&gt;
&lt;property name="beanNames"&gt;
&lt;list&gt;
&lt;value&gt;userService&lt;/value&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;property name="interceptorNames"&gt;
&lt;list&gt;
&lt;value&gt;jamonInterceptor&lt;/value&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="jamonInterceptor" class="org.springframework.aop.interceptor.JamonPerformanceMonitorInterceptor"&gt;
&lt;/bean&gt;</pre>
<br />
上面这个是典型的spring的aop的配置，如果对spring的aop配置不了解的可以去看一下spring中文文档，当然如果不想了解的话即使直接把这段配置拷到自己的项目中也是可以直接使用的。 <br />
<br />
还有一个步骤就是在你的log4j.properties中加入这句代码： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://www.javaeye.com/topic/112172#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span>log4j.logger.org.springframework.aop.interceptor.JamonPerformanceMonitorInterceptor&nbsp;=&nbsp;TRACE&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">log4j.logger.org.springframework.aop.interceptor.JamonPerformanceMonitorInterceptor = TRACE</pre>
<br />
如果没有这一行，那么这个拦截器是不会把方法调用的信息向MonitorFactory注册的。 <br />
<br />
只需要这些步骤，userservice中的方法在调用的时候就可以被拦截，然后将其注册到MonitorFactory中去了。 <br />
<br />
所有的配置完成之后我们来看一下效果吧: <br />
<a href="http://www.javaeye.com/topics/download/b2bac96e-6c18-4340-b7e0-f84c7bb6adca" target="_blank">http://www.javaeye.com/topics/download/b2bac96e-6c18-4340-b7e0-f84c7bb6adca</a>从这个图上我们可以看到，所有页面被访问的次数，UserService中的getAllUsers被调用的次数，最右边的是访问时间。这只是整个图的一部分，当然这个页面中也包括每一个页面被访问的次数和第一次访问的时间等等。下载附件运行，就可以看到所有的页面了。 <br />
<br />
三，总结 <br />
根据以上的步骤，我们就可以监测我们的程序了，应用程序中哪些页面被访问的多，哪些页面被访问的少，哪些方法被访问的多，哪些方法被访问的少，以及访问高峰期集中在什么时间等等，有了这些参数，我们更可以有针对性的对应用程序进行优化了，比如说某个页面访问比较频繁，我就可以用ehcache或oscache给这个页面做一个缓存。如果某个方法的访问比较频繁那就看看这个方法能否进一步优化，是需要异步，还是需要缓存，还是需要其他等等，总之有了jamon可以给我们带来更多的便捷，既可以让我们知道我们的客户的行为，也可以让我们知道我们开发的程序的&#8220;能力&#8221;。 <br />
<br />
其实本文提供的只是对页面和方法调用的监控，但是jamon可以提供更多功能，比如说sql语句的监控等等，这就需要我们共同去发掘了。 <br />
<br />
附件中包括了一个easywebwork的例子，我把jamon导入到这个例子工程中去，大家可以直接下载运行观看效果。Easywebwork是一个旨在减少webwork2.2.x系列的xml配置文件的项目， <br />
如果对这个主题感兴趣请到 <br />
<a href="http://www.javaeye.com/topic/91614" target="_blank">http://www.javaeye.com/topic/91614</a> <br />
<a href="http://www.javaeye.com/topic/93814" target="_blank">http://www.javaeye.com/topic/93814</a> <br />
参加讨论。 <br />
<br />
<br />
<br />
<br />
<br />
之前有一篇文章讲到如何使用jamon来监控请求以及方法得调用(原文地址见：[url]http://www.javaeye.com/post/354575 [/url])，本文属于其姊妹篇，使用jamon监控系统的sql调用及其调用效率。 <br />
<br />
需求： <br />
1我们知道在使用hibernate得时候，我们可以打开show sql选项，可以直接查看sql语句调用的情况，那么当我们使用其他持久技术的时候我们也需要这个功能怎么办呢，没有关系，jamon能够帮我们做到。 <br />
<br />
2 很多时候，不同的程序员会写出不同的性能的sql，有时候可能会不小心或者因为不知道而写出性能很差的sql，我自己曾经就发生过这种事情，在500w条数据的表里使用了一个limit来分页，到后面，执行一条sql都需要几分钟，诸如此类的时候可能大家都有碰到过，如果能有监控sql性能的工具嵌在应用里该多好，当然有jamon就可以帮我们做到。 <br />
<br />
对于jamon来说，每一个query的执行之后的统计结果都会被保存下来，这些概要统计都以MonProxy-SQL开头。这些统计中包括查询执行的时间，有比如平均时间，执行总时间，最小执行时间，最大执行时间，这些东西难道不是我们正想要的吗。 <br />
<br />
那么让我们开始吧，我们知道，这些query执行的统计应该是在connection中被统计的，也就是说我们要代理一般的connection，而connection又是由datasource产生的，所以我们可以代理datasource，说干就干。 <br />
<br />
一个datasource接口中关于connection的方法只有两个： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://www.javaeye.com/topic/164758#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span class="comment">/** </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;*&nbsp;&lt;p&gt;Attempts&nbsp;to&nbsp;establish&nbsp;a&nbsp;connection&nbsp;with&nbsp;the&nbsp;data&nbsp;source&nbsp;that </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;*&nbsp;this&nbsp;&lt;code&gt;DataSource&lt;/code&gt;&nbsp;object&nbsp;represents. </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;* </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;&nbsp;a&nbsp;connection&nbsp;to&nbsp;the&nbsp;data&nbsp;source </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;*&nbsp;@exception&nbsp;SQLException&nbsp;if&nbsp;a&nbsp;database&nbsp;access&nbsp;error&nbsp;occurs </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;*/</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;Connection&nbsp;getConnection()&nbsp;</span><span class="keyword">throws</span><span>&nbsp;SQLException; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span><span class="comment">/** </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;*&nbsp;&lt;p&gt;Attempts&nbsp;to&nbsp;establish&nbsp;a&nbsp;connection&nbsp;with&nbsp;the&nbsp;data&nbsp;source&nbsp;that </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;*&nbsp;this&nbsp;&lt;code&gt;DataSource&lt;/code&gt;&nbsp;object&nbsp;represents. </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;* </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;username&nbsp;the&nbsp;database&nbsp;user&nbsp;on&nbsp;whose&nbsp;behalf&nbsp;the&nbsp;connection&nbsp;is&nbsp; </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;*&nbsp;&nbsp;being&nbsp;made </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;password&nbsp;the&nbsp;user's&nbsp;password </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;&nbsp;a&nbsp;connection&nbsp;to&nbsp;the&nbsp;data&nbsp;source </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;*&nbsp;@exception&nbsp;SQLException&nbsp;if&nbsp;a&nbsp;database&nbsp;access&nbsp;error&nbsp;occurs </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;*&nbsp;@since&nbsp;1.4 </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;*/</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;Connection&nbsp;getConnection(String&nbsp;username,&nbsp;String&nbsp;password)&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">throws</span><span>&nbsp;SQLException;&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">/**
* &lt;p&gt;Attempts to establish a connection with the data source that
* this &lt;code&gt;DataSource&lt;/code&gt; object represents.
*
* @return  a connection to the data source
* @exception SQLException if a database access error occurs
*/
Connection getConnection() throws SQLException;
/**
* &lt;p&gt;Attempts to establish a connection with the data source that
* this &lt;code&gt;DataSource&lt;/code&gt; object represents.
*
* @param username the database user on whose behalf the connection is
*  being made
* @param password the user's password
* @return  a connection to the data source
* @exception SQLException if a database access error occurs
* @since 1.4
*/
Connection getConnection(String username, String password)
throws SQLException;
</pre>
<br />
也就是说我们只要override这两个方法即可。 <br />
根据这个思路我写了以下代码： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://www.javaeye.com/topic/164758#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span class="comment">/** </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;@author&nbsp;ahuaxuan(aaron&nbsp;zhang) </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;@since&nbsp;2008-2-25 </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;@version&nbsp;$Id$ </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*/</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;MonitorDataSource&nbsp;</span><span class="keyword">implements</span><span>&nbsp;DataSource&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;DataSource&nbsp;realDataSource; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;setRealDataSource(DataSource&nbsp;realDataSource)&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">this</span><span>.realDataSource&nbsp;=&nbsp;realDataSource; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;DataSource&nbsp;getRealDataSource()&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;realDataSource; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;Connection&nbsp;getConnection()&nbsp;</span><span class="keyword">throws</span><span>&nbsp;SQLException&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span class="comment">//表示由jamon来代理realDataSource返回的Connection </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;MonProxyFactory.monitor(realDataSource.getConnection()); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;Connection&nbsp;getConnection(String&nbsp;username,&nbsp;String&nbsp;password) &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">throws</span><span>&nbsp;SQLException&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span class="comment">//表示由jamon来代理realDataSource返回的Connection </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;MonProxyFactory.monitor(realDataSource.getConnection(username, &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;password)); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>}&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">/**
* @author ahuaxuan(aaron zhang)
* @since 2008-2-25
* @version $Id$
*/
public class MonitorDataSource implements DataSource {
public DataSource realDataSource;
public void setRealDataSource(DataSource realDataSource) {
this.realDataSource = realDataSource;
}
public DataSource getRealDataSource() {
return realDataSource;
}
public Connection getConnection() throws SQLException {
//表示由jamon来代理realDataSource返回的Connection
return MonProxyFactory.monitor(realDataSource.getConnection());
}
public Connection getConnection(String username, String password)
throws SQLException {
//表示由jamon来代理realDataSource返回的Connection
return MonProxyFactory.monitor(realDataSource.getConnection(username,
password));
}
}
</pre>
<br />
显然这个一个代理模式。接下来就是生成这个代理类,我是在spring中注册了这么一个类： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://www.javaeye.com/topic/164758#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span>&lt;bean&nbsp;id=</span><span class="string">"writeMonitorDataSource"</span><span>&nbsp;</span><span class="keyword">class</span><span>=</span><span class="string">"org.ahuaxuan.MonitorDataSource"</span><span>&nbsp;destroy-method=</span><span class="string">"close"</span><span>&gt; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property&nbsp;name=</span><span class="string">"realDataSource"</span><span>&nbsp;ref=</span><span class="string">"writeDataSource"</span><span>/&gt; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/bean&gt;&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">&lt;bean id="writeMonitorDataSource" class="org.ahuaxuan.MonitorDataSource" destroy-method="close"&gt;
&lt;property name="realDataSource" ref="writeDataSource"/&gt;
&lt;/bean&gt;</pre>
<br />
<br />
writeMonitorDataSource 所依赖的writeDataSource就是我们真正配置的datasource，比如： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://www.javaeye.com/topic/164758#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span>&lt;bean&nbsp;id=</span><span class="string">"writeDataSource"</span><span>&nbsp;</span><span class="keyword">class</span><span>=</span><span class="string">"org.apache.commons.dbcp.BasicDataSource"</span><span>&nbsp;destroy-method=</span><span class="string">"close"</span><span>&gt; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property&nbsp;name=</span><span class="string">"driverClassName"</span><span>&gt; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;value&gt;${jdbc.driverClassName}&lt;/value&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/property&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property&nbsp;name=</span><span class="string">"url"</span><span>&gt; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;value&gt;${jdbc.url}&lt;/value&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/property&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property&nbsp;name=</span><span class="string">"username"</span><span>&gt; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;value&gt;${jdbc.username}&lt;/value&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/property&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property&nbsp;name=</span><span class="string">"password"</span><span>&gt; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;value&gt;${jdbc.password}&lt;/value&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/property&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property&nbsp;name=</span><span class="string">"maxActive"</span><span>&gt; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;value&gt;${jdbc.maxActive}&lt;/value&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/property&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property&nbsp;name=</span><span class="string">"maxIdle"</span><span>&gt; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;value&gt;${jdbc.maxIdle}&lt;/value&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/property&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property&nbsp;name=</span><span class="string">"maxWait"</span><span>&gt; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;value&gt;${jdbc.maxWait}&lt;/value&gt; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/property&gt; &nbsp;&nbsp;</span></li>
    <li><span>&lt;/bean&gt;&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">&lt;bean id="writeDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"&gt;
&lt;property name="driverClassName"&gt;
&lt;value&gt;${jdbc.driverClassName}&lt;/value&gt;
&lt;/property&gt;
&lt;property name="url"&gt;
&lt;value&gt;${jdbc.url}&lt;/value&gt;
&lt;/property&gt;
&lt;property name="username"&gt;
&lt;value&gt;${jdbc.username}&lt;/value&gt;
&lt;/property&gt;
&lt;property name="password"&gt;
&lt;value&gt;${jdbc.password}&lt;/value&gt;
&lt;/property&gt;
&lt;property name="maxActive"&gt;
&lt;value&gt;${jdbc.maxActive}&lt;/value&gt;
&lt;/property&gt;
&lt;property name="maxIdle"&gt;
&lt;value&gt;${jdbc.maxIdle}&lt;/value&gt;
&lt;/property&gt;
&lt;property name="maxWait"&gt;
&lt;value&gt;${jdbc.maxWait}&lt;/value&gt;
&lt;/property&gt;
&lt;/bean&gt;
</pre>
<br />
好了，那么在使用datasource的时候，我们应该用哪个呢，当然是writeMonitorDataSource这个里，我们可以把它注入给jdbcTemplate，或者sessionfactory，或者其他需要用到datasource的地方。 <br />
<br />
到这里，就一切准备完毕了，我们可以看看我们sql语句的执行效率了(这个页面的地址为sql.jsp)： <br />
<span style="color: darkred">见图1</span> <br />
当然要我们的应用能够显示这个页面，我们需要把jamon的一组页面拷到我们的应用中，这一组页面包含在我提供下载的包中，最新的jamon版本是2.7。 <br />
<br />
我们可以看到id为153的那条sql语句执行了78ms，我要去看看这条sql语句是不是有点什么问题或者是否有优化的可能性。 <br />
<br />
当然，刚才说到每一条sql语句都是有统计平均时间，最大最小执行时间等等，没错，在另外一个页面jamonadmin.jsp上就包含这些内容 <br />
<span style="color: darkred">见图2</span> <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
<br />
上面的图片代表hits表示执行次数，avg表示sql执行的平均时间，后面的min和max表示sql执行的最小耗时和最大耗时。从这里我们能够更直观的看到我们每条sql语句执行的情况。很有用的一个功能。 <br />
<br />
而且在上面那两个页面上，我们还可以选择把sql执行的结果导出来，可以导成xml或excel格式。 <br />
<br />
总结：使用jamon来监控我们的sql语句我觉得很有使用意义，而且使用jamon对我们的应用来说完全是松耦合的，根本不需要更改我们的业务逻辑代码，完全是可插拔的，我们也可以开发时使用jamon，部署时拔掉jamon。有了它能够使一些程序员能够更多一点的关注自己所写的sql的效率，当然如果之前开发的时候没有使用jamon也没有关系，即使上线后也可以查看一下sql语句是否有问题，比如哪些sql语句执行得比较频繁，是否存在给其做缓存得可能性等等。总之使用jamon在应用程序中来监控我们得sql语句具有很强得实用意义， <br />
<br />
再次总结：jamon，很好，很强大。 <br />
<img src ="http://www.blogjava.net/titanaly/aggbug/327330.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/titanaly/" target="_blank">不高兴</a> 2010-07-28 16:06 <a href="http://www.blogjava.net/titanaly/archive/2010/07/28/327330.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java 推荐读物与源代码阅读(转) </title><link>http://www.blogjava.net/titanaly/archive/2010/01/17/309807.html</link><dc:creator>不高兴</dc:creator><author>不高兴</author><pubDate>Sat, 16 Jan 2010 17:16:00 GMT</pubDate><guid>http://www.blogjava.net/titanaly/archive/2010/01/17/309807.html</guid><wfw:comment>http://www.blogjava.net/titanaly/comments/309807.html</wfw:comment><comments>http://www.blogjava.net/titanaly/archive/2010/01/17/309807.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/titanaly/comments/commentRss/309807.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/titanaly/services/trackbacks/309807.html</trackback:ping><description><![CDATA[<p>1. Java语言基础<br />
<br />
谈到Java语言基础学习的书籍，大家肯定会推荐Bruce Eckel的《Thinking in Java》。它是一本写的相当深刻的技术书籍，Java语言基础部分基本没有其它任何一本书可以超越它。该书的作者Bruce Eckel在网络上被称为天才的投机者，作者的《Thinking in C++》在1995年曾获SoftwareDevelopment Jolt Award最佳书籍大奖，《Thinking in Java》被评为1999年Java World&#8220;最爱读者欢迎图书&#8221;，并且赢得了编辑首选图书奖。作者从1986年至今，已经发表了超过150篇计算机技术文章，出版了6本书（其中4本是关 于C++的），并且在全世界做了数百次演讲。他是《Thinking in Java》、《Thinking in C++》、《C++ Inside &amp; Out》《Using C++》和《Thinking in Patterns》的作者，同时还是《Black Belt C++》文集的编辑。他的书被读者称为&#8220;最好的Java参考书&#8230;&#8230;绝对让人震惊&#8221;；&#8220;购买Java参考书最明智的选择&#8221;；&#8220;我见过的最棒的编程指南&#8221;。作 者的非凡才华，极其跨越语言的能力，使作者被选为Java发展10年间与Java关系最密切的10个人物之一。<br />
<br />
《Thinking in Java》讲述了Java语言的方方面面，很多Java语言的老手都评价&#8220;这是一本将Java语言讲得相当丑陋的书&#8221;。该书谈及了java语言的很多细节，每一个方面都是相当深刻的。通过本书你可以看到&#8220;丑陋的&#8221;java语言。<br />
<br />
网络上关于java语言讲解的视频很多很多，其中不凡有垃圾。《翁恺—JAVA语言》可能是你学习java语言基础的唯一选择，该讲座基本按照 《Thinking in Java》这本书讲解，其中不凡有翁老师的很多有意思的笑话。我很幸运学习就是从此视频开始的。内容包括30讲，我总共看了3遍。<br />
<br />
不过，对于初学者我不太推荐使用《Thinking in Java》，我比较推荐Prentice Hall PTR 的《Core Java 2》国内称为《Java 2 核心技术》，目前是第七版。网络上大家都可以下载到电子版。Oreilly的《Java in a nutshell》也是一个不错的选择。读完以上两本后，你可以看看翁恺老师的视频，接着可以研究《Thinking in Java》了。<br />
<br />
<br />
2. Java数据结构<br />
<br />
市面上关于Java数据结构的书本身就很少很少。大致有APress 的《Java Collections》，Jones 和Bartlett 的《Data Structures in Java》、《Object-oriented Data Structures Using Java》以及Prentice Hall 出版的《Data Structures and Algorithms in Java》 (Dec 19, 2005)还有一本就是《Data Structures And Algorithms With Object-oriented Design Patterns In Java》。很幸运我的第一本英文书就是APress 的《Java Collections》（本书在国内可能根本就没有中文版――只能下载英文版了），很不错，讲得很有条例、很简单，是一本完完全全Java Collections API介绍的书籍，其中不凡有扩展API的例子。这是我推荐你学习java数据结构的唯一一本好书。其它的Jones 和Bartlett的那两本国内好像有一本中文版，想看你也可以看看。<br />
<br />
在学习完API后，你可以看看java.util包中对应的类了。不过只有在学习过设计模式后你才有可能完全理解整个Java Collections Framework。Java Collections Framework使用了很多著名的设计模式如：迭代器（Iterator）模式，工厂方法模式、装饰器模式、适配器模式等等。通过研究 java.util包中数据结构的源代码，你可以知道臭名昭著的Properties类的设计了，同时可能基本具备设计简单的数据结构的能力了。<br />
<br />
所谓学习无止境，学习完Sun提供了Java Collections Framework后，你可以研究Apche的另一个Java Collections Framework，很有意思哦。互为补充的两个Framework。<br />
<br />
<br />
<br />
在大家学习、研究Java Collections之前，我提示一下Java Collections主要包括以下三部分：接口（Interface）、实现（Implemention）和算法（Algorithm）。<br />
<br />
1. 接口主要有List、Set、Queue和 Map。List 、Se t和Queue是 Collection接口的子接口。<br />
<br />
2. 实现主要是实现这些接口的具体类。如实现List接口的ArrayList、LinkedList、Stack和Vector；实现Set接口的 HashSet、TreeSet 和LinkedHashSet；实现Queue接口的PriorityQueue、SynchronousQueue等等；实现Map接口的 HashMap、TreeMap、Hashtable、Properties、WeakHashMap等等。<br />
<br />
3. 算法主要是由Arrays类和Collections类提供的，它是整个Java Collection Framework算法的核心。支持各种类型的排序，查找等常用操作。<br />
<br />
Java Collections中包含两个版本的数据结构，主要是原先的支持同步的数据结构和后来不支持同步的数据结构。<br />
<br />
Java Collection Framework在使用Comparator和Comparable接口支持排序。同时提供新旧两个版本的迭代器Iterator和Enumeraton，以及它们如何转换等等。<br />
<br />
在java.util包中的Obserable接口和Observer类是考察者模式的核心。<br />
<br />
&#8230;&#8230;<br />
<br />
<br />
3. Java IO<br />
<br />
市面上关于IO的书籍也仅仅只有Oreilly出版社的两本，都是Elliotte Rusty Harold的著作。两本书的风格基本一致，推荐阅读是第一版的《Jvava I/O》，讲得比较浅显，内容相对比较集中，实例也很多。第二版今年5月国外才出版，很有幸我在网络上下载了第二版，讲得极其详细――726页的大块头（我化了两个星期），这次将NIO和IO和在一起，还包括J2ME部分的，不过串口、并口通信部分好像类库支持不够，自己不能实际操作。<br />
<br />
与第一版的《Jvava I/O》一起的Oreilly还有一本《Jvava NIO》，也是很不错的哦。<br />
<br />
大家在依次阅读完《Jvava I/O》以及《Jvava NIO》后，可以研究java.io包中的源代码了。在大家研究源代码前我给点提示：<br />
<br />
Java的io包主要包括：<br />
<br />
1. 两种流：字节流（byte Stream）和字符流（character stream），这两种流不存在所谓的谁代替谁、谁比谁高级之说，它们互为补充，只是侧重点不同而已。<br />
<br />
2. 两种对称：1.字节流、字符流的对称；2.输入、输出的对称。<br />
<br />
3. 一个桥梁：将字节流转变为字符流的InputStreamReader和OutputStreamWriter。<br />
<br />
其中必须注意：<br />
<br />
1. PipedInputStream和PipedOutputStrem是两个比较有趣的类。<br />
<br />
2. 支持Buffered的流是我们经常使用的类。<br />
<br />
3. 装饰器（Decorator）模式在java最著名的应用就是用于io的设计。仔细研究各个Filter流与具体流的关系，多看设计模式的书籍。相信你会有所所获。<br />
<br />
4. 学习好io包，是研究net包，rmi包&#8230;&#8230;的基础哦！<br />
<br />
<br />
4 . Java数据库<br />
<br />
数据库的书籍太多太多了，也是太烂太烂了！这方面的书我基本都研究过，推荐的你就看看Apress的《JDBC Recipes A Problem Solution Approach 》很不错，国外2005年底才出版，（国内好像没有中文版，不过出了中文版也不一定值得看――国内经常将国外的书翻译得一塌糊涂、不堪入目）不过我们真的很幸运，网络上有电子版的。值得一看。推荐我看的第一本比较满意的――Wiley出版的《Java Database Bible》，讲得很不错！Sun公司自己的关于JDBC API介绍的那一本《JDBC API Tutorial andRefernece》也不错。我第二本JDBC的就是研究的这套API。<br />
<br />
不过目前这些书都是一些相对比较浮浅的API应用的书籍。有机会我会给大家带来介绍JDBC API以及JDBC实现内部细节的书！我尽快努力，同时希望得到大家的支持！<br />
<br />
顺便给学习JDBC的朋友一点提示：<br />
<br />
JDBC的学习和使用主要是这套API，其使用过程也是极其简单，下面是使用JDBC的一般流程：<br />
<br />
1. 加载某个数据库的驱动（Driver类），通常使用Class.forName(&#8220;驱动的类名&#8220;);<br />
<br />
2. 连接数据库――<br />
<br />
Connection con = DriverManager.getConnection(url,username,password)；<br />
<br />
3. 得到会话――Statement stmt = con.createStatement();<br />
<br />
4. 执行操作――Result rs = stmt.executeQuery(&#8220;SQL查询语句&#8221;)；<br />
<br />
5. 处理结果――<br />
<br />
while(rs.next()){<br />
<br />
String col1 = rs.getString(1);<br />
<br />
&#8230;&#8230;<br />
<br />
}<br />
<br />
简单吧！整个JDBC中可以变化的一般是：<br />
<br />
1. 可以由Connection对象创建Statement、PreparedStatement和CallableStatement创建三种类型的Statement。<br />
<br />
2. 可以创建多种类型的ResultSet：支持单向移动和个自由移动；可更新的和不可更新的；支持不同等级的交易的&#8230;..<br />
<br />
3. 数据输入的批处理。<br />
<br />
4. 结果集中特殊类型（Blob、Clob、Arrary和Ref、Struct）列的操作。<br />
<br />
5. 这些特殊类型的录入数据库。<br />
<br />
6. javax.sql包中特殊结果集（CachedRowSet、JdbcRowSet、WebRowSet）的操作。<br />
<br />
7. 其它的就是一个DataSource了，也很简单！一个J2EE中的被管理对象<br />
<br />
简单吧！相信大家很快就会征服JDBC。<br />
<br />
<br />
5. Java 网络编程<br />
<br />
网络编程――一个神秘的、充满挑战的方向。不过在谈Java网络编程之前首先感谢Sun公司的开发人员，因为它们天才的设想，充满智慧的架构，使广大java程序员学习java网络编程变得异常简单。<br />
<br />
Java网络编程方面的书，我推荐O'Reilly的《Java Network Programming》，目前已经第三版了，以前的版本市面上肯定有！网络上早有第三版的电子版，国外2004年出版，706页哦！讲得很全，比较深入，太深入的可能由于Sun有些东西没有完全公开，所以也就不好讲了，有兴趣的可以下载看看！第二本还是O'Reilly 1998年出版的《Java distributed computing 》，基础部分写得比较详细，后面的实例还是值得研究的。<br />
<br />
在大家阅读这些书之前，给大家一点提示：<br />
<br />
java网络编程其实相对比较简单，入门也很快很快。java网络编程主要包括两个部分：1.Socket；2.URL部分。不过第二部分也完全建立在第一部分的基础上。<br />
<br />
1. Socket包括客户端的Socket和服务器端的ServerSocket。还有就是DatagramSocket和DatagramPacket，它对应于UDP通信协议。 总之，Socket部分是建立其它高级协议的基础。<br />
<br />
2. URL类是一个网络资源定位器，通常和具体的网络协议如HTTP，FTP，Telnet&#8230;&#8230;相关。通过该类可以连接网络上的资源，通过其 openStream可以以io包中的流（InputStream）的形式读取网络资源；通过其OpenConnection方法，可以打开一个连接，在此连接上可以不仅可以完成读的操作，还可以完成写的操作。<br />
<br />
Java的网络编程大体包括以上两部分。网络编程和IO以及多线程部分非常密切，在学习此部分前大家一定对这两部分了解比较透彻。<br />
<br />
学习了以上部分你可以研究java.net 包中的与此相关的源代码了！研究所有的源代码还为时尚早。在整个net包中包含： ContentHandlerFactory、URLStreamHandlerFactory、URLStreamHandler、 URLClassLoader等辅助类，它们构成了java.net网络编程的框架，通过研究其源代码，你不仅可以快速理解java.net包，还可以为 以后扩展该包打下基础，甚至可以将此思维方式运用到自己的项目中。<br />
<br />
到此为止你对java.net 包应该才了解60％，还有一部分你可以使用JDecompiler之类的反编译软件打开你JDK安装目录下\jdkxxx\ jre\lib目录中的rt.jar，用WinRAR之类的软件打开它的sun.net包，反编译所有的文件，它是URL类工作的细节。当研究完该 sun.net包，你就会对整个网络编程很熟悉很熟悉了。<br />
<br />
一切看起来我们已经对网络编程很精通了。其实不然，刚刚开始而已，要想深入，请继续吧！网络上很多优秀的网络编程库甚至软件可以为我们&#8220;添加功力&#8221;。如 Apache的HttpCore和HTTPConnection 是两个和HTTP协议相关库；JGroups是研究分布式通信、群组通信的必读库；接着我们可以研究P2P的软件包，如Sun公司的JXTA，它可能是 java平台点对点通信未来的标准哦！接着你可以研究成熟得不得了，使用极其广泛得P2P软件Azureus！www.sourceforge.net可以下载到！<br />
<br />
千里之行始于足下！Just do it ！（目前我也只研究了net包，其它的会在不久的将来继续深入。Sun公司因为某些原因没有公开net的其它实现细节，在其允许将其源代码以文字的形式加 以研究，以及允许将其没有公开的实现写入书中时，我很希望能出一本java网络编程的书籍，以飧广大读者！！）<br />
6. Servlet和JSP<br />
<br />
Servlet、JSP的书也是满地都是！值得推荐的也仅仅两三本。实推Addison Wiley的《Servlets and JavaServer pages ：The J2EE Technology Web Tier》，又是一本很厚的哦！国外2003年出版、784页，讲得比较全，例子也很多，特别是第八章Filter，举了几个不错的例子。其它所有我看到的关于Servlet和JSP的书都没有如此深入的！（可能有我没有看到而已）。O&#8217;reilly的《Java Servlet Programming》和《Java Server Pages》相对比较好懂一些，可以读读！<br />
<br />
在大家学习Servlet和Jsp之前我还是要提醒一下：<br />
<br />
本质上说Servlet就是一个实现Servlet接口的、部署于服务器端的服务器端的程序罢了！它可以象写其它任何java应用程序一样编写，它可以操作数据库、可以操作本地文件、可以连接本地EJB&#8230;&#8230;编写Servlet程序的一般流程为：<br />
<br />
1. 继承一个HttpServlet类；<br />
<br />
2. 覆盖其doGet、doPost方法；<br />
<br />
3. 在覆盖方法的内部操作方法参数HttpServletRequest和HttpServletResponse。<br />
<br />
4. 读取请求利用HttpServletRequest。利用HttpServletRequest你可以操作Http协议的协议头、可以得到请求的操作方法、可以得到请求的路径、可以得到请求的字符串、以及和请求客户相关的信息，更主要的你可以得到Cookie和HttpSession这两个对象。<br />
<br />
5. 利用Cookie你可以操作&#8220;甜心&#8221;对象或者将其写入HttpServletResponse中。<br />
<br />
6. 向客户输出信息可以使用HttpServletResponse。使用HttpServletResponse可以写入各种类型的协议头、可以增加Cookie、可以重定向其它URL、可以向客户发送Http协议的状态码。<br />
<br />
7. 利用HttpSession在会话内完成你想实现的任何功能。<br />
<br />
同时Servlet还提供了一些事件和事件监听器（简单的观察者模式而已）。还有就是过滤器（Filter）和包装器（ServletRequestWrapper、ServletResponseWrapper）――简单的流的使用和装饰器模式的使用。<br />
<br />
学习Sevlet、JSP必然要部署到服务器中，记住通常文件部署的步骤和参数的设置以及在程序中如何使用就可以了。<br />
<br />
完全理解Servlet后，学习jsp相对比较容易了！Jsp完全建立在Servlet的基础上，它是为了迎合那些喜欢在Html文档中嵌入脚本（如：PHP之类的网页编程语言）的程序员的需要罢了！学起来也相当的容易！<br />
<br />
一切看起来似乎那么的风平浪静，简单好学！简单的表象背后有其复杂的机理。要想对Servlet和Jsp彻底研究，你得研究Tomcat等开源软件的具体实现。它无非就是一个服务器，在客户利用网页通过HTTP协议向服务器发送请求后，服务器将此HTTP请求转化为相应的 HttpServletRequest对象，调用你编写的Servlet罢了，在你的Servlet中你肯定操作了此 HttpServletRequest了吧，同时操作了HttpServletResponse了吧，服务器就将此 HttpServletResponse按照HTTP协议的要求利用HTTP协议发送给你的浏览器了！在服务器端的Jsp网页在被客户请求后， Tomcat会利用编译软件，使用javax.servlet.jsp包中的模板，编译此jsp文件，编译后就是一个Servlet！以后的操作和 Servlet完全一样哦！<br />
<br />
在Servlet和Jsp的基础上出现了，所谓的高级技术：JSTL，Struts&#8230;&#8230;无非就是一些标签和MVC模式的使用。<br />
<br />
继续前进吧！胜利就在前方！！<br />
<br />
<br />
7. 多线程<br />
<br />
一个看起来很神秘，却很容易上手、很难精通的方向！<br />
<br />
我推荐两本我感觉很好的书籍。首先是我第一本能上手看的这方面的书，Sams 1998年出版的《Java Thread Programming》，写得暴好，很容易读懂，我有空还时常看当时的笔记！要知道怎么好你自己看吧！第二本OReilly三次出版的《Java Threads》，最新是2004版，国内好像有中文版，推荐你还是看英文版的吧！书中谈到了与多线程相关的N个方向，如IO、Swing、 Collection等等。<br />
<br />
给大家一点提示吧！java类库中与多线程相关的类不是很多，主要有：Thread、ThreadGroup以及ThreadLocal和 InheritableThreadLocal四个类和一个Runnable接口；关键字synchronize、volatile ；以及Object对象的wait、notify、notifyAll方法！<br />
<br />
1 Thread是多线程的核心类，提供了一系列创建和操作多线程的方法。<br />
<br />
2 ThreadGroup是一个管理Thread的工具类。<br />
<br />
3 ThreadLocal和InheritableThreadLocal为Thread提供了一个类似保险箱功能的存储线程对象的类！<br />
<br />
4 Runnable不用说了吧！<br />
<br />
5 synchronize是同步方法和同步块的核心哦！多个线程调用此方法时，只有一个线程可以使用此方法，其它方法阻塞，从而保证被操作对象内部状态完整性。某个线程调用带有synchronize的方法或块时会得到该对象的对象锁，完成块中的操作后释放此对象锁，从而其它对象可以继续操作。<br />
<br />
6 wait、notify、notifyAll提供了有效的等待/通知机制。Java语言中每一个对象都有一个休息室，任何线程在其操作的对象的状态不满足 的情况下，在该对象的休息室中休息，释放对象锁；当其它线程操作该对象后，唤醒休息室中的线程，它们再检查条件，当条件满足后，执行相应的操作。<br />
<br />
多线程大致就这么多基础的！简单吗！这对于一个真正的程序员应该是不够的，真正对多线程要有所掌握，请您研究java.util.concurrent包 吧！大师Doug Lea的作品，原先是一个开源的一致性编程的库，后来被Sun公司并入java类库。作者的网站上也有另外一个版本的该类库！值得研究的好东西! Hibernation、OpenJMS等开源软件都使用了此包！<br />
<br />
<br />
8. 设计模式<br />
<br />
谈到设计模式很多人多会推荐GOF的那本，该书在Amzon上是五星级的推荐书籍。不过对于学习java没多久的、特别是java初学者，我很不推荐这本书。主要是该书的例子基本都是C++的，很多细节没有讲述得足够清楚。<br />
<br />
我给大家推荐的第一本是阎宏博士的《Java 与模式》，它是第一本中国人自己写的关于设计模式的书籍，写的比较有趣，融合了很多中华民族的文化和观念，例子、类图都比较多，且相对简单！非常不错的入门书籍――又是大块头哦！<br />
<br />
其次我推荐Wiley出版社出版的《Pattern In Java》一套三本，我才看了第一本，好像第二本不怎么样，第三本还不错！<br />
<br />
第三本是中文翻译版的关于多线程模式的（很难得的中文翻译版）中国铁道出版社2003年出版的《Java多线程设计模式》，将多线程模式讲得非常浅显，配有大量的图例，每章都有习题，最后有答案！我研究多线程模式就是由它开始的！<br />
<br />
第四本，今年出版的Head First系列的《Head First Design Pattern》，秉承Head First系列图书的优点，大量的类图、丰富的实例、有趣的注解，值得购买！<br />
<br />
其次在J2EE方向你可以研究阅读Addison Wesley 2002年出版的《Patterns of Enterprise Application Architecture》，众多大腕的作品，讲企业消息集成的！Sun提供的《J2EE PATTERNS SL500》也很好！晚了推荐那一本Amzon 4星半的《Holub on patterns》，大师的作品，提供了，很值得研究的例子，不过对上面四本不是很熟悉的读者，最好不要读它！可能会让你比较累！<br />
<br />
我学习设计模式经过一段很曲折的路线，前前后后大约看了20本，阎宏博士的《Java 与模式》我看了4遍，还排除我第一次基本没看懂的看！记得研一时老师给我们讲了GOF的那本，作为选修课，我和它们计算机系的硕士、博士们一起，到最后一个班40－50个人，不超过3个人明白，我也没有明白任何一点（基础差吧――主要我对C++语言一点都不了解），凭我不伏输的性格，我认为我对java语 言理解还可以，我就借了《Java 与模式》，结果还是基本没看懂。很有幸的是读研三时，听过了上交大饶若楠老师关于Java OOP语言的讲座，我懂了组合书籍模式等三种设计模式后，对其它模式有了强烈的兴趣和要征服它的愿望！工作后我买的第一本就是《Java 与模式》，第一遍花了2个月研究了这个1000多页的大块头，后来第三遍15天左右就可以搞定，笔记记了一大本！从此一发不可收拾。<br />
<br />
选对书、埋头研究。相信很快就会入门的！<br />
<br />
<br />
<br />
学习Java语言8个简单的部分，这只是我们研究Java语言的开始！这些都懂了充其量一个java程序员而已，后面的路很长很长！我们可以继续研究数据库实现的源代码、Servlet服务器的源代码、RMI、EJB、JNDI、面向方面编程、重构、ANT工具、Eclipse工具、Spring工具、 JBoss、JOnAS、Apache Geronimo等J2EE服务器！研究了这些你可能会成为一个出色的J2EE Architecture！你可以继续研究剖析器、编译器、JNODE（java写的操作系统）&#8230;&#8230;<br />
<br />
<br />
<br />
感谢大家有此耐心，听我罗罗嗦嗦大半天！感谢大家的阅读，感谢群里的朋友！这篇文章主要应群里朋友的呼声――不知道如何选书、不知道从何看起！大半天的功夫完成赶此文章，字句上难免有失误，同时由于能力有限不凡有错误！请阅读后批评指正！<br />
<br />
上面基本是我研究java语言的顺序，以上书籍都是我阅读过的，不存在替任何出版社宣传的成分！有的方法可能不适合你，假如你能收获一点，两点甚至更多，请你不要吝啬推荐给你的朋友――共同学习！<br />
<br />
感谢大家的阅读；感谢互联网的设计者；感谢java的设计师；感谢www.open-open.com和www.sourceforge.net网站！ </p>
<img src ="http://www.blogjava.net/titanaly/aggbug/309807.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/titanaly/" target="_blank">不高兴</a> 2010-01-17 01:16 <a href="http://www.blogjava.net/titanaly/archive/2010/01/17/309807.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C3P0连接池详细配置</title><link>http://www.blogjava.net/titanaly/archive/2009/08/11/290696.html</link><dc:creator>不高兴</dc:creator><author>不高兴</author><pubDate>Tue, 11 Aug 2009 09:47:00 GMT</pubDate><guid>http://www.blogjava.net/titanaly/archive/2009/08/11/290696.html</guid><wfw:comment>http://www.blogjava.net/titanaly/comments/290696.html</wfw:comment><comments>http://www.blogjava.net/titanaly/archive/2009/08/11/290696.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/titanaly/comments/commentRss/290696.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/titanaly/services/trackbacks/290696.html</trackback:ping><description><![CDATA[&lt;<span class="hilite1">c3p0</span>-config&gt; <br />
&nbsp; &lt;default-config&gt; <br />
&lt;!--当连接池中的连接耗尽的时候<span class="hilite1">c3p0</span>一次同时获取的连接数。Default: 3 --&gt; <br />
&lt;property name="acquireIncrement"&gt;3&lt;/property&gt; <br />
<br />
&lt;!--定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 --&gt; <br />
&lt;property name="acquireRetryAttempts"&gt;30&lt;/property&gt; <br />
<br />
&lt;!--两次连接中间隔时间，单位毫秒。Default: 1000 --&gt; <br />
&lt;property name="acquireRetryDelay"&gt;1000&lt;/property&gt; <br />
<br />
&lt;!--连接关闭时默认将所有未提交的操作回滚。Default: false --&gt; <br />
&lt;property name="autoCommitOnClose"&gt;false&lt;/property&gt; <br />
<br />
&lt;!--<span class="hilite1">c3p0</span>将建一张名为Test的空表，并使用其自带的查询语句进行测试。如果定义了这个参数那么 <br />
&nbsp; 属性preferredTestQuery将被忽略。你不能在这张Test表上进行任何操作，它将只供<span class="hilite1">c3p0</span>测试 <br />
&nbsp; 使用。Default: null--&gt; <br />
&lt;property name="automaticTestTable"&gt;Test&lt;/property&gt; <br />
<br />
&lt;!--获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效 <br />
&nbsp; 保留，并在下次调用getConnection()的时候继续尝试获取连接。如果设为true，那么在尝试 <br />
&nbsp; 获取连接失败后该数据源将申明已断开并永久关闭。Default: false--&gt; <br />
&lt;property name="breakAfterAcquireFailure"&gt;false&lt;/property&gt; <br />
<br />
&lt;!--当连接池用完时客户端调用getConnection()后等待获取新连接的时间，超时后将抛出 <br />
&nbsp; SQLException,如设为0则无限期等待。单位毫秒。Default: 0 --&gt; <br />
&lt;property name="checkoutTimeout"&gt;100&lt;/property&gt; <br />
<br />
&lt;!--通过实现ConnectionTester或QueryConnectionTester的类来测试连接。类名需制定全路径。 <br />
&nbsp; Default: com.mchange.v2.<span class="hilite1">c3p0</span>.impl.DefaultConnectionTester--&gt; <br />
&lt;property name="connectionTesterClassName"&gt;&lt;/property&gt; <br />
<br />
&lt;!--指定<span class="hilite1">c3p0</span> libraries的路径，如果（通常都是这样）在本地即可获得那么无需设置，默认null即可 <br />
&nbsp; Default: null--&gt; <br />
&lt;property name="factoryClassLocation"&gt;null&lt;/property&gt; <br />
<br />
&lt;!--Strongly disrecommended. Setting this to true may lead to subtle and bizarre bugs. <br />
&nbsp; （文档原文）作者强烈建议不使用的一个属性--&gt; <br />
&lt;property name="forceIgnoreUnresolvedTransactions"&gt;false&lt;/property&gt; <br />
<br />
&lt;!--每60秒检查所有连接池中的空闲连接。Default: 0 --&gt; <br />
&lt;property name="idleConnectionTestPeriod"&gt;60&lt;/property&gt; <br />
<br />
&lt;!--初始化时获取三个连接，取值应在minPoolSize与maxPoolSize之间。Default: 3 --&gt; <br />
&lt;property name="initialPoolSize"&gt;3&lt;/property&gt; <br />
<br />
&lt;!--最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 --&gt; <br />
&lt;property name="maxIdleTime"&gt;60&lt;/property&gt; <br />
<br />
&lt;!--连接池中保留的最大连接数。Default: 15 --&gt; <br />
&lt;property name="maxPoolSize"&gt;15&lt;/property&gt; <br />
<br />
&lt;!--JDBC的标准参数，用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements <br />
&nbsp; 属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。 <br />
&nbsp; 如果maxStatements与maxStatementsPerConnection均为0，则缓存被关闭。Default: 0--&gt; <br />
&lt;property name="maxStatements"&gt;100&lt;/property&gt; <br />
<br />
&lt;!--maxStatementsPerConnection定义了连接池内单个连接所拥有的最大缓存statements数。Default: 0&nbsp; --&gt; <br />
&lt;property name="maxStatementsPerConnection"&gt;&lt;/property&gt; <br />
<br />
&lt;!--<span class="hilite1">c3p0</span>是异步操作的，缓慢的JDBC操作通过帮助进程完成。扩展这些操作可以有效的提升性能 <br />
&nbsp; 通过多线程实现多个操作同时被执行。Default: 3--&gt; <br />
&lt;property name="numHelperThreads"&gt;3&lt;/property&gt; <br />
<br />
&lt;!--当用户调用getConnection()时使root用户成为去获取连接的用户。主要用于连接池连接非<span class="hilite1">c3p0</span> <br />
&nbsp; 的数据源时。Default: null--&gt; <br />
&lt;property name="overrideDefaultUser"&gt;root&lt;/property&gt; <br />
<br />
&lt;!--与overrideDefaultUser参数对应使用的一个参数。Default: null--&gt; <br />
&lt;property name="overrideDefaultPassword"&gt;password&lt;/property&gt; <br />
<br />
&lt;!--密码。Default: null--&gt; <br />
&lt;property name="password"&gt;&lt;/property&gt; <br />
<br />
&lt;!--定义所有连接测试都执行的测试语句。在使用连接测试的情况下这个一显著提高测试速度。注意： <br />
&nbsp; 测试的表必须在初始数据源的时候就存在。Default: null--&gt; <br />
&lt;property name="preferredTestQuery"&gt;select id from test where id=1&lt;/property&gt; <br />
<br />
&lt;!--用户修改系统配置参数执行前最多等待300秒。Default: 300 --&gt; <br />
&lt;property name="propertyCycle"&gt;300&lt;/property&gt; <br />
<br />
&lt;!--因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的 <br />
&nbsp; 时候都将校验其有效性。建议使用idleConnectionTestPeriod或automaticTestTable <br />
&nbsp; 等方法来提升连接测试的性能。Default: false --&gt; <br />
&lt;property name="testConnectionOnCheckout"&gt;false&lt;/property&gt; <br />
<br />
&lt;!--如果设为true那么在取得连接的同时将校验连接的有效性。Default: false --&gt; <br />
&lt;property name="testConnectionOnCheckin"&gt;true&lt;/property&gt; <br />
<br />
&lt;!--用户名。Default: null--&gt; <br />
&lt;property name="user"&gt;root&lt;/property&gt; <br />
<br />
&lt;!--早期的<span class="hilite1">c3p0</span>版本对JDBC接口采用动态反射代理。在早期版本用途广泛的情况下这个参数 <br />
&nbsp; 允许用户恢复到动态反射代理以解决不稳定的故障。最新的非反射代理更快并且已经开始 <br />
&nbsp; 广泛的被使用，所以这个参数未必有用。现在原先的动态反射与新的非反射代理同时受到 <br />
&nbsp; 支持，但今后可能的版本可能不支持动态反射代理。Default: false--&gt; <br />
&lt;property name="usesTraditionalReflectiveProxies"&gt;false&lt;/property&gt; <br />
<br />
&nbsp;&nbsp;&nbsp; &lt;property name="automaticTestTable"&gt;con_test&lt;/property&gt; <br />
&nbsp;&nbsp;&nbsp; &lt;property name="checkoutTimeout"&gt;30000&lt;/property&gt; <br />
&nbsp;&nbsp;&nbsp; &lt;property name="idleConnectionTestPeriod"&gt;30&lt;/property&gt; <br />
&nbsp;&nbsp;&nbsp; &lt;property name="initialPoolSize"&gt;10&lt;/property&gt; <br />
&nbsp;&nbsp;&nbsp; &lt;property name="maxIdleTime"&gt;30&lt;/property&gt; <br />
&nbsp;&nbsp;&nbsp; &lt;property name="maxPoolSize"&gt;25&lt;/property&gt; <br />
&nbsp;&nbsp;&nbsp; &lt;property name="minPoolSize"&gt;10&lt;/property&gt; <br />
&nbsp;&nbsp;&nbsp; &lt;property name="maxStatements"&gt;0&lt;/property&gt; <br />
&nbsp;&nbsp;&nbsp; &lt;user-overrides user="swaldman"&gt; <br />
&nbsp;&nbsp;&nbsp; &lt;/user-overrides&gt; <br />
&nbsp; &lt;/default-config&gt; <br />
&nbsp; &lt;named-config name="dumbTestConfig"&gt; <br />
&nbsp;&nbsp;&nbsp; &lt;property name="maxStatements"&gt;200&lt;/property&gt; <br />
&nbsp;&nbsp;&nbsp; &lt;user-overrides user="poop"&gt; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="maxStatements"&gt;300&lt;/property&gt; <br />
&nbsp;&nbsp;&nbsp; &lt;/user-overrides&gt; <br />
&nbsp;&nbsp; &lt;/named-config&gt; <br />
&lt;/<span class="hilite1">c3p0</span>-config&gt; <br />
<img src ="http://www.blogjava.net/titanaly/aggbug/290696.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/titanaly/" target="_blank">不高兴</a> 2009-08-11 17:47 <a href="http://www.blogjava.net/titanaly/archive/2009/08/11/290696.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Communications link failure due to underlying exception</title><link>http://www.blogjava.net/titanaly/archive/2009/08/11/290691.html</link><dc:creator>不高兴</dc:creator><author>不高兴</author><pubDate>Tue, 11 Aug 2009 09:27:00 GMT</pubDate><guid>http://www.blogjava.net/titanaly/archive/2009/08/11/290691.html</guid><wfw:comment>http://www.blogjava.net/titanaly/comments/290691.html</wfw:comment><comments>http://www.blogjava.net/titanaly/archive/2009/08/11/290691.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/titanaly/comments/commentRss/290691.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/titanaly/services/trackbacks/290691.html</trackback:ping><description><![CDATA[<br />
<p>最近的一个项目在Hibernate使用C3P0的连接池，数据库为Mysql。开发测试没有问题，在运行中每个一段长的空闲时间就出现异常:</p>
<br />
<ol class="dp-j">
    <li class="alt"><span><span>org.hibernate.exception.JDBCConnectionException: could not execute query </span></span>
    <li class=""><span>at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:</span><span class="number">74</span><span>) </span>
    <li class="alt"><span>at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:</span><span class="number">43</span><span>) </span>
    <li class=""><span>....... </span>
    <li class="alt"><span>Caused by: com.mysql.jdbc.exceptions.MySQLNonTransientConnectionException: No operations allowed after connection closed.Connection was implicitly closed <span class="hilite4">due</span> <span class="hilite5">to</span> <span class="hilite6">underlying</span> exception/error: </span>
    <li class="">
    <li class="alt">
    <li class=""><span>** BEGIN NESTED EXCEPTION ** </span>
    <li class="alt">
    <li class=""><span>com.mysql.jdbc.CommunicationsException </span>
    <li class="alt"><span>MESSAGE: <span class="hilite1">Communications</span> <span class="hilite2">link</span> <span class="hilite3">failure</span> <span class="hilite4">due</span> <span class="hilite5">to</span> <span class="hilite6">underlying</span> exception: </span>
    <li class="">
    <li class="alt"><span>** BEGIN NESTED EXCEPTION ** </span>
    <li class="">
    <li class="alt"><span>java.net.SocketException </span>
    <li class=""><span>MESSAGE: Broken pipe </span>
    <li class="alt">
    <li class=""><span>STACKTRACE: </span>
    <li class="alt">
    <li class=""><span>java.net.SocketException: Broken pipe </span>
    <li class="alt"><span>at java.net.SocketOutputStream.socketWrite0(Native Method) </span>
    <li class=""><span>...... </span>
    <li class="alt"><span>** END NESTED EXCEPTION ** </span></li>
</ol>
<span>
<p>查看了Mysql的文档，以及Connector/J的文档以及在线说明发现，出现这种异常的原因是：</p>
<p>Mysql服务器默认的&#8220;wait_timeout&#8221;是8小时，也就是说一个connection空闲超过8个小时，Mysql将自动断开该connection。这就是问题的所在，在C3P0 pools中的connections如果空闲超过8小时，Mysql将其断开，而C3P0并不知道该connection已经失效，如果这时有Client请求connection，C3P0将该失效的Connection提供给Client，将会造成上面的异常。</p>
<p>解决的方法有3种：</p>
<ol>
    <li>增加wait_timeout的时间。
    <li>减少Connection pools中connection的lifetime。
    <li>测试Connection pools中connection的有效性。 </li>
</ol>
<p>当然最好的办法是同时综合使用上述3种方法，下面就DBCP和C3P0分别做一说明，假设wait_timeout为默认的8小时</p>
<p>DBCP增加以下配置信息:</p>
<li class="alt"><span><span class="comment">//set <span class="hilite5">to</span> 'SELECT 1' </span></span>
<li class=""><span>validationQuery = </span><span class="string">"SELECT 1"</span><span> </span>
<li class="alt"><span><span class="comment">//set <span class="hilite5">to</span> 'true' </span></span>
<li class=""><span>testWhileIdle = </span><span class="string">"true"</span><span> </span>
<li class="alt"><span><span class="comment">//some positive integer </span></span>
<li class=""><span>timeBetweenEvictionRunsMillis = </span><span class="number">3600000</span><span> </span>
<li class="alt"><span><span class="comment">//set <span class="hilite5">to</span> something smaller than 'wait_timeout' </span></span>
<li class=""><span>minEvictableIdleTimeMillis = </span><span class="number">18000000</span><span> </span>
<li class="alt"><span><span class="comment">//if you don't mind a hit for every getConnection(), set <span class="hilite5">to</span> "true" </span></span>
<li class=""><span>testOnBorrow = </span><span class="string">"true"</span><span> </span>
<p class="alt"><br />
<br />
<br />
C3P0增加以下配置信息:<br />
</span>&nbsp;</p>
<li class="alt"><span><span class="comment">//获取connnection时测试是否有效</span>
<li class=""><span>testConnectionOnCheckin = true</span>
<li class=""><span>//自动测试的table名称<br />
</span>
<li class=""><span>automaticTestTable=C3P0TestTable<br />
</span>
<li class="alt"><span class="comment">//set <span class="hilite5"><span class="hilite5"><span class="hilite5">to</span></span></span> something much less than wait_timeout, prevents connections from going stale </span>
<li class=""><span>idleConnectionTestPeriod = </span><span class="number">18000</span><span> </span>
<li class="alt"><span><span class="comment">//set <span class="hilite5"><span class="hilite5"><span class="hilite5">to</span></span></span> something slightly less than wait_timeout, preventing 'stale' connections from being handed out </span></span>
<li class=""><span>maxIdleTime = </span><span class="number">25000</span><span> </span>
<li class="alt"><span><span class="comment">//if you can take the performance 'hit', set <span class="hilite5"><span class="hilite5"><span class="hilite5">to</span></span></span> "true" </span></span>
<li class=""><span>testConnectionOnCheckout = </span><span class="keyword">true</span><span> </span></li>
<p class="">&nbsp;</p>
<p class="">&nbsp;</p>
<p class="">&nbsp;</p>
<p class=""><span style="color: red">在配置文件中要写成&nbsp; &lt;property name="minPoolSize"&gt;&lt;value&gt;1&lt;/value&gt;&lt;/property&gt; 格式</span></p>
<p class=""><span style="color: red"><span style="color: #ff0000">不能写成 这样&lt;property name="properties"&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;props&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;prop key="c3p0.initialPoolSize"&gt;1&lt;/prop&gt;</span></span></p>
<p class=""><span style="color: red"><span style="color: #ff0000">&nbsp;&nbsp;&nbsp;&lt;/props&gt;</span></span></p>
<p class=""><span style="color: red"><span style="color: #ff0000">&lt;/property&gt;</span></span></p>
<p class=""><span style="color: red"><span style="color: #ff0000">c3p0不能完全识别!!</span></span></span></p>
<img src ="http://www.blogjava.net/titanaly/aggbug/290691.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/titanaly/" target="_blank">不高兴</a> 2009-08-11 17:27 <a href="http://www.blogjava.net/titanaly/archive/2009/08/11/290691.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java 解析csv文件 </title><link>http://www.blogjava.net/titanaly/archive/2009/08/10/290584.html</link><dc:creator>不高兴</dc:creator><author>不高兴</author><pubDate>Mon, 10 Aug 2009 13:21:00 GMT</pubDate><guid>http://www.blogjava.net/titanaly/archive/2009/08/10/290584.html</guid><wfw:comment>http://www.blogjava.net/titanaly/comments/290584.html</wfw:comment><comments>http://www.blogjava.net/titanaly/archive/2009/08/10/290584.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/titanaly/comments/commentRss/290584.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/titanaly/services/trackbacks/290584.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: import&nbsp;java.io.BufferedReader;import&nbsp;java.io.BufferedWriter;import&nbsp;java.io.File;import&nbsp;java.io.FileNotFoundException;import&nbsp;java.io.FileReader;import&nbsp;java.io.Fi...&nbsp;&nbsp;<a href='http://www.blogjava.net/titanaly/archive/2009/08/10/290584.html'>阅读全文</a><img src ="http://www.blogjava.net/titanaly/aggbug/290584.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/titanaly/" target="_blank">不高兴</a> 2009-08-10 21:21 <a href="http://www.blogjava.net/titanaly/archive/2009/08/10/290584.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【转】Email电子邮件应用分析</title><link>http://www.blogjava.net/titanaly/archive/2009/06/05/280152.html</link><dc:creator>不高兴</dc:creator><author>不高兴</author><pubDate>Fri, 05 Jun 2009 01:42:00 GMT</pubDate><guid>http://www.blogjava.net/titanaly/archive/2009/06/05/280152.html</guid><wfw:comment>http://www.blogjava.net/titanaly/comments/280152.html</wfw:comment><comments>http://www.blogjava.net/titanaly/archive/2009/06/05/280152.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/titanaly/comments/commentRss/280152.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/titanaly/services/trackbacks/280152.html</trackback:ping><description><![CDATA[<p>原文地址:http://www.csna.cn/viewthread.php?tid=569&amp;sid=FbE5VS</p>
<p>一、&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 邮件传输协议简介<br />
1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 邮件传输概念<br />
邮件服务是Internet上最常用的服务之一，它提供了与操作系统平台无关的通信服务，使用邮件服务，用户可通过电子邮件在网络之间交换数据信息。邮件传输包括将邮件从发送者客户端发往邮件服务器，以及接收者从邮件服务器将邮件取回到接收者客户端。<br />
2.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SMTP和POP3<br />
在TCP/IP协议簇中，一般使用SMTP协议发送邮件，POP3协议接收邮件。<br />
SMTP，全称Simple Message Transfer Protocol，中文名为简单邮件传输协议，工作在TCP/IP层次的应用层。SMTP采用Client/Server工作模式，默认使用TCP 25端口，提供可靠的邮件发送服务。<br />
POP3，全称Post Office Protocol 3，中文名为第三版邮局协议，工作在TCP/IP层次的应用层。POP3采用Client/Server工作模式，默认使用TCP 110端口，提供可靠的邮件接收服务。<br />
3.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SMTP和POP3的工作原理<br />
发送和接收邮件都需要以下两个组件：用户代理（UA，常用的是Foxmail或Outlook）和SMTP/POP3服务器。<br />
SMTP工作原理：<br />
1)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 客户端使用TCP协议连接SMTP服务器的25端口；<br />
2)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 客户端发送HELO报文将自己的域地址告诉给SMTP服务器；<br />
3)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SMTP服务器接受连接请求，向客户端发送请求账号密码的报文；<br />
4)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 客户端向SMTP服务器传送账号和密码，如果验证成功，向客户端发送一个OK命令，表示可以开始报文传输；<br />
5)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 客户端使用MAIL命令将邮件发送者的名称发送给SMTP服务器；<br />
6)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SMTP服务器发送OK命令做出响应；<br />
7)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 客户端使用RCPT命令发送邮件接收者地址，如果SMTP服务器能识别这个地址，就向客户端发送OK命令，否则拒绝这个请求；<br />
8)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 收到SMTP服务器的OK命令后，客户端使用DATA命令发送邮件的数据。<br />
9)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 客户端发送QUIT命令终止连接。<br />
POP3工作原理：<br />
1)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 客户端使用TCP协议连接邮件服务器的110端口；<br />
2)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 客户端使用USER命令将邮箱的账号传给POP3服务器；<br />
3)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 客户端使用PASS命令将邮箱的账号传给POP3服务器；<br />
4)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 完成用户认证后，客户端使用STAT命令请求服务器返回邮箱的统计资料；<br />
5)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 客户端使用LIST命令列出服务器里邮件数量；<br />
6)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 客户端使用RETR命令接收邮件，接收一封后便使用DELE命令将邮件服务器中的邮件置为删除状态；<br />
7)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 客户端发送QUIT命令，邮件服务器将将置为删除标志的邮件删除，连接结束。<br />
（注：客户端UA可以设定将邮件在邮件服务器上保留备份，而不将其删除。）</p>
<p>二、&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 跟踪分析Email电子邮件通讯过程<br />
1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 分析Email的具体流程<br />
1)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 发送邮件<br />
我们使用科来网络分析系统5.0捕获并分析一个使用SMTP协议的发送邮件过程，客户端主机名为&#8220;wangym&#8221;，客户端用户代理使用Foxmail 5.0 beta2，邮件发送者test1@colasoft.com，邮件接收者test2@colasoft.com。<br />
在客户端主机上打开科来网络分析系统5.0。为避免数据干扰，设定一个过滤器，只捕获本机的数据通讯。<br />
打开客户端主机上的Foxmail 5.0 beta2，新建两个邮件账户，test1@colasoft.com和test2@colasoft.com，设置好账户的SMTP/POP3服务器地址、用户名、密码等信息并测试成功。<br />
在科来网络分析系统5.0中开始数据捕获，在Foxmail中使用test1@colasoft.com向test2@colasoft.com发送一封邮件，邮件原始信息如图1所示。发送完成后即可在科来网络分析系统5.0对刚才的邮件发送操作进行分析（为避免数据包干扰，分析时可停止捕获。）。<br />
注意：此文里提到的发送邮件均指使用TCP 25端口的标准SMTP通信，对于非25端口的邮件发送，用户可在&#8220;工程-&gt;高级分析模块-&gt;邮件分析模块-&gt;SMTP设置-&gt;SMTP端口&#8221;处进行更改，系统默认为25，当SMTP服务器有多个端口时，多个端口之间用分号分隔，如25;125。</p>
<p><br />
科来网络分析系统5.0对上面发送邮件操作的报文跟踪，详细信息如下：<br />
A.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 第1、2、3个数据包是TCP连接的三次握手数据包，连接的双方是本机与域名ns1.colasoft.com对应的IP地址；<br />
B.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 从第4个数据包开始，客户端开始通过TCP协议连接SMTP服务器，并与SMTP服务器进行命令的交互，及邮件的发送，具体的交互过程详见图3以及对图3的分析。<br />
[attach]604[/attach]&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>&nbsp;</p>
<p>科来网络分析系统5.0对上面发送邮件操作的TCP原始数据流重组信息。具体分析数据流重组信息，可以得到上面发送邮件操作的详细过程如下：<br />
A.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 客户端使用EHLO（或HELO）命令向SMTP服务器发送HELO报文，启动邮件传输过程，并同时将客户端地址发送SMTP服务器端，此处为wangym；<br />
B.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SMTP服务器接受了客户端的连接请求，并请求输入账号和密码进行认证；<br />
C.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 客户端向服务器端传送账号和密码；<br />
D.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SMTP服务器通过验证，客户端使用MAIL命令将邮件发送者的名称传送给SMTP服务器；<br />
E.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 客户端使用RCPT命令将邮件接收者的名称传送给SMTP服务器；<br />
F.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 客户端使用DATA命令传送邮件数据给SMTP服务器；<br />
G.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 数据传送完毕后，客户端发送QUIT命令关闭连接。<br />
注意：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SMTP传输使用的是base64编码，图4中AUTH LOGIN下的&#8220;dGVzdDFAY29sYXNvZnQuY29t&#8221;是当前使用账号对应的base64编码；<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 图3所示的SMTP数据流中，客户端向SMTP服务器传送了两次发件人名称和收件人名称，可能的原因有两种：<br />
a.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 网络的延迟较大，客户端在规定时间内未收到SMTP服务器的响应，认为传送发件人名称和收件人名称的数据包丢失而进行的重传；<br />
b.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 客户端主机上的防病毒软件在邮件发送前对邮件进行的检测，如Norton Antivirus就会进行这种检测，禁用此检测功能即可避免此种情况的发生。</p>
<p><br />
2)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 接收邮件<br />
我们再使用科来网络分析系统5.0捕获并分析一个使用POP3协议的接收邮件过程，客户端主机名为&#8220;wangym&#8221;，客户端用户代理使用Foxmail 5.0 beta2，邮件接收者test2@colasoft.com。<br />
在客户端主机上打开科来网络分析系统5.0。与上面相同，设定一个过滤器，只捕获本机的数据通讯，选择高级分析模块，在邮件分析模块的常规设置中，将保存邮件选择为&#8220;是&#8221;，并选择好邮件的保存位置，如图1所示。<br />
在科来网络分析系统5.0中开始数据捕获，同时在Foxmail中选中test2@colasoft.com，并收取邮件。接收完成后即可在科来网络分析系统5.0对刚才的邮件接收操作进行分析（为避免数据包干扰，分析时可停止捕获。）。<br />
注意：此文里提到的接收邮件均指使用TCP 110端口的标准POP3通信，对于非110端口的邮件发送，用户可在&#8220;工程-&gt;高级分析模块-&gt;邮件分析模块-&gt;SMTP设置-&gt;POP3端口&#8221;处进行更改，系统默认为110，当SMTP服务器有多个端口时，多个端口之间用分号分隔，如110;1110。</p>
<p>科来网络分析系统5.0对上面接收邮件操作的报文跟踪。　<br />
A.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1、2、3数据包是TCP连接的三次握手数据包，连接的双方是本机与域名ns1.colasoft.com对应的IP地址；<br />
B.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 从第4个数据包开始，客户端开始通过TCP协议连接POP3服务器，并与POP3服务器进行命令的交互，及邮件的接收，具体的交互过程详见图4以及对图4的分析。</p>
<p><br />
科来网络分析系统5.0对上面接收邮件操作的TCP原始数据流重组信息。具体分析其数据流重组信息，可以得到上面接收邮件操作的详细过程：<br />
A.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 客户端使用USER命令向POP3服务器传送用户账号test2@colasoft.com；<br />
B.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 客户端使用PASS命令向POP3服务器传送用户密码1234567890；<br />
C.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; POP3服务器通过验证，向客户端发送一个OK报文；<br />
D.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 客户端使用STAT命令请求POP3服务器返回邮箱的统计资料信息，POP3服务器返回当前有一封邮件；<br />
E.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 客户端使用LIST命令列出POP3服务器里的邮件数量，当前为1封邮件；<br />
F.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 客户端使用RETR命令接收邮件，接收后使用DELE命令将邮件POP3服务器中的邮件置为删除状态；<br />
G.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 客户端发送QUIT命令，邮件服务器将将置为删除标志的邮件删除，连接结束。<br />
注意：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; POP3直接使用明文传输；<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 直接重组出了接收到的邮件内容，此信息不经过任何编码或加密处理，直接为明文方式，与图1所示的邮件原始信息一致。</p>
<p><br />
3)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SMTP/POP3命令码<br />
通过SMTP/POP3协议进行邮件收发操作时，均通过不同的命令码进行不同的操作，现将其命令码总结如下：<br />
SMTP命令如表1所示：<br />
命令&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 作用<br />
HELO&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 客户端发送此命令与SMTP服务器建立连接，将发送者邮件地址发送给SMTP服务器<br />
MAIL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 客户端将邮件发送者的名称传送给SMTP服务器<br />
RCPT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 客户端将邮件接收者的名称传送给SMTP服务器<br />
DATA&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 客户端将邮件报文内容传送给SMTP服务器<br />
SEND&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用于向指定用户传送邮件<br />
SAML/SOML&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用于发送邮件<br />
RSET&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 取消客户端与SMTP服务器间的当前事务，释放与当前事务相关的内存<br />
EXPN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 标识邮件接收者列表<br />
QUIT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 终止客户端与SMTP服务器间的连接</p>
<p><br />
POP3命令如表2所示：<br />
命令&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 作用<br />
USER&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 客户端向POP3服务器传送账号<br />
PASS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 客户端向POP3服务器传送密码<br />
STAT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 客户端请求POP3服务器返回邮箱的统计信息<br />
UIDL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 客户端请求POP3服务器返回邮件的唯一标识符 <br />
LIST&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 客户端请求POP3服务器返回邮件数量和每封邮件的大小<br />
RETR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 客户端请求POP3服务器返回由参数标识的邮件的全部文本<br />
DELE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; POP3服务器将由参数标识的邮件标记为删除<br />
RSET&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; POP3服务器重置所有标记为删除的邮件，用于撤消DELE命令<br />
NOOP&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; POP3服务器返回一个肯定的响应<br />
QUIT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 终止客户端POP3服务器间的连接</p>
<p><br />
三、&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 总结<br />
以上简单介绍了SMTP和POP3协议，并使用科来网络分析分析系统5.0跟踪分析了一个基于SMTP/POP3协议的邮件收发操作。据此，用户在遇到不能正常收发邮件（使用SMTP/POP3协议）的问题时，即可结合上述的SMTP/POP3相关知识，使用网络检测分析软件（这儿是科来网络分析系统5.0）对邮件接收和邮件发送的报文进行跟踪分析，以完成对此类故障的快速排查。</p>
<p><br />
&nbsp;</p>
<p>&nbsp;</p>
<p>本文来自CSDN博客，转载请标明出处：http://blog.csdn.net/hyde82/archive/2007/06/13/1650581.aspx</p>
<img src ="http://www.blogjava.net/titanaly/aggbug/280152.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/titanaly/" target="_blank">不高兴</a> 2009-06-05 09:42 <a href="http://www.blogjava.net/titanaly/archive/2009/06/05/280152.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>『转』【Java】java.net.HttpURLConnection的使用</title><link>http://www.blogjava.net/titanaly/archive/2009/06/05/280150.html</link><dc:creator>不高兴</dc:creator><author>不高兴</author><pubDate>Fri, 05 Jun 2009 01:33:00 GMT</pubDate><guid>http://www.blogjava.net/titanaly/archive/2009/06/05/280150.html</guid><wfw:comment>http://www.blogjava.net/titanaly/comments/280150.html</wfw:comment><comments>http://www.blogjava.net/titanaly/archive/2009/06/05/280150.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/titanaly/comments/commentRss/280150.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/titanaly/services/trackbacks/280150.html</trackback:ping><description><![CDATA[<p>1.网页内容获取 <br />
java.io.inputstream in; <br />
java.net.url url = new java.net.url(www.xyz.com/content.html); <br />
java.net.httpurlconnection connection = (java.net.httpurlconnection) <br />
url.openconnection(); <br />
connection = (java.net.httpurlconnection) url.openconnection(); <br />
//模拟成ie <br />
connection.setrequestproperty("user-agent","mozilla/4.0 (compatible; msie 6.0; windows 2000)"); <br />
connection.connect(); <br />
in = connection.getinputstream(); <br />
java.io.bufferedreader breader = <br />
new bufferedreader(new inputstreamreader(in , "gbk")); <br />
string str=breader.readline()); <br />
while(st != null){ <br />
system.out.println(str); <br />
str=breader.readline()); <br />
} <br />
2.cookie管理 </p>
<p>1.直接的方式 <br />
取得cookie： <br />
httpurlconnection huc= (httpurlconnection) url.openconnection(); <br />
inputstream is = huc.getinputstream(); <br />
// 取得sessionid. <br />
string cookieval = hc.getheaderfield("set-cookie"); <br />
string sessionid; <br />
if(cookieval != null) <br />
{ <br />
sessionid = cookieval.substring(0, cookieval.indexof(";")); <br />
} </p>
<p>发送设置cookie： <br />
httpurlconnection huc= (httpurlconnection) url.openconnection(); <br />
if(sessionid != null) <br />
{ <br />
huc.setrequestproperty("cookie", sessionid); <br />
} <br />
inputstream is = huc.getinputstream(); </p>
<p>&nbsp;</p>
<p>2.利用的jcookie包(http://jcookie.sourceforge.net/ ) <br />
获取cookie: <br />
url url = new url("http://www.site.com/"); <br />
httpurlconnection huc = (httpurlconnection) url.openconnection(); <br />
huc.connect(); <br />
inputstream is = huc.getinputstream(); <br />
client client = new client(); <br />
cookiejar cj = client.getcookies(huc); </p>
<p><br />
新的请求,利用上面获取的cookie: </p>
<p>url = new url("http://www.site.com/"); <br />
huc = (httpurlconnection) url.openconnection(); <br />
client.setcookies(huc, cj); </p>
<p><br />
3.post方式的模拟 <br />
url url = new url("www.xyz.com"); <br />
httpurlconnection huc = (httpurlconnection) url.openconnection(); <br />
//设置允许output <br />
huc.setdooutput(true); <br />
//设置为post方式 <br />
huc.setrequestmethod("post"); <br />
huc.setrequestproperty("user-agent","mozilla/4.7 [en] (win98; i)"); <br />
stringbuffer sb = new stringbuffer(); <br />
sb.append("username="+usernme); <br />
sb.append("&amp;password="+password); </p>
<p>//post信息 <br />
outputstream os = huc.getoutputstream(); <br />
os.write(sb.tostring().getbytes("gbk")); <br />
os.close(); </p>
<p>bufferedreader br = new bufferedreader(new inputstreamreader(huc.getinputstream())) </p>
<p><br />
huc.connect(); </p>
<p>string line = br.readline(); </p>
<p>while(line != null){ </p>
<p>l </p>
<p>system.out.printli(line); </p>
<p><br />
line = br.readline(); </p>
<p>} </p>
<p><br />
本文来自CSDN博客，转载请标明出处：http://blog.csdn.net/hyde82/archive/2007/06/06/1640817.aspx</p>
<img src ="http://www.blogjava.net/titanaly/aggbug/280150.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/titanaly/" target="_blank">不高兴</a> 2009-06-05 09:33 <a href="http://www.blogjava.net/titanaly/archive/2009/06/05/280150.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>