﻿<?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-幸福是把温暖的枪-文章分类-java</title><link>http://www.blogjava.net/liveandletdie/category/2656.html</link><description /><language>zh-cn</language><lastBuildDate>Fri, 20 Jul 2007 17:20:00 GMT</lastBuildDate><pubDate>Fri, 20 Jul 2007 17:20:00 GMT</pubDate><ttl>60</ttl><item><title>Maven学习笔记（1.基础概念）</title><link>http://www.blogjava.net/liveandletdie/articles/130959.html</link><dc:creator>幸福是把温暖的枪</dc:creator><author>幸福是把温暖的枪</author><pubDate>Wed, 18 Jul 2007 01:37:00 GMT</pubDate><guid>http://www.blogjava.net/liveandletdie/articles/130959.html</guid><wfw:comment>http://www.blogjava.net/liveandletdie/comments/130959.html</wfw:comment><comments>http://www.blogjava.net/liveandletdie/articles/130959.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liveandletdie/comments/commentRss/130959.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liveandletdie/services/trackbacks/130959.html</trackback:ping><description><![CDATA[Maven的核心概念是POM，project object model，一个最简单的POM文件如下所示<br>&lt;project xmlns="<a href="http://maven.apache.org/POM/4.0.0">http://maven.apache.org/POM/4.0.0</a>" xmlns:xsi="<a href="http://www.w3.org/2001/XMLSchema-instance">http://www.w3.org/2001/XMLSchema-instance</a>"<br>&nbsp; xsi:schemaLocation="<a href="http://maven.apache.org/POM/4.0.0">http://maven.apache.org/POM/4.0.0</a> <a href="http://maven.apache.org/maven-v4_0_0.xsd">http://maven.apache.org/maven-v4_0_0.xsd</a>"&gt;<br>&nbsp; &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;<br>&nbsp; &lt;groupId&gt;net.blogjava.prometheus&lt;/groupId&gt;<br>&nbsp; &lt;artifactId&gt;prometheus&lt;/artifactId&gt;<br>&nbsp; &lt;packaging&gt;jar&lt;/packaging&gt;<br>&nbsp; &lt;version&gt;1.0-SNAPSHOT&lt;/version&gt;<br>&nbsp; &lt;name&gt;prometheus&lt;/name&gt;<br>&nbsp; &lt;url&gt;http://maven.apache.org&lt;/url&gt;<br>&nbsp; &lt;dependencies&gt;<br>&nbsp;&nbsp;&nbsp; &lt;dependency&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;groupId&gt;junit&lt;/groupId&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;artifactId&gt;junit&lt;/artifactId&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;version&gt;3.8.1&lt;/version&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;scope&gt;test&lt;/scope&gt;<br>&nbsp;&nbsp;&nbsp; &lt;/dependency&gt;<br>&nbsp; &lt;/dependencies&gt;<br>&lt;/project&gt;<br>project：pom.xml的顶级元素<br>modelVersion：指明了POM正在使用的对象模型的版本。这个版本号极少改变。<br>groupId：指明了创建工程者的唯一标识符。一般来说基于工程创建者的域名，例如net.blogjava.prometheus。<br>artifactId：指明了工程生成的artifact的唯一基础名称，Maven最后产生的artifact是这样一个格式：&lt;artifactId&gt;&lt;version&gt;.&lt;extension&gt;，比如prometheus-1.0-SNAPSHOT.jar。<br>packaging：指明了当前artifact打包的格式（war，jar，ear等）<br>version：指明了工程产生的artifact的版本。SNAPSHOT表明当前版本正处于开发状态。<br>name：指明了工程的显示名称。<br>url：指明了工程的web site位于何处。<br><br><br>
<img src ="http://www.blogjava.net/liveandletdie/aggbug/130959.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liveandletdie/" target="_blank">幸福是把温暖的枪</a> 2007-07-18 09:37 <a href="http://www.blogjava.net/liveandletdie/articles/130959.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>常用正则表达式（摘录）</title><link>http://www.blogjava.net/liveandletdie/articles/59242.html</link><dc:creator>幸福是把温暖的枪</dc:creator><author>幸福是把温暖的枪</author><pubDate>Thu, 20 Jul 2006 09:21:00 GMT</pubDate><guid>http://www.blogjava.net/liveandletdie/articles/59242.html</guid><wfw:comment>http://www.blogjava.net/liveandletdie/comments/59242.html</wfw:comment><comments>http://www.blogjava.net/liveandletdie/articles/59242.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liveandletdie/comments/commentRss/59242.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liveandletdie/services/trackbacks/59242.html</trackback:ping><description><![CDATA[
		<p>匹配中文字符的正则表达式： [\u4e00-\u9fa5]</p>
		<p>匹配双字节字符(包括汉字在内)：[^\x00-\xff]</p>
		<p>匹配空行的正则表达式：\n[\s| ]*\r</p>
		<p>匹配HTML标记的正则表达式：/&lt;(.*)&gt;.*&lt;\/\1&gt;|&lt;(.*) \/&gt;/ </p>
		<p>匹配首尾空格的正则表达式：(^\s*)|(\s*$)</p>
		<p>匹配IP地址的正则表达式：(\d+)\.(\d+)\.(\d+)\.(\d+)/ <br /><br />匹配Email地址的正则表达式：\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*</p>
		<p>匹配网址URL的正则表达式：http://([\w-]+\.)+[\w-]+(/[\w- ./?%&amp;=]*)?</p>
<img src ="http://www.blogjava.net/liveandletdie/aggbug/59242.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liveandletdie/" target="_blank">幸福是把温暖的枪</a> 2006-07-20 17:21 <a href="http://www.blogjava.net/liveandletdie/articles/59242.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>cronExpression的说明(摘自http://www.opensymphony.com)</title><link>http://www.blogjava.net/liveandletdie/articles/42100.html</link><dc:creator>幸福是把温暖的枪</dc:creator><author>幸福是把温暖的枪</author><pubDate>Thu, 20 Apr 2006 02:32:00 GMT</pubDate><guid>http://www.blogjava.net/liveandletdie/articles/42100.html</guid><wfw:comment>http://www.blogjava.net/liveandletdie/comments/42100.html</wfw:comment><comments>http://www.blogjava.net/liveandletdie/articles/42100.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liveandletdie/comments/commentRss/42100.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liveandletdie/services/trackbacks/42100.html</trackback:ping><description><![CDATA[
		<p>Cron expressions are comprised of 6 required fields and one optional field separated by white space. The fields respectively are described as follows: </p>
		<table cellspacing="8">
				<tbody>
						<tr>
								<th align="left">Field Name</th>
								<th align="left"> </th>
								<th align="left">Allowed Values</th>
								<th align="left"> </th>
								<th align="left">Allowed Special Characters</th>
						</tr>
						<tr>
								<td align="left">
										<code>Seconds</code>
								</td>
								<td align="left"> </td>
								<td align="left">
										<code>0-59</code>
								</td>
								<td align="left"> </td>
								<td align="left">
										<code>, - * /</code>
								</td>
						</tr>
						<tr>
								<td align="left">
										<code>Minutes</code>
								</td>
								<td align="left"> </td>
								<td align="left">
										<code>0-59</code>
								</td>
								<td align="left"> </td>
								<td align="left">
										<code>, - * /</code>
								</td>
						</tr>
						<tr>
								<td align="left">
										<code>Hours</code>
								</td>
								<td align="left"> </td>
								<td align="left">
										<code>0-23</code>
								</td>
								<td align="left"> </td>
								<td align="left">
										<code>, - * /</code>
								</td>
						</tr>
						<tr>
								<td align="left">
										<code>Day-of-month</code>
								</td>
								<td align="left"> </td>
								<td align="left">
										<code>1-31</code>
								</td>
								<td align="left"> </td>
								<td align="left">
										<code>, - * ? / L W C</code>
								</td>
						</tr>
						<tr>
								<td align="left">
										<code>Month</code>
								</td>
								<td align="left"> </td>
								<td align="left">
										<code>1-12 or JAN-DEC</code>
								</td>
								<td align="left"> </td>
								<td align="left">
										<code>, - * /</code>
								</td>
						</tr>
						<tr>
								<td align="left">
										<code>Day-of-Week</code>
								</td>
								<td align="left"> </td>
								<td align="left">
										<code>1-7 or SUN-SAT</code>
								</td>
								<td align="left"> </td>
								<td align="left">
										<code>, - * ? / L #</code>
								</td>
						</tr>
						<tr>
								<td align="left">
										<code>Year (Optional)</code>
								</td>
								<td align="left"> </td>
								<td align="left">
										<code>empty, 1970-2099</code>
								</td>
								<td align="left"> </td>
								<td align="left">
										<code>, - * /</code>
								</td>
						</tr>
				</tbody>
		</table>
		<p>The '*' character is used to specify all values. For example, "*" in the minute field means "every minute". </p>
		<p>The '?' character is allowed for the day-of-month and day-of-week fields. It is used to specify 'no specific value'. This is useful when you need to specify something in one of the two fileds, but not the other. </p>
		<p>The '-' character is used to specify ranges For example "10-12" in the hour field means "the hours 10, 11 and 12". </p>
		<p>The ',' character is used to specify additional values. For example "MON,WED,FRI" in the day-of-week field means "the days Monday, Wednesday, and Friday". </p>
		<p>The '/' character is used to specify increments. For example "0/15" in the seconds field means "the seconds 0, 15, 30, and 45". And "5/15" in the seconds field means "the seconds 5, 20, 35, and 50". Specifying '*' before the '/' is equivalent to specifying 0 is the value to start with. Essentially, for each field in the expression, there is a set of numbers that can be turned on or off. For seconds and minutes, the numbers range from 0 to 59. For hours 0 to 23, for days of the month 0 to 31, and for months 1 to 12. The "/" character simply helps you turn on every "nth" value in the given set. Thus "7/6" in the month field only turns on month "7", it does NOT mean every 6th month, please note that subtlety. </p>
		<p>The 'L' character is allowed for the day-of-month and day-of-week fields. This character is short-hand for "last", but it has different meaning in each of the two fields. For example, the value "L" in the day-of-month field means "the last day of the month" - day 31 for January, day 28 for February on non-leap years. If used in the day-of-week field by itself, it simply means "7" or "SAT". But if used in the day-of-week field after another value, it means "the last xxx day of the month" - for example "6L" means "the last friday of the month". When using the 'L' option, it is important not to specify lists, or ranges of values, as you'll get confusing results. </p>
		<p>The 'W' character is allowed for the day-of-month field. This character is used to specify the weekday (Monday-Friday) nearest the given day. As an example, if you were to specify "15W" as the value for the day-of-month field, the meaning is: "the nearest weekday to the 15th of the month". So if the 15th is a Saturday, the trigger will fire on Friday the 14th. If the 15th is a Sunday, the trigger will fire on Monday the 16th. If the 15th is a Tuesday, then it will fire on Tuesday the 15th. However if you specify "1W" as the value for day-of-month, and the 1st is a Saturday, the trigger will fire on Monday the 3rd, as it will not 'jump' over the boundary of a month's days. The 'W' character can only be specified when the day-of-month is a single day, not a range or list of days. </p>
		<p>The 'L' and 'W' characters can also be combined for the day-of-month expression to yield 'LW', which translates to "last weekday of the month". </p>
		<p>The '#' character is allowed for the day-of-week field. This character is used to specify "the nth" XXX day of the month. For example, the value of "6#3" in the day-of-week field means the third Friday of the month (day 6 = Friday and "#3" = the 3rd one in the month). Other examples: "2#1" = the first Monday of the month and "4#5" = the fifth Wednesday of the month. Note that if you specify "#5" and there is not 5 of the given day-of-week in the month, then no firing will occur that month. </p>
		<p>
				<!--The 'C' character is allowed for the day-of-month and day-of-week fields.
 This character is short-hand for "calendar". This means values are
 calculated against the associated calendar, if any. If no calendar is
 associated, then it is equivalent to having an all-inclusive calendar. A
 value of "5C" in the day-of-month field means "the first day included by the
 calendar on or after the 5th". A value of "1C" in the day-of-week field
 means "the first day included by the calendar on or after sunday".-->
		</p>
		<p>The legal characters and the names of months and days of the week are not case sensitive. </p>
<img src ="http://www.blogjava.net/liveandletdie/aggbug/42100.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liveandletdie/" target="_blank">幸福是把温暖的枪</a> 2006-04-20 10:32 <a href="http://www.blogjava.net/liveandletdie/articles/42100.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>href中target属性的用法（摘录自http://www.zhcfw.com/new/List.Asp?ListID=752）</title><link>http://www.blogjava.net/liveandletdie/articles/39414.html</link><dc:creator>幸福是把温暖的枪</dc:creator><author>幸福是把温暖的枪</author><pubDate>Wed, 05 Apr 2006 08:22:00 GMT</pubDate><guid>http://www.blogjava.net/liveandletdie/articles/39414.html</guid><wfw:comment>http://www.blogjava.net/liveandletdie/comments/39414.html</wfw:comment><comments>http://www.blogjava.net/liveandletdie/articles/39414.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/liveandletdie/comments/commentRss/39414.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liveandletdie/services/trackbacks/39414.html</trackback:ping><description><![CDATA[target属性<br /><br />　　这个属性指定所链接的页面在浏览器窗口中的打开方式，它的参数值主要有：_blank、_parent、_self、_top，这些参数值代表的含义如下：<br /><br />　　◎_blank，在新浏览器窗口中打开链接文件。<br /><br />　　◎_parent，将链接的文件载入含有该链接框架的父框架集或父窗口中。如果含有该链接的框架不是嵌套的，则在浏览器全屏窗口中载入链接的文件，就象_self参数一样。<br /><br />　　◎_self，在同一框架或窗口中打开所链接的文档。此参数为默认值，通常不用指定。<br /><br />　　◎_top，在当前的整个浏览器窗口中打开所链接的文档，因而会删除所有框架。<br /><img src ="http://www.blogjava.net/liveandletdie/aggbug/39414.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liveandletdie/" target="_blank">幸福是把温暖的枪</a> 2006-04-05 16:22 <a href="http://www.blogjava.net/liveandletdie/articles/39414.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>hibernate学习笔记－－－（入门）</title><link>http://www.blogjava.net/liveandletdie/articles/33230.html</link><dc:creator>幸福是把温暖的枪</dc:creator><author>幸福是把温暖的枪</author><pubDate>Thu, 02 Mar 2006 07:49:00 GMT</pubDate><guid>http://www.blogjava.net/liveandletdie/articles/33230.html</guid><wfw:comment>http://www.blogjava.net/liveandletdie/comments/33230.html</wfw:comment><comments>http://www.blogjava.net/liveandletdie/articles/33230.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liveandletdie/comments/commentRss/33230.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liveandletdie/services/trackbacks/33230.html</trackback:ping><description><![CDATA[unsaved-value<BR><BR>Hibernate提供了saveOrUpdate()方法，在定义映射文件时，可以通过设定&lt;id&gt;标签的unsaved-value来决定更新方式<BR><BR>unsaved-value取值范围为： <BR>*any -&nbsp;总是存储 <BR>*none -&nbsp;总是更新 <BR>*null - id为null的时候存储（缺省） <BR>*valid - id为null或者是指定值的时候存储 <img src ="http://www.blogjava.net/liveandletdie/aggbug/33230.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liveandletdie/" target="_blank">幸福是把温暖的枪</a> 2006-03-02 15:49 <a href="http://www.blogjava.net/liveandletdie/articles/33230.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>XPATH学习笔记</title><link>http://www.blogjava.net/liveandletdie/articles/19804.html</link><dc:creator>幸福是把温暖的枪</dc:creator><author>幸福是把温暖的枪</author><pubDate>Tue, 15 Nov 2005 02:11:00 GMT</pubDate><guid>http://www.blogjava.net/liveandletdie/articles/19804.html</guid><wfw:comment>http://www.blogjava.net/liveandletdie/comments/19804.html</wfw:comment><comments>http://www.blogjava.net/liveandletdie/articles/19804.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liveandletdie/comments/commentRss/19804.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liveandletdie/services/trackbacks/19804.html</trackback:ping><description><![CDATA[XPath的基本语法由表达式构成。在计算表达式的值之后产生一个对象，对象有以下四种基本类型：节点集合、布尔型、数字型和字符串型<BR><BR>/代表根目录<BR><BR>/node 代表根目录下名称为node的子节点<BR><BR>//* 代表所有元素<BR><BR>//parent/child 代表所有本身为child父亲为parent的元素<BR><BR>/node/*&nbsp; 根目录下node节点的所有子元素<BR><BR>/*/*/node 第三层的节点,名称必须为node<BR><BR>[]代表元素的顺序,@代表属性<BR><BR>//node[@*] 选择node元素,有任意属性<BR><BR>//node[@name] 选择具有name属性的node<BR><BR>//*[@name="abc"] 所有元素中name属性等于abc的<BR><BR>引用:Ancestor表示当前节点的所有祖先节点，所以不仅包括该元素的直接父节点，还包括父节点的父节点等<BR><BR>等。用一棵树表示节点层次关系的话，所有该节点的上层都叫做Ancestor。例子：//足球网站/ancestor::*就<BR><BR>表示所有足球网站元素的祖先节点<BR><BR><BR><img src ="http://www.blogjava.net/liveandletdie/aggbug/19804.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liveandletdie/" target="_blank">幸福是把温暖的枪</a> 2005-11-15 10:11 <a href="http://www.blogjava.net/liveandletdie/articles/19804.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java类加载内幕(转载自matrix)</title><link>http://www.blogjava.net/liveandletdie/articles/18110.html</link><dc:creator>幸福是把温暖的枪</dc:creator><author>幸福是把温暖的枪</author><pubDate>Fri, 04 Nov 2005 03:53:00 GMT</pubDate><guid>http://www.blogjava.net/liveandletdie/articles/18110.html</guid><wfw:comment>http://www.blogjava.net/liveandletdie/comments/18110.html</wfw:comment><comments>http://www.blogjava.net/liveandletdie/articles/18110.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liveandletdie/comments/commentRss/18110.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liveandletdie/services/trackbacks/18110.html</trackback:ping><description><![CDATA[<CENTER><B><SPAN style="FONT-SIZE: 20px">Java类加载内幕</SPAN></B></CENTER><BR>
<CENTER>作者：Binildas Christudas 01/26/2005</CENTER><BR>
<CENTER>翻译：<A href="http://www.matrix.org.cn/user.shtml?username=purplerain" target=_new>purplerain</A></CENTER><BR><BR><SPAN style="COLOR: purple">版权声明</SPAN>：可以任意转载，转载时请务必以超链接形式标明文章原始出处和作者信息及本声明<BR>作者:<BR>Binildas;<A href="http://www.matrix.org.cn/user.shtml?username=purplerain" target=_new>purplerain</A><BR>原文地址:<A href="http://www.onjava.com/pub/a/onjava/2005/01/26/classloading.html" target=_new>http://www.onjava.com/pub/a/onjava/2005/01/26/classloading.html</A><BR>中文地址:<BR><A href="http://www.matrix.org.cn/resource/article/43/43875_Class_Loading.html" target=_new>http://www.matrix.org.cn/resource/article/43/43875_Class_Loading.html</A><BR>关键词： Java Class Loading<BR><BR><BR>类加载是java语言提供的最强大的机制之一。尽管类加载并不是讨论的热点话题，但所有的编程人员都应该了解其工作机制，明白如何做才能让其满足我们的需要。这能有效节省我们的编码时间，从不断调试ClassNotFoundException, ClassCastException的工作中解脱出来。<BR><BR>这篇文章从基础讲起，比如代码与数据的不同之处是什么，他们是如何构成一个实例或对象的。然后深入探讨java虚拟机（JVM）是如何利用类加载器读取代码，以及java中类加载器的主要类型。接着用一个类加载的基本算法看一下类加载器如何加载一个内部类。本文的下一节演示一段代码来说明扩展和开发属于自己的类加载器的必要性。紧接着解释如何使用定制的类加载器来完成一个一般意义上的任务，使其可以加载任意远端客户的代码，在JVM中定义，实例化并执行它。本文包括了J2EE关于类加载的规范——事实上这已经成为了J2EE的标准之一。<BR><BR><B><SPAN style="FONT-SIZE: 16px">类与数据</SPAN></B><BR>一个类代表要执行的代码，而数据则表示其相关状态。状态时常改变，而代码则不会。当我们将一个特定的状态与一个类相对应起来，也就意味着将一个类事例化。尽管相同的类对应的实例其状态千差万别，但其本质都对应着同一段代码。在JAVA中，一个类通常有着一个.class文件，但也有例外。在JAVA的运行时环境中（Java runtime），每一个类都有一个以第一类(first-class)的Java对象所表现出现的代码，其是java.lang.Class的实例。我们编译一个JAVA文件，编译器都会嵌入一个public, static, final修饰的类型为java.lang.Class，名称为class的域变量在其字节码文件中。因为使用了public修饰，我们可以采用如下的形式对其访问：<BR><BR><PRE class=overflow title="pre code">java.lang.Class klass = Myclass.class;</PRE><BR><BR>一旦一个类被载入JVM中，同一个类就不会被再次载入了（切记，同一个类）。这里存在一个问题就是什么是“同一个类”？正如一个对象有一个具体的状态，即标识，一个对象始终和其代码(类)相关联。同理，载入JVM的类也有一个具体的标识，我们接下来看。<BR><BR>在JAVA中，一个类用其完全匹配类名(fully qualified class name)作为标识，这里指的完全匹配类名包括包名和类名。但在JVM中一个类用其全名和一个加载类ClassLoader的实例作为唯一标识。因此，如果一个名为Pg的包中，有一个名为Cl的类，被类加载器KlassLoader的一个实例kl1加载，Cl的实例，即C1.class在JVM中表示为(Cl, Pg, kl1)。这意味着两个类加载器的实例(Cl, Pg, kl1) 和 (Cl, Pg, kl2)是不同的，被它们所加载的类也因此完全不同，互不兼容的。那么在JVM中到底有多少种类加载器的实例？下一节我们揭示答案。<BR><BR><B><SPAN style="FONT-SIZE: 16px">类加载器</SPAN></B><BR><BR>在JVM中，每一个类都被java.lang.ClassLoader的一些实例来加载.类ClassLoader是在包中java.lang里，开发者可以自由地继承它并添加自己的功能来加载类。<BR><BR>无论何时我们键入java MyMainClass来开始运行一个新的JVM，“引导类加载器(bootstrap class loader)”负责将一些关键的Java类，如java.lang.Object和其他一些运行时代码先加载进内存中。运行时的类在JRE\lib\rt.jar包文件中。因为这属于系统底层执行动作，我们无法在JAVA文档中找到引导类加载器的工作细节。基于同样的原因，引导类加载器的行为在各JVM之间也是大相径庭。<BR>同理，如果我们按照如下方式：<BR><BR><PRE class=overflow title="pre code">log(java.lang.String.class.getClassLoader());</PRE><BR><BR>来获取java的核心运行时类的加载器，就会得到null。<BR><BR>接下来介绍java的扩展类加载器。扩展库提供比java运行代码更多的特性，我们可以把扩展库保存在由java.ext.dirs属性提供的路径中。<BR><BR>(编辑注：java.ext.dirs属性指的是系统属性下的一个key，所有的系统属性可以通过System.getProperties()方法获得。在编者的系统中，java.ext.dirs的value是” C:\Program Files\Java\jdk1.5.0_04\jre\lib\ext”。下面将要谈到的如java.class.path也同属系统属性的一个key。)<BR><BR>类ExtClassLoader专门用来加载所有java.ext.dirs下的.jar文件。开发者可以通过把自己的.jar文件或库文件加入到扩展目录的classpath，使其可以被扩展类加载器读取。<BR><BR>从开发者的角度，第三种同样也是最重要的一种类加载器是AppClassLoader。这种类加载器用来读取所有的对应在java.class.path系统属性的路径下的类。<BR><BR>Sun的java指南中，文章“理解扩展类加载”（Understanding Extension Class Loading）对以上三个类加载器路径有更详尽的解释，这是其他几个JDK中的类加载器<BR>●java.net.URLClassLoader <BR>●java.security.SecureClassLoader <BR>●java.rmi.server.RMIClassLoader <BR>●sun.applet.AppletClassLoader <BR><BR>java.lang.Thread，包含了public ClassLoader getContextClassLoader()方法，这一方法返回针对一具体线程的上下文环境类加载器。此类加载器由线程的创建者提供，以供此线程中运行的代码在需要加载类或资源时使用。如果此加载器未被建立，缺省是其父线程的上下文类加载器。原始的类加载器一般由读取应用程序的类加载器建立。<BR><BR><B><SPAN style="FONT-SIZE: 16px">类加载器如何工作？</SPAN></B><BR>除了引导类加载器，所有的类加载器都有一个父类加载器，不仅如此，所有的类加载器也都是java.lang.ClassLoader类型。以上两种类加载器是不同的，而且对于开发者自订制的类加载器的正常运行也至关重要。最重要的方面是正确设置父类加载器。任何类加载器，其父类加载器是加载该类加载器的类加载器实例。（记住，类加载器本身也是一个类！）<BR><BR>使用loadClass()方法可以从类加载器中获得该类。我们可以通过java.lang.ClassLoader的源代码来了解该方法工作的细节，如下：<BR><BR><PRE class=overflow title="pre code">protected synchronized Class&lt;?&gt; loadClass<BR>&nbsp;&nbsp;&nbsp;&nbsp;(String name, boolean resolve)<BR>&nbsp;&nbsp;&nbsp;&nbsp;throws ClassNotFoundException{<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;// First check if the class is already loaded<BR>&nbsp;&nbsp;&nbsp;&nbsp;Class c = findLoadedClass(name);<BR>&nbsp;&nbsp;&nbsp;&nbsp;if (c == null) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (parent != null) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c = parent.loadClass(name, false);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} else {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c = findBootstrapClass0(name);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} catch (ClassNotFoundException e) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// If still not found, then invoke<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// findClass to find the class.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c = findClass(name);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;if (resolve) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;resolveClass(c);<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;return c;<BR>}</PRE><BR><BR>我们可以使用ClassLoader的两种构造方法来设置父类加载器：<BR><BR><PRE class=overflow title="pre code">public class MyClassLoader extends ClassLoader{<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;public MyClassLoader(){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;super(MyClassLoader.class.getClassLoader());<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR>}</PRE><BR><BR>或<BR><BR><PRE class=overflow title="pre code">public class MyClassLoader extends ClassLoader{<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;public MyClassLoader(){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;super(getClass().getClassLoader());<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR>}</PRE><BR><BR>第一种方式较为常用，因为通常不建议在构造方法里调用getClass()方法，因为对象的初始化只是在构造方法的出口处才完全完成。因此，如果父类加载器被正确建立，当要示从一个类加载器的实例获得一个类时，如果它不能找到这个类，它应该首先去访问其父类。如果父类不能找到它(即其父类也不能找不这个类，等等)，而且如果findBootstrapClass0()方法也失败了，则调用findClass()方法。findClass()方法的缺省实现会抛出ClassNotFoundException，当它们继承java.lang.ClassLoader来订制类加载器时开发者需要实现这个方法。findClass()的缺省实现方式如下：<BR><BR><PRE class=overflow title="pre code">&nbsp;&nbsp;&nbsp;&nbsp;protected Class&lt;?&gt; findClass(String name)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throws ClassNotFoundException {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw new ClassNotFoundException(name);<BR>&nbsp;&nbsp;&nbsp;&nbsp;}</PRE><BR><BR>在findClass()方法内部，类加载器需要获取任意来源的字节码。来源可以是文件系统，URL，数据库，可以产生字节码的另一个应用程序，及其他类似的可以产生java规范的字节码的来源。你甚至可以使用BCEL (Byte Code Engineering Library：字节码工程库)，它提供了运行时创建类的捷径。BCEL已经被成功地使用在以下方面：编译器，优化器，混淆器，代码产生器及其他分析工具。一旦字节码被检索，此方法就会调用defineClass()方法，此行为对不同的类加载实例是有差异的。因此，如果两个类加载实例从同一个来源定义一个类，所定义的结果是不同的。<BR><BR>JAVA语言规范（Java language specification）详细解释了JAVA执行引擎中的类或接口的加载（loading），链接（linking）或初始化（initialization）过程。<BR><BR>图一显示了一个主类称为MyMainClass的应用程序。依照之前的阐述，MyMainClass.class会被AppClassLoader加载。 MyMainClass创建了两个类加载器的实例：CustomClassLoader1 和 CustomClassLoader2,他们可以从某数据源（比如网络）获取名为Target的字节码。这表示类Target的类定义不在应用程序类路径或扩展类路径。在这种情况下，如果MyMainClass想要用自定义的类加载器加载Target类，CustomClassLoader1和CustomClassLoader2会分别独立地加载并定义Target.class类。这在java中有重要的意义。如果Target类有一些静态的初始化代码，并且假设我们只希望这些代码在JVM中只执行一次，而这些代码在我们目前的步骤中会执行两次——分别被不同的CustomClassLoaders加载并执行。如果类Target被两个CustomClassLoaders加载并创建两个实例Target1和Target2，如图一显示，它们不是类型兼容的。换句话说，在JVM中无法执行以下代码：<BR><BR><PRE class=overflow title="pre code">Target target3 = (Target) target2;</PRE><BR><BR>以上代码会抛出一个ClassCastException。这是因为JVM把他们视为分别不同的类，因为他们被不同的类加载器所定义。这种情况当我们不是使用两个不同的类加载器CustomClassLoader1 和 CustomClassLoader2，而是使用同一个类加载器CustomClassLoader的不同实例时，也会出现同样的错误。这些会在本文后边用具体代码说明。<BR><BR><IMG onmouseover=javascript:ImgShowTip(this); style="DISPLAY: inline" onclick=javascript:ImgClick(this); height=450 alt=image src="http://www.matrix.org.cn/resource/upload/forum/2005_10_19_004045_OIMbZSVwPg.jpg" width=356 onload=javascript:ImgLoad(this); border=0 resized="1"><BR>图1. 在同一个JVM中多个类加载器加载同一个目标类<BR><BR>关于类加载、定义和链接的更多解释，请参考Andreas Schaefer的"Inside Class Loaders."<BR><BR><B><SPAN style="FONT-SIZE: 16px">为什么我们需要我们自己的类加载器</SPAN></B><BR>原因之一为开发者写自己的类加载器来控制JVM中的类加载行为，java中的类靠其包名和类名来标识，对于实现了java.io.Serializable接口的类，serialVersionUID扮演了一个标识类版本的重要角色。这个唯一标识是一个类名、接口名、成员方法及属性等组成的一个64位的哈希字段，而且也没有其他快捷的方式来标识一个类的版本。严格说来，如果以上的都匹配，那么则属于同一个类。<BR><BR>但是让我们思考如下情况：我们需要开发一个通用的执行引擎。可以执行实现某一特定接口的任何任务。当任务被提交到这个引擎，首先需要加载这个任务的代码。假设不同的客户对此引擎提交了不同的任务，凑巧，这些所有的任务都有一个相同的类名和包名。现在面临的问题就是这个引擎是否可以针对不同的用户所提交的信息而做出不同的反应。这一情况在下文的参考一节有可供下载的代码样例，samepath 和 differentversions，这两个目录分别演示了这一概念。<BR><BR>图2 显示了文件目录结构，有三个子目录samepath, differentversions, 和 differentversionspush，里边是例子：<BR><BR><IMG onmouseover=javascript:ImgShowTip(this); style="DISPLAY: inline" onclick=javascript:ImgClick(this); height=450 alt=image src="http://www.matrix.org.cn/resource/upload/forum/2005_10_19_004130_ogkBYMcMCh.jpg" width=435 onload=javascript:ImgLoad(this); border=0 resized="1"><BR>图2. 文件夹结构组织示例<BR><BR>在samepath 中，类version.Version保存在v1和v2两个子目录里，两个类具有同样的类名和包名，唯一不同的是下边这行：<BR><BR><PRE class=overflow title="pre code">&nbsp;&nbsp;&nbsp;&nbsp;public void fx(){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log("this = " + this + "; Version.fx(1).");<BR>&nbsp;&nbsp;&nbsp;&nbsp;}</PRE><BR><BR>V1中，日志记录中有Version.fx(1)，而在v2中则是Version.fx(2)。把这个两个存在细微不同的类放在一个classpath下，然后运行Test类：<BR><BR><SPAN style="COLOR: blue">set CLASSPATH=.;%CURRENT_ROOT%\v1;%CURRENT_ROOT%\v2<BR>%JAVA_HOME%\bin\java Test</SPAN><BR><BR>图3显示了控制台输出。我们可以看到对应着Version.fx(1)的代码被执行了，因为类加载器在classpath首先看到此版本的代码。<BR><BR><IMG onmouseover=javascript:ImgShowTip(this); style="DISPLAY: inline" onclick=javascript:ImgClick(this); alt=image src="http://www.matrix.org.cn/resource/upload/forum/2005_10_19_004203_mLUCtcjlYr.jpg" onload=javascript:ImgLoad(this); border=0 resized="0"><BR>图3. 在类路径中samepath测试排在最前面的version 1<BR><BR>再次运行，类路径做如下微小改动。 <BR><BR><SPAN style="COLOR: blue">set CLASSPATH=.;%CURRENT_ROOT%\v2;%CURRENT_ROOT%\v1<BR>%JAVA_HOME%\bin\java Test</SPAN><BR><BR>控制台的输出变为图4。对应着Version.fx(2)的代码被加载，因为类加载器在classpath中首先找到它的路径。<BR><BR><IMG onmouseover=javascript:ImgShowTip(this); style="DISPLAY: inline" onclick=javascript:ImgClick(this); alt=image src="http://www.matrix.org.cn/resource/upload/forum/2005_10_19_004327_CJTHAGsqXH.jpg" onload=javascript:ImgLoad(this); border=0 resized="0"><BR>图4. 在类路径中samepath测试排在最前面的version 2<BR><BR>根据以上例子可以很明显地看出，类加载器加载在类路径中被首先找到的元素。如果我们在v1和v2中删除了version.Version，做一个非version.Version形式的.jar文件，如myextension.jar，把它放到对应java.ext.dirs的路径下，再次执行后看到version.Version不再被AppClassLoader加载，而是被扩展类加载器加载。如图5所示。<BR><BR><IMG onmouseover=javascript:ImgShowTip(this); style="DISPLAY: inline" onclick=javascript:ImgClick(this); alt=image src="http://www.matrix.org.cn/resource/upload/forum/2005_10_19_004332_ekqtjLmLnG.jpg" onload=javascript:ImgLoad(this); border=0 resized="0"> <BR>图5. AppClassLoader及ExtClassLoader<BR><BR>继续这个例子，文件夹differentversions包含了一个RMI执行引擎，客户端可以提供给执行引擎任何实现了common.TaskIntf接口的任务。子文件夹client1 和 client2包含了类client.TaskImpl有个细微不同的两个版本。两个类的区别在以下几行：<BR><BR><PRE class=overflow title="pre code">&nbsp;&nbsp;&nbsp;&nbsp;static{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log("client.TaskImpl.class.getClassLoader<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(v1) : " + TaskImpl.class.getClassLoader());<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;public void execute(){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log("this = " + this + "; execute(1)");<BR>&nbsp;&nbsp;&nbsp;&nbsp;}</PRE><BR><BR>在client1和client2里分别有getClassLoader(v1) 与 execute(1)和getClassLoader(v2) 与 execute(2)的的log语句。并且，在开始执行引擎RMI服务器的代码中，我们随意地将client2的任务实现放在类路径的前面。<BR><BR><SPAN style="COLOR: blue">CLASSPATH=%CURRENT_ROOT%\common;%CURRENT_ROOT%\server;<BR>&nbsp;&nbsp;&nbsp;&nbsp;%CURRENT_ROOT%\client2;%CURRENT_ROOT%\client1<BR>%JAVA_HOME%\bin\java server.Server</SPAN><BR><BR>如图6，7，8的屏幕截图，在客户端VM，各自的client.TaskImpl类被加载、实例化，并发送到服务端的VM来执行。从服务端的控制台，可以明显看到client.TaskImpl代码只被服务端的VM执行一次，这个单一的代码版本在服务端多次生成了许多实例，并执行任务。<BR><BR><BR><IMG onmouseover=javascript:ImgShowTip(this); style="DISPLAY: inline" onclick=javascript:ImgClick(this); alt=image src="http://www.matrix.org.cn/resource/upload/forum/2005_10_19_004337_coYFTMZQNl.jpg" onload=javascript:ImgLoad(this); border=0 resized="0"><BR>图6. 执行引擎服务器控制台<BR><BR>图6显示了服务端的控制台，加载并执行两个不同的客户端的请求，如图７，８所示。需要注意的是，代码只被加载了一次（从静态初始化块的日志中也可以明显看出），但对于客户端的调用这个方法被执行了两次。<BR><BR><IMG onmouseover=javascript:ImgShowTip(this); style="DISPLAY: inline" onclick=javascript:ImgClick(this); alt=image src="http://www.matrix.org.cn/resource/upload/forum/2005_10_19_004342_nOFwjQNyVF.jpg" onload=javascript:ImgLoad(this); border=0 resized="0"><BR>图７. 执行引擎客户端 1控制台　<BR><BR>图７中，客户端VM加载了含有client.TaskImpl.class.getClassLoader(v1)的日志内容的类TaskImpl的代码，并提供给服务端的执行引擎。图8的客户端VM加载了另一个TaskImpl的代码，并发送给服务端。<BR><BR><IMG onmouseover=javascript:ImgShowTip(this); style="DISPLAY: inline" onclick=javascript:ImgClick(this); alt=image src="http://www.matrix.org.cn/resource/upload/forum/2005_10_19_004346_AghgLgkiIz.jpg" onload=javascript:ImgLoad(this); border=0 resized="0"> <BR>图8. 执行引擎客户端 2控制台　<BR><BR>在客户端的VM中，类client.TaskImpl被分别加载，初始化，并发送到服务端执行。图6还揭示了client.TaskImpl的代码只在服务端的VM中加载了一次，但这“唯一的一次”却在服务端创造了许多实例并执行。或许客户端1该不高兴了因为并不是它的client.TaskImpl(v1)的方法调用被服务端执行了，而是其他的一些代码。如何解决这一问题？答案就是实现定制的类加载器。<BR><BR><B><SPAN style="FONT-SIZE: 16px">定制类加载器</SPAN></B><BR><BR>要较好地控制类的加载，就要实现定制的类加载器。所有自定义的类加载器都应继承自java.lang.ClassLoader。而且在构造方法中，我们也应该设置父类加载器。然后重写findClass()方法。differentversionspush文件夹包含了一个叫做FileSystemClassLoader的自订制的类加载器。其结构如图9所示。<BR><BR><IMG onmouseover=javascript:ImgShowTip(this); style="DISPLAY: inline" onclick=javascript:ImgClick(this); height=450 alt=image src="http://www.matrix.org.cn/resource/upload/forum/2005_10_19_004644_QETAGHAHIZ.jpg" width=285 onload=javascript:ImgLoad(this); border=0 resized="1"> <BR>图9. 定制类加载器关系<BR><BR>以下是在common.FileSystemClassLoader实现的主方法：<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;<PRE class=overflow title="pre code">public byte[] findClassBytes(String className){<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String pathName = currentRoot +<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File.separatorChar + className.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;replace('.', File.separatorChar)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+ ".class";<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FileInputStream inFile = new<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FileInputStream(pathName);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;byte[] classBytes = new<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;byte[inFile.available()];<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inFile.read(classBytes);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return classBytes;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;catch (java.io.IOException ioEx){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return null;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;public Class findClass(String name)throws<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ClassNotFoundException{<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;byte[] classBytes = findClassBytes(name);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (classBytes==null){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw new ClassNotFoundException();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return defineClass(name, classBytes,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0, classBytes.length);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;public Class findClass(String name, byte[]<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;classBytes)throws ClassNotFoundException{<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (classBytes==null){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw new ClassNotFoundException(<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"(classBytes==null)");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return defineClass(name, classBytes,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0, classBytes.length);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;public void execute(String codeName,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;byte[] code){<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Class klass = null;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;klass = findClass(codeName, code);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TaskIntf task = (TaskIntf)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;klass.newInstance();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;task.execute();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;catch(Exception exception){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exception.printStackTrace();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;}</PRE><BR><BR>这个类供客户端把client.TaskImpl(v1)转换成字节数组，之后此字节数组被发送到RMI服务端。在服务端，一个同样的类用来把字节数组的内容转换回代码。客户端代码如下：<BR><BR><PRE class=overflow title="pre code">public class Client{<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;public static void main (String[] args){<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;byte[] code = getClassDefinition<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;("client.TaskImpl");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;serverIntf.execute("client.TaskImpl",<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;code);<BR>&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;catch(RemoteException remoteException){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;remoteException.printStackTrace();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;private static byte[] getClassDefinition<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(String codeName){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String userDir = System.getProperties().<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;getProperty("BytePath");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FileSystemClassLoader fscl1 = null;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fscl1 = new FileSystemClassLoader<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(userDir);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;catch(FileNotFoundException<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fileNotFoundException){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fileNotFoundException.printStackTrace();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return fscl1.findClassBytes(codeName);<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR>}</PRE><BR><BR>在执行引擎中，从客户端收到的代码被送到定制的类加载器中。定制的类加载器把其从字节数组定义成类，实例化并执行。需要指出的是，对每一个客户请求，我们用类FileSystemClassLoader的不同实例来定义客户端提交的client.TaskImpl。而且，client.TaskImpl并不在服务端的类路径中。这也就意味着当我们在FileSystemClassLoader调用findClass()方法时，findClass()调用内在的defineClass()方法。类client.TaskImpl被特定的类加载器实例所定义。因此，当FileSystemClassLoader的一个新的实例被使用，类又被重新定义为字节数组。因此，对每个客户端请求类client.TaskImpl被多次定义，我们就可以在相同执行引擎JVM中执行不同的client.TaskImpl的代码。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;<PRE class=overflow title="pre code">public void execute(String codeName, byte[] code)throws RemoteException{<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FileSystemClassLoader fileSystemClassLoader = null;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fileSystemClassLoader = new FileSystemClassLoader();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fileSystemClassLoader.execute(codeName, code);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;catch(Exception exception){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw new RemoteException(exception.getMessage());<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;}</PRE><BR><BR>示例在differentversionspush文件夹下。服务端和客户端的控制台界面分别如图10，11，12所示：<BR><BR><IMG onmouseover=javascript:ImgShowTip(this); style="DISPLAY: inline" onclick=javascript:ImgClick(this); alt=image src="http://www.matrix.org.cn/resource/upload/forum/2005_10_19_004649_UQoeQhWPjQ.jpg" onload=javascript:ImgLoad(this); border=0 resized="0"><BR>图10. 定制类加载器执行引擎<BR><BR>图10显示的是定制的类加载器控制台。我们可以看到client.TaskImpl的代码被多次加载。实际上针对每一个客户端，类都被加载并初始化。<BR><BR><IMG onmouseover=javascript:ImgShowTip(this); style="DISPLAY: inline" onclick=javascript:ImgClick(this); alt=image src="http://www.matrix.org.cn/resource/upload/forum/2005_10_19_004653_wJwxDiTtAW.jpg" onload=javascript:ImgLoad(this); border=0 resized="0"> <BR>图11. 定制类加载器，客户端1<BR><BR>图11中，含有client.TaskImpl.class.getClassLoader(v1)的日志记录的类TaskImpl的代码被客户端的VM加载，然后送到服务端。图12 另一个客户端把包含有client.TaskImpl.class.getClassLoader(v1)的类代码加载并送往服务端。<BR><BR><IMG onmouseover=javascript:ImgShowTip(this); style="DISPLAY: inline" onclick=javascript:ImgClick(this); alt=image src="http://www.matrix.org.cn/resource/upload/forum/2005_10_19_004658_akDsqMYhmR.jpg" onload=javascript:ImgLoad(this); border=0 resized="0"> <BR>图12. 定制类加载器，客户端1<BR><BR>这段代码演示了我们如何利用不同的类加载器实例来在同一个VM上执行不同版本的代码。<BR><BR><B><SPAN style="FONT-SIZE: 16px">J2EE的类加载器</SPAN></B><BR>J2EE的服务器倾向于以一定间隔频率，丢弃原有的类并重新载入新的类。在某些情况下会这样执行，而有些情况则不。同样，对于一个web服务器如果要丢弃一个servlet实例，可能是服务器管理员的手动操作，也可能是此实例长时间未相应。当一个JSP页面被首次请求，容器会把此JSP页面翻译成一个具有特定形式的servlet代码。一旦servlet代码被创建，容器就会把这个servlet翻译成class文件等待被使用。对于提交给容器的每次请求，容器都会首先检查这个JSP文件是否刚被修改过。是的话就重新翻译此文件，这可以确保每次的请求都是及时更新的。企业级的部署方案以.ear, .war, .rar等形式的文件，同样需要重复加载，可能是随意的也可能是依照某种配置方案定期执行。对所有的这些情况——类的加载、卸载、重新加载……全部都是建立在我们控制应用服务器的类加载机制的基础上的。实现这些需要扩展的类加载器，它可以执行由其自身所定义的类。Brett Peterson已经在他的文章 Understanding J2EE Application Server Class Loading Architectures给出了J2EE应用服务器的类加载方案的详细说明，详见网站TheServerSide.com。<BR><BR><B><SPAN style="FONT-SIZE: 16px">结要</SPAN></B><BR>本文探讨了类载入到虚拟机是如何进行唯一标识的，以及类如果存在同样的类名和包名时所产生的问题。因为没有一个直接可用的类版本管理机制，所以如果我们要按自己的意愿来加载类时，需要自己订制类加载器来扩展其行为。我们可以利用许多J2EE服务器所提供的“热部署”功能来重新加载一个新版本的类，而不改动服务器的VM。即使不涉及应用服务器，我们也可以利用定制类加载器来控制java应用程序载入类时的具体行为。Ted Neward的书Server-Based Java Programming中详细阐述java的类加载，J2EE的API以及使用他们的最佳途径。<BR><BR><B><SPAN style="FONT-SIZE: 16px">参考</SPAN></B><BR>●本文的源码:[<A href="http://www.matrix.org.cn/resource/upload/forum/2005_10_19_004826_dgTsHmDOPq.zip">下载文件</A>]<BR>●JDK 1.5 API文档 <BR>●Java语言规范 <BR>●Java tutorial 中的"Understanding Extension Class Loading "<BR>●ONJava 中的"Inside Class Loaders" <BR>●ONJava 中的"Inside Class Loaders: Debugging" <BR>●JavaWorld中的"What version is your Java code?" <BR>●TheServerSide中的" Understanding J2EE Application Server Class Loading Architectures"<BR>●字节码工程库 <BR>●Server-Based Java Programming，作者：Ted Neward <BR><BR>Binildas Christudas 是Infosys的Communication Service Providers Practice (CSP)中的高级技术架构师，也是Sun认证企业架构师及微软认证专家。 <BR><img src ="http://www.blogjava.net/liveandletdie/aggbug/18110.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liveandletdie/" target="_blank">幸福是把温暖的枪</a> 2005-11-04 11:53 <a href="http://www.blogjava.net/liveandletdie/articles/18110.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>FreeMaker学习笔记</title><link>http://www.blogjava.net/liveandletdie/articles/13149.html</link><dc:creator>幸福是把温暖的枪</dc:creator><author>幸福是把温暖的枪</author><pubDate>Fri, 16 Sep 2005 05:42:00 GMT</pubDate><guid>http://www.blogjava.net/liveandletdie/articles/13149.html</guid><wfw:comment>http://www.blogjava.net/liveandletdie/comments/13149.html</wfw:comment><comments>http://www.blogjava.net/liveandletdie/articles/13149.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liveandletdie/comments/commentRss/13149.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liveandletdie/services/trackbacks/13149.html</trackback:ping><description><![CDATA[1.<FONT face="Courier New"><FONT color=#a03d10>${data model</FONT><FONT color=#a03d10>}</FONT></FONT> 类似于jsp的&lt;%=data model%&gt;<%=data model%><BR><BR>2.JTL tag:以<FONT color=#a03d10>#</FONT>开头,除了某些特定的tag会以<FONT color=#a03d10>@</FONT>开头(用户自定义的tag)<BR><BR>3.注释:<FONT face="Courier New" color=#a03d10>&lt;#--</FONT> 注释内容<TT style="COLOR: #a03d10">--&gt;</TT> <BR><BR>4.几个tag的例子<BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp; <TT style="COLOR: #a03d10">&lt;#if <I style="COLOR: #dd4400">condition</I>&gt;</TT> 内容<STRONG>&lt;/#if&gt;<BR></STRONG><TT style="COLOR: #a03d10"></#IF><BR><FONT color=#000000>&nbsp; </FONT><TT style="COLOR: #a03d10">&lt;#else&gt;&nbsp;&nbsp;<BR><BR>&nbsp;&nbsp;例子:<BR>&nbsp; <PRE class=smallpre style="MARGIN: 0px"> &lt;#if animals.python.price &lt; animals.elephant.price&gt;
   Pythons are cheaper than elephants today.
<B> &lt;#else&gt;</B>
<BR><BR>   Pythons are not cheaper than elephants today.
<BR><BR> &lt;/#if&gt;&nbsp;<BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR></TT>&nbsp;&nbsp;循环读取数据<BR><BR>  &lt;#list <I style="COLOR: #dd4400">SequenceVar</I> as <I style="COLOR: #dd4400">variable</I>&gt;<EM>repeatThis</EM>&lt;/#list&gt;<BR><BR><BR><BR><BR><FONT color=#000000><B><BR>  &lt;#list animals as being&gt;</B><BR>&nbsp;   <TR><TD>${being.name}</TD><TD>${being.price}</TD><BR><B></#LIST>&nbsp; &lt;/#list&gt;<BR></B><BR><STRONG>&nbsp; <BR><BR><BR><BR><BR><BR>  &lt;#list whatnot.fruits as fruit&gt;<BR></STRONG><BR>    ${fruit}<BR><B>&nbsp; &lt;/#list&gt;<BR><BR>  插入文件中的内容</B><FONT color=#a03d10>&lt;#include "filename"&gt;<BR></PRE></FONT>
<P><BR>&nbsp;</P></FONT></TT><img src ="http://www.blogjava.net/liveandletdie/aggbug/13149.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liveandletdie/" target="_blank">幸福是把温暖的枪</a> 2005-09-16 13:42 <a href="http://www.blogjava.net/liveandletdie/articles/13149.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用jsp产生随机验证码(收藏)</title><link>http://www.blogjava.net/liveandletdie/articles/11202.html</link><dc:creator>幸福是把温暖的枪</dc:creator><author>幸福是把温暖的枪</author><pubDate>Fri, 26 Aug 2005 07:25:00 GMT</pubDate><guid>http://www.blogjava.net/liveandletdie/articles/11202.html</guid><wfw:comment>http://www.blogjava.net/liveandletdie/comments/11202.html</wfw:comment><comments>http://www.blogjava.net/liveandletdie/articles/11202.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liveandletdie/comments/commentRss/11202.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liveandletdie/services/trackbacks/11202.html</trackback:ping><description><![CDATA[&lt;%@ page contentType="image/jpeg" import="java.awt.*,java.awt.image.*,java.util.*,javax.imageio.*" %&gt;<BR>&lt;%!<BR>Color getRandColor(int fc,int bc){//给定范围获得随机颜色<BR>Random random = new Random();<BR>if(fc&gt;255) fc=255;<BR>if(bc&gt;255) bc=255;<BR>int r=fc+random.nextInt(bc-fc);<BR>int g=fc+random.nextInt(bc-fc);<BR>int b=fc+random.nextInt(bc-fc);<BR>return new Color(r,g,b);<BR>}<BR>%&gt;<BR>&lt;%<BR>//设置页面不缓存<BR>response.setHeader("Pragma","No-cache");<BR>response.setHeader("Cache-Control","no-cache");<BR>response.setDateHeader("Expires", 0);
<P>// 在内存中创建图象<BR>int width=60, height=20;<BR>BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);</P>
<P>// 获取图形上下文<BR>Graphics g = image.getGraphics();</P>
<P>//生成随机类<BR>Random random = new Random();</P>
<P>// 设定背景色<BR>g.setColor(getRandColor(200,250));<BR>g.fillRect(0, 0, width, height);</P>
<P>//设定字体<BR>g.setFont(new Font("Times New Roman",Font.PLAIN,18));</P>
<P>//画边框<BR>g.setColor(new Color(255,255,255));<BR>g.drawRect(0,0,width-1,height-1);</P>
<P>// 随机产生155条干扰线，使图象中的认证码不易被其它程序探测到<BR>g.setColor(getRandColor(160,200));<BR>for (int i=0;i&lt;155;i++)<BR>{<BR>int x = random.nextInt(width);<BR>int y = random.nextInt(height);<BR>int xl = random.nextInt(12);<BR>int yl = random.nextInt(12);<BR>g.drawLine(x,y,x+xl,y+yl);<BR>}</P>
<P>// 取随机产生的认证码(4位数字)<BR>String sRand="";<BR>for (int i=0;i&lt;4;i++){<BR>String rand=String.valueOf(random.nextInt(10));<BR>sRand+=rand;<BR>// 将认证码显示到图象中<BR>g.setColor(new Color(20+random.nextInt(110),20+random.nextInt(110),20+random.nextInt(110)));<BR>//调用函数出来的颜色相同，可能是因为种子太接近，所以只能直接生成<BR>g.drawString(rand,13*i+6,16);<BR>}</P>
<P>// 将认证码存入SESSION<BR>session.setAttribute("rand",sRand);</P>
<P>// 图象生效<BR>g.dispose();</P>
<P>// 输出图象到页面<BR>ImageIO.write(image, "JPEG", response.getOutputStream());</P>
<P>%&gt;<BR></P>
<P>-------------我是漂亮的分割线---------------</P>
<P><FONT style="BACKGROUND-COLOR: #a9a9a9">display.jsp</FONT></P>
<P>&lt;%@ page contentType="text/html;charset=gb2312" %&gt;<BR>&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"&gt;<BR>&lt;html&gt;<BR>&lt;head&gt;<BR>&lt;title&gt;认证码输入页面&lt;/title&gt;<BR>&lt;meta http-equiv="Content-Type" content="text/html; charset=gb2312"&gt;<BR>&lt;META HTTP-EQUIV="Pragma" CONTENT="no-cache"&gt; <BR>&lt;META HTTP-EQUIV="Cache-Control" CONTENT="no-cache"&gt; <BR>&lt;META HTTP-EQUIV="Expires" CONTENT="0"&gt; <BR>&lt;/head&gt;<BR>&lt;body&gt;<BR>&lt;form method=post action="check.jsp"&gt;<BR>&lt;table&gt;<BR>&lt;tr&gt;<BR>&lt;td align=left&gt;系统产生的认证码：&lt;/td&gt;<BR>&lt;td&gt;&lt;img border=0 src="image.jsp"&gt;&lt;/td&gt;<BR>&lt;/tr&gt;<BR>&lt;tr&gt;<BR>&lt;td align=left&gt;输入上面的认证码：&lt;/td&gt;<BR>&lt;td&gt;&lt;input type=text name=rand maxlength=4 value=""&gt;&lt;/td&gt;<BR>&lt;/tr&gt;<BR>&lt;tr&gt;<BR>&lt;td colspan=2 align=center&gt;&lt;input type=submit value="提交检测"&gt;&lt;/td&gt;<BR>&lt;/tr&gt;<BR>&lt;/form&gt;<BR>&lt;/body&gt;<BR>&lt;/html&gt;</P>
<P>------------分割线,又见分割线--------------------------</P>
<P><FONT style="BACKGROUND-COLOR: #a9a9a9">check.jsp</FONT></P>
<P>&lt;%@ page contentType="text/html; charset=gb2312" language="java" import="java.sql.*" errorPage="" %&gt;<BR>&lt;html&gt;<BR>&lt;head&gt;<BR>&lt;title&gt;认证码验证页面&lt;/title&gt;<BR>&lt;meta http-equiv="Content-Type" content="text/html; charset=gb2312"&gt;<BR>&lt;META HTTP-EQUIV="Pragma" CONTENT="no-cache"&gt; <BR>&lt;META HTTP-EQUIV="Cache-Control" CONTENT="no-cache"&gt; <BR>&lt;META HTTP-EQUIV="Expires" CONTENT="0"&gt; <BR>&lt;/head&gt;</P>
<P>&lt;body&gt;<BR>&lt;% <BR>&nbsp;String rand = (String)session.getAttribute("rand");<BR>&nbsp;String input = request.getParameter("rand");<BR>%&gt;<BR>系统产生的认证码为： &lt;%= rand %&gt;&lt;br&gt;<BR>您输入的认证码为： &lt;%= input %&gt;&lt;br&gt;<BR>&lt;br&gt;<BR>&lt;%<BR>&nbsp; if (rand.equals(input)) {<BR>%&gt;<BR>&lt;font color=green&gt;输入相同，认证成功！&lt;/font&gt;<BR>&lt;%<BR>&nbsp; } else {<BR>%&gt;<BR>&lt;font color=red&gt;输入不同，认证失败！&lt;/font&gt;<BR>&lt;%<BR>&nbsp; }<BR>%&gt;<BR>&lt;/body&gt;<BR>&lt;/html&gt;</P><img src ="http://www.blogjava.net/liveandletdie/aggbug/11202.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liveandletdie/" target="_blank">幸福是把温暖的枪</a> 2005-08-26 15:25 <a href="http://www.blogjava.net/liveandletdie/articles/11202.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java编程思想读书笔记</title><link>http://www.blogjava.net/liveandletdie/articles/11201.html</link><dc:creator>幸福是把温暖的枪</dc:creator><author>幸福是把温暖的枪</author><pubDate>Fri, 26 Aug 2005 07:24:00 GMT</pubDate><guid>http://www.blogjava.net/liveandletdie/articles/11201.html</guid><wfw:comment>http://www.blogjava.net/liveandletdie/comments/11201.html</wfw:comment><comments>http://www.blogjava.net/liveandletdie/articles/11201.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liveandletdie/comments/commentRss/11201.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liveandletdie/services/trackbacks/11201.html</trackback:ping><description><![CDATA[<DIV class=postbody>
<P><FONT color=#000080>存放数据的地方</FONT>:</P>
<P>1.寄存器(Registers):位于处理器内部,速度最快,程序员无法直接操纵.</P>
<P>2.栈(Stack):位于一般的RAM当中,处理器由指针提供支持.因为要移动指针,所以存放在stack中的数据的实际大小和存活时间都是明确的.reference可以置入其中,但是java对象不可以.</P>
<P>3.堆(Heap):位于RAM当中,放置所有的java对象.new的对象都是自Heap分配空间的.</P>
<P>4.静态存储空间(Static storage):static可以将某个对象内的特定成员置为静态.java对象不可能置入此地.</P>
<P>5.常量存储空间(Constant storage):位于ROM中.</P>
<P>6.Non-RAM存储空间:streamed objects和persistent objects.</P>
<P><FONT color=#000080>两种型别</FONT></P>
<P>1.对象型别:object type</P>
<P>2.基本型别:primitive type 不以new分配空间,而是一种automatic变量直接存放数据值,置于stack</P>
<P>如果想在heap内代替基本型别,可以适用外覆类.比如Character(char)</P>
<P><FONT color=#000080>类的初始化过程</FONT></P>
<P><FONT color=#000000>1.当一个对象首次生成,或者当类的static函数和static对象首次被访问,java inter Preter首先根据classpath环境变量来查找该对象.</FONT></P>
<P><FONT color=#000000>2.一旦类被装载,就执行它的static初始动作,因此static初始化动作仅发生一次,就是在Class对象首次被装载时.</FONT></P>
<P>3.当new Class(),则先为class对象在Heap上分配足够的存储空间.</P>
<P>4.该存储空间先被清空.并自动将class对象内部所有隶属基本类型的数据设为缺省值,并将reference置为null</P>
<P>5.执行所有出现于数据定义处的初始化动作</P>
<P>6.执行构造函数</P></DIV><img src ="http://www.blogjava.net/liveandletdie/aggbug/11201.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liveandletdie/" target="_blank">幸福是把温暖的枪</a> 2005-08-26 15:24 <a href="http://www.blogjava.net/liveandletdie/articles/11201.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>jsp跳转中绝对路径和相对路径的解决办法(来源:csdn)</title><link>http://www.blogjava.net/liveandletdie/articles/11060.html</link><dc:creator>幸福是把温暖的枪</dc:creator><author>幸福是把温暖的枪</author><pubDate>Thu, 25 Aug 2005 06:48:00 GMT</pubDate><guid>http://www.blogjava.net/liveandletdie/articles/11060.html</guid><wfw:comment>http://www.blogjava.net/liveandletdie/comments/11060.html</wfw:comment><comments>http://www.blogjava.net/liveandletdie/articles/11060.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liveandletdie/comments/commentRss/11060.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liveandletdie/services/trackbacks/11060.html</trackback:ping><description><![CDATA[&nbsp;为了避免jsp跳jsp，servlet跳jsp，forward方式跳转，sendRedirect跳转产生的路径问题，<BR>&nbsp;&nbsp;&nbsp;对于jsp和使用sendRedirect跳转的servlet，采用直接使用带<BR>&nbsp;&nbsp;&nbsp;容器路径[String request.getContextPath()]的绝对路径就可以彻底解决，即：<BR>&nbsp;&nbsp;&nbsp;&nbsp;1）&lt;% <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String contextPath = request.getContextPath();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String url = contextPath + "/user/login.jsp";<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;%&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;a href="&lt;%=url%&gt;"&gt; login&lt;/a&gt;<BR>&nbsp;&nbsp;&nbsp;2） ....<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String contextPath = request.getContextPath();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String targetPath = contextPath + "/user/login.jsp";<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RequestDispatcher rd = request.getRequestDispatcher(targetPath);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rd.forward(request, response);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;......<BR><BR>&nbsp;&nbsp;&nbsp;对于使用forward跳转的servlet，则不要加容器路径，否则就重复出现 容器路径，<BR><img src ="http://www.blogjava.net/liveandletdie/aggbug/11060.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liveandletdie/" target="_blank">幸福是把温暖的枪</a> 2005-08-25 14:48 <a href="http://www.blogjava.net/liveandletdie/articles/11060.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>commons logging笔记</title><link>http://www.blogjava.net/liveandletdie/articles/10310.html</link><dc:creator>幸福是把温暖的枪</dc:creator><author>幸福是把温暖的枪</author><pubDate>Wed, 17 Aug 2005 02:19:00 GMT</pubDate><guid>http://www.blogjava.net/liveandletdie/articles/10310.html</guid><wfw:comment>http://www.blogjava.net/liveandletdie/comments/10310.html</wfw:comment><comments>http://www.blogjava.net/liveandletdie/articles/10310.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liveandletdie/comments/commentRss/10310.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liveandletdie/services/trackbacks/10310.html</trackback:ping><description><![CDATA[
		<p>1.下载commons logging和log4j的jar包<br />2.配置2个properties文件,分别为<strong>commons-logging.properties和log4j.properties<br />commons-logging.properties文件内容:<br /></strong><font color="#0000ff">org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JLogger<br /></font><font color="#000000"><strong>log4j.properties文件内容<br /><font color="#0000ff">log4j.rootLogger=info,stdout,file<br />log4j.appender.stdout=org.apache.log4j.ConsoleAppender<br />log4j.appender.stdout.Target=System.out<br />log4j.appender.stdout.layout=org.apache.log4j.PatternLayout<br />log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %p [%c] %m%n<br /></font></strong></font><font color="#0000ff"><strong>log4j.appender.file=org.apache.log4j.RollingFileAppender<br />log4j.appender.file.File=youapp.log<br />log4j.appender.file.MaxFileSize=512KB<br />log4j.appender.file.MaxBackupIndex=5<br />log4j.appender.file.layout=org.apache.log4j.PatternLayout<br />log4j.appender.file.layout.ConversionPattern==%d{yyyy-MM-dd HH:mm:ss} %p [%c] %m%n<br /></strong></font><font color="#000000"><strong>3.将这2个properties文件放到classes目录下<br />4.程序中调用log<br /></strong><font color="#0000ff"><strong>import org.apache.commons.logging.Log;<br />import org.apache.commons.logging.LogFactory;<br />..........<br /></strong>protected final Log logger = LogFactory.getLog(getClass());<br /><br /><br />-------------log4j的一些零散笔记------------<br />1.</font><font color="#000000"><font face="Courier New">log4j.additivity.mypackage.myclass=false</font><br />默认设置为true，即继承root logger，会导致自定义的子logger和父logger出现重复记录<br />设为false，则不再从父logger继承，记录将只出现在子logger当中。<br />2.MDC<br />为多个client的环境提供记录各自信息，可以通过filter来扩展<br />所记录信息在配置文件中可以通过<font face="Courier New">%X{key}</font> 来获取<br />例如<font face="Courier New">MDC.put("remoteHost", request.getRemoteHost());</font><br /></font></font></p>
<img src ="http://www.blogjava.net/liveandletdie/aggbug/10310.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liveandletdie/" target="_blank">幸福是把温暖的枪</a> 2005-08-17 10:19 <a href="http://www.blogjava.net/liveandletdie/articles/10310.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>