﻿<?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-桔子园</title><link>http://www.blogjava.net/orangelizq/</link><description>&lt;div id="MySignature" style="display: block;"&gt;&lt;p&gt;&lt;a title="程序员休闲,程序员放松,程序员笑话,程序员段子" href="http://www.itmmd.com/boke.html" target="_blank"&gt;&lt;img src="http://images.cnitblog.com/blog/437282/201411/041405283617635.gif" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
欢迎大家访问我的个人网站 &lt;a href="http://www.itmmd.com"&gt;萌萌的IT人&lt;/a&gt;&lt;/div&gt;</description><language>zh-cn</language><lastBuildDate>Wed, 29 Apr 2026 02:13:45 GMT</lastBuildDate><pubDate>Wed, 29 Apr 2026 02:13:45 GMT</pubDate><ttl>60</ttl><item><title>[转]处理线程泄露</title><link>http://www.blogjava.net/orangelizq/archive/2013/05/29/399926.html</link><dc:creator>桔子汁</dc:creator><author>桔子汁</author><pubDate>Wed, 29 May 2013 08:43:00 GMT</pubDate><guid>http://www.blogjava.net/orangelizq/archive/2013/05/29/399926.html</guid><wfw:comment>http://www.blogjava.net/orangelizq/comments/399926.html</wfw:comment><comments>http://www.blogjava.net/orangelizq/archive/2013/05/29/399926.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/orangelizq/comments/commentRss/399926.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/orangelizq/services/trackbacks/399926.html</trackback:ping><description><![CDATA[<br /><a href="http://sunnylocus.iteye.com/blog/538282">http://sunnylocus.iteye.com/blog/538282</a><br /><br /><span style="font-size: x-small">当一个单线程化的控制台程序因为未捕获的异常终止的时候，程序停止运行，并生了栈追踪，这与典型的程序输出不同，当一个程序发生了异常说明有不稳定的因素存在。如果并发程序中线程失败就没那么容易发现了。栈追踪可能会从控制台输出，但是没有人会去一直在看控制台，并且，当线程失败的时候，应用程序可能看起来仍在工作。就象程序能跑在50个线程池上，也能够跑在49个线程的线程池上，区别在于50个人干的活要比49个人干的活要多的多。</span> 
<p><span style="font-size: x-small">　　导致线程死亡的的最主要的原因是RuntimeException。因为这些异常表明一个程序错误或者不可修复的错误，它们不着顺着栈的调用传递，此时，默认的行为是在控制台打印栈追踪的信息，并终止线程。</span></p>
<p><span style="font-size: x-small">　　我们举个例子，将奴隶主比作是你写的程序，奴隶比作是线程。假如你是奴隶主，你手下有5名奴隶，你分派他们一项任务去将不断开采来的石头搬到某个地方。如果中途有奴隶逃跑，那么搬运石头的效率就会下降，如果你没有措施发现奴隶逃跑，最后连一个奴隶也没有了，没有人再去搬石头了。当你发现程序有问题，比如程序刚启动的时候处理速度很快，以后越跑越慢，最后完全停止了，你可能不知道问题出在哪儿，其实这都是因为线程泄露引起的。想解决奴隶逃跑问题，不难，给每个奴隶戴上个报警器，一逃跑报警器就给你发信息，告诉哪个奴隶，因为什么原因逃跑了，可以根据需要再增加一名奴隶，让搬石头的奴隶数量始终维持在5名或着将信息记录到文件，便于分析导致线程泄露的原意改进程序。ok,我们用代码说话</span></p>
<p><span style="font-size: x-small">１、定义好报警器</span></p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" href="http://sunnylocus.iteye.com/blog/538282#"><img alt="复制代码" src="http://sunnylocus.iteye.com/images/icon_copy.gif" /></a>&nbsp;<a title="收藏这段代码" href="javascript:void()"><img class="star" alt="收藏代码" src="http://sunnylocus.iteye.com/images/icon_star.png" /><img class="spinner" style="display: none" src="http://sunnylocus.iteye.com/images/spinner.gif"  alt="" /></a></div></div>
<ol class="dp-j"><li><span class="keyword">package</span><span>&nbsp;com.bill99.thread.test; &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;</span></li><li><span></span><span class="keyword">import</span><span>&nbsp;java.lang.Thread.UncaughtExceptionHandler; &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;</span></li><li><span></span><span class="comment">//将泄露的线程信息输出到控制台 </span><span>&nbsp;&nbsp;</span></span></li><li><span></span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;UEHLogger&nbsp;</span><span class="keyword">implements</span><span>&nbsp;UncaughtExceptionHandler&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;uncaughtException(Thread&nbsp;t,&nbsp;Throwable&nbsp;e)&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(String.format(</span><span class="string">"不好了，有奴隶逃跑了!奴隶姓名：%1$s,编号：%2$s,逃跑原因：%3$s"</span><span>,&nbsp;t.getName(),t.getId(),e.getMessage())); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span class="string">"还剩"</span><span>+HelotPool.helotPool.getActiveCount()+</span><span class="string">"个奴隶"</span><span>); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>}&nbsp;&nbsp;</span></li></ol></div><pre title="处理线程泄露" class="java" style="display: none" pre_index="0" source_url="http://sunnylocus.iteye.com/blog/538282" codeable_type="Blog" codeable_id="538282" name="code">package com.bill99.thread.test;

import java.lang.Thread.UncaughtExceptionHandler;

//将泄露的线程信息输出到控制台
public class UEHLogger implements UncaughtExceptionHandler {
	public void uncaughtException(Thread t, Throwable e) {
		System.out.println(String.format("不好了，有奴隶逃跑了!奴隶姓名：%1$s,编号：%2$s,逃跑原因：%3$s", t.getName(),t.getId(),e.getMessage()));
		System.out.println("还剩"+HelotPool.helotPool.getActiveCount()+"个奴隶");
	}
}
</pre>
<p>&nbsp;&nbsp;</p>
<p><span style="font-size: x-small">２、我们先建立一个奴隶工厂，每名奴隶出工厂的时候都会有一个报警器</span></p>
<p><span style="font-size: x-small">&nbsp;　　　 </p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" href="http://sunnylocus.iteye.com/blog/538282#"><img alt="复制代码" src="http://sunnylocus.iteye.com/images/icon_copy.gif" /></a>&nbsp;<a title="收藏这段代码" href="javascript:void()"><img class="star" alt="收藏代码" src="http://sunnylocus.iteye.com/images/icon_star.png" /><img class="spinner" style="display: none" src="http://sunnylocus.iteye.com/images/spinner.gif"  alt="" /></a></div></div>
<ol class="dp-j"><li><span class="keyword">package</span><span>&nbsp;com.bill99.thread.test; &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;</span></li><li><span></span><span class="keyword">import</span><span>&nbsp;java.util.concurrent.ThreadFactory; &nbsp;&nbsp;</span></span></li><li><span></span><span class="comment">//奴隶制造工厂 </span><span>&nbsp;&nbsp;</span></span></li><li><span></span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;HelotFactory&nbsp;</span><span class="keyword">implements</span><span>&nbsp;ThreadFactory&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">private</span><span>&nbsp;</span><span class="keyword">volatile</span><span>&nbsp;</span><span class="keyword">int</span><span>&nbsp;helotId=</span><span class="number"><font color="#c00000">0</font></span><span>;</span><span class="comment">//奴隶编号 </span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//产生一个新奴隶 </span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;Thread&nbsp;newThread(Runnable&nbsp;r)&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread&nbsp;helotThread&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;Thread(r); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;helotThread.setName(</span><span class="string">"helot-Thread-"</span><span>+gethelotId());</span><span class="comment">//设置奴隶姓名 </span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;helotThread.setUncaughtExceptionHandler(</span><span class="keyword">new</span><span>&nbsp;UEHLogger());</span><span class="comment">//UEHLogger就是报警器 </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;helotThread; &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">private</span><span>&nbsp;</span><span class="keyword">int</span><span>&nbsp;gethelotId(){ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;++helotId; &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>}&nbsp;&nbsp;</span></li></ol></div><pre title="处理线程泄露" class="java" style="display: none" pre_index="1" source_url="http://sunnylocus.iteye.com/blog/538282" codeable_type="Blog" codeable_id="538282" name="code">package com.bill99.thread.test;

import java.util.concurrent.ThreadFactory;
//奴隶制造工厂
public class HelotFactory implements ThreadFactory {
	private volatile int helotId=0;//奴隶编号
	//产生一个新奴隶
	public Thread newThread(Runnable r) {
		Thread helotThread = new Thread(r);
		helotThread.setName("helot-Thread-"+gethelotId());//设置奴隶姓名
		helotThread.setUncaughtExceptionHandler(new UEHLogger());//UEHLogger就是报警器
		return helotThread;
	}
	private int gethelotId(){
		return ++helotId;
	}
}
</pre>
<p>&nbsp;３、奴隶逃跑测试,看看是否会触发报警器</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" href="http://sunnylocus.iteye.com/blog/538282#"><img alt="复制代码" src="http://sunnylocus.iteye.com/images/icon_copy.gif" /></a>&nbsp;<a title="收藏这段代码" href="javascript:void()"><img class="star" alt="收藏代码" src="http://sunnylocus.iteye.com/images/icon_star.png" /><img class="spinner" style="display: none" src="http://sunnylocus.iteye.com/images/spinner.gif"  alt="" /></a></div></div>
<ol class="dp-j"><li><span class="keyword">package</span><span>&nbsp;com.bill99.thread.test; &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;</span></li><li><span></span><span class="keyword">import</span><span>&nbsp;java.util.concurrent.ThreadFactory; &nbsp;&nbsp;</span></span></li><li><span></span><span class="comment">//奴隶逃跑测试 </span><span>&nbsp;&nbsp;</span></span></li><li><span></span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;HelotEscapeTest&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">private</span><span>&nbsp;ThreadFactory&nbsp;factory&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;HelotFactory(); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">private</span><span>&nbsp;Thread&nbsp;helotThread&nbsp;=&nbsp;</span><span class="keyword">null</span><span>; &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;HelotEscapeTest(){ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Runnable&nbsp;task&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;Runnable()&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">int</span><span>&nbsp;stoneNum=</span><span class="number"><font color="#c00000">1</font></span><span>; &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;run()&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">while</span><span>(!Thread.interrupted()){ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(helotThread.getName()+</span><span class="string">"&nbsp;搬第"</span><span>+stoneNum+</span><span class="string">"块石头.."</span><span>); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;stoneNum++; &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">try</span><span>{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.sleep(</span><span class="number"><font color="#c00000">500</font></span><span>); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span class="keyword">catch</span><span>(InterruptedException&nbsp;e){e.printStackTrace();} &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span>(stoneNum&gt;</span><span class="number"><font color="#c00000">100</font></span><span>){ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">throw</span><span>&nbsp;</span><span class="keyword">new</span><span>&nbsp;RuntimeException(</span><span class="string">"又饿又累没力气搬石头了"</span><span>); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>&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;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;helotThread&nbsp;=&nbsp;factory.newThread(task); &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//开始干活 </span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;startWork(){ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;helotThread.start(); &nbsp;&nbsp;</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;</span><span class="keyword">static</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;main(String[]&nbsp;args)&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HelotEscapeTest&nbsp;test&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;HelotEscapeTest(); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;test.startWork(); &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>}&nbsp;&nbsp;</span></li></ol></div><pre title="处理线程泄露" class="java" style="display: none" pre_index="2" source_url="http://sunnylocus.iteye.com/blog/538282" codeable_type="Blog" codeable_id="538282" name="code">package com.bill99.thread.test;

import java.util.concurrent.ThreadFactory;
//奴隶逃跑测试
public class HelotEscapeTest {
	private ThreadFactory factory = new HelotFactory();
	private Thread helotThread = null;
	
	public HelotEscapeTest(){
		Runnable task = new Runnable() {
			int stoneNum=1;
			public void run() {
				while(!Thread.interrupted()){
					System.out.println(helotThread.getName()+" 搬第"+stoneNum+"块石头..");
					stoneNum++;
					try{
						Thread.sleep(500);
					} catch(InterruptedException e){e.printStackTrace();}
					if(stoneNum&gt;100){
						throw new RuntimeException("又饿又累没力气搬石头了");
					}
				}
			}
		};
		helotThread = factory.newThread(task);
	}
	//开始干活
	public void startWork(){
		helotThread.start();
	}
	public static void main(String[] args) {
		HelotEscapeTest test = new HelotEscapeTest();
		test.startWork();
	}
}
</pre>
<p>&nbsp;运行程序后，奴隶在搬完100块石头后不干了，报警器给出提示信息</p>
<p>&nbsp;&nbsp; <strong>不好了，有奴隶逃跑了!奴隶姓名：helot-Thread-1,编号：7,逃跑原因：又饿又累没力气搬石头了</strong></p>
<p>这样我就能找出线程泄露的原因了。如果在线程池中发生了泄露是否也能记录？</p>
<p>4、奴隶池测试</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" href="http://sunnylocus.iteye.com/blog/538282#"><img alt="复制代码" src="http://sunnylocus.iteye.com/images/icon_copy.gif" /></a>&nbsp;<a title="收藏这段代码" href="javascript:void()"><img class="star" alt="收藏代码" src="http://sunnylocus.iteye.com/images/icon_star.png" /><img class="spinner" style="display: none" src="http://sunnylocus.iteye.com/images/spinner.gif"  alt="" /></a></div></div>
<ol class="dp-j"><li><span class="keyword">package</span><span>&nbsp;com.bill99.thread.test; &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;</span></li><li><span></span><span class="keyword">import</span><span>&nbsp;java.util.Random; &nbsp;&nbsp;</span></span></li><li><span></span><span class="keyword">import</span><span>&nbsp;java.util.concurrent.BlockingQueue; &nbsp;&nbsp;</span></span></li><li><span></span><span class="keyword">import</span><span>&nbsp;java.util.concurrent.LinkedBlockingQueue; &nbsp;&nbsp;</span></span></li><li><span></span><span class="keyword">import</span><span>&nbsp;java.util.concurrent.ThreadFactory; &nbsp;&nbsp;</span></span></li><li><span></span><span class="keyword">import</span><span>&nbsp;java.util.concurrent.ThreadPoolExecutor; &nbsp;&nbsp;</span></span></li><li><span></span><span class="keyword">import</span><span>&nbsp;java.util.concurrent.TimeUnit; &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;</span></li><li><span></span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;HelotPoolTest&nbsp;{ &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;</span><span class="keyword">static</span><span>&nbsp;ThreadPoolExecutor&nbsp;helotPool; &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">private</span><span>&nbsp;</span><span class="keyword">int</span><span>&nbsp;helotNum=&nbsp;</span><span class="number"><font color="#c00000">5</font></span><span>;&nbsp;&nbsp;</span><span class="comment">//奴隶数 </span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">private</span><span>&nbsp;Random&nbsp;random&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;Random(</span><span class="number"><font color="#c00000">100</font></span><span>); &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">private</span><span>&nbsp;BlockingQueue&lt;Runnable&gt;&nbsp;queue&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;LinkedBlockingQueue&lt;Runnable&gt;(); &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;HelotPoolTest()&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ThreadFactory&nbsp;factory&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;HelotFactory(); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;helotPool&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;ThreadPoolExecutor(&nbsp;helotNum,helotNum,</span><span class="number"><font color="#c00000">1000</font></span><span>,TimeUnit.SECONDS,queue,factory); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//分配任务 </span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;assignTask(){ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">final</span><span>&nbsp;</span><span class="keyword">int</span><span>&nbsp;MAX=</span><span class="number"><font color="#c00000">100</font></span><span>; &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">final</span><span>&nbsp;</span><span class="keyword">int</span><span>&nbsp;MIN=</span><span class="number"><font color="#c00000">10</font></span><span>; &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Runnable&nbsp;task&nbsp;=&nbsp;</span><span class="keyword">null</span><span>; &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">for</span><span>(</span><span class="keyword">int</span><span>&nbsp;j=</span><span class="number"><font color="#c00000">0</font></span><span>;j&lt;</span><span class="number"><font color="#c00000">20</font></span><span>;j++){ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;task&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;Runnable()&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">int</span><span>&nbsp;stoneNum&nbsp;=&nbsp;random.nextInt(MAX&nbsp;-&nbsp;MIN&nbsp;+&nbsp;</span><span class="number"><font color="#c00000">1</font></span><span>)&nbsp;+&nbsp;MIN;</span><span class="comment">//&nbsp;生成10~100范围的随机数 </span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;run()&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">for</span><span>&nbsp;(</span><span class="keyword">int</span><span>&nbsp;i&nbsp;=&nbsp;</span><span class="number"><font color="#c00000">1</font></span><span>;&nbsp;i&nbsp;&lt;=&nbsp;stoneNum;&nbsp;i++)&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(Thread.currentThread().getName()&nbsp;+&nbsp;</span><span class="string">"&nbsp;搬完"</span><span>+&nbsp;i&nbsp;+&nbsp;</span><span class="string">"块石头"</span><span>); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span>&nbsp;(i&nbsp;==&nbsp;</span><span class="number"><font color="#c00000">60</font></span><span>)&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&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;</span><span class="keyword">throw</span><span>&nbsp;</span><span class="keyword">new</span><span>&nbsp;RuntimeException(</span><span class="string">"搬完第60块石头不干了"</span><span>); &nbsp;&nbsp;</span></span></li><li><span>&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;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">try</span><span>{ &nbsp;&nbsp;</span></span></li><li><span>&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;Thread.sleep(</span><span class="number"><font color="#c00000">100</font></span><span>);</span><span class="comment">//休息下 </span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span><span class="keyword">catch</span><span>(InterruptedException&nbsp;e){e.printStackTrace();} &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>&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;queue.add(task); &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//开始干活 </span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;startWork(){ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;helotPool.prestartAllCoreThreads(); &nbsp;&nbsp;</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;</span><span class="keyword">static</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;main(String[]&nbsp;args)&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HelotPoolTest&nbsp;pool&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;HelotPoolTest(); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pool.assignTask(); &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pool.startWork(); &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>}&nbsp;&nbsp;</span></li></ol></div><pre title="处理线程泄露" class="java" style="display: none" pre_index="3" source_url="http://sunnylocus.iteye.com/blog/538282" codeable_type="Blog" codeable_id="538282" name="code">package com.bill99.thread.test;

import java.util.Random;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class HelotPoolTest {
	
	public static ThreadPoolExecutor helotPool;
	private int helotNum= 5;  //奴隶数
	private Random random = new Random(100);
	
	private BlockingQueue&lt;Runnable&gt; queue = new LinkedBlockingQueue&lt;Runnable&gt;();
	
	public HelotPoolTest() {
		ThreadFactory factory = new HelotFactory();
		helotPool = new ThreadPoolExecutor( helotNum,helotNum,1000,TimeUnit.SECONDS,queue,factory);
	}
	//分配任务
	public void assignTask(){
		final int MAX=100;
		final int MIN=10;
		Runnable task = null;
		for(int j=0;j&lt;20;j++){
			task = new Runnable() {
				int stoneNum = random.nextInt(MAX - MIN + 1) + MIN;// 生成10~100范围的随机数
				public void run() {
					for (int i = 1; i &lt;= stoneNum; i++) {
						System.out.println(Thread.currentThread().getName() + " 搬完"+ i + "块石头");
						if (i == 60) {
							throw new RuntimeException("搬完第60块石头不干了");
						}
						try{
							Thread.sleep(100);//休息下
						}catch(InterruptedException e){e.printStackTrace();}
					}
				}
			};
			queue.add(task);
		}
	}
	//开始干活
	public void startWork(){
		helotPool.prestartAllCoreThreads();
	}
	public static void main(String[] args) {
		HelotPoolTest pool = new HelotPoolTest();
		pool.assignTask();
		pool.startWork();
	}
}
</pre>
<p>&nbsp;程序启动，用Jprofiler监控，刚启动时会有5名奴隶干活不一会就会有线程退出，最后5个线程全部退，报警器对每个线程退出都能记录到导致线程退出的原因。标准的Executor实现是:</p>
<p><span style="color: #ff0000">在需求不高时回收空闲的线程，在需求增加时添加新的线程，如果任务抛出了异常，就会用一个全新的工作线程取代出错的那个。</span></p>
<p><span style="color: #000000">JDK文档是这么说的，不过通过Jprofiler监控只有在5名奴隶全部逃跑，没人干活的时候ThreadPoolExecutor才会生成一个新线程继续搬石头，并不是只要一个线程退出就会马上生成新线程去代替。</span></p><img src ="http://www.blogjava.net/orangelizq/aggbug/399926.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/orangelizq/" target="_blank">桔子汁</a> 2013-05-29 16:43 <a href="http://www.blogjava.net/orangelizq/archive/2013/05/29/399926.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>“奇思妙想”15位计算机大师</title><link>http://www.blogjava.net/orangelizq/archive/2012/08/07/384987.html</link><dc:creator>桔子汁</dc:creator><author>桔子汁</author><pubDate>Tue, 07 Aug 2012 07:58:00 GMT</pubDate><guid>http://www.blogjava.net/orangelizq/archive/2012/08/07/384987.html</guid><wfw:comment>http://www.blogjava.net/orangelizq/comments/384987.html</wfw:comment><comments>http://www.blogjava.net/orangelizq/archive/2012/08/07/384987.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/orangelizq/comments/commentRss/384987.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/orangelizq/services/trackbacks/384987.html</trackback:ping><description><![CDATA[<strong>语言大师：<br /></strong><br />@ <strong>Backus,John W. （约翰.巴科斯） Fortran语言和BNF范式的提出者<br /></strong>！1924年，Backus出生在费城。<br />！<strong>Fortran</strong> 第一门高级计算机语言，1957年商用。<br />！对Fortran的改进诞生了国际化的代数算法语言<strong>Algol</strong>，1958。<br />！巴科斯-诺尔（BNF）范式1959年6月，用于描述Algol的语法<br /><br />@ <strong>McCarthy,John. （约翰.麦卡锡） 发明了人工智能领域的首要语言Lisp<br /></strong>&nbsp; &#8220;如果希望计算机具有一般的智能，那么其外在结构就必须基于一般的常识和推理。&#8221;<br />！1927年，McCarthy出生在波士顿。<br />！1958年，为了向Fortran中加入递归，发明了Lisp(List processing language, 表处理语言)。<br /><br />@ <strong>Key,Alan. （艾伦） 面向对象，Smalltalk语言的发明者<br /></strong>&nbsp;&nbsp;&nbsp;&#8220;所有对事物的认识都始自于我们不愿盲目的接受这个世界。&#8221;<br />！1940年，出生于美国马萨诸塞州的春田市。获得过分子生物学和数学双学位，计算机博士学位。<br />！要想成为伟大的软件设计者，首先需要有能力把单纯的想法转化为正确、有效的程序，其次要能慧眼识珠，善于发现其他的优秀编程思想的价值。<br />！1972年9月，Alan完成了SmallTalk的第一版设计。<br />！1979年，史蒂夫.乔布斯和苹果的其他技术专家拜访了Alan的团队。<br />！1984年，Alan加盟了苹果。<br /><img src ="http://www.blogjava.net/orangelizq/aggbug/384987.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/orangelizq/" target="_blank">桔子汁</a> 2012-08-07 15:58 <a href="http://www.blogjava.net/orangelizq/archive/2012/08/07/384987.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]为什么 ESB 是 SOA 的基本组成部分</title><link>http://www.blogjava.net/orangelizq/archive/2010/11/30/339364.html</link><dc:creator>桔子汁</dc:creator><author>桔子汁</author><pubDate>Tue, 30 Nov 2010 02:05:00 GMT</pubDate><guid>http://www.blogjava.net/orangelizq/archive/2010/11/30/339364.html</guid><wfw:comment>http://www.blogjava.net/orangelizq/comments/339364.html</wfw:comment><comments>http://www.blogjava.net/orangelizq/archive/2010/11/30/339364.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/orangelizq/comments/commentRss/339364.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/orangelizq/services/trackbacks/339364.html</trackback:ping><description><![CDATA[原文地址：http://space.itpub.net/14789789/viewspace-421356<br />
<br />
<p><a name="N10098"><span class="atitle">引言</span></a></p>
<p><a onclick="javascript:tagshow(event, 'IBM');" href="javascript:;" target="_self"><u><strong>IBM</strong></u></a> 对 <a onclick="javascript:tagshow(event, 'ESB');" href="javascript:;" target="_self"><u><strong>ESB</strong></u></a> 的立场是——并且一贯是——认为 ESB 作为 <a onclick="javascript:tagshow(event, 'SOA');" href="javascript:;" target="_self"><u><strong>SOA</strong></u></a> 中的一种体系结构模式发挥了根本性的作用。ESB 是实现成功 SOA 采用的重要入口点，并且是任何面向服务的解决方案的关键成功因素。事实上，作为对 SOA 中的 ESB 承诺的一部分，IBM 提供了实现 ESB 模式的<a href="http://www.ibm.com/developerworks/cn/architecture/ar-esbpat2/index.html#products" cmimpressionsent="1"><font color="#996699">三个战略产品</font></a>。</p>
<p>本系列的<a href="http://www.ibm.com/developerworks/cn/architecture/ar-esbpat1/" cmimpressionsent="1"><font color="#5c81a7">第 1 部分</font></a>描述了企业服务总线 (ESB) 体系结构模式如何适应 IBM SOA Foundation，以及 ESB与 Foundation 的其他部分如何相关。</p>
<p>本文介绍以下主题：</p>
<ul>
    <li><a onclick="javascript:tagshow(event, '%C9%E8%BC%C6');" href="javascript:;" target="_self"><u><strong>设计</strong></u></a>良好和实现良好的 ESB 能够为面向服务的解决方案提供的价值
    <li>一些在设计和实现 ESB 时要遵循的最佳实践
    <li>IBM 对作为 SOA 组成部分 ESB 的承诺</li>
</ul>
<p><a name="N100E9"><span class="atitle">与 SOA 相关的 ESB</span></a></p>
<p><a href="http://www.ibm.com/developerworks/webservices/library/ws-soa-whitepaper/" nmouseover="linkQueryAppend(this)" cmimpressionsent="1"><font color="#5c81a7">IBM SOA Foundation 白皮书</font></a>描述了 IBM 交付 SOA 价值的整体方法。SOA Foundation 的参考体系结构（<a href="http://www.ibm.com/developerworks/cn/architecture/ar-esbpat2/figure1.html" cmimpressionsent="1"><font color="#5c81a7">图 1</font></a>显示了逻辑模型视图）的核心中具有 ESB。该参考体系结构的描述声明&#8220;ESB 的存在是简化服务调用任务的基础&#8221;。虽然该白皮书是在 2005 年末发布的，但是其中预述的论点却随着时间推移而通过我们在采用 SOA 的客户方面的经验得到加强。</p>
<p>本系列的<a href="http://www.ibm.com/developerworks/cn/architecture/ar-esbpat1/" cmimpressionsent="1"><font color="#5c81a7">第 1 部分</font></a>表明了 ESB 是称为 SOA 的更大体系结构模式中的一个关键体系结构模式。充当中间层的 ESB 提供了服务交互中参与者之间的松散耦合连接，从而提供了 SOA 的中枢。作为中间层，ESB 执行服务虚拟化以协调服务请求程序和服务提供程序之间的差异，并提供面向方面的连接以用作诸如<a onclick="javascript:tagshow(event, '%B9%DC%C0%ED');" href="javascript:;" target="_self"><u><strong>管理</strong></u></a>和安全性等 SOA 策略的执行点。松散耦合允许解决方案中的组成部分之间彻底分离关注事项（时间上、技术上和组织上的分离），从而同时支持业务流程和 IT 系统的灵活性和敏捷性。</p>
<p>通过 ESB 实现的松散耦合的部分优点（包括本系列的<a href="http://www.ibm.com/developerworks/cn/architecture/ar-esbpat1/" cmimpressionsent="1"><font color="#5c81a7">第 1 部分</font></a>详细描述的服务虚拟化和面向方面的连接中所固有的优点）如下：</p>
<ul>
    <li>请求程序和提供程序不必就消息格式、消息传输甚至目标地址达成一致。
    <li>请求消息可由多个提供程序中的任何一个进行处理，请求程序不必显式地确定提供程序。这种路由可以基于相应的版本、服务质量或其他度量。
    <li>现有的请求程序无需更改即可连接到新的提供程序。
    <li>现有的提供程序无需更改即可对新的请求程序公开。
    <li>可以对请求程序做出更改而不影响提供程序，或者对提供程序做出更改而不影响请求程序。
    <li>解决方案的横切方面，例如安全性和管理等等，可由 ESB 进行添加、执行或加强。
    <li>可以实现新级别的动态行为，因为 ESB 能够为请求程序和提供程序之间的每个交互实时执行策略。</li>
</ul>
<p><a name="N10122"><span class="atitle">作为 SOA 入口点的 ESB</span></a></p>
<p>一次性全面采用 SOA 可能是一项艰巨的任务。IBM 已确定了五个<a href="http://www-306.ibm.com/software/solutions/soa/entrypoints/" nmouseover="linkQueryAppend(this)" cmimpressionsent="1"><font color="#5c81a7">SOA 入口点</font></a>，这些入口点提供了有关如何开始渐进地采用 SOA 的指导。渐进的采用方法允许企业以最适合需要的方式和步调采用 SOA。为什么我们要确定五个入口点？简单的原因在于众口难调；企业的在成熟度级别和特定需求方面各不相同，适合于一家企业的入口点可能不适合于另一家企业。这五个入口点基于已导致我们的客户成功实现了 SOA 的方法。存在两种类别的入口点：</p>
<ul>
    <li><strong>以业务为中心的入口点</strong>——人员、信息和流程——允许您从一种侧重于基本企业资产的方法开始。
    <li><strong>以 IT 为中心的入口点</strong>——连接性和重用——允许您为 SOA 奠定技术基础。</li>
</ul>
<p>您也许已经从<a href="http://www.ibm.com/developerworks/webservices/library/ws-soa-whitepaper/" nmouseover="linkQueryAppend(this)" cmimpressionsent="1"><font color="#5c81a7">SOA Foundation 白皮书</font></a>中预料到，<em>连接性</em>意味着使用 ESB 来&#8220;通过更加安全、可靠和可伸缩的方法简化 IT 环境，从而在企业内外进行连接&#8221;。IBM 认为，虽然 ESB 无疑是一种以 IT 为中心的 SOA 方法，但是&#8220;它本身交付了实际业务价值，并且是将来的 SOA 计划的核心构件&#8221;。本文中的一个关键问题（将在下面进行讨论）是如何最好地使用 ESB 来形成将来的 SOA 计划的构件，以及如何通过连接性入口点获得最大的业务价值。</p>
<p>存在多种利用连接性入口点的方法。有时客户已经在其环境中定义了一些服务（也许是通过合作伙伴），不过是直接连接的服务；这种情况导致缺乏灵活性并增加管理成本。如上所述，在此类环境中插入 ESB 可以提供直接的松散耦合优点。此外，ESB 的存在为将来定义附加服务、创造附加重用机会、支持新的重用渠道、降低管理成本和获得更多敏捷性的工作创造了条件。</p>
<p>客户通常知道 ESB 的价值并渴望开始从 ESB 中实现好处，但是他们还没有在其环境中定义服务。我们看到了两种已采用过的成功技术，这两种技术帮助在这种情况下从 ESB 获得好处。客户经常混合使用重用和连接性入口点。他们确定需要作为服务来连接的功能或应用程序（请求程序或提供程序）。同时，他们将 ESB 插入该体系结构，以提供新的服务请求程序和提供程序之间所需的松散耦合。混合方法得以流行的一个重要因素是 ESB 产品的转换和变换功能。此类功能允许使用同一个 ESB 产品作为某种形式的适配器，以便以更加可重用的形式公开功能或应用程序，并提供所需的服务虚拟化和面向方面的连接。这里成功的关键是谨慎地开始，公开少量的服务并开发对应的中介，但是这些服务和中介都在为考虑中的整个最终范围而设计的体系结构之内。</p>
<p>有些客户插入 ESB 以建立组织中连接的所需方向，尽管起初还没有确定要连接的服务。在此情况下，ESB 是组织的总体参考体系结构的一部分；<em>参考体系结构</em>提供了体系结构方向，并强制要求最终将作为解决方案一部分而创建的所有服务（请求程序和提供程序）进行松散耦合连接。ESB 是用于实现该松散耦合的首选机制。采用 ESB 实际上消除了解决方案中的直接连接不知不觉地增长的可能性。这里成功的关键是：</p>
<ul>
    <li>采用一个要求并演示 ESB 使用的参考体系结构。
    <li>考虑解决方案的整个最终范围，并支持最佳的 ESB 产品选择。
    <li>随着解决方案的发展而实施强有力的治理，以确保利用 ESB 来连接到引入解决方案的新服务（请求程序和提供程序）。</li>
</ul>
<p><a name="N10163"><span class="atitle">SOA 入口点最佳实践</span></a></p>
<p>存在一组 IBM 强烈建议用于任何 SOA 采用的最佳实践。这些最佳实践的最重要元素是建立一个路线图并渐进地实现该路线图，该路线图定义了实现所需业务目标的采用计划（请参见<a href="http://www.ibm.com/developerworks/cn/architecture/ar-esbpat2/index.html#resources" cmimpressionsent="1"><font color="#996699">参考资料</font></a>部分以获得指向文章&#8220;Service Oriented Architecture:An Introduction for Managers&#8221;的链接）。该路线图包括两个重要组成部分：</p>
<ol>
    <li><strong>战略远景</strong>，业务或 IT 的方向陈述（包括参考体系结构和治理计划），可用作决策制定、组织参与和标准采用的指导原则。
    <li><strong>一组项目计划</strong>，定义实现项目以满足当前业务驱动因素的即时和将来需要。</li>
</ol>
<p>此类路线图允许您渐进地实现 SOA，以在每个项目步骤中回报业务价值。</p>
<p>您应该在执行该路线图的早期确定您业务的最佳 SOA 入口点。您应该基于从您的总体战略远景和当前 SOA 成熟度级别得出的要求来选择该入口点。该入口点可能是也可能不是连接性入口点；它可能是上述入口点的混合。但是，连接性入口点是最普遍的入口点，因为有如此多的客户具有将请求程序连接到提供程序的即时需要，并希望获得 ESB 提供的松散耦合的好处。IBM 提供了一个在线工具<a href="http://www.ibm.com/software/cn/solution/soa/" nmouseover="linkQueryAppend(this)" cmimpressionsent="1"><font color="#5c81a7">Business Value Analyzer</font></a>，以帮助您选择 SOA 入口点。</p>
<p>另一个最佳实践是建立治理框架以确保组织遵循该路线图（请参见<a href="http://www.ibm.com/developerworks/cn/architecture/ar-esbpat2/index.html#resources" cmimpressionsent="1"><font color="#996699">参考资料</font></a>以获得指向文章&#8220;SOA Governance and Service Lifecycle Management&#8221;的链接）。SOA 所促进的灵活性增强和跨组织性质要求组织建立治理框架，以实现主动的决策制定、准确的跟踪、改进的服务能力和更好的交流。有效的治理通过在增添价值的同时平衡风险和回报，从而帮助实现企业的业务目标。</p>
<p>正如上面所建议的，渐进的 SOA 采用是成功的关键。IBM 建议从试验项目开始，该试验项目：</p>
<ul>
    <li>处理得到充分了解、重要但不关键的业务需要。
    <li>实现参考体系结构的某些重要方面（也许是 ESB 和一组示例服务、提供程序、请求程序，这些方面用于演示 SOA 的使用）。
    <li>需要一个超出当前能力的可达范围。
    <li>积累 SOA 技能。
    <li>用作对采用 SOA 治理和新的服务生命周期管理流程所进行的试验。
    <li>产生将会投入生产应用并将交付投资回报的结果。</li>
</ul>
<p>通过 SOA 实现的关注事项分离甚至允许试验项目以能够积累专业经验和验证业务价值但不中断主要操作的方式引入 SOA。</p>
<br />
<p><a name="N101AD"><span class="atitle">SOA 连接性入口点最佳实践</span></a></p>
<p>除了 SOA 最佳实践以外，还存在其他更特定于 ESB 的最佳实践：</p>
<ul>
    <li>仅当 ESB 在您的路线图中有意义时才采用 ESB。例如，如果 SOA 入口点以业务为中心，您可以推迟通过 ESB 实现的松散耦合，尽管您的参考体系结构中包括了 ESB。
    <li>基于您的参考体系结构和一组跨全套项目计划的实际要求来设计 ESB 并选择 ESB 产品。我们说<em>实际</em>是因为您应该集中于未来几年中的需要；到您超过该时间期限时，产品和需求已经发生了改变。如果仅考虑即时需求，尤其是忽略服务请求程序和提供程序的预期需要，则会导致选择非最优 ESB 产品。您必须明确地在公司的约束内行事，例如年度资金周期和预算，但您同时还希望将短期采购和决策与考虑中的长期（三至五年）目标保持一致。
    <li>根据情况考虑 ESB 联合。更大型的异构企业通常作为某种自治域的联合体出现，这些自治域基于各个业务部门或者职能或治理方面。在此类环境中，某些服务可以在单个域中进行共享或重用，而其他服务可以在整个企业中进行共享或重用。在这些情况下，我们建议采用某种形式的 ESB 联合，该形式的 ESB 联合与域联合的需要相匹配。ESB 联合允许在不同的域中使用不同的 ESB 产品，并支持域需求与产品功能之间的最佳匹配。路线图和参考体系结构应该为任何给定域的产品选择提供指导原则甚至选项，以确保实现企业范围的优化。我们进一步建议使用联合服务注册中心和存储库，为企业范围的管理和可重用服务的治理提供帮助。</li>
</ul>
<br />
<p><a name="N101C6"><span class="atitle">您是否需要 ESB 来成功采用 SOA？</span></a></p>
<p>前面几个部分说明了从 ESB 开始成功的 SOA 之旅。另外四个入口点不需要 ESB 即可开始该旅程。然而 IBM 认为，无论其入口点是什么，绝大多数成熟的面向服务的解决方案都将包括 ESB，以最大化 SOA 中所需的敏捷性和灵活性。因此，虽然初始项目可以不包括 ESB，但是在您的长期业务和 IT 路线图中，ESB 应该是参考体系结构的一部分，以实现成功的 SOA。如果没有 ESB 提供的敏捷性和灵活性，您会发现在面临不可避免的变更时，管理解决方案将变得非常困难，并且开销很大。</p>
<p>这是否意味着在准备好包括 ESB 在内的所有体系结构组件之前，您还没有拥有真正的 SOA 呢？此问题没有正确或错误的答案，并且可能存在许多选项。在某种程度上，此问题并不重要——重要的是在实现新的 SOA 项目以及解决方案根据您的路线图逐渐变得成熟时，您要渐进地向业务交互越来越多的价值。</p>
<p>我们的客户好像同意这个观点。几乎我们的所有采用 SOA 的客户都从 ESB 开始，或最终在解决方案中使用了 ESB，并从 ESB 支持的灵活性和敏捷性中获得了重大的 IT 和业务价值。</p>
<br />
<p><a name="products"><span class="atitle">IBM 的 ESB 产品系列</span></a></p>
<p>IBM 对 ESB 的重视及其对 ESB 的承诺体现在我们如何使用产品来履行对 SOA Foundation 的承诺上。IBM 推出了一个产品系列，其中包括三个实现 ESB 体系结构模式的产品：</p>
<ul>
    <li><a href="http://www.ibm.com/software/integration/wbimessagebroker/" nmouseover="linkQueryAppend(this)" cmimpressionsent="1"><font color="#5c81a7">IBM WebSphere&#174; Message Broker</font></a>是一个成熟的产品，此产品在多年前就已实现了该模式。
    <li><a href="http://www.ibm.com/software/integration/wsesb/" nmouseover="linkQueryAppend(this)" cmimpressionsent="1"><font color="#996699">IBM WebSphere Enterprise Service Bus</font></a>于 2005 年推出，此产品专门设计用于在侧重于标准的环境中实现该模式。
    <li><a href="http://www.ibm.com/software/integration/datapower/xi50/" nmouseover="linkQueryAppend(this)" cmimpressionsent="1"><font color="#5c81a7">IBM WebSphere DataPower Integration Appliance XI50</font></a>于 2006 年推出，此产品以可容易地部署和管理的工具的形式封装了该模式。</li>
</ul>
<p>为什么要推出三个产品？同样是由于众口难调。所有三个产品都实现了 ESB 模式，但是分别强调了使它们适合于特定情况的特定功能。您将在<a href="http://www.ibm.com/developerworks/cn/" cmimpressionsent="1"><font color="#996699">developerWorks</font></a>上找到许多文章和<a href="http://www.redbooks.ibm.com/" nmouseover="linkQueryAppend(this)" cmimpressionsent="1"><font color="#5c81a7">IBM 红皮书&#174;</font></a>，编写这些内容的目的是为了帮助在面向服务的解决方案中使用这些产品。<br />
</p>
<p><a name="N1020B"><span class="atitle">结束语</span></a></p>
<p>本文再次强调了 IBM 一如既往的信仰，即 ESB 是称为 SOA 的更大模式中的一种基本体系结构模式。您通过阅读本文了解了 ESB 如何帮助从 SOA 获得业务价值，以及 ESB 如何成为成功的 SOA 采用的重要入口点——ESB 模式是如此重要，以致于 IBM 目前在 SOA Foundation 组合中推出了三个实现该模式的战略产品。
<table border="0" cellspacing="0" cellpadding="0" width="150" align="right">
    <tbody>
        <tr>
            <td width="10"><img style="cursor: pointer" title="点击图片可在新窗口打开" alt="" src="http://www.ibm.com/i/c.gif" width="10" height="1" /></td>
            <td></td>
        </tr>
    </tbody>
</table>
</p>
<br />
<img src ="http://www.blogjava.net/orangelizq/aggbug/339364.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/orangelizq/" target="_blank">桔子汁</a> 2010-11-30 10:05 <a href="http://www.blogjava.net/orangelizq/archive/2010/11/30/339364.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]SCA和SDO</title><link>http://www.blogjava.net/orangelizq/archive/2010/11/30/339363.html</link><dc:creator>桔子汁</dc:creator><author>桔子汁</author><pubDate>Tue, 30 Nov 2010 01:57:00 GMT</pubDate><guid>http://www.blogjava.net/orangelizq/archive/2010/11/30/339363.html</guid><wfw:comment>http://www.blogjava.net/orangelizq/comments/339363.html</wfw:comment><comments>http://www.blogjava.net/orangelizq/archive/2010/11/30/339363.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/orangelizq/comments/commentRss/339363.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/orangelizq/services/trackbacks/339363.html</trackback:ping><description><![CDATA[<span style="widows: 2; text-transform: none; text-indent: 0px; border-collapse: separate; font: medium Simsun; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(0,0,0); word-spacing: 0px; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class="Apple-style-span"><span style="text-align: left; line-height: 21px; font-family: simsun, 宋体, sans-serif; color: rgb(73,73,73); font-size: 14px" class="Apple-style-span">服务组件架构（SCA）语言无关的编程模型，它提供了一种统一的面向服务构件的调用方式，使得客户可以把不同的软件模块通过服务构件的标准化而统一地封装起来和被调用访问。SCA描述了利用面向服务架构（SOA）来构建应用程序和系统的模型。SCA是基于开放标准（例如Web服务）构建的，它扩展和补充了先前的服务实现方法。<br />
<br />
SCA的基本思想是将业务功能作为一系列服务来提供，这些服务组合到一起，以创建满足特定业务需要的解决方案。这些复合应用程序既可以包含专门为该应用程序创建的新服务，也可以包含来自现有系统和应用程序的业务功能（作为复合应用程序的一部分来重用）。SCA为服务组合和服务组件的创建（包括SCA复合应用程序内部现有应用程序功能的重用）提供了模型。<br />
<br style="color: rgb(255,0,0)" />
<span style="line-height: 21px; word-wrap: normal; color: rgb(255,0,0); word-break: normal">注：UML也是一种建模语言，而可以看到SCA组件模型是对应的不是UML中的类，而可能是一个粗粒度的组件包，对于粗粒度的组件包，特别是一个服务组件，我们关注的就是它暴露了哪些服务，有哪些属性，引用了哪些其它子组件等。这些描述清楚了一个服务基本就描述清楚了。特别是在构建组合服务的时候，我们看到服务和应用描述方式很容易将多个子组件串联在一起，而不需要通过BPEL服务编排方式实现。</span><br />
<br />
SCA这一模型旨在包含广泛的服务组件技术以及用于连接这些组件的访问方法。对于组件，它不仅包括各种编程语言，还包括通常与这些语言一起使用的框架和环境。对于访问方法，SCA复合应用程序允许使用各种常用的通信和服务访问技术，例如，Web服务、消息传递系统和远程过程调用（RPC）。<br />
<br />
SCA包括如下规范<br />
<ul style="padding-bottom: 0px; border-right-width: 0px; list-style-type: none; margin: 0px; padding-left: 0px; padding-right: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px">
    <li style="padding-bottom: 0px; border-right-width: 0px; list-style-type: disc; margin: 0px 0px 0px 30px; padding-left: 0px; padding-right: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px">SCA Java EJB客户及实现（SCA Java EJB Client and Implementation）</li>
    <li style="padding-bottom: 0px; border-right-width: 0px; list-style-type: disc; margin: 0px 0px 0px 30px; padding-left: 0px; padding-right: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px">SCA装配模型（SCA Assembly Model）定义了构成一个SCA系统的各种构件和他们之间的关系</li>
    <li style="padding-bottom: 0px; border-right-width: 0px; list-style-type: disc; margin: 0px 0px 0px 30px; padding-left: 0px; padding-right: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px">SCA策略框架（SCA Policy Framework）</li>
    <li style="padding-bottom: 0px; border-right-width: 0px; list-style-type: disc; margin: 0px 0px 0px 30px; padding-left: 0px; padding-right: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px">SCA Java注释、API和组件实现</li>
    <li style="padding-bottom: 0px; border-right-width: 0px; list-style-type: disc; margin: 0px 0px 0px 30px; padding-left: 0px; padding-right: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px">SCA绑定（SCA Binding）规范适用于服务和服务需求</li>
</ul>
<br />
服务组件提供给别的服务调用的入口叫Interface(接口)。而服务组件本身可能也需要调用别的服务，这个调用出口叫Reference(引用)。无论是接口还是引用，其调用规范都是WSDL或Java接口SCA服务组件与传统组件的主要区别在于:<br />
<ul style="padding-bottom: 0px; border-right-width: 0px; list-style-type: none; margin: 0px; padding-left: 0px; padding-right: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px">
    <li style="padding-bottom: 0px; border-right-width: 0px; list-style-type: disc; margin: 0px 0px 0px 30px; padding-left: 0px; padding-right: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px">服务组件往往是粗粒度的，而传统组件以细粒度居多。</li>
    <li style="padding-bottom: 0px; border-right-width: 0px; list-style-type: disc; margin: 0px 0px 0px 30px; padding-left: 0px; padding-right: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px">服务组件的接口是标准的，主要是WSDL接口，而传统组件常以具体API形式出现。</li>
    <li style="padding-bottom: 0px; border-right-width: 0px; list-style-type: disc; margin: 0px 0px 0px 30px; padding-left: 0px; padding-right: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px">服务组件的实现与语言是无关的，而传统组件常绑定某种特定的语言</li>
</ul>
<br style="font-weight: bold" />
<span style="line-height: 21px; word-wrap: normal; word-break: normal; font-weight: bold">服务数据对象（SDO）</span><br />
<br />
统一访问不同数据源的数据编程模型，让开发人员可以从不同的数据源以统一的方式访问和操纵数据。服务数据对象（SDO）的设计是为了简化和统一应用程序处理数据的方式。利用SDO，应用程序编程人员可以一致地访问和操纵来自异构数据源的数据，包括关系数据库、XML数据源、Web服务和企业信息系统。<br />
<br />
在SDO中有两个要素，一个是数据视图，一个是数据视图中的数据对象。数据视图是描述数据对象的分层结构，包括数据对象树和更改摘要；而数据对象是保存数据的组件，有键/值对组成，每个值可以是原始的数据类型，也可以是一个数据对象，并支持序列化。<br />
<br />
为何要采用SCA和SDO?因为通过SCA和SDO获得了更高的灵活性和更高的开发效率。可以在不改变应用程序情况下,使用不同的技术来作为组件的实现,或者改变通信协议等等，同时模块也可以根据容易的被重用和组装，易于修改和变更。</span></span>
<img src ="http://www.blogjava.net/orangelizq/aggbug/339363.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/orangelizq/" target="_blank">桔子汁</a> 2010-11-30 09:57 <a href="http://www.blogjava.net/orangelizq/archive/2010/11/30/339363.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]SCA/SDO规范的来龙去脉</title><link>http://www.blogjava.net/orangelizq/archive/2010/11/30/339362.html</link><dc:creator>桔子汁</dc:creator><author>桔子汁</author><pubDate>Tue, 30 Nov 2010 01:54:00 GMT</pubDate><guid>http://www.blogjava.net/orangelizq/archive/2010/11/30/339362.html</guid><wfw:comment>http://www.blogjava.net/orangelizq/comments/339362.html</wfw:comment><comments>http://www.blogjava.net/orangelizq/archive/2010/11/30/339362.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/orangelizq/comments/commentRss/339362.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/orangelizq/services/trackbacks/339362.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SOA已经成为公认的IT基础架构发展的趋势，它为我们描绘了一幅美妙的IT系统和业务系统完美结合的图画。然而，即使是在各咨询机构推崇SOA，各厂商大肆宣传推广SOA，用户普遍认可SOA的今天，SOA的美好未来依然给人一种不清晰、不踏实的感觉。
<p>　　我们常常说SOA需要解决如何落地的问题。这个难题无法一蹴而就，必须花费很多时间才能逐步进行解决。但在目前，我们已经为SOA找到了一个着地的落脚点，这就是SCA/SDO规范。</p>
<p>　　2005年11月， IBM、BEA、IONA、Oracle、S等几家厂商就合作建立新的业内规范来简化 SOA 应用发展达成了一致，共同发布了两项针对SOA的重要构件模型规范——SCA 0.9和SDO。此后，该团体陆续吸引了Red Hat、普元、TIBCO等多家公司的加盟，形成了OSOA（Open Service Oriented Architecture）联盟，目前成员数量达到18家。OSOA联盟旨在为SOA起草一系列的规范，并以免版税的许可方式提供给业界使用。AP</p>
<p>　　2007年3月，OSOA联盟宣布了SCA和SDO规范中关键部分的完成，发布了SCA 1.0和SDO 2.1，并将其正式提交给OASIS，通过其开放式标准过程进行推动。</p>
<p>　　SCA规范旨在简化服务的创建和合成，对于运用基于SOA方式服务的应用构建十分关键。随着SCA规范的完成，联盟合作厂商希望将其标准化过程提交给OASIS。此外，联盟厂商也已完成了SDO规范，旨在实现对多个站点中多种格式数据的统一访问，并将把SDO基于Java的规范开发和<a onclick="javascript:tagshow(event, '%B9%DC%C0%ED');" href="javascript:;" target="_self"><u><strong>管理</strong></u></a>提交给Java社团过程（Java Community Process，JCP）组织，而基于非Java的规范（C++）提交给OASIS。</p>
<p>　　SCA和SDO规范能帮助企业更便捷地创建新的以及改造现有的IT资产，使之可复用、易整合，以满足不断变化的业务需求。这些规范提供了统一服务的途径，大大降低了在应用开发过程中，因程序<a onclick="javascript:tagshow(event, '%C9%E8%BC%C6');" href="javascript:;" target="_self"><u><strong>设计</strong></u></a>语言与部署平台的不同而产生的复杂性。SCA和SDO规范都是用于简化业务逻辑和业务数据呈现的新兴技术。</p>
<p>　　&#8220;我们对OSOA联盟取得这一里程碑成就，并选择了在接下来通过开放标准过程继续推动这一重要工作表示欢迎和赞赏，&#8221;OASIS CEO和总裁Patrick Gannon说，&#8220;我们希望能进一步推进SCA规范，实现标准化，获得最广泛的行业应用。&#8221;</p>
<p>　　OASIS不只是研究和产生标准，同时也跟其他国际组织一起合作推动标准的采用和技术的发展。通过十多年的努力，OASIS已经得到广泛的承认，可以直接向国际标准组织、国际电联和联合国相关标准组织直接提交标准提案。</p>
<p>　　SCA是一种规范，它使开发人员可以将注意力集中在业务逻辑的编写上。更直接地说，它是一种大大改进了的部署描述符，它可以使用任何语言而不限于Java。此外，编程人员还可以使用编程式语言和声明式语言，比如BPEL和XSLT（eXtensible Stylesheet Language Transformation，扩展样式表转换语言）。SCA的特别之处在于，它对安全性、事务和可靠消息传递之类的特性使用了声明式策略的理念。</p>
<p>　　SCA是专门针对SOA设计的，而不像J2EE只是面向SOA做了修改。SCA关注的是如何描述按照各种编程模型和协议编写的组件所组成的程序集。SCA允许开发应用程序集而不考虑特定的API或具体语言。中间件</p>
<p>　　SCA的核心概念是服务及其相关实现。服务由接口定义，而接口包含一组操作。服务实现可以引用其他服务，称为引用。服务可以有一个或多个属性，这些属性是可以在外部配置的数据值。</p>
<p>　　SCA中的一个关键推动因素是SDO（Service Data Object，服务数据对象）。SDO用于表示业务数据、参数以及服务调用的返回值，当它遍历服务网络时，它还是一种表示数据的方式。注意，也可以使用XML Beans及其他技术。</p>
<p>　　SCA组件被组成为程序集。程序集是服务级的应用程序，它是服务的集合，这些服务被连接在一起，并进行了正确的配置。SCA程序集运行在两个级别：第一种情况，程序集是系统内的一组松散连接的组件；另一种情况，程序集是模块内的一组松散连接的组件。二者的区别在于，一般来说，模块是组件的集合，而系统是模块的集合。此外，系统对应于&#8220;大规模编程&#8221;（programming in the large或megaprogramming），而模块对应于&#8220;小规模编程&#8221;（programming in the small），比如构建当今的典型应用程序。</p>
<p>　　将组件连接到它所依赖的服务的方式就是服务网络&#8220;装配&#8221;的方式。程序集已经在许多技术和框架中广为应用，比如CORBA、J2EE、ATG Dynamo和Spring，也就是说，它并不是新出现的。从这些技术中我们可以知道，程序集提供了许多重要的优点，比如更轻松的迭代开发，以及避免使业务逻辑依赖于中间件容器。SCA使用程序集解决了许多SOA开发中的重要问题，包括：</p>
<p>　　*业务逻辑与底层基础架构、服务质量和传输的分离。</p>
<p>　　*&#8220;小规模编程&#8221;与&#8220;大规模编程&#8221;的联系。</p>
<p>　　*为架构的设计、编码和操作性部署在自底向上（bottom-up）和自顶向下（top-down）两种方法中来回切换提供了一种统一的方式。<br />
</p>
<br />
<img src ="http://www.blogjava.net/orangelizq/aggbug/339362.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/orangelizq/" target="_blank">桔子汁</a> 2010-11-30 09:54 <a href="http://www.blogjava.net/orangelizq/archive/2010/11/30/339362.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]有效编写软件的75条建议 </title><link>http://www.blogjava.net/orangelizq/archive/2010/08/19/329411.html</link><dc:creator>桔子汁</dc:creator><author>桔子汁</author><pubDate>Thu, 19 Aug 2010 12:15:00 GMT</pubDate><guid>http://www.blogjava.net/orangelizq/archive/2010/08/19/329411.html</guid><wfw:comment>http://www.blogjava.net/orangelizq/comments/329411.html</wfw:comment><comments>http://www.blogjava.net/orangelizq/archive/2010/08/19/329411.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/orangelizq/comments/commentRss/329411.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/orangelizq/services/trackbacks/329411.html</trackback:ping><description><![CDATA[<p>有效编写软件的75条建议 <br />
建议只是建议而已。<br />
&nbsp;1. 你们的项目组使用源代码管理工具了么？ <br />
应该用。VSS、CVS、PVCS、ClearCase、CCC/Harvest、FireFly都可以。我的选择是VSS。<br />
&nbsp;<br />
2. 你们的项目组使用缺陷管理系统了么？<br />
&nbsp;应该用。ClearQuest太复杂，我的推荐是BugZilla。 </p>
<p>3. 你们的测试组还在用Word写测试用例么？　<br />
&nbsp;不要用Word写测试用例（Test Case）。应该用一个专门的系统，可以是Test Manager，也可以是自己开发一个ASP.NET的小网站。主要目的是Track和Browse。<br />
&nbsp;<br />
4. 你们的项目组有没有建立一个门户网站？　<br />
　要有一个门户网站，用来放Contact Info、Baselined Schedule、News等等。推荐Sharepoint Portal Server 2003来实现，15分钟就搞定。买不起SPS 2003可以用WSS (Windows Sharepoint Service)。 </p>
<p>5. 你们的项目组用了你能买到最好的工具么？　<br />
　应该用尽量好的工具来工作。比如，应该用VS.NET而不是Notepad来写C#。用Notepad写程序多半只是一种炫耀。但也要考虑到经费，所以说是"你能买到最好的"。<br />
&nbsp;<br />
6. 你们的程序员工作在安静的环境里么？　<br />
　需要安静环境。这点极端重要，而且要保证每个人的空间大于一定面积。<br />
&nbsp;<br />
7. 你们的员工每个人都有一部电话么？<br />
需要每人一部电话。而且电话最好是带留言功能的。当然，上这么一套带留言电话系统开销不小。不过至少每人一部电话要有，千万别搞得经常有人站起来喊："某某某电话"。《人件》里面就强烈谴责这种做法。<br />
&nbsp;<br />
8. 你们每个人都知道出了问题应该找谁么？　<br />
　应该知道。任何一个Feature至少都应该有一个Owner，当然，Owner可以继续Dispatch给其他人。 </p>
<p>9. 你遇到过有人说"我以为&#8230;"么？　<br />
　要消灭"我以为"。Never assume anything。<br />
&nbsp;<br />
10. 你们的项目组中所有的人都坐在一起么？　<br />
　需要。我反对Virtual Team，也反对Dev在美国、Test在中国这种开发方式。能坐在一起就最好坐在一起，好处多得不得了。<br />
&nbsp;<br />
11. 你们的进度表是否反映最新开发进展情况？ 　<br />
　应该反映。但是，应该用Baseline的方法来管理进度表：维护一份稳定的Schedule，再维护一份最新更改。Baseline的方法也应该用于其它的Spec。Baseline是变更管理里面的一个重要手段。<br />
&nbsp;<br />
12. 你们的工作量是先由每个人自己估算的么？　<br />
　应该让每个人自己估算。要从下而上估算工作量，而不是从上往下分派。除非有其他原因，比如政治任务工期固定等。<br />
&nbsp;<br />
13. 你们的开发人员从项目一开始就加班么？　<br />
　不要这样。不要一开始就搞疲劳战。从项目一开始就加班，只能说明项目进度不合理。当然，一些对日软件外包必须天天加班，那属于剥削的范畴。<br />
&nbsp;<br />
14. 你们的项目计划中Buffer Time是加在每个小任务后面的么？　<br />
　不要。Buffer Time加在每个小任务后面，很容易轻易的就被消耗掉。Buffer Time要整段的加在一个Milestone或者checkpoint前面。<br />
&nbsp;<br />
15. 值得再多花一些时间，从95%做到100%好值得，非常值得。　<br />
　尤其当项目后期人困马乏的时候，要坚持。这会给产品带来质的区别。<br />
&nbsp;<br />
16. 登记新缺陷时，是否写清了重现步骤？<br />
　要。这属于Dev和Test之间的沟通手段。面对面沟通需要，详细填写Repro Steps也需要。<br />
&nbsp;<br />
17. 写新代码前会把已知缺陷解决么？<br />
&nbsp;要。每个人的缺陷不能超过10个或15个，否则必须先解决老的bug才能继续写新代码。<br />
&nbsp;<br />
18. 你们对缺陷的轻重缓急有事先的约定么？　<br />
　必须有定义。Severity要分1、2、3，约定好：蓝屏和Data Lost算Sev 1，Function Error算Sev 2，界面上的算Sev 3。但这种约定可以根据产品质量现状适当进行调整。<br />
&nbsp;<br />
19. 你们对意见不一的缺陷有三国会议么？<br />
&nbsp;必须要有。要有一个明确的决策过程。这类似于CCB (Change Control Board)的概念。<br />
&nbsp;<br />
20. 所有的缺陷都是由登记的人最后关闭的么？ 　<br />
　Bug应该由Opener关闭。Dev不能私自关闭Bug。<br />
&nbsp;<br />
21. 你们的程序员厌恶修改老的代码么？　<br />
　厌恶是正常的。解决方法是组织Code Review，单独留出时间来。XP也是一个方法。<br />
&nbsp;<br />
22. 你们项目组有Team Morale Activity么？　<br />
　每个月都要搞一次，吃饭、唱歌、Outing、打球、开卡丁车等等，一定要有。不要剩这些钱。<br />
&nbsp;<br />
23. 你们项目组有自己的Logo么？　<br />
　要有自己的Logo。至少应该有自己的Codename。<br />
&nbsp;<br />
24. 你们的员工有印有公司Logo的T-Shirt么？　<br />
　要有。能增强归属感。当然，T-Shirt要做的好看一些，最好用80支的棉来做。别没穿几次就破破烂烂的。 </p>
<p>25. 总经理至少每月参加次项目组会议要的。　<br />
　要让team member觉得高层关注这个项目。<br />
&nbsp;<br />
26. 你们是给每个Dev开一个分支么？　<br />
　反对。Branch的管理以及Merge的工作量太大，而且容易出错。<br />
&nbsp;<br />
27. 有人长期不Check-In代码么？　<br />
　不可以。对大部分项目来说，最多两三天就应该Check-In。<br />
&nbsp;<br />
28. 在Check-In代码时都填写注释了么？　<br />
　要写的，至少一两句话，比如"解决了Bug No.225（给bug编号）"。如果往高处拔，这也算做"配置审计"的一部分。<br />
&nbsp;<br />
29. 有没有设定每天Check-In的最后期限？　<br />
　要的，要明确Check-In Deadline。否则会Build Break。<br />
&nbsp;<br />
30. 你们能把所有源码一下子编译成安装文件吗？ 　<br />
　要的。这是每日编译（Daily Build）的基础。而且必须要能够做成自动的。<br />
&nbsp;<br />
31. 你们的项目组做每日编译么？　<br />
　当然要做。有三样东西是软件项目/产品开发必备的：1. bug management; 2. source control; 3. daily build。 </p>
<p>32. 你们公司有没有积累一个项目风险列表？　<br />
　要。Risk Inventory。否则，下个项目开始的时候，又只能拍脑袋分析Risk了。<br />
&nbsp;<br />
33. 设计越简单越好越简单越好。　<br />
　设计时候多一句话，将来可能就带来无穷无尽的烦恼。应该从一开始就勇敢的砍。这叫scope management。 </p>
<p>34. 尽量利用现有的产品、技术、代码千万别什么东西都自己Coding。<br />
BizTalk和Sharepoint就是最好的例子，有这两个作为基础，可以把起点提高很多。或者可以尽量多用现成的Control之类的。或者尽量用XML，而不是自己去Parse一个文本文件；尽量用RegExp，而不是自己从头操作字符串，等等等等。这就是"软件复用"的体现。<br />
&nbsp;<br />
35. 你们会隔一段时间就停下来夯实代码么？　<br />
　要。最好一个月左右一次。传言去年年初Windows组在Stevb的命令下停过一个月增强安全。Btw，"夯"这个字念"hang"，第一声。 </p>
<p>36. 你们的项目组每个人都写Daily Report么？　<br />
　要写。五分钟就够了，写10句话左右，告诉自己小组的人今天我干了什么。一则为了沟通，二则鞭策自己（要是游手好闲一天，自己都会不好意思写的）。 </p>
<p>37. 你们的项目经理会发出Weekly Report么？　<br />
　要。也是为了沟通。内容包括目前进度，可能的风险，质量状况，各种工作的进展等。<br />
&nbsp;<br />
38. 你们项目组是否至少每周全体开会一次？　<br />
　要。一定要开会。程序员讨厌开会，但每个礼拜开会时间加起来至少应该有4小时。包括team meeting, spec review meeting, bug triage meeting。千万别大家闷头写code。<br />
&nbsp;<br />
39. 你们项目组的会议、讨论都有记录么？　<br />
　会前发meeting request和agenda，会中有人负责主持和记录，会后有人负责发meeting minutes，这都是effective meeting的要点。而且，每个会议都要形成agreements和action items。<br />
&nbsp;<br />
40. 其他部门知道你们项目组在干什么么？　<br />
　要发一些Newsflash给整个大组织。Show your team's value。否则，当你坐在电梯里面，其他部门的人问："你们在干嘛"，你回答"ABC项目"的时候，别人全然不知，那种感觉不太好。<br />
&nbsp;<br />
41. 通过Email进行所有正式沟通<br />
Email的好处是免得抵赖。但也要避免矫枉过正，最好的方法是先用电话和当面说，然后Email来确认。 </p>
<p>42. 为项目组建立多个Mailing Group 　<br />
　如果在AD+Exchange里面，就建Distribution List。比如，我会建ABC Project Core Team，ABC Project Dev Team，ABC Project All Testers，ABC Project Extended Team等等。这样发起Email来方便，而且能让该收到email的人都收到、不该收到不被骚扰。<br />
&nbsp;<br />
43. 每个人都知道哪里可以找到全部的文档么？　<br />
　应该每个人都知道。这叫做知识管理（Knowledge Management）。最方便的就是把文档放在一个集中的File Share，更好的方法是用Sharepoint。<br />
&nbsp;<br />
44. 你做决定、做变化时，告诉大家原因了么？　<br />
　要告诉大家原因。Empower team member的手段之一是提供足够的information，这是MSF一开篇的几个原则之一。的确如此，tell me why是人之常情，tell me why了才能有understanding。中国人做事喜欢搞限制，限制信息，似乎能够看到某一份文件的人就是有身份的人。大错特错。权威、权力，不在于是不是能access information/data，而在于是不是掌握资源。<br />
&nbsp;<br />
45. Stay agile and expect change 要这样。　<br />
　需求一定会变的，已经写好的代码一定会被要求修改的。做好心理准备，对change不要抗拒，而是expect change。<br />
&nbsp;<br />
46. 你们有没有专职的软件测试人员？　<br />
　要有专职测试。如果人手不够，可以peer test，交换了测试。千万别自己测试自己的。<br />
&nbsp;<br />
47. 你们的测试有一份总的计划来规定做什么和怎么做么？<br />
&nbsp;这就是Test Plan。要不要做性能测试？要不要做Usability测试？什么时候开始测试性能？测试通过的标准是什么？用什么手段，自动的还是手动的？这些问题需要用Test Plan来回答。<br />
&nbsp;<br />
48. 你是先写Test Case然后再测试的么？　<br />
　应该如此。应该先设计再编程、先test case再测试。当然，事情是灵活的。我有时候在做第一遍测试的同时补上test case。至于先test case再开发，我不喜欢，因为不习惯，太麻烦，至于别人推荐，那试试看也无妨。<br />
&nbsp;<br />
49. 你是否会为各种输入组合创建测试用例？　<br />
　不要，不要搞边界条件组合。当心组合爆炸。有很多test case工具能够自动生成各种边界条件的组合--但要想清楚，你是否有时间去运行那么多test case。 </p>
<p>50. 你们的程序员能看到测试用例么？　<br />
　要。让Dev看到Test Case吧。我们都是为了同一个目的走到一起来的：提高质量。 </p>
<p>51. 你们是否随便抓一些人来做易用性测试？ 　<br />
　要这么做。自己看自己写的程序界面，怎么看都是顺眼的。这叫做审美疲劳--臭的看久了也就不臭了，不方便的永久了也就习惯了。<br />
&nbsp;<br />
52. 你对自动测试的期望正确么？　<br />
　别期望太高。依我看，除了性能测试以外，还是暂时先忘掉"自动测试"吧，忘掉WinRunner和LoadRunner吧。对于国内的软件测试的现状来说，只能"矫枉必须过正"了。 </p>
<p>53. 你们的性能测试是等所有功能都开发完才做的么？　<br />
　不能这样。性能测试不能被归到所谓的"系统测试"阶段。早测早改正，早死早升天。<br />
&nbsp;<br />
54. 你注意到测试中的杀虫剂效应了么？　<br />
　虫子有抗药性，Bug也有。发现的新Bug越来越少是正常的。这时候，最好大家交换一下测试的area，或者用用看其他工具和手法，就又会发现一些新bug了。<br />
&nbsp;<br />
55. 你们项目组中有人能说出产品的当前整体质量情况么？　<br />
　要有。当老板问起这个产品目前质量如何，Test Lead/Manager应该负责回答。<br />
&nbsp;<br />
56. 你们有单元测试么？　<br />
　单元测试要有的。不过没有单元测试也不是不可以，我做过没有单元测试的项目，也做成功了--可能是侥幸，可能是大家都是熟手的关系。还是那句话，软件工程是非常实践、非常工程、非常灵活的一套方法，某些方法在某些情况下会比另一些方法好，反之亦然。 </p>
<p>57. 你们的程序员是写完代码就扔过墙的么？　<br />
　大忌。写好一块程序以后，即便不做单元测试，也应该自己先跑一跑。虽然有了专门的测试人员，做开发的人也不可以一点测试都不做。微软还有Test Release Document的说法，程序太烂的话，测试有权踢回去。<br />
&nbsp;<br />
58. 你们的程序中所有的函数都有输入检查么？　<br />
　不要。虽然说做输入检查是write secure code的要点，但不要做太多的输入检查，有些内部函数之间的参数传递就不必检查输入了，省点功夫。同样的道理，未必要给所有的函数都写注释。写一部分主要的就够了。<br />
&nbsp;<br />
59. 产品有统一的错误处理机制和报错界面么？　<br />
　要有。最好能有统一的error message，然后每个error message都带一个error number。这样，用户可以自己根据error number到user manual里面去看看错误的具体描述和可能原因，就像SQL Server的错误那样。同样，ASP.NET也要有统一的Exception处理。可以参考有关的Application Block。<br />
&nbsp;<br />
60. 你们有统一的代码书写规范么？　<br />
　要有。Code Convention很多，搞一份来发给大家就可以了。当然，要是有FxCop这种工具来检查代码就更好了。<br />
&nbsp;<br />
61. 你们的每个人都了解项目的商业意义么？　<br />
　要。这是Vision的意思。别把项目只当成工作。有时候要想着自己是在为中国某某行业的信息化作先驱者，或者时不时的告诉team member，这个项目能够为某某某国家部门每年节省多少多少百万的纳税人的钱，这样就有动力了。平凡的事情也是可以有个崇高的目标的。<br />
&nbsp;<br />
62. 产品各部分的界面和操作习惯一致么？　<br />
　要这样。要让用户觉得整个程序好像是一个人写出来的那样。<br />
&nbsp;<br />
63. 有可以作为宣传亮点的Cool Feature么？　<br />
　要。这是增强团队凝聚力、信心的。而且，"一俊遮百丑"，有亮点就可以掩盖一些问题。这样，对于客户来说，会感觉产品从质量角度来说还是acceptable的。或者说，cool feature或者说亮点可以作为质量问题的一个事后弥补措施。<br />
&nbsp;<br />
64. 尽可能缩短产品的启动时间要这样。　<br />
　软件启动时间（Start-Up time）是客户对性能好坏的第一印象。<br />
&nbsp;<br />
65. 不要过于注重内在品质而忽视了第一眼的外在印象程序员容易犯这个错误：太看重性能、稳定性、存储效率，但忽视了外在感受。而高层经理、客户正相反。这两方面要兼顾，协调这些是PM的工作。<br />
&nbsp;<br />
66. 你们根据详细产品功能说明书做开发么？　<br />
　要这样。要有设计才能开发，这是必须的。设计文档，应该说清楚这个产品会怎么运行，应该采取一些讲故事的方法。设计的时候千万别钻细节，别钻到数据库、代码等具体实现里面去，那些是后面的事情，一步步来不能着急。<br />
&nbsp;<br />
67. 开始开发和测试之前每个人都仔细审阅功能设计么？　<br />
　要做。Function Spec review是用来统一思想的。而且，review过以后形成了一致意见，将来再也没有人可以说"你看，当初我就是反对这么设计的，现在吃苦头了吧" </p>
<p>68. 所有人都始终想着The Whole Image么？<br />
要这样。项目里面每个人虽然都只是在制造一片叶子，但每个人都应该知道自己在制造的那片叶子所在的树是怎么样子的。我反对软件蓝领，反对过分的把软件制造看成流水线、车间。参见第61条。<br />
&nbsp;<br />
69. Dev工作的划分是单纯纵向或横向的么？　<br />
　不能单纯的根据功能模块分，或者单纯根据表现层、中间层、数据库层分。我推荐这么做：首先根据功能模块分，然后每个"层"都有一个Owner来Review所有人的设计和代码，保证consistency。<br />
&nbsp;<br />
70. 你们的程序员写程序设计说明文档么？　<br />
　要。不过我听说微软的程序员1999年以前也不写。所以说，写不写也不是绝对的，偷懒有时候也是可以的。参见第56条。<br />
&nbsp;<br />
71. 你在招人面试时让他写一段程序么？　<br />
　要的。我最喜欢让人做字符串和链表一类的题目。这种题目有很多循环、判断、指针、递归等，既不偏向过于考算法，也不偏向过于考特定的API。<br />
&nbsp;<br />
72. 你们有没有技术交流讲座？　<br />
　要的。每一两个礼拜搞一次内部的Tech Talk或者Chalk Talk吧。让组员之间分享技术心得，这笔花钱送到外面去培训划算。 </p>
<p>73. 你们的程序员都能专注于一件事情么？　<br />
　要让程序员专注一件事。例如说，一个部门有两个项目和10个人，一种方法是让10个人同时参加两个项目，每个项目上每个人都花50%时间；另一种方法是5个人去项目A，5个人去项目B，每个人都100%在某一个项目上。我一定选后面一种。这个道理很多人都懂，但很多领导实践起来就把属下当成可以任意拆分的资源了。<br />
&nbsp;<br />
74. 你们的程序员会夸大完成某项工作所需要的时间么？　<br />
　会的，这是常见的，尤其会在项目后期夸大做某个change所需要的时间，以次来抵制change。解决的方法是坐下来慢慢磨，磨掉程序员的逆反心理，一起分析，并把估算时间的颗粒度变小。<br />
&nbsp;<br />
75. 尽量不要用Virtual Heads 最好不要用Virtual Heads。　　Virtual heads意味着resource is not secure，shared resource会降低resource的工作效率，容易增加出错的机会，会让一心二用的人没有太多时间去review spec、review design。一个dedicated的人，要强过两个只能投入50%时间和精力的人。我是吃过亏的：7个part time的tester，发现的Bug和干的活，加起来还不如两个full-time的。参见第73条。73条是针对程序员的，75条是针对Resource Manager的。<br />
&nbsp;</p>
<p>记住建议就是建议！！！ </p>
 <img src ="http://www.blogjava.net/orangelizq/aggbug/329411.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/orangelizq/" target="_blank">桔子汁</a> 2010-08-19 20:15 <a href="http://www.blogjava.net/orangelizq/archive/2010/08/19/329411.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]内部类详解 </title><link>http://www.blogjava.net/orangelizq/archive/2010/04/21/318984.html</link><dc:creator>桔子汁</dc:creator><author>桔子汁</author><pubDate>Wed, 21 Apr 2010 07:03:00 GMT</pubDate><guid>http://www.blogjava.net/orangelizq/archive/2010/04/21/318984.html</guid><wfw:comment>http://www.blogjava.net/orangelizq/comments/318984.html</wfw:comment><comments>http://www.blogjava.net/orangelizq/archive/2010/04/21/318984.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/orangelizq/comments/commentRss/318984.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/orangelizq/services/trackbacks/318984.html</trackback:ping><description><![CDATA[内部类详解 <br />1、定义 <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/442435#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" /></a></div></div><ol class="dp-j"><li><span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">class</font></strong></span><span> First {   </span></span></li><li><span></span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">class</font></strong></span><span> Contents{   </span></li><li><span>    </span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">void</font></strong></span><span> f(){   </span></li><li><span>    System.out.println(</span><span class="string"><font color="#0000ff">"In Class First's inner Class Contents method f()"</font></span><span>);   </span></li><li><span>    }   </span></li><li><span>}   </span></li><li><span> }  </span></li></ol></div><pre class="java" style="DISPLAY: none" name="code"> </pre>像这样的，Contents就叫做内部类 <br />内部类了解外围类，并能与之通信(后面详细讲) <br /><br />2、链接到外围类 <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/442435#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" /></a></div></div><ol class="dp-j"><li><span><span>   </span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">class</font></strong></span><span> First {   </span></span></li><li><span></span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">class</font></strong></span><span> Contents{   </span></li><li><span>         </span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">void</font></strong></span><span> getStr(){   </span></li><li><span>        System.out.println(</span><span class="string"><font color="#0000ff">"First.str="</font></span><span>+str);   </span></li><li><span>     }   </span></li><li><span>}   </span></li><li><span></span><span class="keyword"><strong><font color="#7f0055">private</font></strong></span><span> String str;   </span></li><li><span>    }   </span></li><li><span>   </span></li></ol></div>  在内部类Contents中，可以使用外围类First的字段str。 <br />  那么，它是如何实现的呢？ <br />  是这样的，用外围类创建内部类对象时，此内部类对象会秘密的捕获一个指向外围类的引用，于是，可以通过这个引用来访问外围类的成员。 <br />  通常，这些都是编译器来处理，我们看不到，也不用关心这个。 <br />  正是因为如此，我们创建内部类对象时，必须与外围类对象相关联。 <br />  注：嵌套类(后面会讲到)除外。 <br /><br />3、使用关键字.this与.new <br />  内部类中得到当前外围类对象的引用，可以使用.this关键字，注意与new的区别 <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/442435#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" /></a></div></div><ol class="dp-j"><li><span><span>    </span><span class="keyword"><strong><font color="#7f0055">private</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">int</font></strong></span><span> num ;   </span></span></li><li><span></span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> Test2(){   </span></li><li><span>       </span></li><li><span>}   </span></li><li><span>  </span></li><li><span></span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> Test2(</span><span class="keyword"><strong><font color="#7f0055">int</font></strong></span><span> num){   </span></li><li><span>    </span><span class="keyword"><strong><font color="#7f0055">this</font></strong></span><span>.num = num;   </span></li><li><span>}   </span></li><li><span>  </span></li><li><span></span><span class="keyword"><strong><font color="#7f0055">private</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">class</font></strong></span><span> Inner{   </span></li><li><span>    </span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> Test2 getTest2(){   </span></li><li><span>        </span><span class="keyword"><strong><font color="#7f0055">return</font></strong></span><span> Test2.</span><span class="keyword"><strong><font color="#7f0055">this</font></strong></span><span>;   </span></li><li><span>    }   </span></li><li><span>       </span></li><li><span>    </span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> Test2 newTest2(){   </span></li><li><span>        </span><span class="keyword"><strong><font color="#7f0055">return</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">new</font></strong></span><span> Test2();   </span></li><li><span>    }   </span></li><li><span>}   </span></li><li><span>  </span></li><li><span></span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">static</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">void</font></strong></span><span> main(String [] args){   </span></li><li><span>    Test2 test = </span><span class="keyword"><strong><font color="#7f0055">new</font></strong></span><span> Test2(</span><span class="number"><font color="#c00000">5</font></span><span>);   </span></li><li><span>    Test2.Inner inner = test.</span><span class="keyword"><strong><font color="#7f0055">new</font></strong></span><span> Inner();   </span></li><li><span>    Test2 test2 = inner.getTest2();   </span></li><li><span>    Test2 test3 = inner.newTest2();   </span></li><li><span>    System.out.println(test2.num);   </span></li><li><span>    System.out.println(test3.num);   </span></li><li><span>}   </span></li><li><span>   </span></li></ol></div>  输出结果为5 0 <br />  使用.this后，得到时创建该内部类时使用的外围类对象的引用，new则是创建了一个新的引用。 <br /><br />  .new关键字 <br />  如果想直接创建一个内部类对象，而不是通过外围类对象的方法来得到，可以使用.new关键字 <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/442435#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" /></a></div></div><ol class="dp-j"><li><span><span>OutClass.InnerClass obj = outClassInstance.</span><span class="keyword"><strong><font color="#7f0055">new</font></strong></span><span> InnerClass();   </span></span></li></ol></div><br />  必须是外围类对象.new，而不能是外围类.new <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/442435#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" /></a></div></div><ol class="dp-j"><li><span><span>   </span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">class</font></strong></span><span> First {   </span></span></li><li><span></span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">class</font></strong></span><span> Contents{   </span></li><li><span>    </span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">void</font></strong></span><span> f(){   </span></li><li><span>        System.out.println(</span><span class="string"><font color="#0000ff">"In Class First's inner Class Contents method f()"</font></span><span>);   </span></li><li><span>    }   </span></li><li><span>    </span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">void</font></strong></span><span> getStr(){   </span></li><li><span>        System.out.println(</span><span class="string"><font color="#0000ff">"First.str="</font></span><span>+str);   </span></li><li><span>    }   </span></li><li><span>}   </span></li><li><span>  </span></li><li><span></span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">static</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">void</font></strong></span><span> main(String [] args){   </span></li><li><span>    First first = </span><span class="keyword"><strong><font color="#7f0055">new</font></strong></span><span> First();   </span></li><li><span>    First.Contents contents = first.</span><span class="keyword"><strong><font color="#7f0055">new</font></strong></span><span> Contents();   </span></li><li><span>    contents.f();   </span></li><li><span>}   </span></li><li><span>    }   </span></li><li><span>   </span></li></ol></div><pre class="java" style="DISPLAY: none" name="code"></pre>  必须通过外围类First的对象first来创建一个内部类的对象 <br />  而且需要注意的是，在创建外围类对象之前，不可能创建内部类的对象(嵌套类除外)。 <br />4、内部类与向上转型 <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/442435#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" /></a></div></div><ol class="dp-j"><li><span><span>    </span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">interface</font></strong></span><span> Shape {   </span></span></li><li><span></span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">void</font></strong></span><span> paint();   </span></li><li><span>    }   </span></li><li><span>    </span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">class</font></strong></span><span> Painter {   </span></li><li><span>       </span></li><li><span>       </span><span class="keyword"><strong><font color="#7f0055">private</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">class</font></strong></span><span> InnerShape </span><span class="keyword"><strong><font color="#7f0055">implements</font></strong></span><span> Shape{   </span></li><li><span>    </span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">void</font></strong></span><span> paint(){   </span></li><li><span>        System.out.println(</span><span class="string"><font color="#0000ff">"painter paint() method"</font></span><span>);   </span></li><li><span>    }   </span></li><li><span>}   </span></li><li><span>  </span></li><li><span></span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> Shape getShape(){   </span></li><li><span>    </span><span class="keyword"><strong><font color="#7f0055">return</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">new</font></strong></span><span> InnerShape();   </span></li><li><span>}      </span></li><li><span>       </span></li><li><span>       </span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">static</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">void</font></strong></span><span> main(String []args){   </span></li><li><span>    Painter painter = </span><span class="keyword"><strong><font color="#7f0055">new</font></strong></span><span> Painter();   </span></li><li><span>    Shape shape = painter. getShape();   </span></li><li><span>    shape.paint();   </span></li><li><span>}   </span></li><li><span>    }   </span></li><li><span>   </span></li></ol></div>  此时，内部类是private的，可以它的外围类Painter以外，没人能访问。 <br />  这样,private内部类给累的设计者提供了一种途径，通过这种方式可以完全阻止任何依赖于类型的编码，并完全隐藏实现的细节。 <br /><br />5、方法内的类 <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/442435#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" /></a></div></div><ol class="dp-j"><li><span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">void</font></strong></span><span> test(){   </span></span></li><li><span>ass Inner{   </span></li><li><span> </span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">void</font></strong></span><span> method(){   </span></li><li><span>ystem.out.println(</span><span class="string"><font color="#0000ff">"在方法内创建的类"</font></span><span>);   </span></li><li><span> }   </span></li><li><span>  </span></li><li><span>}   </span></li></ol></div><pre class="java" style="DISPLAY: none" name="code"></pre>  值得注意的是：方法内创建的类，不能加访问修饰符。 <br />  另外，方法内部的类也不是在调用方法时才会创建的，它们一样也被编译了(怎么知道的？后面会有讲解)。 <br /><br />6、匿名内部类 <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/442435#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" /></a></div></div><ol class="dp-j"><li><span><span>  </span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">class</font></strong></span><span> Painter {   </span></span></li><li><span>ublic Shape getShape(){   </span></li><li><span></span><span class="keyword"><strong><font color="#7f0055">return</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">new</font></strong></span><span> Shape(){   </span></li><li><span>    </span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">void</font></strong></span><span> paint(){   </span></li><li><span>        System.out.println(</span><span class="string"><font color="#0000ff">"painter paint() method"</font></span><span>);   </span></li><li><span>    }   </span></li><li><span>};   </span></li><li><span>  </span></li><li><span>      </span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">static</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">void</font></strong></span><span> main(String [] args){   </span></li><li><span>            Painter painter = </span><span class="keyword"><strong><font color="#7f0055">new</font></strong></span><span> Painter();   </span></li><li><span>            Shape shape = painter.getShape();   </span></li><li><span>            shape.paint();   </span></li><li><span>      }   </span></li><li><span>  }   </span></li><li><span>  </span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">interface</font></strong></span><span> Shape {   </span></li><li><span>ublic </span><span class="keyword"><strong><font color="#7f0055">void</font></strong></span><span> paint();   </span></li><li><span>  }   </span></li></ol></div><pre class="java" style="DISPLAY: none" name="code"></pre>  注意，匿名内部类后面的分号不可缺少！ <br />   匿名类，顾名思义，就是没有名称。 <br />  getShape（）方法里，就使用了匿名内部类。 <br />  看上去很奇怪，不符合传统的写法？ <br />  第一眼看上去确实是这样的。 <br /><br />  这样写，意思是创建了一个实现了Shape的匿名类的对象。 <br />  匿名类可以创建，接口，抽象类，与普通类的对象。创建接口时，必须实现接口中所有方法。 <br />  <br />  这是无参的，如果需要参数呢？ <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/442435#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" /></a></div></div><ol class="dp-j"><li><span><span>   </span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">class</font></strong></span><span> B {   </span></span></li><li><span></span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> A getA(</span><span class="keyword"><strong><font color="#7f0055">int</font></strong></span><span> num){   </span></li><li><span>    </span><span class="keyword"><strong><font color="#7f0055">return</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">new</font></strong></span><span> A(num){   </span></li><li><span>           </span></li><li><span>    };   </span></li><li><span>}   </span></li><li><span>   }   </span></li><li><span>   </span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">class</font></strong></span><span> A {   </span></li><li><span></span><span class="keyword"><strong><font color="#7f0055">private</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">int</font></strong></span><span> num;   </span></li><li><span></span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> A(</span><span class="keyword"><strong><font color="#7f0055">int</font></strong></span><span> num){   </span></li><li><span>    </span><span class="keyword"><strong><font color="#7f0055">this</font></strong></span><span>.num = num;   </span></li><li><span>}   </span></li><li><span></span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> A(){   </span></li><li><span>       </span></li><li><span>}   </span></li><li><span>   }   </span></li><li><span>   </span></li></ol></div>  Ok，在这个例子中，可以为A的构造方法传入一个参数。在匿名内部类中，并没有使用到这个参数。 <br />  如果使用到了这个参数，那么这个参数就必须是final的。 <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/442435#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" /></a></div></div><ol class="dp-j"><li><span><span>   </span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">class</font></strong></span><span> B {   </span></span></li><li><span></span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> A getA(</span><span class="keyword"><strong><font color="#7f0055">final</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">int</font></strong></span><span> num){   </span></li><li><span>    </span><span class="keyword"><strong><font color="#7f0055">return</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">new</font></strong></span><span> A(num){   </span></li><li><span>       </span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">int</font></strong></span><span> getNum(){   </span></li><li><span>                     </span><span class="keyword"><strong><font color="#7f0055">return</font></strong></span><span> num;   </span></li><li><span>                  }   </span></li><li><span>    };   </span></li><li><span>}   </span></li><li><span>   }   </span></li><li><span>   </span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">class</font></strong></span><span> A {   </span></li><li><span></span><span class="keyword"><strong><font color="#7f0055">private</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">int</font></strong></span><span> num;   </span></li><li><span></span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> A(</span><span class="keyword"><strong><font color="#7f0055">int</font></strong></span><span> num){   </span></li><li><span>    </span><span class="keyword"><strong><font color="#7f0055">this</font></strong></span><span>.num = num;   </span></li><li><span>}   </span></li><li><span></span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> A(){   </span></li><li><span>       </span></li><li><span>}   </span></li><li><span>   }   </span></li><li><span>   </span></li></ol></div>  如果不是final的，编译器就会提示出错。 <br />  另外，还可以在匿名内部类里定义属性 <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/442435#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" /></a></div></div><ol class="dp-j"><li><span><span>   </span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> A getA(){   </span></span></li><li><span></span><span class="keyword"><strong><font color="#7f0055">return</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">new</font></strong></span><span> A(){   </span></li><li><span>    </span><span class="keyword"><strong><font color="#7f0055">int</font></strong></span><span> num = </span><span class="number"><font color="#c00000">0</font></span><span>;   </span></li><li><span>    String str;   </span></li><li><span>    {   </span></li><li><span>        str = </span><span class="string"><font color="#0000ff">"javaeye"</font></span><span>;   </span></li><li><span>        System.out.println(</span><span class="string"><font color="#0000ff">"hello robbin"</font></span><span>);   </span></li><li><span>    }   </span></li><li><span>};   </span></li><li><span>   }   </span></li><li><span>   </span></li></ol></div>  匿名内部类通过实例初始化，可以达到类似构造器的效果~ <br /><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/442435#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" /></a></div></div><ol class="dp-j"><li><span><span>  </span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">interface</font></strong></span><span> Service {   </span></span></li><li><span></span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">void</font></strong></span><span> method1();   </span></li><li><span>  }   </span></li><li><span>  </span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">interface</font></strong></span><span> ServiceFactory {   </span></li><li><span>Service getService();   </span></li><li><span>  }   </span></li><li><span>  </span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">class</font></strong></span><span> Implemention1 </span><span class="keyword"><strong><font color="#7f0055">implements</font></strong></span><span> Service{   </span></li><li><span></span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">void</font></strong></span><span> method1(){   </span></li><li><span>    System.out.println(</span><span class="string"><font color="#0000ff">"In Implemention1 method method1()"</font></span><span>);   </span></li><li><span>}   </span></li><li><span>  </span></li><li><span></span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">static</font></strong></span><span> ServiceFactory factory = </span><span class="keyword"><strong><font color="#7f0055">new</font></strong></span><span> ServiceFactory(){   </span></li><li><span>    </span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> Service getService(){   </span></li><li><span>        </span><span class="keyword"><strong><font color="#7f0055">return</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">new</font></strong></span><span> Implemention1();   </span></li><li><span>    }   </span></li><li><span>};   </span></li><li><span>  }   </span></li><li><span>  </span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">class</font></strong></span><span> Implemention2 </span><span class="keyword"><strong><font color="#7f0055">implements</font></strong></span><span> Service {   </span></li><li><span></span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">void</font></strong></span><span> method1(){   </span></li><li><span>    System.out.println(</span><span class="string"><font color="#0000ff">"in Implemention2 method method1()"</font></span><span>);   </span></li><li><span>}   </span></li><li><span>  </span></li><li><span></span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">static</font></strong></span><span> ServiceFactory factory = </span><span class="keyword"><strong><font color="#7f0055">new</font></strong></span><span> ServiceFactory(){   </span></li><li><span>    </span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> Service getService(){   </span></li><li><span>        </span><span class="keyword"><strong><font color="#7f0055">return</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">new</font></strong></span><span> Implemention2();   </span></li><li><span>    }   </span></li><li><span>};   </span></li><li><span>  </span></li><li><span>  }   </span></li><li><span>  </span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">class</font></strong></span><span> Test {   </span></li><li><span></span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">static</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">void</font></strong></span><span> main(String []args){   </span></li><li><span>    service(Implemention1.factory);   </span></li><li><span>    service(Implemention2.factory);   </span></li><li><span>       </span></li><li><span>    ServiceFactory factory1 = Implemention1.factory;   </span></li><li><span>    Service service1 = factory1.getService();   </span></li><li><span>    service1.method1();   </span></li><li><span>       </span></li><li><span>    ServiceFactory factory2 = Implemention1.factory;   </span></li><li><span>    Service service2 = factory2.getService();   </span></li><li><span>    service2.method1();   </span></li><li><span>}   </span></li><li><span>  }   </span></li></ol></div><br />在Implemention1和2中匿名内部类用在字段初始化地方。 <br />这样定义的工厂方法，代码上看起来是不是优雅一些？<img src="http://www.javaeye.com/images/smiles/icon_redface.gif" /><br /><br />7、嵌套类 <br />static的内部类就叫做嵌套类 <br />前面提到了很多次，嵌套类是个例外 <br />使用嵌套类时有两点需要注意： <br />   a、创建嵌套类对象时，不需要外围类 <br />   b、在嵌套类中，不能像普通内部类一样访问外围类的非static成员 <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/442435#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" /></a></div></div><ol class="dp-j"><li><span><span>  </span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">class</font></strong></span><span> StaticClass {   </span></span></li><li><span></span><span class="keyword"><strong><font color="#7f0055">private</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">int</font></strong></span><span> num;   </span></li><li><span></span><span class="keyword"><strong><font color="#7f0055">private</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">static</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">int</font></strong></span><span> sum = </span><span class="number"><font color="#c00000">2</font></span><span>;   </span></li><li><span></span><span class="keyword"><strong><font color="#7f0055">private</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">static</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">class</font></strong></span><span> StaticInnerClass{   </span></li><li><span>    </span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">int</font></strong></span><span> getNum(){   </span></li><li><span>    </span><span class="comment"><font color="#008200">//只能访问sum，不能访问num </font></span><span>  </span></li><li><span>               </span><span class="keyword"><strong><font color="#7f0055">return</font></strong></span><span> sum;   </span></li><li><span>    }   </span></li><li><span>}   </span></li><li><span>  }   </span></li><li><span>  </span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">class</font></strong></span><span> Test {   </span></li><li><span></span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">static</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">void</font></strong></span><span> main(String [] args){   </span></li><li><span>               </span><span class="comment"><font color="#008200">//可以直接通过new来创建嵌套类对象 </font></span><span>  </span></li><li><span>    StaticClass.StaticInnerClass inner = </span><span class="keyword"><strong><font color="#7f0055">new</font></strong></span><span> StaticClass.StaticInnerClass();   </span></li><li><span>    inner.getNum();   </span></li><li><span>}   </span></li><li><span>  }   </span></li></ol></div>  另外，嵌套类还有特殊之处，就是嵌套类中可以有static方法，static字段与嵌套类，而普通内部类中不能有这些。 <br /><br />  8、内部类标识符 <br />  我们知道每个类会产生一个.class文件，文件名即为类名 <br />  同样，内部类也会产生这么一个.class文件，但是它的名称却不是内部类的类名，而是有着严格的限制：外围类的名字，加上$,再加上内部类名字。 <br />  前面说到得定义在方法内的内部类，不是在调用方法时生成，而是与外围类一同编译，就可以通过查看.class文件的方式来证明。 <br /><br />  9、为何要内部类？ <br />    a、内部类提供了某种进入外围类的窗户。 <br />    b、也是最吸引人的原因，每个内部类都能独立地继承一个接口，而无论外围类是否已经继承了某个接口。 <br />  因此，内部类使多重继承的解决方案变得更加完整。 <br />  在项目中，需要多重继承，如果是两个接口，那么好办，接口支持多重继承。 <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/442435#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" /></a></div></div><ol class="dp-j"><li><span><span>   </span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">interface</font></strong></span><span> One {   </span></span></li><li><span></span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">void</font></strong></span><span> inOne();   </span></li><li><span>   }   </span></li><li><span>   </span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">interface</font></strong></span><span> Two {   </span></li><li><span></span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">void</font></strong></span><span> inTwo();   </span></li><li><span>   }   </span></li><li><span>   </span><span class="comment"><font color="#008200">//两个接口，用普通类就可实现多重继承 </font></span><span>  </span></li><li><span>   </span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">class</font></strong></span><span> CommonClass </span><span class="keyword"><strong><font color="#7f0055">implements</font></strong></span><span> One,Two {   </span></li><li><span></span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">void</font></strong></span><span> inOne(){   </span></li><li><span>    System.out.println(</span><span class="string"><font color="#0000ff">"CommonClass inOne() method"</font></span><span>);   </span></li><li><span>}   </span></li><li><span>  </span></li><li><span></span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">void</font></strong></span><span> inTwo(){   </span></li><li><span>    System.out.println(</span><span class="string"><font color="#0000ff">"CommonClass inTwo() method"</font></span><span>);   </span></li><li><span>}   </span></li><li><span>   }   </span></li><li><span>   </span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">abstract</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">class</font></strong></span><span> Three {   </span></li><li><span></span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">abstract</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">void</font></strong></span><span> inThree();   </span></li><li><span>   }   </span></li><li><span>   </span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">abstract</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">class</font></strong></span><span> Four {   </span></li><li><span></span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">abstract</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">void</font></strong></span><span> inFour();   </span></li><li><span>   }   </span></li><li><span>   </span><span class="comment"><font color="#008200">//两个抽象类，使用普通类无法实现多重继承 </font></span><span>  </span></li><li><span>      </span></li><li><span>   </span><span class="comment"><font color="#008200">//使用内部类可以实现 </font></span><span>  </span></li><li><span>   </span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">class</font></strong></span><span> Contents </span><span class="keyword"><strong><font color="#7f0055">extends</font></strong></span><span> Three {   </span></li><li><span></span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">void</font></strong></span><span> inThree(){   </span></li><li><span>    System.out.println(</span><span class="string"><font color="#0000ff">"In Contents inThress() method"</font></span><span>);   </span></li><li><span>}   </span></li><li><span>  </span></li><li><span></span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">class</font></strong></span><span> InnerFour </span><span class="keyword"><strong><font color="#7f0055">extends</font></strong></span><span> Four{   </span></li><li><span>    </span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">void</font></strong></span><span> inFour(){   </span></li><li><span>        System.out.println(</span><span class="string"><font color="#0000ff">"In Contents"</font></span><span>);   </span></li><li><span>    }   </span></li><li><span>       </span></li><li><span>}   </span></li><li><span>   }   </span></li><li><span>   </span></li></ol></div><br />  另外，还有好多地方可以使用内部类。读过hibernate源代码的同学，应该可以发现，里面有好多内部类。 <br />  最常见的内部类，应该是Map.Entry了，可以看看源代码~  <br /><br />总结： <br />  内部类的特性大致就是上述了，特性很直观，了解了之后，使用也很简单。 <br />  但是，何时使用我说的并不是很明确，因为本人知识有限，使用内部类也不是很多。项目中很少用，好像就是ActiveMQ那里用了一些。 <br />  不过，相信大家在了解了内部类的特性之后，再随着时间的推移，慢慢积累经验，应该会做出自己的判断，会在何时使用内部类，怎样应用了。<img src="http://www.javaeye.com/images/smiles/icon_wink.gif" /><img src ="http://www.blogjava.net/orangelizq/aggbug/318984.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/orangelizq/" target="_blank">桔子汁</a> 2010-04-21 15:03 <a href="http://www.blogjava.net/orangelizq/archive/2010/04/21/318984.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]领略内部类的“内部”</title><link>http://www.blogjava.net/orangelizq/archive/2010/04/21/318982.html</link><dc:creator>桔子汁</dc:creator><author>桔子汁</author><pubDate>Wed, 21 Apr 2010 07:00:00 GMT</pubDate><guid>http://www.blogjava.net/orangelizq/archive/2010/04/21/318982.html</guid><wfw:comment>http://www.blogjava.net/orangelizq/comments/318982.html</wfw:comment><comments>http://www.blogjava.net/orangelizq/archive/2010/04/21/318982.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/orangelizq/comments/commentRss/318982.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/orangelizq/services/trackbacks/318982.html</trackback:ping><description><![CDATA[内部类有两种情况： 
<p>(1) 在类中定义一个类(私有内部类，静态内部类)</p><p>(2) 在方法中定义一个类(局部内部类，匿名内部类)</p><p><strong><span style="COLOR: #800000">1、揭露类中内部类</span></strong></p><p>      我们首先看看类中内部类的两个特点：</p><p>     (1) 在外部类的作用范围内可以任意创建内部类对象，即使内部类是私有的(私有内部类)。即内部类对包围它的外部类可见。</p><p><span style="FONT-SIZE: small"></span></p><div class="bar"><div class="tools"><span><span class="comment"><font color="#008200">//代码2：内部类对外部类可见 </font></span><span>  </span></span></div></div><div class="dp-highlighter"><ol class="dp-j"><li><span></span><span class="keyword"><strong><font color="#7f0055">class</font></strong></span><span> Outer{   </span></li><li><span>     </span><span class="comment"><font color="#008200">//创建私有内部类对象 </font></span><span>  </span></li><li><span>     </span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> Inner in=</span><span class="keyword"><strong><font color="#7f0055">new</font></strong></span><span> Inner();   </span></li><li><span>     </span><span class="comment"><font color="#008200">//私有内部类 </font></span><span>  </span></li><li><span>     </span><span class="keyword"><strong><font color="#7f0055">private</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">class</font></strong></span><span> Inner{   </span></li><li><span>          ...   </span></li><li><span>     }   </span></li><li><span>}  </span> </li></ol></div><p><br />(2) 在内部类中可以访问其外部类的所有域，即使是私有域。即外部类对内部类可见。</p><div class="dp-highlighter"><div class="bar"><div class="tools"><span><span class="comment"><font color="#008200">//代码3：外部类对内部类可见 </font></span><span>  </span></span></div></div><ol class="dp-j"><li><span></span><span class="keyword"><strong><font color="#7f0055">class</font></strong></span><span> Outer{   </span></li><li><span>       </span><span class="comment"><font color="#008200">//外部类私有数据域 </font></span><span>  </span></li><li><span>       </span><span class="keyword"><strong><font color="#7f0055">private</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">int</font></strong></span><span> data=</span><span class="number"><font color="#c00000">0</font></span><span>;   </span></li><li><span>       </span><span class="comment"><font color="#008200">//内部类 </font></span><span>  </span></li><li><span>       </span><span class="keyword"><strong><font color="#7f0055">class</font></strong></span><span> Inner{   </span></li><li><span>           </span><span class="keyword"><strong><font color="#7f0055">void</font></strong></span><span> print(){   </span></li><li><span>                 </span><span class="comment"><font color="#008200">//内部类访问外部私有数据域 </font></span><span>  </span></li><li><span>                 System.out.println(data);   </span></li><li><span>           }    </span></li><li><span>       }   </span></li><li><span>}  </span></li></ol></div><p>       问题来了：上面两个特点到底如何办到的呢？内部类的"内部"到底发生了什么？</p><p><span style="FONT-SIZE: small"><font size="2"><strong><span style="COLOR: #800000">      其实，内部类是Java编译器一手操办的。虚拟机并不知道内部类与常规类有什么不同。</span></strong>编译器是如何瞒住虚拟机的呢？</font></span></p><p><span style="FONT-SIZE: small"><br /></span></p><p><span style="FONT-SIZE: small"><font size="2">     对内部类进行编译后发现有两个class文件：<strong><span style="COLOR: #ff0000">Outer.class</span></strong>和<span style="COLOR: #ff0000"><strong><span>Outer$Inner.class</span></strong></span>。这说明<strong><span style="COLOR: #800000">内部类Inner仍然被编译成一个独立的类(Outer$Inner.class)，而不是Outer类的某一个域。</span></strong>虚拟机运行的时候，也是把Inner作为一种常规类来处理的。</font></span></p><p>        <span style="FONT-SIZE: small"><font size="2">但问题来了，即然是两个常规类，为什么他们之间可以互相访问私有域那(最开始提到的两个内部类特点)？这就要问问编译器到底把这两个类编译成什么东西了。</font></span></p><p>        <span style="FONT-SIZE: small"><font size="2">我们利用reflect反射机制来探查了一下内部类编译后的情况（关于探查类内部机制的代码提供在下面的附件里Reflect.java）。</font></span></p><p>        <span style="FONT-SIZE: small"><font size="2">(1)、编译代码2生成</font></span><span style="FONT-SIZE: small"><span style="FONT-SIZE: x-small"><font size="1">Outer$Inner.class</font></span><font size="2"> 文件后使用</font></span><span style="FONT-SIZE: small"><font size="2">ReflectUtil.reflect("Outer$Inner")</font></span><span style="FONT-SIZE: small"><font size="2">对内部类Inner进行反射。运行结果</font></span><span style="FONT-SIZE: small"><font size="2">发现了三个隐含的成分：           </font></span></p><div class="dp-highlighter"><div class="bar"><span><span>class Outer$Inner   </span></span></div><ol class="dp-xml"><li><span>{   </span></li><li><span>        Outer$Inner(Outer,Outer$Inner);  //包可见构造器   </span></li><li><span>        private Outer$Inner(Outer);   //私有构造器将设置this$0域   </span></li><li><span>        final Outer this$0;   //外部类实例域this$0   </span></li><li><span>}  </span><pre class="html" style="DISPLAY: none" name="code"> </pre></li></ol></div><p><span style="FONT-SIZE: small"><font size="2">      好了，现在我们可以解释上面的第一个内部类特点了：</font></span><strong><span style="FONT-SIZE: small; COLOR: #ff0000"><font size="2">为什么外部类可以创建内部类的对象？</font></span></strong></p><p><span style="FONT-SIZE: small"><font size="2">     <strong><span style="COLOR: #800000">首先编译器将外、内部类编译后放在同一个包中。</span></strong></font></span></p><p>        <span style="FONT-SIZE: small"><strong><font size="2"><span style="COLOR: #800000">然后在内部类中附加一个包可见构造器。</span></font></strong></span></p><p>        <span style="FONT-SIZE: small"><font size="2"><strong><span style="COLOR: #800000">这样，</span></strong><strong><span style="COLOR: #800000">虚拟机运行Outer类中Inner in=new Inner();</span><span style="COLOR: #800000">实际上调用的是包可见构造： new </span></strong></font></span><strong><span style="FONT-SIZE: small; COLOR: #800000"><font size="2">Outer$Inner(this,null)。</font></span></strong></p><p>        <strong><span style="FONT-SIZE: small; COLOR: #800000"><font size="2">因此即使是private内部类，也会通过隐含的包可见构造器成功的获得私有内部类的构造权限。</font></span></strong></p><p><span style="FONT-SIZE: small"><font size="2">  </font></span><span style="FONT-SIZE: small"><font size="2">   (2)、编译代码3生成</font></span><span style="FONT-SIZE: small"><font size="2">Outer.class文件，然后使用</font></span><span style="FONT-SIZE: small"><font size="2">ReflectUtil.reflect("Outer")</font></span><span style="FONT-SIZE: small"><font size="2">对外部类Outer进行反射</font></span><span style="FONT-SIZE: small"><font size="2">。 运行结果</font></span><span style="FONT-SIZE: small"><font size="2">发现一个隐含成分如下：</font></span></p><div class="dp-highlighter"><div class="bar"><div class="tools"><a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://www.javaeye.com/topic/494230#"></a> </div></div><ol class="dp-xml"><li><span><span>class Outer   </span></span></li><li><span>{   </span></li><li><span>          static int access$0(Outer);  //静态方法，返回值是外部类私有域 data 的值。   </span></li><li><span>}  </span></li></ol></div><p><span style="FONT-SIZE: small"><font size="2">      现在可以解释第二个特点了：<strong><span style="COLOR: #ff0000">为什么内部类可以引用外部类的私有域？ </span></strong></font></span></p><p>        <strong><span style="COLOR: #800000"></span><span style="FONT-SIZE: small; COLOR: #800000"><font size="2">原因的关键就在编译器在外围类中添加了静态方法access$0。 它将返回值作为参数传递给他的对象域data。这样内部类Inner中的打印语句：</font></span></strong></p><p><strong><span style="COLOR: #800000">                     </span><span style="FONT-SIZE: small; COLOR: #800000"><font size="2">System.out.println(data);</font></span></strong></p><p><strong><span style="COLOR: #800000">         </span><span style="FONT-SIZE: small; COLOR: #800000"><font size="2">实际上运行的时候调用的是：</font></span></strong></p><p><strong><span style="FONT-SIZE: small; COLOR: #800000"><font size="2">                 S</font></span><span style="FONT-SIZE: small; COLOR: #800000"><font size="2">ystem.out.println(access$0(Outer));</font></span></strong></p><p><span style="COLOR: #ff0000"><strong><span style="FONT-SIZE: small"><font size="2">总结一下编译器对类中内部类做的手脚吧：</font></span></strong></span></p><p><span style="COLOR: #ff0000"><strong><span style="FONT-SIZE: small"><font size="2">(1)  在内部类中偷偷摸摸的创建了包可见构造器，从而使外部类获得了创建权限。</font></span></strong></span></p><p><span style="COLOR: #ff0000"><strong><span style="FONT-SIZE: small"><font size="2">(2)  在外部类中偷偷摸摸的创建了访问私有变量的静态方法，从而</font></span></strong></span><span style="COLOR: #ff0000"><strong><span style="FONT-SIZE: small"><font size="2">使</font></span></strong></span><span style="COLOR: #ff0000"><strong><span style="FONT-SIZE: small"><font size="2">内部类获得了访问权限。</font></span></strong></span></p><p><span style="COLOR: #ff0000"><strong>这样，类中定义的内部类无论私有，公有，静态都可以被包围它的外部类所访问。</strong></span></p><p> </p><p><strong><span style="COLOR: #800000">2、方法中内部类的特点</span></strong></p><p>      方法内部类也有两个特点</p><p>      (1)  方法中的内部类没有访问修饰符，即方法内部类对包围它的方法之外的任何东西都不可见。</p><p>      (2)  方法内部类只能够访问该方法中的局部变量，所以也叫局部内部类。而且这些局部变量一定要是final修饰的常量。</p><div class="dp-highlighter"><div class="bar"><div class="tools"><span><span class="keyword"><strong><font color="#7f0055">class</font></strong></span><span> Outter{   </span></span></div></div><ol class="dp-j"><li><span>      </span><span class="keyword"><strong><font color="#7f0055">public</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">void</font></strong></span><span> outMethod(){   </span></li><li><span>             </span><span class="keyword"><strong><font color="#7f0055">final</font></strong></span><span> </span><span class="keyword"><strong><font color="#7f0055">int</font></strong></span><span> beep=</span><span class="number"><font color="#c00000">0</font></span><span>;   </span></li><li><span>             </span><span class="keyword"><strong><font color="#7f0055">class</font></strong></span><span> Inner{   </span></li><li><span>                   </span><span class="comment"><font color="#008200">//使用beep </font></span><span>  </span></li><li><span>             }   </span></li><li><span>             Inner in=</span><span class="keyword"><strong><font color="#7f0055">new</font></strong></span><span> Inner();   </span></li><li><span>      }   </span></li><li><span>}  </span></li></ol></div><p>      这又是为什么呢？</p><p>      (1) 我们首先对Outter类进行反射发现，Outter中再也没有返回私有域的隐藏方法了。</p><p>      (2) 对Inner类的反射发现，Inner类内部多了一个对beep变量的备份隐藏域：final int val$i;</p><p>      我们可以这样解释Inner类中的这个备份常量域，首先当JVM运行到需要创建Inner对象之后，Outter类已经全部运行完毕，这是垃圾回收机制很有可能释放掉局部变量beep。那么Inner类到哪去找beep变量呢？</p><p>    <strong><span style="COLOR: #800000">  编译器又出来帮我们解决了这个问题，他在Inner类中创建了一个beep的备份</span></strong>，也就是说即使Ouuter中的beep被回收了，Inner中还有一个备份存在，自然就不怕找不到了。</p><p>      但是问题又来了。如果Outter中的beep不停的在变化那。那岂不是也要让备份的beep变量无时无刻的变化。<strong><span style="COLOR: #ff0000">为了保持局部变量与局部内部类中备份域保持一致。</span></strong>编译器不得不规定死这些局部域必须是常量，一旦赋值不能再发生变化了。</p><p>      所以为什么局部内部类应用外部方法的域必须是常量域的原因所在了。</p><img src ="http://www.blogjava.net/orangelizq/aggbug/318982.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/orangelizq/" target="_blank">桔子汁</a> 2010-04-21 15:00 <a href="http://www.blogjava.net/orangelizq/archive/2010/04/21/318982.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]Java中的内部类</title><link>http://www.blogjava.net/orangelizq/archive/2010/04/21/318981.html</link><dc:creator>桔子汁</dc:creator><author>桔子汁</author><pubDate>Wed, 21 Apr 2010 06:57:00 GMT</pubDate><guid>http://www.blogjava.net/orangelizq/archive/2010/04/21/318981.html</guid><wfw:comment>http://www.blogjava.net/orangelizq/comments/318981.html</wfw:comment><comments>http://www.blogjava.net/orangelizq/archive/2010/04/21/318981.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/orangelizq/comments/commentRss/318981.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/orangelizq/services/trackbacks/318981.html</trackback:ping><description><![CDATA[
		<div class="blog_content">
				<p>内部类：定义在其他类里面的类。<br />使用内部类的理由：<br />1.内部类方法能够访问外部类的任何数据成员包括私有成员。<br />2.对同一个包的其他类，内部类是不可见的。<br />3.匿名内部类能够方便的定义回调而不用写太多代码。</p>
				<p>非静态内部类没有默认的构造函数(无参数的)，非静态内部类的构造函数都有一个final的外围类对象引用this$0。<br />内部类的特殊语法规则：<br />1.相对内部类，引用其外部类隐式对象的形式：OuterClass.this<br />2.调用内部类的构造函数：outerObject.new InnerClass(construction parameters);<br />3.外部类外面引用内部类：OuterClass.InnerClass</p>
				<p>内部类是一种编译器现象与虚拟机无关。编译器将内部类翻译为用$分隔外部类名和内部类名的常规类文件，虚拟机对此并无所知。<br />使用javap -private OuterClass$InnerClass。javap这个工具确实挺不错的，对分析字节码和源码都有很大的帮助。<br />可以看出详细的内部类源码清单，其中包括了编译器自动添加的部分：<br />public class Outer<br />{<br /> public class Inner<br /> {<br /> }<br />}<br />当内部类是非静态内部类时相应的内部类的详细源码如下：<br />Compiled from "Outer.java"<br />public class Outer$Inner extends java.lang.Object{<br />    final Outer this$0;  //编译器自动在内部类里面添加了指向外部类对象的引用<br />    public Outer$Inner(Outer);  //内部类的构造函数默认有一个外部类对象作为参数。<br />}</p>
				<p>当内部类是静态内部类时：<br />Compiled from "Outer.java"<br />public class Outer$Inner extends java.lang.Object{<br />    public Outer$Inner(); //没有了对外部类对象的引用<br />}</p>
				<p>
						<br />如下代码模拟了上面内部类的情形唯一不同的是这里的Inner没有访问Outer私有数据的权限：<br />class Outer{<br />   Inner in = new Inner(this);<br />}</p>
				<p>class Inner{<br />   public Inner(Outer outer){<br />      this.outer = outer;<br />   }<br />   <br />   private Outer outer;<br />}</p>
				<p> </p>
				<p>//那么权限是如何控制的呢？当内部类中的方法访问到外部类的私有数据时(注意如果内部类没有方法去访问外部类的私有数据不会生成该静态方法static int access$000(Outer);)<br />public class Outer<br />{<br /> private int i;<br /> public void methodOne()<br /> {<br /> }</p>
				<p> class Inner<br /> {<br />  public void print(){<br />   System.out.println(Outer.this.i);<br />  }<br /> }<br />}</p>
				<p>相应的外部类详细源码如下：<br />public class Outer<br />{<br />   public Outer();</p>
				<p>   public void methodOne();<br />   static int access$000(Outer); //由编译器合成的用于内部类对外部类进行特殊访问权限的控制：这也是<br />                                //为什么内部类能够访问外部类中的私有数据的原因。<br />   private int i;<br />}</p>
				<p>内部类访问外部类的private数据的这种方式很可能导致危险，虽然access$000不是一个合法的Java方法名，但是熟悉class文件结构的黑客可以使用十六进制编辑器轻松创建一个用虚拟机指令调用那个方法的类文件。由于隐秘的访问方法需要拥有包可见性，所以攻击代码需要与被攻击类放在同一个包中。总之，如果内部类访问了外部类的私有数据域，就有可能通过附加在外部类所在包中的其他类访问私有数据。</p>
				<p>局部内部类：定义在方法之中，因此局部类没有public和private修饰符。对外界是完全隐藏的。<br />局部类不仅能够访问外部类，还能访问方法中的局部变量(或方法的参数)。不过那些局部变量要声明为final的。</p>
				<p>
						<br />匿名内部类：用外部类+$+数字的形式表示。一个外部类中有多个匿名内部类时，其生成的class文件对应有Outer$(1、2、3)的形式表示。注意到该匿名内部类是final的。<br />final class Outer$1<br />{<br />   Outer$1(Outer);</p>
				<p>   public void method();</p>
				<p>   final Outer this$0;<br />}</p>
				<p>嵌套类：当内部类不需要访问外部类的数据成员时应该使用嵌套类。注意只有内部类可以声明为static的其他不行。<br />在接口中声明的内部类自动转换为public static的，在接口中定义的成员自动都是public static的。</p>
				<p>内部类构造函数的可见性与其类的可见性相同。当内部类是private时其构造函数也是private的，当内部类是public的其构造函数也是public的。</p>
		</div>
		<script type="text/javascript">
				<!--
google_ad_client = "pub-4348265167276910";
/* 468x60, 个人博客 */
google_ad_slot = "2046406163";
google_ad_width = 468;
google_ad_height = 60;
//-->
		</script>
		<script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript">
		</script>
		<script src="http://pagead2.googlesyndication.com/pagead/expansion_embed.js">
		</script>
		<script src="http://googleads.g.doubleclick.net/pagead/test_domain.js">
		</script>
		<script src="http://pagead2.googlesyndication.com/pagead/render_ads.js">
		</script>
		<script><![CDATA[oogle_protectAndRun("render_ads.js::google_render_ad", google_handleError, google_render_ad);]]&gt;</script>
<img src ="http://www.blogjava.net/orangelizq/aggbug/318981.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/orangelizq/" target="_blank">桔子汁</a> 2010-04-21 14:57 <a href="http://www.blogjava.net/orangelizq/archive/2010/04/21/318981.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]计算机语言的形式语义研究</title><link>http://www.blogjava.net/orangelizq/archive/2009/12/18/306558.html</link><dc:creator>桔子汁</dc:creator><author>桔子汁</author><pubDate>Fri, 18 Dec 2009 07:15:00 GMT</pubDate><guid>http://www.blogjava.net/orangelizq/archive/2009/12/18/306558.html</guid><wfw:comment>http://www.blogjava.net/orangelizq/comments/306558.html</wfw:comment><comments>http://www.blogjava.net/orangelizq/archive/2009/12/18/306558.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/orangelizq/comments/commentRss/306558.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/orangelizq/services/trackbacks/306558.html</trackback:ping><description><![CDATA[
		<p>计算机科学对语言的研究（包括对自然语言和对人工语言）大致有三个路向：语法syntax、语义semantics、语用pragmatics，语法研究语言的形态结构，语义研究语言与其所指代对象的联系，语用研究语言和其使用者之间的联系（从使用者角度、按使用者的需求对语料进行差异化）。计算机没有智能，计算机智能都是假的，是人给它安装上去的（像是变魔术，有人创造，目的在骗人，当然达到了目的：娱乐、教育、传递信息等），所以计算机语言最大的特点是形式化（Formalization，包含规范化Normalization的意思），计算机语言的形式化分为语法形式化和语义形式化两个方面，形式语义学研究语义形式化，包括操作语义学、指称语义学、公理语义学和代数语义学四种。具体可参考：</p>
		<p>陆汝钤，计算机语言的形式语义.北京:科学出版社,1992<br />屈延文，形式语义学基础与形式说明.北京:科学出版社,1998<br />周巢尘，形式语义学引论，长沙：湖南科学技术出版社，1985<br />另外上海师范大学物理信息学院陈仪香教授对此也有深入研究。以下对四种语义学的简介来即自陈教授"形式语义的论语理论研究进展"一文（见下列著作第二章：陆汝钤主编，《知识科学与计算科学》.北京：清华大学出版社，2003）</p>
		<p>
				<font color="#ff3333">操作语义</font>的基本思想是建立一个抽象机器以模拟程序在执行过程中如何进行数据处理。<br /><font color="#ff3300">指称语义</font>的思想是使语言的每一成分对应于一个数学对象，该对象称为该语言成分的指称，程序看作输入域到输出域的映射，输入域和输出域统称为论域。因此论域与映射是指称语义的基本研究对象。<br /><font color="#ff0000">公理语义</font>实在程序正确性验证的基础上发展起来的，它给出一种方法，使人们在给定的前提下，验证某种特性是否成立。<br /><font color="#ff0000">代数语义</font>的基本思想是把描述语义的逻辑体系和满足这个逻辑系统的各种模型统一在一起，同时把模型的集合看成是以代数机构，研究这些模型之间的关系。<br /><br />戴维民主编的《信息组织》一书（高等教育出版社.2004 面向21世纪课程教材）中认为语法、语义和语用信息的分法是"按照信息组织的层次分"，具体解释如下：<br />"从认知的角度，可把信息分为语法信息、语义信息和语用信息。由于主体具有观察力，能够感知事物运动状态及其变化方式的外在形式，由此获得的信息称为语法 信息；由于主体具有理解力，能够领悟事物运动状态及其变化方式的逻辑含义，由此获得的信息称为语义信息；又由于主体具有明确的目的性，能够判断事物运动状 态及其变化方式的效用，由此获得的信息称为语用信息。"有一定道理，好像又不是很确切。不知道这种理解出自何处？语言学？哲学？认识论？</p>
		<p>
				<br />计算机形式语义学参考书：</p>
		<p>1、周巢尘，《形式语义学引论》，湖南科技出版社（绝版）<br />2、周之英，翻译，《计算机形式规范概论》，清华大学出版社（绝版）<br />3、屈延文，《形式语义学基础与形式说明》，科学版（绝版）<br />4、陆汝钤，《计算机语言的形式语义》，科学版<br />5、陈意云，（实际是编译的），《形式语义学基础》，中国科技大学出版社<br />6、陈意云，（实际是编译的），《程序设计语言理论》，中国科技大学出版社<br />7、宋国新，翻译，《程序设计语言的形式语法及语义》，机工版</p>
		<p>
				<br />从发展来说，国内的形式语义学或程序理论的教材，落后国外十年以上。国外现在最流行的几本教材是：</p>
		<p>1、《Semantics of Programming Languages》（Carl A.Gunter）MIT Press 1992<br />这是目前也许是最流行的一本教材，主要采用了简单类型的Lambda Calculus和范畴学来表达语义学，内容取舍比较合理，章节安排也不错，属于高级教程，评价也很高，很多大学都推荐使用。</p>
		<p>2、《The Formal Semantics of Programming Languages》（Glynn Winskel）MIT Press 1993<br />另一本流行的一本教材，作者Winskel是剑桥大学的教授，该书在欧洲几乎成为标准教材了，评价也很高，中高级教程，很多大学都推荐使用，已经出了中文版，大家可以到书店买到。</p>
		<p>3、《Foundations for Programming Languages 》（John C. Mitchell ）MIT Press 1996<br />作为桌案上的参考书就最好了，作者是斯坦福教授。这本书是一本巨作，内容齐全，大量泛代数内容，绝对是超高级教程，但作为教材的话内容太多了，850页，真的是本大部头</p>
		<p>4、《Theories of Progamming Languages》（John C. Reynolds）Cambridge Press 1998<br />Reynolds是CMU教授，他的这本教材出发角度和上面的几本有所不同，按作者的话来说，就是尽量避免使用高深的数学理论，诸如范畴学之类的东西，同时这本书内容涉及也比较广，甚至有并发理论和CSP。该书在评价非常高，推荐大家看。</p>
		<p>5、《Semantics of Programming Languages》（R.D. Tennent）Prentice-Hall 1990<br />这本书的最大特点就是采用imperative language作为研究对象，和国内的教学最符合了，国外很多大学，特别是欧洲的大学，普遍采用函数式汝ML语言作为研究和教学语言。作者R.D. Tennent在八十年代初，曾经出版过一本《Principles of Programming Languages》，国际国内都很多人参考过这本书。</p>
		<p>6、《Introduction to the Theory of Programming Languages》（Bertrand Meyer）Prentice-Hall 1988<br />作者大家都很熟悉了，他的另一本书《Object-Oriented Software Construction》前几年就已经引进中国了。这本书几乎没有高深的数学内容，可能这本书出的比较早些，书的内容要比前面的几本书都要容易浅些，但作为入门的书，我推荐这本。</p>
<img src ="http://www.blogjava.net/orangelizq/aggbug/306558.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/orangelizq/" target="_blank">桔子汁</a> 2009-12-18 15:15 <a href="http://www.blogjava.net/orangelizq/archive/2009/12/18/306558.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]XML技术与数据库的发展趋势分析</title><link>http://www.blogjava.net/orangelizq/archive/2009/12/09/305308.html</link><dc:creator>桔子汁</dc:creator><author>桔子汁</author><pubDate>Wed, 09 Dec 2009 09:07:00 GMT</pubDate><guid>http://www.blogjava.net/orangelizq/archive/2009/12/09/305308.html</guid><wfw:comment>http://www.blogjava.net/orangelizq/comments/305308.html</wfw:comment><comments>http://www.blogjava.net/orangelizq/archive/2009/12/09/305308.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/orangelizq/comments/commentRss/305308.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/orangelizq/services/trackbacks/305308.html</trackback:ping><description><![CDATA[
		<p>数据库技术及其应用系统经历了从层次数据库、网状数据库到关系数据库以及面向对象数据库的发展，在传统的商业和事务处理领域内逐步成熟，取代了原有的基于文件系统的数据处理方式，成为计算机信息系统中的重要基础和支柱。但随着Internet的飞速发展，Web的出现改变了人们习惯的处理方式，也给数据库技术提出了必须面对的重要问题，即如何有效地存储和管理Web上的数据(文档)，使其既能被高效地操作和维护，又能在Internet平台上方便地表示和交换。 </p>
		<p>XML技术自出现以来发展非常迅速，在许多领域内得到广泛的支持而有着广阔的应用前景。例如电子数据交换、电子商务等更是将XML作为一种基础性、支柱性的技术来看待。</p>
		<p>
				<strong>1、数据库简史</strong>
		</p>
		<p>数据库系统是随着计算机技术的不断发展，在特定的历史时期、特定的需求环境下出现的。在1946年的第一台计算机到20世纪60年代这漫长的20年里，计算机操作系统主要局限于文件的操作，对数据的管理也主要是通过文件系统来实现。进行计算所需要的各种数据存放在各自的文件里，使用这些数据时将文件打开，读取文件中的数据到内存中，当计算完毕后，将计算结果仍旧写入到文件中去，它的不足主要集中在无法对数据进行有效的统一管理。针对文件系统的重要缺点，人们逐步发展了以统一管理数据和共享数据为主要特征的系统，即数据库系统。1964年，美国通用电气公司开发成功了世界上的第一个数据库系统IDS(IntegratedDataStore)。IDS奠定了网状数据库的基础，并得到了广泛的发行和应用，成为数据库系统发展史上的一座丰碑。1969年，美国国际商用机器公司(IBM)也推出世界上第一个层次数据库系统IMS(InformationManagement System)，同样在数据库系统发展史上占有重要的地位。</p>
		<p>70年代初，E.F.Codd在总结前面的层次、网状数据库优缺点的基础上，提出了关系数据模型的概念及关系代数和关系演算。在70年代，关系数据库系统无论从理论上还是实践上都取得了丰硕的成果。在理论上确立了完整的关系模型理论、数据依赖理论和关系数据库的设计理论；在实践上，世界上出现了很多著名的关系数据库系统，比较著名的如SystemR、INGRES、Oracle等。</p>
		<p>与文件系统相比，数据库系统有几个方面的特点：向用户提供高级的接口；向用户提供非过程化的数据库语言(即SQL语言)；查询的处理和优化；并发控制；数据的完整性约束。</p>
		<p>进入80年代之后，计算机硬件技术的飞速提高促使计算机应用不断深入，产生了许多新的应用领域，例如计算机辅助设计、计算机辅助制造、计算机辅助教学、办公自动化、智能信息处理、决策支持等。这些新的领域对数据库系统提出了新的要求。但由于应用的多元化，不能设计出一个统一的数据模型来表示这些新型的数据及其相互关系，因而出现了百家争鸣的局面，产生了演绎数据库、面向对象数据库、分布式数据库、工程数据库、时态数据库、模糊数据库等新型数据库的研究和应用。</p>
		<p>
				<strong>2、XML简介</strong>
		</p>
		<p>XML推荐标准1.0版发布于1998年2月，之后迅速在全球掀起了XML应用的浪潮。XML是一种描述型的标记语言，与HTML同为SGML(标准通用标记语言，ISO-8879国际标准)的一种应用。由于XML在可扩展性、可移植性和结构性等方面的突出优点，它的应用范围突破了HTML所达到的范围。</p>
		<p>一篇XML文档由标记和内容组成。XML中有六种标记：元素(elements)、属性(attributes)、实体引用(entityreferences)、注释(comments)、处理指令(processinginstructions)和CDATA段(CDATAsections)。XML与HTML最显著的不同是XML文档中引入了“文档类型声明”(Document Type Declarations)。DTD使文档可以与分析器交流关于它的内容的元信息。DTD的出现，赋予了XML文档可扩展性、结构性和可验证性，使XML具备了类似于数据库的一些性质，可以利用XML来组织和管理信息；又可以与HTML一样在浏览器中方便地表示，在Internet上高效地传递和交换。考虑到与HTML的兼容，DTD并不是XML文档必需的成份。具有DTD的XML文档称作“Valid”，否则就是“Well-formed”。</p>
		<p>目前，处理XML文档的方式主要有SAX与DOM两种。SAX(SimpleAPIforXML)是一种基于流的、以事件处理方式工作的接口。SAX 2.0在2000年5月发布，增强了许多功能，包括对名字空间的支持。DOM(Document Object Model)则是在对XML文档进行分析后，在内存中建立起一个完整的树结构，然后在此基础上进行各种操作。简单地比较来看，SAX对系统资源要求低、速度快，但对文档的操作是只读的；DOM的处理能力强大，但要求大量的系统资源，尤其是对于大的文档。而后还出现了Xpath和Xpointer用以完成XML的搜索和转换；XSL、XSLT和SOAP用以完成XML的远程对象访问，XML Query Languages的出现使XML查询语言可用于任何XML文档。</p>
		<p>
				<strong>3、XML与数据库</strong>
		</p>
		<p>XML文件是数据的集合，它是自描述的、可交换的，能够以树型或图形结构描述数据。XML提供了许多数据库所具备的工具：存储(XML文档)、模式(DTD，XMLschema，RE1AXNG等)、查询语言(XQuery，XPath，XQL，XML-QL，QUILT等)、编程接口(SAX，DOM，JDOM)等。但XML并不能完全替代数据库技术。XML缺少作为实用的数据库所应具备的特性：高效的存储、索引和数据修改机制；严格的数据安全控制；完整的事务和数据一致性控制；多用户访问机制；触发器、完善的并发控制等。因此，尽管在数据量小、用户少和性能要求不太高的环境下，可以将XML文档用作数据库，但却不适用于用户量大、数据集成度高以及性能要求高的作业环境。</p>
		<p>随着Web技术的不断发展，信息共享和数据交换的范围不断扩大，传统的关系数据库也面临着挑战。数据库技术的应用是建立在数据库管理系统基础上的，各数据库管理系统之间的异构性及其所依赖操作系统的异构性，严重限制了信息共享和数据交换范围；数据库技术的语义描述能力差，大多通过技术文档表示，很难实现数据语义的持久性和传递性，而数据交换和信息共享都是基于语义进行的，在异构应用数据交换时，不利于计算机基于语义自动进行正确数据的检索与应用；数据库属于高端应用，需要昂贵的价格和运行环境。而随着网络和Internet的发展，数据交换的能力已成为新的应用系统的一个重要的要求。XML的好处是数据的可交换性(portable)，同时在数据应用方面还具有如下优点：(1)XML文件为纯文本文件，不受操作系统、软件平台的限制；(2)XML具有基于Schema自描述语义的功能，容易描述数据的语义，这种描述能为计算机理解和自动处理；(3)XML不仅可以描述结构化数据，还可有效描述半结构化，甚至非结构化数据。</p>
		<p>
				<strong>4、XML文件的存储</strong>
		</p>
		<p>XML文件的存储方式有三大类：(1)将文件存储于文件系统(StoringDocumentsinthe File System)；(2)将文件存储于BLOB(Storing Documents in BLOBs)，利用数据库的事务管理、安全、多用户访问等优点。此外许多关系数据库提供的检索工具可以进行全文检索、近似检索、同义词检索和模糊检索。其中某些工具将会支持XML，这样就可消除将XML文件作为纯文本检索所带来的问题。(3)将文件存储于原生XML数据库(Native XML Databases，NXD)。NXD是专用于存储XML文件的数据库，支持事务管理、安全、多用户访问、编程API和查询语言等。与其它数据库的唯一区别在于其内部模型是基于XML的。其中，最重要的存储方式当属原生XML数据库。<br /></p>
		<p>
				<strong>4.1、原生XML数据库</strong>
		</p>
		<p>原生XML数据库(NativeXMLDatabases)为XML文档定义了一个(逻辑)模型，并根据该模型存取文件。这个模型至少应包括元素、属性、PCDATA和文件顺序。其例子有XPath数据模型、XMLIn-foset以及DOM所用的模型和SAX 1.0的事件。它以XML文件作为其基本存储单位，对底层的物理存储模型没有特殊要求。例如，它可以建在关系型、层次型或面向对象的数据库之上，或者使用专用的存储格式，比如索引或压缩文件。</p>
		<p>NXD最适于存储以文档为中心的文件。这是由于NXD保留了文件、顺序、处理指令、注释、CDA-TA块以及实体引用等，而支持XML的数据库XED(XML-enableddatabase)无法做到。XED是在原有数据库基础上扩展了XML支持模块，完成XML数据和数据库之间的格式转换和传输。从存储粒度上，可以把整个XML文档作为RDBMS表中一行，或把XML文档进行解析后，存储到相应的表格中。为了支持W3C的一些XML操作标准，Xpath、XED提供一些新的原语(如Oracle9iR2增加了一些数据包来操作XML数据等)，并优化了XML处理模块。</p>
		<p>NXD一般采用层次数据存储模型，保持XML文档的树形结构，省掉了XML文档和传统数据库的数据转换过程。NXD还适用于存储“天然格式”为XML的文件，NXD还可以存储半结构化数据、在某种特定情形下提高存取速度以及存储没有DTD的文件(良构的文件)。</p>
		<p>
				<strong>4.2、原生XML数据库的结构</strong>
		</p>
		<p>原生XML数据库的结构可分为两大类：基于文本的和基于模型的。</p>
		<p>基于文本的NXD(Text-BasedNativeXMLDatabases)将XML作为文本存储。它可以是文件系统中的文件、关系数据库中的BLOB或特定的文件格式。基于文本的NXD与层次结构的数据库很相似，当存取预先定义好层次的数据时，它比关系数据库更胜一筹。和层次结构的数据库一样，当以其它形式比如转置层次存取数据时，NXD也会遇到麻烦。这个问题的严重程度尚未可知，很多关系数据库都使用逻辑指针，使相同复杂度的查询以相同的速度完成。</p>
		<p>基于模型的NXD(Model-BasedNativeXMLDatabases)是根据文件构造一个内部模型并存储这个模型。有些数据库将该模型存储于关系型和面向对象的数据库中，例如在关系型数据库中存储DOM时，就会有元素、属性、PCDATA、实体、实体引用等表格。其他数据库使用了专为这种模型优化了的存储格式。使用专用存储格式的基于模型的NXD如果以文件的存储顺序读取文件，其性能与基于文本的NXD相似。</p>
		<p>
				<strong>4.3、原生XML数据库的特性</strong>
		</p>
		<p>原生XML数据库的特性(FeaturesofNativeXML Databases)有：(1)文件集(Document Collections)，支持集合(Collection)的概念，其作用相当于关系数据库中的表和文件系统中的文件夹。(2)查询语言(Query Languages)，最常用的有XPath(对多个文件的查询作了扩充)和XQL，以及专有的查询语言。(3)更新和删除(Updates and Deletes)，NXD对文件的更新和删除方式从简单的替换或删除现有文件，到修改当前活动的DOM树，以及用于指定如何修改文件片断的语言。(4)事务、锁定和并发(Transactions，Locking，and Concurrency)，支持事务处理。锁定通常是对整个文档的，所以多用户并发性相对较低。问题的大小取决于应用程序以及“文件”的构成。(5)原生数据库提供应用程序接口API(Application Programming Interfaces，APIs)。(6)NXD的一个重要特性是它可以为XML文档提供“往返车票(round-trip)”。可以将XML文件存放在NXD中，而且再取回“同样的”文件。对于以文档为中心的应用程序来说非常重要，因为CDATA部分、实体用法、注释和处理指令是这些文档不可缺少的组成部分。特别是对于法律和医学文件，按规定这些文档必须要保持原样。(7)外部数据(Remote Data)，某些NXD可包含有外部数据，它来自存储在数据库中的文档。通常这些数据通过OD-BC、OLE DB或JDBC从关系数据中取出，模型可以是基于表格的或对象-关系型映射。(8)支持元素和属性的索引。</p>
		<p>
				<strong>5、结论</strong>
		</p>
		<p>XML技术的出现，使数据处理从文件方式到数据库系统再到文件方式的循环，但新的文件方式已经与最初的文件系统有了本质的区别----格式化文档。XML和关系数据库在数据应用和数据管理方面各有优势。</p>
		<p>一方面，我们要研究数据库的新技术、探索数据库的发展方向；另一方面，在数据库的基本实现基础上，添加必要的新技术是探索新数据库的发展方向。</p>
<img src ="http://www.blogjava.net/orangelizq/aggbug/305308.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/orangelizq/" target="_blank">桔子汁</a> 2009-12-09 17:07 <a href="http://www.blogjava.net/orangelizq/archive/2009/12/09/305308.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]XML数据库发展迅猛</title><link>http://www.blogjava.net/orangelizq/archive/2009/12/09/305305.html</link><dc:creator>桔子汁</dc:creator><author>桔子汁</author><pubDate>Wed, 09 Dec 2009 09:05:00 GMT</pubDate><guid>http://www.blogjava.net/orangelizq/archive/2009/12/09/305305.html</guid><wfw:comment>http://www.blogjava.net/orangelizq/comments/305305.html</wfw:comment><comments>http://www.blogjava.net/orangelizq/archive/2009/12/09/305305.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/orangelizq/comments/commentRss/305305.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/orangelizq/services/trackbacks/305305.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp; XML数据的爆炸式增长，以及访问此类数据的Web服务的增长，都在推动企业创造新的信息架构，而在此过程中，XML数据存储将是一项非常关键的组件。</p>
<p>&nbsp;&nbsp;&nbsp; 目前，正当用户们准备引入真正的XML数据库产品之时，Microsoft和IBM等传统数据库厂商已经发起了更加猛烈的竞争攻势。此外，Oracle和Sybase也在努力说服企业IT部门采用自己的下一代数据存储技术以及与之相关的数据管理和应用开发工具。</p>
<p align="center"><img class="fit-image" onmousewheel="javascript:return big(this)" src="http://database.51cto.com/files/uploadimg/20060425/1121230.jpg" onload="javascript:if(this.width  alt="" />498)this.style.width=498;" border=1></p>
<p><strong>热烈欢迎XML</strong> </p>
<p>在IDC最近发布的一份报告中，500家受访企业的IT部门中有29%称，正在大量使用XML存储库和数据库；约有同样比例的受访者称，正在探索这方面的使用前景。此外，这项研究还发现XML技术的使用是非常广泛的，包括编辑器、基于XML的电子表格和XML图表等。其中，约有三分之一的受访者都在使用其中的一种技术，其比例与声称正在探索此类技术使用前景的受访问者几乎相同。随着用户兴趣的提高，传统数据库厂商开始调整自己的产品计划，而原有的XML服务器厂商则更加野心勃勃地投身于市场的竞争。 </p>
<p>微软公司在2005年年底发布了代号为Yukon的SQL Server 2005。该产品可以存储和处理XML数据，且无须将这些数据转换为关系列和行，更不需要将其存储为二进制大型对象。编程人员可以使用XML Query或称XQuery来检索XML数据。这种语言即将获得World Wide Web Consortium（W3C）的批准。</p>
<p>IBM正在对其DB2 Viper进行测试。该产品可以存储传统的关系数据和XML数据。按计划，Viper将于今年晚些时候正式推出。IBM已经明确指出，Viper的XML数据管理能力完全符合面向服务架构（SOA）的要求。在面向服务的架构中，用户可以使用标准的Web服务界面对程序和所有格式的数据进行分类、查找、访问和使用。 </p>
<p>目前，W3C创建XQuery最终建议的工作已经完成。XQuery 将创建出一种标准的查询语言，能够对已经存储的XML数据进行访问和处理。在XML的环境中，该语言相当于SQL语言在关系数据库中的地位，并且可以大幅度地简化XML应用的编程过程。 </p>
<p>XML将提高非结构性文件的通用表达能力，这类文件包括文档、报告和表格。Gartner集团高性能市场事业群的副总裁Rita Knox说：&#8220;高端出版应用（如航空航天和汽车工业的技术手册）在很久以前就开始使用XML。但目前，XML正在朝着更贴近人们日常生活的领域进军（如银行业）。美国银行业中正在开发一种名为可扩展商业报告语言（XBRL）实现通用的XML表达，主要用于向联邦储蓄保险公司发送资产及负债报告和其他信息。&#8221;<br />
<strong>拿来做些什么</strong></p>
<p>厂商的热捧并不奇怪，但更为关键的问题是提供内容服务方面能够用XML做些什么事？IDC内容技术项目主管Melissa Webster说，下一阶段的开发工作就正在这些方面作出努力。 </p>
<p>大体上看，原有的XML数据库产品和传统数据库中新展现出的XML能力在基础工作方面的表现都非常好，比如良好的扩展性、出色的性能、管理XML文档版本的能力，以及链接内容中各部分的能力等等。但Webster也认为，真正的优势来自两个更高级的领域。其中一个就是连续修改内容，例如将技术手册的更新或修改与工程师创建的注释和说明结合在一起。Webster将这一方面的能力称为配置管理。 </p>
<p>其二，是将已存储的XML信息与关键业务流程联系起来。例如处理一份按揭贷款或修理一架喷气式客机，您可以从飞机的CAD工程图纸开始着手，并为发动机维修技师生成最终技术文档，然后将修理单与特定的说明和图纸一并提交给有关的维修人员。同时，维修工作流中的重要事件将被反馈到发动机的维修历史中，并将这些内容写入那些提交给制造商和联邦航空管理局的报告中。</p>
<p>Webster指出：&#8220;过去，技术手册与使用它的业务流程相互隔离。在此过程中，需要有人才能把两者联系起来。而现在，则可以借助智能XML内容服务把业务流程和特定内容结合起来。&#8221; </p>
<p>这种潜力进一步刺激了原有XML产品厂商在市场中的野心。尽管IBM、Microsoft和Oracle等厂商在这方面的声势很大，但投资者们显然非常看好像Mark Logic这类新兴的XML内容服务厂商。 </p>
<p>Mark Logic公司负责客户解决方案的副总裁Max Schireson指出：&#8220;如果XML内容只是由XML包装的简单数据，那么，用户就没有理由不用Oracle或Microsoft的产品。&#8221; 但是，如果是在复杂的文档和流程中，关系数据库就很难对文档和其他内容实施有效的智能管理了。</p>
<p>比如O'Reilly Media公司使用Mark Logic服务器创建了一个系统。利用该系统，大学教授可以针对不同的课程创建定制的阅读教程。教授们可以对O'Reilly 那些以XML文档形式存储的图书和出版物内容库进行复杂搜索，他们还可以添加一些自己编写的内容，并且根据需要下订单，由出版商负责将其印刷出来并直接交付到教授们的手中。 </p>
<p><strong>链接：XML数据库的应用先驱</strong></p>
<p>其实，XML数据库最初只是应用于一种特殊产品。 Command金融出版社是美国纽约的一家金融信息出版商，该公司使用Ixiasoft XML服务器来存储和管理其共有基金客户的募股说明书。每一家客户都有多种基金，因此该公司需要每年出版大量的此类信息。Command公司IT部门的项目管理主管Will Montgomery说：&#8220;很多数据都是独一无二的，但其中也有很大一部分对于所有客户的基金来说都是通用的。&#8221; </p>
<p>过去，在编写、校对、修改和再次校对等过程中，即使是那些通常应保持完全一致的模板文件也必须经常修改。Montgomery说：&#8220;如果客户有100个基金，他们就必须进行数百次修改。&#8221; 而在使用Ixiasoft XML服务器之后，客户在Microsoft Word 2003中完成这些修改工作只需一次即可，修改后的内容可随时复制到有关的文档。 <br />
现在，Command金融公司正在评估另外一种做法，即在股东报告这种非结构性文件中使用这种技术。</p>
<img src ="http://www.blogjava.net/orangelizq/aggbug/305305.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/orangelizq/" target="_blank">桔子汁</a> 2009-12-09 17:05 <a href="http://www.blogjava.net/orangelizq/archive/2009/12/09/305305.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]XML数据库发展路在何方</title><link>http://www.blogjava.net/orangelizq/archive/2009/12/09/305303.html</link><dc:creator>桔子汁</dc:creator><author>桔子汁</author><pubDate>Wed, 09 Dec 2009 09:02:00 GMT</pubDate><guid>http://www.blogjava.net/orangelizq/archive/2009/12/09/305303.html</guid><wfw:comment>http://www.blogjava.net/orangelizq/comments/305303.html</wfw:comment><comments>http://www.blogjava.net/orangelizq/archive/2009/12/09/305303.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/orangelizq/comments/commentRss/305303.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/orangelizq/services/trackbacks/305303.html</trackback:ping><description><![CDATA[
		<p>虽然学术界和工业界对XML数据库的研究和开发并不完全一致，但是两者的目标却非常相似：解决现有问题，扩展应用领域。</p>
		<p>
				<strong>一.学术界与工业界的两种不同索求</strong>
		</p>
		<p>Ronald Bourret 在他那篇著名的《XML Database Products》中，将XML数据库产品分为中间件(Middleware)、支持XML的数据库(XML-Enabled Databases)、纯XML数据库(Native XML Databases)、XML服务器(XML Servers)、Wrappers、内容管理系统(Content Management Systems)、XML查询引擎(XML Query Engines)、XML Data Binding、Discontinued products等九种，在业界影响很大。但是，在XML数据库的研究和开发人员眼里，或许只有支持XML的数据库、纯XML数据库能够称得上是真正意义上的XML数据库。支持XML的数据库可以被看做是支持XML数据的数据库系统，它可能是关系数据库、对象数据库等。就在一年半以前，还有相当多的人在争论关系库支持的XML数据库和纯XML数据库孰优孰劣的问题。但是，纯XML数据库却在这种争论中悄然进步，在技术上有了长足的发展。</p>
		<p>人们已经越来越倾向于认为XML数据库就是纯XML数据库。随着金融界确立XBRL(XML的一个子集)标准和政府规范电子政务的XML格式，实践推动着XML数据库技术不断向前发展。</p>
		<p>XML数据库系统从最初简单的查询引擎，不断地加入查询优化、事务处理、触发器、并发控制、代数系统等传统的数据库技术，一步步地从性能和功能上完善自己。</p>
		<p>从目前XML数据库的产品情况来看，学术界的实验系统和市场产品之间有着些许微妙的差别，尽管它们的主流技术是一致的。</p>
		<p>学术界完成的实验室原型系统一般侧重于下面的一些特点：</p>
		<p>● 专注于查询性能的提高，对查询优化的研究较多。为了提高查询效率，学术界十分重视索引结构的设计，先后提出二十几种适合于XML数据的索引方式，比如影响很大、简单易用的三元组索引，并在此基础上开发出了以结构化联接为基础的查询模式匹配方法。</p>
		<p>● 强调平台无关性。在XML数据库研究的早期，业界曾存在一个争论:到底将XML数据存储在关系库中，还是另外开发存储XML的物理数据库。这在一定程度上影响着XML的研究者，在设计索引结构时必须考虑使索引过的XML数据可以存储在多种数据库结构中。</p>
		<p>● 从理论的角度较多地考虑了XML数据库的模式设计规范化问题。设计了基于键的函数依赖推理，在如何优化XML数据库设计、消除数据冗余和不一致方面有了一些实质上的进展。</p>
		<p>工业界的XML数据库产品更加强调实用，有着一些与学术界原型系统不尽相同的特点：</p>
		<p>● 现有的主流XML数据库产品都在底层提供collection数据结构，以存储XML元素节点，通过B+树结构来索引这些元素节点。这一点与关系库系统的底层处理如出一辙。在collection之上一般还会有一级或两级索引，以加快查询处理速度。这一点比平台无关的实验原型系统更高效实用。</p>
		<p>● 市场上的数据库产品通过引入日志管理，建立了较完善的事务处理机制，这为上层的数据库应用开发提供了便利。目前的商用XML数据库一般提供事务处理功能，包括提交、回滚和日志文件。通过提供事务日志机制，纪录系统执行的每个事务的详细情况，保证在系统出现问题后可以完全恢复。</p>
		<p>● 增强了对异构数据源的集成管理。树型结构的XML数据有其难以管理的一面，但是，XML技术的可扩展性又使得它具有集成异构数据源的强大能力。因此，市场上的XML数据库产品普遍具有较强的集成多种数据源的功能。这也是当前市场上的XML数据库产品的一大亮点。</p>
		<p>
				<strong>二.实验室的原型系统和商用化产品</strong>
		</p>
		<p>最近几年以来，在学术界和工业界的共同推动下，如雨后春笋般诞生出大量的XML数据库原型系统和商用产品。</p>
		<p>在Ronald Bourret的《XML Database Products》中一共列了36种XML数据库产品，大致上可分为三大类型：</p>
		<p>● 商业类(commercial)：如Ipedo、Tamino、Natix、Xyleme等。其中，美国Ipedo公司的Ipedo XML Database和德国Software AG公司的Tamino是其中的佼佼者，成为目前市场上的主流产品。</p>
		<p>● 研究类(research)：如Stanford大学早期开发的Lore等。</p>
		<p>● 开放源码类(open source)：其中影响较大的是Berkeley DB XML、dbXML、XDB和Xindice。</p>
		<p>需要指出的是， Lore database systems 只是Stanford大学早期针对半结构化数据而开发的数据库系统。Lore连同其专设语言Lorel都是为半结构化数据而写的。尽管说XML数据在某种程度上也是一种半结构化数据，但是，两者之间还是有着一些差别，导致Lore database systems很难成为一种完全意义上的XML数据库系统。</p>
		<p>事实上，在学术界，真正受到关注的XML数据库原型系统有三家：密歇根大学安阿伯分校的Timber、西雅图华盛顿大学的Tukwila和威斯康星大学麦迪逊分校的Niagara。其中，影响最大的是Timber，在该系统的实施过程中，产生了许多有关XML数据库的新的概念和方法。当然，多伦多大学的Tox也是一个相当不错的系统，尤其是其出色的索引结构。但是，总体上不如前面的三家有名。<br /><br /></p>
		<p>
				<strong>三.核心技术的进展</strong>
		</p>
		<p>综合XML数据库的实验室原型和商业产品的共性，XML数据库的核心技术主要包括：</p>
		<p>
				<strong>1.查询语言</strong>
		</p>
		<p>自从1995年XML技术的研究和开发逐渐升温以来，形形色色的XML查询语言不断问世。比较有代表性的如早期的XML-QL、XQL、UnQL，后来的Quilt、Xpath，以及由Quilt发展而来的XQuery。在W3C的极力推动和学术界、工业界的大力支持下，XQuery逐渐在这些查询语言中脱颖而出，成为事实上的工业标准。</p>
		<p>XQuery的FLWR语句规范，有着与关系数据库的SQL完全类似的表达方式，使得它在一般用户眼里，也变得友好起来。</p>
		<p>而Xpath可以理解为是XQuery的一个子集。Xpath表达式在相关文献中被证明与查询模式树是等价的，这也与学术界推崇的模式树查询方式一致，使得实验室系统可以毫不困难地处理Xpath查询表达式，并能进行查询优化。这一点在XML数据库研究中显得颇有价值。</p>
		<p>
				<strong>2.XML文档解析</strong>
		</p>
		<p>在图1中，将XML文档载入数据库时，会经过一个XML数据解析器。数据解析器会依据一定的规则对XML数据进行解析后装入数据库。目前的数据解析器一般提供SAX(simple API for XML)和DOM(document object model)两种方式。</p>
		<p>SAX和DOM是针对XML文档的两种不同的应用程序编程接口API。SAX更多地依赖语法制导(syntax driven)，而DOM则提供一组功能程序来开发与XML数据相关的应用。</p>
		<p>SAX解析器是边读入边解析，带有一定的实时性，特别适合于XML流数据的处理。而DOM解析器是待整个文档均导入内存后才开始解析，在一定程度上受到内存容量的限制。目前的XML数据库产品均支持这两种解析方式。</p>
		<p>
				<strong>3.查询处理</strong>
		</p>
		<p>查询处理的方式和效率，一直是XML数据库研究和开发者关注的首要问题。</p>
		<p>如图1所示，XML数据库的查询处理一般是从解析查询语言(如XQuery)的查询语句表达式开始的。XML数据库的查询解析器将表达式解析为一棵查询模式树(有的系统叫做语法树)。</p>
		<p>假设一个XQuery表达式为：</p>
		<p>book [tittle = ‘XML’] // [ year = ‘2000’]</p>
		<p>它所对应的模式树如图2所示，它表示我们要查询的 book节点满足下面的条件：</p>
		<p>● 有一个子节点tittle，它的内容为串值XML;</p>
		<p>● 它有一个后代节点year，它的内容为串值2000。</p>
		<p>从语义上来说，就是：查找“一本2000年出版的、名为XML的书”。</p>
		<p>接下来就是到XML数据库中去匹配这棵树，得到最终的XML结果文档。</p>
		<p>在如何匹配模式树的技术上，实验室原型系统与商业产品之间有着一些差别。</p>
		<p>比如，在Timber中，考虑了一种叫做“结构化联接”的技术。它的基本思路是将上述的模式树分解为二元关系序列。而在此之前，也已经将XML文档库做了索引处理，文档中每个元素节点均被标以一个三元组索引，形式为：(文档标识符，开始位置：结束位置，层号)。</p>
		<p>于是，该查询模式可以分两步来完成:在索引过的XML数据库中匹配上述分解的二元结构关系;将查找到的二元结构匹配结果组装(stitching)成最终的符合上述查询表达式的完整文档。</p>
		<p>结构化联接技术在2002年被提出并在Timber中实现以后，在学术界引起过较大的反响。自2002年以来不断有技术上的改进文章出现在数据库的三大国际会议(VLDB、SIGMOD/PODS、ICDE)上，其中较有影响的成果是隐检整枝联接(holistic twig join)技术，可以用相互连接的多栈结构一次性生成查询结果文档。</p>
		<p>在商用产品中，由于文档元素节点均存储在B+树结构中，可以直接到底层的数据库中去查找相关的匹配节点序列，再根据其指针关联，将结果节点集组装成结果文档。</p>
		<p>总的来说，实验室产品在输入节点序列较长时效率会较高，尤其是隐检整枝联接技术。而商用产品在查询的文档较大时更显优势。</p>
		<p>在查询处理阶段，实验室产品做了而商用产品没做的事情就是模式树的最小化。它的主要思想就是，模式树的匹配效率依赖于模式树的规模(元素节点的多少)。而一般的模式树均存在一定量的冗余节点，可以通过最小化算法予以去除。</p>
		<p>根据复旦大学数据库研究中心XML小组的实验结果表明，在随机建立的XML查询模式树集合中，最小化算法平均可以消除30%的冗余节点。</p>
		<p>当然，模式树最小化算法的时间复杂度比较高，目前的关注点主要在于时间复杂度的降低上。最新算法的时间复杂度已经降低到低阶的多项式时间了。这项技术的实用化是值得期待的。<br /></p>
		<p>
				<strong>4.事务处理和版本控制</strong>
		</p>
		<p>目前的商用XML数据库一般提供事务处理功能，包括提交、撤回和日志文件。我们知道，事务为数据库的一组操作，这些操作组成一个逻辑单元，执行时要么全部完成，要么全部不做(do all or do nothing)。XML数据库通过提供事务日志机制，纪录系统执行的每个事务的详细情况，保证在系统出现问题后可以完全恢复。</p>
		<p>事务遵循的ACID性质 (原子性、一致性、独立性和持久性) 保证了大部分事务处理稳定地运行。</p>
		<p>商用XML数据库也包含对XML文档的版本控制功能。使用版本控制，用户或应用程序可以检入(check in)或检出(check out)XML文档，利用版本号、日期或者标签获得以前版本的文档，以及显示XML文档的版本历史信息。每一个处于版本控制之下的文档都有自己的历史信息，纪录了修改文档的作者以及时间等。使用者可以根据文档或用户或日期来查看整个的版本历史信息。</p>
		<p>版本控制允许用户通过查询更新原信息。通过更新引擎可以注释、修改和精炼信息。内置的版本系统跟踪信息的变化，提供这些变化的历史信息。</p>
		<p>应该说，在事务处理和版本控制机制上，实验室产品的考虑是不够的，所提供的事务处理的功能显得简单。尽管加州大学洛杉矶分校的数据库实验室在XML的版本控制方面有一些突出的成果，但是，目前尚未形成产品。</p>
		<p>还有一个需要说明的是多事务并发控制机制和加锁协议。这项技术的研发目前刚刚起步。现今的商用XML数据库只在逻辑层面提供并发加锁协议，但粒度为整个文档。随着单个XML文档的增大，这个粒度显然太粗。这一点可能要等待研究界开发出粒度为文档元素节点的并发协议了。</p>
		<p>
				<strong>5.代数系统和模式规范化</strong>
		</p>
		<p>代数表达式和数据库模式设计理论曾经是关系数据库理论的精髓。代数系统成为关系库查询优化的重要工具，而范式理论的提出也曾为RDBMS设计优化的库结构提供了依据。那么，人们不禁要问，在XML数据库中是否存在相类似的理论和方法?</p>
		<p>由于这两个问题有一定的难度，注定只能是由学术界的实验系统先行一步。</p>
		<p>学术界公认的三大实验系统都设计了相应的代数系统，其中影响最为广泛的是Timber中实现的TAX(Tree Algebra for XML)。TAX以整个文档树作为操作的基本单位，在逻辑层提供选择、投影、联接等类似关系库的9种基本操作和5种附加操作，以匹配模式树得到实例树(witness tree)为基本操作方法。在物理层提出7种基本操作实现上述逻辑运算。</p>
		<p>Timber依据TAX对XML查询语句进行改写和优化，但是效果并不理想。业界对TAX存在问题的看法是，过分地模仿了关系库的代数系统而忽略了对XML文档本身特点的考虑。</p>
		<p>XML模式规范化理论的早期开拓者是宾夕法尼亚大学的樊文飞等人。从定义XML的键(key)和函数依赖，到XML和DTD范式，再到基于约束的XML数据库的模式规范化，XML数据库的模式规范化理论在稳步地推动着。国内的复旦大学数据库研究中心等单位也有着不错的研究进展。在未来两年内，估计会有较成熟的XML数据库模式设计理论投入到实验室产品和商用系统中。</p>
		<p>
				<strong>6.多数据源的集成</strong>
		</p>
		<p>多数据源的集成是数据库市场对XML数据库系统提出的要求。从1970年IBM公司的E.F.Codd提出关系数据库的概念以来，关系数据库在几乎所有的应用领域都取得了巨大成功。XML数据库是一个新事物，它从诞生的那一天起，就面临着关系数据库一统天下的局面。有人说，关系数据库完全战胜层次和网状数据库用了将近20年时间，XML数据库也会用20年时间战胜关系数据库。这种看法并不全面。至少从目前来看，两者应该各展所长，共同服务于巨大的数据库市场。</p>
		<p>那么，XML数据库的优势在哪呢?用XML技术来进行多数据源的集成就是其中之一。</p>
		<p>从2001年以后，面对多数据源的集成这个传统关系型数据库系统做不了的事情，Ipedo等商用数据库系统将自己的数据库系统扩展为一个集成平台，它可以将关系数据库系统、MIS系统、OA系统、文件系统等集成在同一个平台上，给用户提供统一的界面。如Ipedo公司的Ipedo XML智能平台，为用户提供XML View来统一访问底层的异构数据。人们也从这一点上进一步看到了XML技术的力量。</p>
		<p>
				<strong>四.未来的技术发展方向</strong>
		</p>
		<p>经过近5年业界同仁的共同努力，XML数据库技术取得了很大的进展，已经有若干种XML数据库产品问世并服务于社会生活的各个方面。但是，XML数据库的事业才刚刚开始，还有很多问题等待着我们去解决。</p>
		<p>未来几年，XML数据库技术有可能在下述方面取得进展：</p>
		<p>● 异构数据源的集成。XML数据库对多数据源的集成，是对XML技术可扩展性这一长处的极好发挥。但是，就目前的集成程度和在应用层上所提供的功能来看还是远远不够的。如何从对数据的集成过渡到对系统的集成，从而在远景目标上实现类似于网格计算(grid computing)概念的系统，恐怕是XML数据库工作者的核心任务之一。</p>
		<p>● 底层索引结构。目前的商用XML数据库系统优于实验室原型系统的特点之一就是其底层的索引结构。但是，现有的商用XML数据库的底层索引结构一般都是B+树。虽然B+树索引是一种成熟的索引结构，但是，研究结果显示，在XML数据库中，它的性能表现并不是最好的。学术界已经开发出了若干种适用于XML数据的索引结构，如XR树、XB树等，需要XML数据库工作者来进一步关注。</p>
		<p>● 并发加锁协议。在现有的XML数据库系统中，加锁的粒度是整个文档，事务并发的层次也在文档一级。随着应用级文档的日益增大，这个粒度在一定程度上将会成为系统效率的瓶颈。如何通过边锁(edge lock)机制来实现元素节点级粒度的加锁?这一工作现在吸引了不少研究者的目光,而且，上述的锁协议是在逻辑层，如何将它映射到底层的B+树索引(或者XR树索引)上，也是必须要做的一件事情。</p>
		<p>● XML模式规范化是一个值得关注的方向。一旦取得突破，将会使我们可以像在关系库中那样方便地设计XML数据库的结构，消除数据的冗余和不一致现象。目前，这一领域已经成为学术界关注的热点。但是，完整的、为业界所公认的理论体系尚未建立。<br /></p>
<img src ="http://www.blogjava.net/orangelizq/aggbug/305303.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/orangelizq/" target="_blank">桔子汁</a> 2009-12-09 17:02 <a href="http://www.blogjava.net/orangelizq/archive/2009/12/09/305303.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]WiKi程序大全－开源WIKI程序</title><link>http://www.blogjava.net/orangelizq/archive/2009/10/31/300455.html</link><dc:creator>桔子汁</dc:creator><author>桔子汁</author><pubDate>Sat, 31 Oct 2009 02:47:00 GMT</pubDate><guid>http://www.blogjava.net/orangelizq/archive/2009/10/31/300455.html</guid><wfw:comment>http://www.blogjava.net/orangelizq/comments/300455.html</wfw:comment><comments>http://www.blogjava.net/orangelizq/archive/2009/10/31/300455.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/orangelizq/comments/commentRss/300455.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/orangelizq/services/trackbacks/300455.html</trackback:ping><description><![CDATA[<p>[转自]http://www.nieqiang.com/archive/wiki-system.html<br />
<br />
一，ASP的WiKi程序。ASP的WiKi程序总体感觉比较弱，或许开放的WiKi更喜欢开放的linux系统吧 <br />
<span style="color: #0000ff">1，Operator&nbsp;Wiki&nbsp;0.3 </span><br />
语言环境：ASP+ACCESS <br />
官方主页：http://cosoft.org.cn/projects/operatorwiki/ <br />
演示：http://my.yeew.net/maxzone/operatorwiki/wiki.asp <br />
下载：http://down2.codepub.com/codepubcom/2006/4/8/operatorwik03.rar <br />
介绍：免费开源的国产WIKI程序，ASP+JavaScript写的&nbsp;Wiki&nbsp;引擎，支持多语言、ACL，综合各种&nbsp;WIKI&nbsp;的功能。 <br />
Operator&nbsp;Wiki&nbsp;升级日志0.3:. <br />
*&nbsp;完整的用户权限 <br />
*&nbsp;支持&nbsp;ACL&nbsp;进行权限控制 <br />
*&nbsp;修正了一个标记冲突问题 <br />
*&nbsp;修正登录问题 <br />
*&nbsp;源代码采用&nbsp;Tab&nbsp;代替空格，进一步缩小体积，主程序目前仅&nbsp;34.4K <br />
*&nbsp;更良好的多语言支持 <br />
*&nbsp;修正数十个关于表格和列表的问题 <br />
<br />
<span style="color: #0000ff">2，OpenWiki&nbsp;中文版Build20060328 </span><br />
语言环境：ASP+ACCESS/SQLServer <br />
官方主页：http://www.openwiki.com/ <br />
演示：http://www.3d-gis.com/yow/ <br />
下载：http://down2.codepub.com/codepubcom/2006/4/8/openviki_yow.rar <br />
介绍：国外的一个ASP&nbsp;Wiki程序，3d-gis汉化。 <br />
<br />
<span style="color: #0000ff">3,JsWiki&nbsp;-&nbsp;开源ASP&nbsp;WIKI程序 </span><br />
语言环境：ASP <br />
官方主页：http://sourceforge.net/projects/jswiki/ <br />
演示：http://www.jswiki.com/ <br />
下载：http://down2.codepub.com/codepubcom/2006/2/10/jswiki.rar <br />
介绍：安装只需要一个文件jswiki.asp <br />
使用javascript写成，能够运行于任何一台支持asp的windows主机 <br />
支持丰富而方便的text语法(混合了标准wiki/textile/markdown三种常见文法) <br />
支持页面的历史记录和版本差异 <br />
支持页面锁定和保密 <br />
支持RSS输出最近更新内容 <br />
提供InterWiki?链接 <br />
使用宏提供额外的功能和扩展 <br />
<br />
二，CGI的WiKi程序 <br />
<span style="color: #0000ff">4，TWiki&nbsp;Release&nbsp;4.0.2 </span><br />
语言环境：Perl <br />
官方主页：http://twiki.org/ <br />
演示：http://www.stlchina.org/twiki/bin/view.pl/TWiki/TWikiQickStart <br />
下载：http://down2.codepub.com/codepubcom/2006/4/8/TWiki-4.0.2.tgz <br />
介绍：TWiki是一个开源（GPL）的wiki程序。软件定位为&#8220;灵活、强大、易于使用的企业协作平台&#8221;，运行于Perl环境。 <br />
TWiki从2001年开始开发，大约每年发行一个重要版本。最新稳定版本为2004-9-4版本，最新beta版本为2006-01-31版本。 <br />
Twiki被很多大型商业公司采用，例如Yahoo、SAP、Motorola、Wind&nbsp;River等。 <br />
TWiki的官方站点内容有版权，TWiki名称是Peter&nbsp;Thoeny所有的一个注册商标，内容的贡献属于Peter&nbsp;Thoeny和其贡献者共同所有。 <br />
TWiki的特点: <br />
TWiki是一个功能完善的wiki系统 <br />
专注于为网站赋予结构，所有页面自动归为TWiki&nbsp;Web，这样就很容易创建协作小组。拥有编程技能的人可以使用变量创建动态页面，譬如内容表格，或者嵌入式搜索结果的页面。 <br />
易于定制和扩展 <br />
允许页面编辑：Darkar版本已经支持所见即所得编辑。 <br />
访问控制:&nbsp;细化的授权机制让管理员可以限制不同部门的读写访问权限。 <br />
TWIKI完全是一个不需要任何数据库，完全基于文件目录的格式化引擎。 <br />
<br />
<span style="color: #0000ff">5，UseModWiki&nbsp;Version&nbsp;1.0 </span><br />
语言环境：Perl <br />
官方主页：http://www.usemod.com/ <br />
演示：http://www.usemod.com/ <br />
下载：http://down2.codepub.com/codepubcom/2006/4/8/usemod10.tar.gz <br />
介绍：September&nbsp;12,&nbsp;2003:&nbsp;Version&nbsp;1.0,官方应该是停止了更新！ <br />
UseModWiki(Usenet&nbsp;Moderation&nbsp;Project&nbsp;(Usemod))是Clifford&nbsp;Adams&nbsp;所开发的维基引擎，它采用Perl做为开发的程序语言，它最大的特点是不使用任何的数据库管理系统来储存页面内容，任何的新增页面都直接储存于档案系统内，维基百科曾采用UseModWiki做为所有语言版本的维基引擎，之后才自行开发MediaWiki做为现有的接口。 <br />
功能特色: <br />
采取单一档案就可以运作 <br />
不需要任何的延伸扩充程序 <br />
所有的变量都直接撰写于程序码中 <br />
页面直接储存于档案系统 <br />
采用CamelCase的连结样式 <br />
可透过对照表而修改其显示语言 <br />
<br />
三，PHP的WiKi程序 <br />
<span style="color: #0000ff">6，MediaWiki&nbsp;1.6.2&nbsp;-应用最广的WiKi程序 </span><br />
语言环境：PHP+MySQL <br />
官方主页：http://www.mediawiki.org/ <br />
演示：http://www.mediawiki.org/ <br />
下载：http://down2.codepub.com/codepub&nbsp;...&nbsp;iawiki-1.6.2.tar.gz <br />
介绍：MediaWiki全球最著名的开源wiki引擎，运行于PHP+MySQL环境。从2002年2月25日被作为维基百科全书的系统软件，并有大量其他应用实例。目前MediaWiki的开发得到维基媒体基金会的支持。 <br />
wiki的重要特征 <br />
记录所有的改动版本，能方便的查阅历史更新记录，这使得开放性编辑成为可能 <br />
自动产生链接，编辑文本中中括号中的内容（如&#8220;[[X条目]]&#8221;）将自动产生链接 <br />
允许使用模板，方便对相同内容的重复使用、更新 <br />
支持分类，并根据分类在不同的文章之间自动产生关联 <br />
允许每个用户自行选择系统外观 <br />
中文支持好 <br />
<br />
<span style="color: #0000ff">7，Tikiwiki&nbsp;v1.9.2&nbsp;多国语言版&nbsp;-&nbsp;又是WiKi又是CMS系统 </span><br />
语言环境：PHP+MySQL <br />
官方主页：http://tikiwiki.org/ <br />
演示：http://tikiwiki.org/ <br />
下载：http://down2.codepub.com/codepubcom/2005/11/13/tikiwiki192.rar <br />
介绍：非常优秀的网站内容管理系统，基于&nbsp;PHP+ADOdb+Smarty等技术构建，功能非常齐全，主要特点： <br />
　　1、有文章、论坛、分类目录、blog、图库、文件下载、在线调查、Wiki等功能。 <br />
　　2、用户权限管理很棒，可以设置启用哪些功能，设置哪些用户使用哪些功能。 <br />
　　3、管理后台和用户界面合在一起，通过用户权限控制界面的显示。 <br />
　　4、界面被分割成上中下、左中右区域，非常结构化。 <br />
　　5、有很多实用模块，如菜单、登录、搜索、在线调查、最新发表文章等等，可以灵活定制显示在左右界面区域。 <br />
　　6、界面很简洁，有很多界面模版来换肤。 <br />
<br />
<span style="color: #0000ff">8，CooCooWakka&nbsp;v0.09&nbsp;rc3&nbsp;-&nbsp;国人开放的PHP&nbsp;WiKi程序 </span><br />
语言环境：PHP+MySQL <br />
官方主页：http://coo.hsfz.net/wiki/ <br />
演示：http://coo.hsfz.net/wiki/[/ <br />
下载：http://down2.codepub.com/codepubcom/2006/3/6/CooCooWakka.tar.gz <br />
介绍：文wiki引擎程序，2004年被很多网站采用。2004年9月后基本停止更新，一直到2005年7月发布v0.0.9rc1,2006年2开发布0.0.9rc3,支持PHP5。 <br />
CooCooWakka是咕咕基于WakkaWiki&nbsp;0.1.2进行修改强化而来。 <br />
CooCooWakka从2003年开始开发，作为CooYip的一项业余小爱好，现在CooCooWakka也是cosoft.org.cn和sourceforge.net的开源项目。至今（2005年4月）已经发布了8个主要的版本。 <br />
CooCooWakka&nbsp;是一种重于合作的超文本编辑环境(基于PHP+MYSQL的Wiki引擎)，简单来说，对于基于CooCooWakka的网站，任何人（包括你！）都可以在线编辑他的几乎（视管理员意愿）任何页面。CooCooWakka可以用于共笔系统、读书会、档案开发、写书、翻译、资料整理（例如课堂笔记、软件使用资料）、常见问题整理等等。由于其使用及扩展方面的快速便捷，CooCooWakka甚至可以作为小型的CMS系统。 <br />
CooCooWakka并不是Wakka的汉化版本，有60%~70%的Wakka代码被CooCooWakka修改或重写（有兴趣的可以比较一下，如果希望得到相似于&nbsp;WakkaWiki?的版本请下载0.0.2,0.0.3，当时自己对修改还是比较节制）。许多特性和策略也有所改变，所以CooCooWakka的站点不支持回复到WakkaWiki?。此外，CooCooWakka也对整个WakkaWiki?进行了多国语言支持化，所以，CooCooWakka支持多种语言——现在提供中文（包括简体gb,utf-8,繁体big5,utf-8），英语的支持。此外，CooCooWakka会自动针对中文站进行功能上的优化。 <br />
咕咕最早是在参与WikiPedia的时候对Wiki产生兴趣的,后来也不知道有什么WIKI好用,结果就下载了WAKKA&nbsp;0.1.2. <br />
结果这套引擎刚好不像MoinMoin或者Tavi那样支持中文，自己就从改charset开始，对wakka0.1.2开始建立自己觉得好用的&nbsp;WikiEngine.本来是本着改给自己用的想法去做CooCooWakka的,结果发现有很多朋友都希望拿份代码试试,也提供了很多好意见,就这样&nbsp;CooCooWakka发展到了现在.(更多历史:History) <br />
<br />
<span style="color: #0000ff">9，PhpWiki&nbsp;1.3.12p2&nbsp;released <br />
</span>语言环境：PHP <br />
官方主页：http://phpwiki.sourceforge.net/ <br />
演示：http://phpwiki.sourceforge.net/p&nbsp;...&nbsp;83fc0492e961639b13f <br />
下载：http://down2.codepub.com/codepub&nbsp;...&nbsp;iki-1.3.12p2.tar.gz <br />
介绍：无需数据库的小巧WIKI程序。架设简单，权限控制、插件扩展都不错。 <br />
<br />
<span style="color: #0000ff">10，PmWiki&nbsp;2.1.5 </span><br />
语言环境：PHP <br />
官方主页：http://www.pmwiki.org/ <br />
演示：http://www.emacs.cn/ <br />
下载：http://down2.codepub.com/codepubcom/2006/4/8/pmwiki-latest.tgz <br />
介绍：PmWiki，一款用PHP编写的,无需数据库支持的维基,个人网站尤其适合。 <br />
在国内还是有不少的应用，演示站点是linuxsir.org旗下一个站点。 <br />
<br />
四，JSP的WiKi程序 <br />
<span style="color: #0000ff">11，JSPWiki&nbsp;stable&nbsp;release&nbsp;v2.2.33 </span><br />
语言环境：JDK+tomcat <br />
官方主页：http://www.jspwiki.org/ <br />
演示：http://www.jspwiki.org/wiki/%E4%B8%AD%E6%96%87%E6%96%87%E6%A1%A3 <br />
下载：http://down2.codepub.com/codepub&nbsp;...&nbsp;wiki-2.2.33-src.rar <br />
介绍：JSPWiki是一个不错的wiki引擎，纯jsp/servlet写的。JSPWiki不使用现成的数据库管理软件，所有的文件以文本文件的形式存放。它利用类似CVS的机制保证了文件版本的完整性。支持中文，支持版本比较、权限管理等功能！ <br />
<br />
五，其他WiKi程序 <br />
<span style="color: #0000ff">12，MoinMoin&nbsp;1.5.3&nbsp;RC1 </span><br />
语言环境：Python <br />
官方主页：http://www.wikiwikiweb.de/ <br />
演示：http://www.wikiwikiweb.de/ <br />
下载：http://down2.codepub.com/codepub&nbsp;...&nbsp;in-1.5.3-rc1.tar.gz <br />
介绍：MoinMoin是一个基于Python环境的wiki引擎程序，支持包括中文在内的多语种特性。 <br />
MoinMoin程序是遵循GNU&nbsp;GPL的开源项目，启动于2000年7月20日，最初由J&#252;rgenHermann撰写。最近的版本为2006年02月05日发布的1.5.2，最高稳定版本为1.3.5，并一直保持正常的更新。 <br />
MoinMoin可运行在Windows、Linux/BSD/UNIX、OS&nbsp;X等环境下。目前能够处理英文、德文、繁简体中文、日文、俄文等约20种语言。 <br />
MoinMoin的特点： <br />
完全使用文件来存储内容，不使用数据库 <br />
实现了全部Wiki规范，Unicode编码支持多语种 <br />
完整实用的wiki文本约定，编辑规则比较轻巧易学 <br />
支持多种扩展方式:&nbsp;宏，插件，预处理&#8230;&#8230; <br />
为数众多的插件中包括Tex科技文本输入、FreeMind思维图谱、GraphViz示意图、gnuplot数据图表绘图等 <br />
支持几种很实用的不同页面样式 <br />
真正跨平台 <br />
<br />
<span style="color: #0000ff">13，TiddlyWiki&nbsp;2.0.7 </span><br />
语言环境：CSS+HTML+javascript <br />
官方主页：http://www.osmosoft.com/ <br />
演示：http://www.tiddlywiki.com/ <br />
下载：http://down2.codepub.com/codepubcom/2006/4/8/ptw-2.0.7.rar <br />
介绍：TiddlyWiki是个非常小巧酷炫的wiki引擎，全部程序只是一个一百多K的HTML页面。TiddlyWiki用CSS+HTML+javascript写成，可以在多种浏览器上使用。 <br />
TiddlyWiki页面所有元素都能都订制,能方便地修改页面结构和CSS表现形式.它不需要任何服务器端的脚本支持,你要你的电脑有有浏览器就能运行.非常适合放在U盘里到处带着走的个人做记事本。 <br />
TiddlyWiki无法真正将数据存储到服务器上，因而不能用来进行团体协作。 <br />
一个使用过的用户这样评价TiddlyWiki&nbsp;： <br />
TiddlyWiki是一个好玩的Wiki记事本，支持Tag，支持丰富的Wiki语法，还支持搜索，用来做记事本不错。 <br />
它很简单，界面简单、操作简单，文件简单到所有内容只有一个html文件，所以最适合随身携带，想起了以前U盘携带的Wordpress，再带上TiddlyWiki就齐了。 <br />
TiddlyWiki是一个纯Javascript操作的Wiki，所有动作都是AJAX的，感觉好酷，要研究AJAX的又多了一个对象。 <script type="text/javascript" src="http://www.nieqiang.com/count.php?do=add&amp;id=385"></script></p>
<img src ="http://www.blogjava.net/orangelizq/aggbug/300455.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/orangelizq/" target="_blank">桔子汁</a> 2009-10-31 10:47 <a href="http://www.blogjava.net/orangelizq/archive/2009/10/31/300455.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]UUID和GUID</title><link>http://www.blogjava.net/orangelizq/archive/2009/09/05/293995.html</link><dc:creator>桔子汁</dc:creator><author>桔子汁</author><pubDate>Sat, 05 Sep 2009 07:22:00 GMT</pubDate><guid>http://www.blogjava.net/orangelizq/archive/2009/09/05/293995.html</guid><wfw:comment>http://www.blogjava.net/orangelizq/comments/293995.html</wfw:comment><comments>http://www.blogjava.net/orangelizq/archive/2009/09/05/293995.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/orangelizq/comments/commentRss/293995.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/orangelizq/services/trackbacks/293995.html</trackback:ping><description><![CDATA[<p>UUID </p>
<p>通用惟一标识符（UUID）是128位比特的数字，用来惟一地标识因特网上的某些对象或者实体。</p>
<p>A Universally Unique Identifier is an identifier standard used in software construction, standardized by the Open Software Foundation (OSF) as part of the Distributed Computing Environment (DCE). The intent of UUIDs is to enable distributed systems to uniquely identify information without significant central coordination. Thus, anyone can create a UUID and use it to identify something with reasonable confidence that the identifier will never be unintentionally used by anyone for anything else. Information labelled with UUIDs can therefore be later combined into a single database without need to resolve name conflicts. The most widespread use of this standard is in Microsoft's Globally Unique Identifiers (GUIDs) which implement this standard.</p>
<p>一个UUID 是一个标识符标准用于软件架构，是由开放软件基金会（OSF）作为分布式计算环境（DCE）的一部分而制定的标准。UUIDs的目的就是使分布式系统可以不需要重要的中央调合系统而能唯一地标识信息。这样，任何人能创造一个UUID 和使用它来标识一些东西，而且，你有足够的信心来确定这个标识是永远不会被任何人无意地使用在任何东西上。因此，信息加上了UUID标签就能合并到单个数据库中而不用去解决命名冲突的问题。这个标准的广泛应用在微软的全球唯一标识符（GUIDs）上，GUID实现了这个标准。</p>
<p>A UUID is essentially a 16-byte number and in its canonical form a UUID may look like this:</p>
<p>:550E8400-E29B-11D4-A716-446655440000</p>
<p>And has this structure in the C programming language:</p>
<p>typedef struct {<br />
unsigned32 time_low;<br />
unsigned16 time_mid;<br />
unsigned16 time_hi_and_version;<br />
unsigned8 clock_seq_hi_and_reserved;<br />
unsigned8 clock_seq_low;<br />
byte node6;<br />
} uuid_t;</p>
<p>The J2SE 5.0 release of Java provides a class that will produce 128-bit UUIDs. The API documentation for the class refers to ISO/IEC 11578:1996.</p>
<p>关于UUID的定义，详细内容可参考http://www.ietf.org/rfc/rfc4122.txt，文档里面还有C语言对UUID标准的各种实现。</p>
<p>GUID</p>
<p>A Globally Unique Identifier or GUID is a pseudo-random number used in software applications. While each generated GUID is not guaranteed to be unique, the total number of unique keys (2128 or 3.4028&#215;1038) is so large that the possibility of the same number being generated twice is very small.</p>
<p>一个全球唯一标识符 或 GUID 是一个假随机数用于软件中。虽然每个产生的GUID是不保证唯一的，但不同的标识符总数是（2128 也就是3.4028&#215;1038）如此之大，以至于相同的数字被产生两次的机率是很相当小的。</p>
<p>The GUID is an implementation by Microsoft of a standard called Universally Unique Identifier (UUID), specified by the Open Software Foundation (OSF).</p>
<p>GUID 是微软对UUID这个标准的实现。UUID是由开放软件基金会（OSF）定义的。</p>
<p>UUID还有其它各种实现，不止GUID一种，其它的在此不详细说明。</p>
<p>&nbsp;</p>
<p>本文来自CSDN博客，转载请标明出处：http://blog.csdn.net/nidehong/archive/2006/11/22/1406125.aspx</p>
<br />
---------------------<br />
<br />
http://blog.csdn.net/happyflystone/archive/2007/11/27/1903854.aspx<br />
<br />
<p>UUID是是128位整数(16字节)的全局唯一标识符(Universally Unique Identifier)，指在一台机器上生成的数字，它保证对在同一时空中的所有机器都是唯一的。通常平台会提供生成UUID的API。UUID按照开放软件基金会(OSF)制定的标准计算，用到了以太网卡地址、纳秒级时间、芯片ID码和许多可能的数字。由以下几部分的组合：当前日期和时间(UUID的第一个部分与时间有关，如果你在生成一个UUID之后，过几秒又生成一个UUID，则第一个部分不同，其余相同)，时钟序列，全局唯一的IEEE机器识别号（如果有网卡，从网卡获得，没有网卡以其他方式获得），UUID的唯一缺陷在于生成的结果串会比较长。关于UUID这个标准使用最普遍的是微软的GUID(Globals Unique Identifiers)。 </p>
<p>UUID，其格式为：xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxxxxxx(8-4-4-16)，其中每个 x 是 0-9 或 a-f 范围内的一个十六进制的数字。而标准的UUID格式为：xxxxxxxx-xxxx-xxxx-xxxxxx-xxxxxxxxxx (8-4-4-4-12)</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在建立数据库的时候，需要为每张表指定一个主键，所谓主键就是能够唯一标识表中某一行的属性或属性组，一个表只能有一个主键，但可以有多个候选索引。因为主键可以唯一标识某一行记录，所以可以确保执行数据更新、删除的时候不会出现张冠李戴的错误。数据库的主键生成有多种方式，每种方式都有其优点和缺点，应该根据不同的需求在主键的时间和空间效率上做平衡折中，从而选择不同的主键生成策略。归纳起来，对主键的选择主要有以下四种方式：</p>
<p>1.&nbsp;&nbsp;&nbsp;&nbsp; 自动增长字段</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 自动增长型字段允许我们在向数据库添加数据时，不考虑主键的取值，记录插入后，数据库系统会自动为其分配一个值，确保绝对不会出现重复。</p>
<p>2.&nbsp;&nbsp;&nbsp;&nbsp; 手动增长字段</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 手动增长型的字段，也就是说主键的值需要自己维护，通常情况下需要建立一张单独的表存储当前主键键值。</p>
<p>3.&nbsp;&nbsp;&nbsp;&nbsp; GUID类型</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GUID是Globally Unique IDentifier的缩写，是一个128位的随机数,并保证不产生重复。</p>
<p>4.&nbsp;&nbsp;&nbsp;&nbsp; COMB类型</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; COMB（combine）型可以理解为一种改进的GUID，它通过组合GUID和系统时间，以使其在索引和检索事有更优的性能。 </p>
<p>&nbsp;</p>
<p>COMB数据类型的基本设计思路是这样的：既然GUID数据因毫无规律可言造成索引效率低下，影响了系统的性能，那么能不能通过组合的方式，保留GUID的10个字节，用另6个字节表示GUID生成的时间（DateTime），这样我们将时间信息与GUID组合起来，在保留GUID的唯一性的同时增加了有序性，以此来提高索引效率。</p>
<p><br />
下面转自：温少，首发于博客园</p>
<p>替代方案之一，就是使用关系数据库的自增长字段，自增长字段的一个问题是，无法预先创建一个ID，只能够在保存的时候才能生成ID，这对于批量关联插入数据来说，不满足需求。</p>
<p>替代方案之二，就是使用一个记录ID的表，每次加一，在事务中使用Select FOR UPDATE来读取然后UPDATE SET FVALUE = FVALUE + 1，或者使用我之前文章中所提到的CAS算法。 这样做，会导致性能低下，每生成一个ID的成本都很高。</p>
<p>替代方案之三，就是把ID分成两部分，Seed和IncrementID。Seed采用上面的方案二或者其他办法生成，IncrementID使用一个AtomicInteger来每次递增生成。SEED转化为九进制数字，这样SEED就不会包含9，于是使用9作为分隔符，把SEED和IncrementID隔开。这样做，就可以做高性能产生ID，而且确保不重复。甚至可以更进一步，SEED由一个中心服务器生成。使用9个分隔符号隔开SEED和IncrementID，好处是SEED是变长，而不是使用固定位数来保存SEED，这样产生的ID会更短，可读性更好。</p>
<p>举例，34915，其中34时SEED，15是IncrementID，9是分隔符，SEED部分采用九进制表示法，确保不出现9，第一个9之后的内容属于IncrementID。</p>
<p>&nbsp;</p>
<p><br />
本文来自CSDN博客，转载请标明出处：http://blog.csdn.net/happyflystone/archive/2007/11/27/1903854.aspx</p>
<img src ="http://www.blogjava.net/orangelizq/aggbug/293995.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/orangelizq/" target="_blank">桔子汁</a> 2009-09-05 15:22 <a href="http://www.blogjava.net/orangelizq/archive/2009/09/05/293995.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]组件-框架-容器</title><link>http://www.blogjava.net/orangelizq/archive/2009/08/29/293060.html</link><dc:creator>桔子汁</dc:creator><author>桔子汁</author><pubDate>Sat, 29 Aug 2009 02:08:00 GMT</pubDate><guid>http://www.blogjava.net/orangelizq/archive/2009/08/29/293060.html</guid><wfw:comment>http://www.blogjava.net/orangelizq/comments/293060.html</wfw:comment><comments>http://www.blogjava.net/orangelizq/archive/2009/08/29/293060.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/orangelizq/comments/commentRss/293060.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/orangelizq/services/trackbacks/293060.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 组件是抽象的概念而已，<span style="color: #2708ff;">通俗的说是一些符合某种规范的类组合在一起就构成了组件</span>。他可以提供某些特定的功能。<br />
&nbsp;&nbsp;&nbsp; 拿J2EE来说，有什么servlet，jsp, javabean，ejb都是组件。但实际他们都是类，只不过有他们特殊的规定。举个例子，那个javabean来说：javabean也就是个类，但你的类想成为javabean你必须，给你的类里的变量 （如xxx）,添两个函数，getXxx()和setXxx()并且类里要有无参的构造函数。 有了这些就是JAVABEAN了。 <br />
<br />
&nbsp;&nbsp;&nbsp; 什么是框架那，用《设计模式》中的定义来说就是，<span style="color: #2708ff;">框架是构成一类特定软件可复用设计的一组相互协作的类</span>。<strong>框架规定了你的应用程序的体系结构。它定义了整体结构，类和对象的分割，各部分的主要责任，类和对象怎么协作，以及控制流程。 </strong><br />
<br />
&nbsp;&nbsp;&nbsp; 框架实现了对具体实现细节的反向控制（IOC），实现者无须考虑框架层已经实现好的设计，只要按照框架的要求开发就可以了，然后把开发好的东西放到框架中就可以了。框架其实就是一组组件，供你选用完成你自己的系统。简单说就是使用别人搭好的舞台，你来做表演。而且，框架一般是成熟的，不断升级的软件。 <br />
<br />
比如Struts框架就是一组相互协作的类、servlet 和 JSP 标记组成的一个可重用的 MVC设计。它有自己实现好的模型，视图，控制器。 <br />
<br />
&nbsp;&nbsp;&nbsp; 所谓<span style="color: #2708ff;">容器就是指符合一定的规范能提供一系列服务的管理器</span>，方便别人使用它来完成一系列的功能。<br />
&nbsp;&nbsp;&nbsp; 例如tomcat，使用tomcat可以为我们提供servlet.jsp等服务，我们俗称叫servlet服务器，在服务器中会有相关的容器，servlet容器可以调用servlet和jsp动态的为我们生成html <br />
&nbsp;&nbsp;&nbsp; 对于刚刚接触的人来说，可以把服务器就理解成一个容器也可以，不过两者的确不是一回事，是服务器为我们提供一个容器使我们的程序能够在容器里运行使用服务器提供的一系列功能。<br />
<img src ="http://www.blogjava.net/orangelizq/aggbug/293060.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/orangelizq/" target="_blank">桔子汁</a> 2009-08-29 10:08 <a href="http://www.blogjava.net/orangelizq/archive/2009/08/29/293060.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]Java杂谈</title><link>http://www.blogjava.net/orangelizq/archive/2009/08/27/292851.html</link><dc:creator>桔子汁</dc:creator><author>桔子汁</author><pubDate>Thu, 27 Aug 2009 09:09:00 GMT</pubDate><guid>http://www.blogjava.net/orangelizq/archive/2009/08/27/292851.html</guid><wfw:comment>http://www.blogjava.net/orangelizq/comments/292851.html</wfw:comment><comments>http://www.blogjava.net/orangelizq/archive/2009/08/27/292851.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/orangelizq/comments/commentRss/292851.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/orangelizq/services/trackbacks/292851.html</trackback:ping><description><![CDATA[原文：http://home.phpchina.com/space.php?uid=108994&amp;do=blog&amp;id=69516<br />
<br />
<strong>接口&amp; 组件、容器</strong><br />
<br />
1. J2ee与接口
<br />
<br />
每一个版本的J2ee都对应着一个确定版本的JDK，J2ee1.4对应Jdk1.4，现在比较新的是JDK5.0，自然也会有J2EE
5.0。其实笔者一直在用的是J2EE1.4，不过没什么关系，大家可以下任何一个版本的J2ee
api来稍微浏览一下。笔者想先声明一个概念，J2ee也是源自Java，所以底层的操作依然调用到很多J2se的库，所以才建议大家先牢牢掌握J2se 的主流技术。
<br />
<br />
J2ee
api有一个特点，大家比较熟悉的几个包java.jms、javax.servlet.http、javax.ejb等都以interface居多，实现类较少。其实大家真正在用的时候百分之六十以上都在反复的查着javax.servlet.http这个包下面几个实现类的api函数，其他的包很少问津。笔者建议在学习一种技术之前，对整体的框架有一个了解是很有必要的，J2ee旨在通过interface的声明来规范实现的行为，任何第三方的厂商想要提供自己品牌的实现前提也是遵循这些接口定义的规则。如果在从前J2se学习的道路上对接口的理解很好的话，这里的体会将是非常深刻的，举个简单的例子：
<br />
<br />
public interface Mp3{ <br />
public void play(); <br />
public void record();
<br />
public void stop(); <br />
}
<br />
<br />
如果我定义这个简单的接口，发布出去，规定任何第三方的公司想推出自己的名字为Mp3的产品都必须实现这个接口，也就是至少提供接口中方法的具体实现。这个意义已经远远不止是面向对象的多态了，只有厂商遵循J2ee的接口定义，世界上的J2ee程序员才能针对统一的接口进行程序设计，最终不用改变代码只是因为使用了不同厂商的实现类而有不同的特性罢了，本质上说，无论哪一种厂商实现都完成了职责范围内的工作。这个就是笔者想一直强调的，针对接口编程的思想。
<br />
<br />
接口到底有什么好处呢？我们这样设想，现在有AppleMp3、SonyMp3、SamsungMp3都实现了这个Mp3的接口，于是都有了play、
record、stop这三个功能。我们将Mp3产品座位一个组件的时候就不需要知道它的具体实现，只要看到接口定义知道这个对象有3个功能就可以使用了。那么类似下面这样的业务就完全可以在任何时间从3个品牌扩展到任意个品牌，开个玩笑的说，项目经理高高在上的写完10个接口里的方法声明，然后就丢给手下的程序员去写里面的细节，由于接口已经统一（即每个方法传入和传出的格式已经统一），经理只需关注全局的业务就可以天天端杯咖啡走来走去了，^_^：
<br />
public Mp3 create(); <br />
public void copy(Mp3 mp3); <br />
public Mp3 getMp3();
<br />
<br />
最后用一个简单的例子说明接口：一个5号电池的手电筒，可以装入任何牌子的5号电池，只要它符合5号电池的规范，装入之后任何看不到是什么牌子，只能感受到手电筒在完成它的功能。那么生产手电筒的厂商和生产5号电池的厂商就可以完全解除依赖关系，可以各自自由开发自己的产品，因为它们都遵守5号电池应有的形状、正负极位置等约定。这下大家能对接口多一点体会了么？
<br />
<br />
2. 组件和容器
<br />
针对接口是笔者特意强调的J2ee学习之路必备的思想，另外一个就是比较常规的组件和容器的概念了。很多教材和专业网站都说J2EE的核心是一组规范与指南，强调J2ee的核心概念就是组件+容器，这确实是无可厚非的。随着越来越多的J2ee框架出现，相应的每种框架都一般有与之对应的容器。
<br />
<br />
容器，是用来管理组件行为的一个集合工具，组件的行为包括与外部环境的交互、组件的生命周期、组件之间的合作依赖关系等等。J2ee包含的容器种类大约有
Web容器、Application
Client容器、EJB容器、Applet客户端容器等。但在笔者看来，现在容器的概念变得有点模糊了，大家耳熟能详是那些功能强大的开源框架，比如
Hibernate、Struts2、Spring、JSF等，其中Hibernate就基于JDBC的基础封装了对事务和会话的管理，大大方便了对数据库操作的繁琐代码，从这个意义上来说它已经接近容器的概念了，EJB的实体Bean也逐渐被以Hibernate为代表的持久化框架所取代。
<br />
<br />
组件，本意是指可以重用的代码单元，一般代表着一个或者一组可以独立出来的功能模块，在J2ee中组件的种类有很多种，比较常见的是EJB组件、DAO组件、客户端组件或者应用程序组件等，它们有个共同特点是分别会打包成.war，.jar，.jar，.ear，每个组件由特定格式的xml描述符文件进行描述，而且服务器端的组件都需要被部署到应用服务器上面才能够被使用。
<br />
<br />
稍微理解完组件和容器，还有一个重要的概念就是分层模型，最著名的当然是MVC三层模型。在一个大的工程或项目中，为了让前台和后台各个模块的编程人员能够同时进行工作提高开发效率，最重要的就是实现层与层之间的耦合关系，许多分层模型的宗旨和开源框架所追求的也就是这样的效果。在笔者看来，一个完整的
Web项目大概有以下几个层次： <br />
<br />
a) 表示层（Jsp、Html、Javascript、Ajax、Flash等等技术对其支持） <br />
b)
控制层（Struts、JSF、WebWork等等框架在基于Servlet的基础上支持，负责把具体的请求数据（有时卸载重新装载）导向适合处理它的模型层对象）
<br />
c) 模型层（笔者认为目前最好的框架是Spring，实质就是处理表示层经由控制层转发过来的数据，包含着大量的业务逻辑） <br />
d)
数据层（Hibernate、JDBC、EJB等，由模型层处理完了持久化到数据库中） <br />
<br />
<br />
<strong>Servlet/Jsp</strong><br />
<font face="Arial ">终于正式进入J2ee的细节部分了，首当其冲的当然是Servlet和Jsp了，上篇曾经提到过J2ee只是一
个规范和指南，定义了一组必须要遵循的接口，核心概念是组件和容器。曾经有的人问笔者Servlet的Class文件是哪里来的？他认为是J2ee官方提
供的，我举了一个简单的反例：稍微检查了一下Tomcat5.0里面的Servlet.jar文件和JBoss里面的Servlet.jar文件大小，很
明显是不一样的，至少已经说明了它们不是源自同根的吧。其实Servlet是由容器根据J2ee的接口定义自己来实现的，实现的方式当然可以不同，只要都
遵守J2ee规范和指南。 <br />
<br />
上述只是一个常见的误区罢了，告诉我们要编译运行Servlet，是要依赖于实现它的容器的，不然连jar文件都没有，编译都无法进
行。那么Jsp呢？ Java Server
Page的简称，是为了开发动态网页而诞生的技术，其本质也是Jsp，在编写完毕之后会在容器启动时经过编译成对应的Servlet。只是我们利用Jsp
的很多新特性，可以更加专注于前后台的分离，早期Jsp做前台是满流行的，毕竟里面支持Html代码，这让前台美工人员可以更有效率的去完成自己的工作。
然后Jsp将请求转发到后台的Servlet，由Servlet处理业务逻辑，再转发回另外一个Jsp在前台显示出来。这似乎已经成为一种常用的模式，最
初笔者学习J2ee的时候，大量时间也在编写这样的代码。 <br />
<br />
尽管现在做前台的技术越来越多，例如Flash、Ajax等，已经有很多人不再认为Jsp重要了。笔者觉得Jsp带来的不仅仅是前后
端分离的设计理念，它的另外一项技术成就了我们今天用的很多框架，那就是Tag标签技术。所以与其说是在学习Jsp，不如更清醒的告诉自己在不断的理解
Tag标签的意义和本质。 <br />
<br />
1． Servlet以及Jsp的生命周期
<br />
Servlet是Jsp的实质，尽管容器对它们的处理有所区别。Servlet有init()方法初始化，service()方法进行Web服
务，
destroy()方法进行销毁，从生到灭都由容器来掌握，所以这些方法除非你想自己来实现Servlet，否则是很少会接触到的。正是由于很少接触，才
容易被广大初学者所忽略，希望大家至少记住Servlet生命周期方法都是回调方法。回调这个概念简单来说就是把自己注入另外一个类中，由它来调用你的方
法，所谓的另外一个类就是Web容器，它只认识接口和接口的方法，注入进来的是怎样的对象不管，它只会根据所需调用这个对象在接口定义存在的那些方法。由
容器来调用的Servlet对象的初始化、服务和销毁方法，所以叫做回调。这个概念对学习其他J2ee技术相当关键！ <br />
<br />
那么Jsp呢？本事上是Servlet，还是有些区别的，它的生命周期是这样的： <br />
a) 一个客户端的Request到达服务器 -&gt;
<br />
b) 判断是否第一次调用 -&gt; 是的话编译Jsp成Servlet <br />
c) 否的话再判断此Jsp是否有改变 -&gt;
是的话也重新编译Jsp成Servlet <br />
d) 已经编译最近版本的Servlet装载所需的其他Class <br />
e)
发布Servlet，即调用它的Service()方法
<br />
<br />
所以Jsp号称的是第一次Load缓慢，以后都会很快的运行。从它的生命的周期确实不难看出来这个特点，客户端的操作很少会改变Jsp的
源码，所以它不需要编译第二次就一直可以为客户端提供服务。这里稍微解释一下Http的无状态性，因为发现很多人误解，Http的无状态性是指每次一张页
面显示出来了，与服务器的连接其实就已经断开了，当再次有提交动作的时候，才会再次与服务器进行连接请求提供服务。当然还有现在比较流行的是Ajax与服
务器异步通过 xml交互的技术，在做前台的领域潜力巨大，笔者不是Ajax的高手，这里无法为大家解释。 <br />
<br />
2． Tag标签的本质
<br />
笔者之前说了，Jsp本身初衷是使得Web应用前后台的开发可以脱离耦合分开有效的进行，可惜这个理念的贡献反倒不如它带来的Tag技术对
J2ee的贡献要大。也许已经有很多人开始使用Tag技术了却并不了解它。所以才建议大家在学习J2ee开始的时候一定要认真学习Jsp，其实最重要的就
是明白标签的本质。 <br />
<br />
Html标签我们都很熟悉了，有 &lt;html&gt; 、 &lt;head&gt; 、 &lt;body&gt; 、
&lt;title&gt; ，Jsp带来的Tag标签遵循同样的格式，或者说更严格的Xml格式规范，例如 &lt;jsp:include&gt; 、
&lt;jsp:useBean&gt; 、 &lt;c:if&gt; 、 &lt;c:forEach&gt;
等等。它们没有什么神秘的地方，就其源头也还是Java
Class而已，Tag标签的实质也就是一段Java代码，或者说一个Class文件。当配置文件设置好去哪里寻找这些Class的路径后，容器负责将页面中存在的标签对应到相应的Class上，执行那段特定的Java代码，如此而已。
<br />
说得明白一点的话还是举几个简单的例子说明一下吧： <br />
<br />
&lt;jsp:include&gt;
去哪里找执行什么class呢?首先这是个jsp类库的标签，当然要去jsp类库寻找相应的class了，同样它也是由Web容器来提供，例如
Tomcat就应该去安装目录的lib文件夹下面的jsp-api.jar里面找，有兴趣的可以去找一找啊！ <br />
<br />
&lt;c:forEach&gt;
又去哪里找呢？这个是由Jsp2.0版本推荐的和核心标记库的内容，例如 &lt;c:if&gt;
就对应在页面中做if判断的功能的一断Java代码。它的class文件在jstl.jar这个类库里面，往往还需要和一个standard.jar类库一起导入，放在具体Web项目的WEB-INF的lib目录下面就可以使用了。
<br />
<br />
顺便罗唆一句，Web
Project的目录结构是相对固定的，因为容器会按照固定的路径去寻找它需要的配置文件和资源，这个任何一本J2ee入门书上都有，这里就不介绍了。了
解Tag的本质还要了解它的工作原理，所以大家去J2ee的API里找到并研究这个包：javax.servlet.jsp.tagext。它有一些接
口，和一些实现类，专门用语开发Tag，只有自己亲自写出几个不同功能的标签，才算是真正理解了标签的原理。别忘记了自己开发的标签要自己去完成配置文
件，容器只是集成了去哪里寻找jsp标签对应class的路径，自己写的标签库当然要告诉容器去哪里找啦。 <br />
<br />
说了这么多，我们为什么要用标签呢？完全在Jsp里面来个 &lt;% %&gt;
就可以在里面任意写Java代码了，但是长期实践发现页面代码统一都是与html同风格的标记语言更加有助于美工人员进行开发前台，它不需要懂Java，
只要Java程序员给个列表告诉美工什么标签可以完成什么逻辑功能，他就可以专注于美工，也算是进一步隔离了前后台的工作吧！ <br />
<br />
3． 成就Web框架
<br />
框架是什么？曾经看过这样的定义：与模式类似，框架也是解决特定问题的可重用方法，框架是一个描述性的构建块和服务集合，开发人员可以用来达成某个目标。一般来说，框架提供了解决某类问题的基础设施，是用来创建解决方案的工具，而不是问题的解决方案。
<br />
<br />
正是由于Tag的出现，成就了以后出现的那么多Web框架，它们都开发了自己成熟实用的一套标签，然后由特定的Xml文件来配置加载信息，力图使得Web
应用的开发变得更加高效。下面这些标签相应对很多人来说相当熟悉了： <br />
&lt;html:password&gt;
<br />
&lt;logic:equal&gt; <br />
&lt;bean:write&gt; <br />
&lt;f:view&gt;
<br />
&lt;h:form&gt; <br />
&lt;h:message&gt;
<br />
<br />
它们分别来自Struts和JSF框架，最强大的功能在于控制转发，就是MVC三层模型中间完成控制器的工作。Struts-1实际上并未做到真正的三层隔离，这一点在Struts-2上得到了很大的改进。而Jsf向来以比较完善合理的标签库受到人们推崇。
<br />
<br />
今天就大概讲这么多吧，再次需要强调的是Servlet/Jsp是学习J2ee必经之路，也是最基础的知识，希望大家给与足够的重视！</font><br />
<br />
<br />
<strong>Struts</strong><br />
<font face="Arial ">J2ee的开源框架很多，笔者只能介绍自己熟悉的几个，其他的目前在中国IT行业应用得不是很多。希望大家对新出的框架不要盲目的推崇，首先一定要熟悉它比旧的到底好在哪里，新的理念和特性是什么？然后再决定是否要使用它。
<br />
<br />
这期的主题是Struts，直译过来是支架。Struts的第一个版本是在2001年5月发布的，它提供了一个Web应用的解决方案，如何让Jsp和
servlet共存去提供清晰的分离视图和业务应用逻辑的架构。在Struts之前，通常的做法是在Jsp中加入业务逻辑，或者在Servlet中生成视图转发到前台去。Struts带着MVC的新理念当时退出几乎成为业界公认的Web应用标准，于是当代IT市场上也出现了众多熟悉Struts的程序员。即使有新的框架再出来不用，而继续用Struts的理由也加上了一条低风险，因为中途如果开发人员变动，很容易的招进新的会Struts的IT民工啊，
^_^!
<br />
<br />
笔者之前说的都是Struts-1，因为新出了Struts-2，使得每次谈到Struts都必须注明它是Struts-1还是2。笔者先谈比较熟悉的
Struts-1，下次再介绍一下与Struts－2的区别： <br />
<br />
1． Struts框架整体结构
<br />
Struts-1的核心功能是前端控制器，程序员需要关注的是后端控制器。前端控制器是是一个Servlet，在Web.xml中间配置所有
Request都必须经过前端控制器，它的名字是ActionServlet，由框架来实现和管理。所有的视图和业务逻辑隔离都是应为这个 ActionServlet，
它就像一个交通警察，所有过往的车辆必须经过它的法眼，然后被送往特定的通道。所有，对它的理解就是分发器，我们也可以叫做Dispatcher，其实了解Servlet编程的人自己也可以写一个分发器，加上拦截request的Filter，其实自己实现一个struts框架并不是很困难。主要目的就是让编写视图的和后台逻辑的可以脱离紧耦合，各自同步的完成自己的工作。
<br />
<br />
那么有了ActionServlet在中间负责转发，前端的视图比如说是Jsp，只需要把所有的数据Submit，这些数据就会到达适合处理它的后端控制器Action，然后在里面进行处理，处理完毕之后转发到前台的同一个或者不同的视图Jsp中间，返回前台利用的也是Servlet里面的forward
和redirect两种方式。所以到目前为止，一切都只是借用了Servlet的API搭建起了一个方便的框架而已。这也是Struts最显著的特性?? 控制器。
<br />
<br />
那么另外一个特性，可以说也是Struts-1带来的一个比较成功的理念，就是以xml配置代替硬编码配置信息。以往决定Jsp往哪个servlet提交，是要写进Jsp代码中的，也就是说一旦这个提交路径要改，我们必须改写代码再重新编译。而Struts提出来的思路是，编码的只是一个逻辑名字，它对应哪个class文件写进了xml配置文件中，这个配置文件记录着所有的映射关系，一旦需要改变路径，改变xml文件比改变代码要容易得多。这个理念可以说相当成功，以致于后来的框架都延续着这个思路，xml所起的作用也越来越大。
<br />
<br />
大致上来说Struts当初给我们带来的新鲜感就这么多了，其他的所有特性都是基于方便的控制转发和可扩展的xml配置的基础之上来完成它们的功能的。
<br />
下面将分别介绍Action和FormBean， 这两个是Struts中最核心的两个组件。 <br />
<br />
2． 后端控制器Action
<br />
Action就是我们说的后端控制器，它必须继承自一个Action父类，Struts设计了很多种Action，例如DispatchAction、
DynaValidationAction。它们都有一个处理业务逻辑的方法execute()，传入的request, response,
formBean和actionMapping四个对象，返回actionForward对象。到达Action之前先会经过一个
RequestProcessor来初始化配置文件的映射关系，这里需要大家注意几点： <br />
<br />
1)
为了确保线程安全，在一个应用的生命周期中，Struts框架只会为每个Action类创建一个Action实例，所有的客户请求共享同一个Action
实例，并且所有线程可以同时执行它的execute()方法。所以当你继承父类Action，并添加了private成员变量的时候，请记住这个变量可以被多个线程访问，它的同步必须由程序员负责。(所有我们不推荐这样做)。在使用Action的时候，保证线程安全的重要原则是在Action类中仅仅使用局部变量，谨慎的使用实例变量。局部变量是对每个线程来说私有的，execute方法结束就被销毁，而实例变量相当于被所有线程共享。
<br />
<br />
2) 当ActionServlet实例接收到Http请求后，在doGet()或者doPost()方法中都会调用process()方法来处理请求。
RequestProcessor类包含一个HashMap，作为存放所有Action实例的缓存，每个Action实例在缓存中存放的属性key为
Action类名。在RequestProcessor类的processActionCreate()方法中，首先检查在HashMap中是否存在
Action实例。创建Action实例的代码位于同步代码块中，以保证只有一个线程创建Action实例。一旦线程创建了Action实例并把它存放到
HashMap中，以后所有的线程会直接使用这个缓存中的实例。 <br />
<br />
3) &lt;action&gt; 元素的 &lt;roles&gt;
属性指定访问这个Action用户必须具备的安全角色，多个角色之间逗号隔开。RequestProcessor类在预处理请求时会调用自身的
processRoles()方法，检查配置文件中是否为Action配置了安全角色，如果有，就调用HttpServletRequest的
isUserInRole()方法来判断用户是否具备了必要的安全性角色，如果不具备，就直接向客户端返回错误。(返回的视图通过 &lt;input&gt;
属性来指定) <br />
<br />
3． 数据传输对象FormBean <br />
Struts并没有把模型层的业务对象直接传递到视图层，而是采用DTO（Data
Transfer Object）来传输数据，这样可以减少传输数据的冗余，提高传输效率；还有助于实现各层之间的独立，使每个层分工明确。Struts的DTO就是
ActionForm，即formBean。由于模型层应该和Web应用层保持独立。由于ActionForm类中使用了Servlet API，
因此不提倡把ActionForm传递给模型层， 而应该在控制层把ActionForm Bean的数据重新组装到自定义的DTO中，
再把它传递给模型层。它只有两个scope，分别是session和request。（默认是session）一个ActionForm标准的生命周期是： <br />
1)
控制器收到请求 -&gt; <br />
2) 从request或session中取出ActionForm实例，如不存在就创建一个 -&gt; <br />
3)
调用ActionForm的reset()方法 -&gt; <br />
4) 把实例放入session或者request中 -&gt; <br />
5)
将用户输入表达数据组装到ActionForm中 -&gt; <br />
6) 如眼张方法配置了就调用validate()方法 -&gt; <br />
7)
如验证错误就转发给 &lt;input&gt; 属性指定的地方，否则调用execute()方法 <br />
<br />
validate()方法调用必须满足两个条件：
<br />
1) ActionForm 配置了Action映射而且name属性匹配 <br />
2) &lt;aciton&gt; 元素的validate属性为true
<br />
<br />
如果ActionForm在request范围内，那么对于每个新的请求都会创建新的ActionForm实例，属性被初始化为默认值，那么reset
()方法就显得没有必要；但如果ActionForm在session范围内，同一个ActionForm实例会被多个请求共享，reset()方法在这种情况下极为有用。
<br />
<br />
4． 验证框架和国际化
<br />
Struts有许多自己的特性，但是基本上大家还是不太常用，说白了它们也是基于JDK中间的很多Java基础包来完成工作。例如国际化、验证框架、插件自扩展功能、与其他框架的集成、因为各大框架基本都有提供这样的特性，Struts也并不是做得最好的一个，这里也不想多说。Struts的验证框架，是通过一个validator.xml的配置文件读入验证规则，然后在validation-rules.xml里面找到验证实现通过自动为Jsp插入
Javascript来实现，可以说做得相当简陋。弹出来的JavaScript框不但难看还很多冗余信息，笔者宁愿用formBean验证或者
Action的saveErrors()，验证逻辑虽然要自己写，但页面隐藏/浮现的警告提示更加人性化和美观一些。
<br />
<br />
至于Struts的国际化，其实无论哪个框架的国际化，java.util.Locale类是最重要的Java
I18N类。在Java语言中，几乎所有的对国际化和本地化的支持都依赖于这个类。如果Java类库中的某个类在运行的时候需要根据Locale对象来调整其功能，那么就称这个类是本地敏感的(Locale-Sensitive)，
例如java.text.DateFormat类就是，依赖于特定Locale。
<br />
<br />
创建Locale对象的时候，需要明确的指定其语言和国家的代码，语言代码遵从的是ISO-639规范，国家代码遵从ISO-3166规范，可以从
<br />
</font><a href="http://www.unicode.org/unicode/onlinedat/languages.html" target="_blank"><font face="Arial "><font color="#0000ff">http://www.unicode.org/unicode/onlinedat/languages.html</font></font></a><font face="Arial "> <br />
</font><a href="http://www.unicode.org/unicode/onlinedat/countries.htm" target="_blank"><font face="Arial "><font color="#0000ff">http://www.unicode.org/unicode/onlinedat/countries.htm</font></font></a><font face="Arial ">
<br />
<br />
Struts的国际化是基于properties的message/key对应来实现的，笔者曾写过一个程序，所有Jsp页面上没有任何Text文本串，全部都用的是
&lt;bean:message&gt;
去Properties文件里面读，这个时候其实只要指定不同的语言区域读不同的Properties文件就实现了国际化。需要注意的是不同语言的字符写进Properties文件的时候需要转化成Unicode码，JDK已经带有转换的功能。JDK的bin目录中有native2ascii这个命令，可以完成对*.txt和*.properties的Unicode码转换。</font><br />
<br />
这次准备继续上次的话题先讲讲Struts-2，手下简短回顾一段历史：随着时间的推移，Web应用框架经常变化的需求，产生了几个下一代
Struts的解决方案。其中的Struts Ti 继续坚持 MVC模式的基础上改进，继续Struts的成功经验。
WebWork项目是在2002年3月发布的，它对Struts式框架进行了革命性改进，引进了不少新的思想，概念和功能，但和原Struts代码并不兼
容。WebWork是一个成熟的框架，经过了好几次重大的改进与发布。在2005年12月，WebWork与Struts Ti决定合拼， 再此同时， Struts
Ti 改名为 Struts Action Framework 2.0,成为Struts真正的下一代。 <br />
<br />
看看Struts-2的处理流程：
<br />
1) Browser产生一个请求并提交框架来处理：根据配置决定使用哪些拦截器、action类和结果等。 <br />
2)
请求经过一系列拦截器：根据请求的级别不同拦截器做不同的处理。这和Struts-1的RequestProcessor类很相似。 <br />
3) 调用Action:
产生一个新的action实例，调用业务逻辑方法。 <br />
4) 调用产生结果：匹配result class并调用产生实例。 <br />
5)
请求再次经过一系列拦截器返回：过程也可配置减少拦截器数量 <br />
6) 请求返回用户：从control返回servlet，生成Html。
<br />
<br />
这里很明显的一点是不存在FormBean的作用域封装，直接可以从Action中取得数据。 这里有一个Strut-2配置的web.xml文件：
<br />
&lt;filter&gt; <br />
&lt;filter-name&gt; controller &lt;/filter-name&gt;
<br />
&lt;filter-class&gt; org.apache.struts.action2.dispatcher.FilterDispatcher
&lt;/filter-class&gt; <br />
&lt;/filter&gt; <br />
&lt;filter-mapping&gt;
<br />
&lt;filter-name&gt; cotroller &lt;/filter-name&gt; <br />
&lt;url-pattern&gt;
/* &lt;/url-pattern&gt; <br />
&lt;/filter-mapping&gt;
<br />
<br />
注意到以往的servlet变成了filter，ActionServlet变成了FilterDispatcher，*.do变成了/*。filter
配置定义了名称(供关联)和filter的类。filter mapping让URI匹配成功的的请求调用该filter。默认情况下，扩展名为 ".action
"。这个是在default.properties文件里的 "struts.action.extension "属性定义的。
<br />
<br />
default.properties是属性定义文件，通过在项目classpath路径中包含一个名为&#8220;struts.properties&#8221;的文件来设置不同的属性值。而Struts-2的默认配置文件名为struts.xml。由于1和2的action扩展名分别为.do和.action，所以很方便能共存。我们再来看一个Struts-2的action代码：
<br />
public class MyAction { <br />
public String execute() throws Exception {
<br />
//do the work <br />
return "success "; <br />
} <br />
}
<br />
<br />
很明显的区别是不用再继承任何类和接口，返回的只是一个String，无参数。实际上在Struts-2中任何返回String的无参数方法都可以通过配置来调用action。所有的参数从哪里来获得呢？答案就是Inversion
of
Control技术（控制反转）。笔者尽量以最通俗的方式来解释，我们先试图让这个Action获得reuqest对象，这样可以提取页面提交的任何参数。那么我们把request设为一个成员变量，然后需要一个对它的set方法。由于大部分的action都需要这么做，我们把这个set方法作为接口来实现。
<br />
public interface ServletRequestAware { <br />
public void
setServletRequest(HttpServletRequest request); <br />
} <br />
<br />
public class
MyAction implements ServletRequestAware { <br />
private HttpServletRequest
request; <br />
<br />
public void setServletRequest(HttpServletRequest request) {
<br />
this.request = request; <br />
} <br />
<br />
public String execute() throws
Exception { <br />
// do the work directly using the request <br />
return
Action.SUCCESS; <br />
} <br />
}
<br />
<br />
那么谁来调用这个set方法呢？也就是说谁来控制这个action的行为，以往我们都是自己在适当的地方写上一句
action.setServletRequest(&#8230;)，也就是控制权在程序员这边。然而控制反转的思想是在哪里调用交给正在运行的容器来决定，只要利用Java反射机制来获得Method对象然后调用它的invoke方法传入参数就能做到，这样控制权就从程序员这边转移到了容器那边。程序员可以减轻很多繁琐的工作更多的关注业务逻辑。Request可以这样注入到action中，其他任何对象也都可以。为了保证action的成员变量线程安全，
Struts-2的action不是单例的，每一个新的请求都会产生一个新的action实例。
<br />
<br />
那么有人会问，到底谁来做这个对象的注入工作呢？答案就是拦截器。拦截器又是什么东西？笔者再来尽量通俗的解释拦截器的概念。大家要理解拦截器的话，首先一定要理解GOF23种设计模式中的Proxy模式。
<br />
<br />
A对象要调用f()，它希望代理给B来做，那么B就要获得A对象的引用，然后在B的f()中通过A对象引用调用A对象的f()方法，最终达到A的f()被调用的目的。有没有人会觉得这样很麻烦，为什么明明只要A.f()就可以完成的一定要封装到B的f()方法中去？有哪些好处呢？
<br />
<br />
1) 这里我们只有一个A，当我们有很多个A的时候，只需要监视B一个对象的f()方法就可以从全局上控制所有被调用的f()方法。 <br />
2)
另外，既然代理人B能获得A对象的引用，那么B可以决定在真正调A对象的f()方法之前可以做哪些前置工作，调完返回前可有做哪些后置工作。
<br />
<br />
讲到这里，大家看出来一点拦截器的概念了么？它拦截下一调f()方法的请求，然后统一的做处理（处理每个的方式还可以不同，解析A对象就可以辨别），处理完毕再放行。这样像不像对流动的河水横切了一刀，对所有想通过的水分子进行搜身，然后再放行？这也就是AOP（Aspect
of Programming面向切面编程）的思想。
<br />
<br />
Anyway，Struts-2只是利用了AOP和IoC技术来减轻action和框架的耦合关系，力图到最大程度重用action的目的。在这样的技术促动下，Struts-2的action成了一个简单被框架使用的POJO（Plain
Old Java
Object）罢了。实事上AOP和IoC的思想已经遍布新出来的每一个框架上，他们并不是多么新的技术，利用的也都是JDK早已可以最到的事情，它们代表的是更加面向接口编程，提高重用，增加扩展性的一种思想。Struts-2只是部分的使用这两种思想来设计完成的，另外一个最近很火的框架
Spring，更大程度上代表了这两种设计思想，笔者将于下一篇来进一步探讨Spring的结构。<br />
<br />
<br />
<strong>Spring</strong><br />
引用《Spring2.0技术手册》上的一段话：
<br />
Spring的核心是个轻量级容器，它是实现IoC容器和非侵入性的框架，并提供AOP概念的实现方式；提供对持久层、事务的支持；提供MVC
Web框架的实现，并对于一些常用的企业服务API提供一致的模型封装，是一个全方位的应用程序框架，除此之外，对于现存的各种框架，Spring也提供了与它们相整合的方案。
<br />
接下来笔者先谈谈自己的一些理解吧，Spring框架的发起者之前一本很著名的书名字大概是《J2ee Development without
EJB》，他提倡用轻量级的组件代替重量级的EJB。笔者还没有看完那本著作，只阅读了部分章节。其中有一点分析觉得是很有道理的：
<br />
<br />
EJB里在服务器端有Web Container和EJB Container，从前的观点是各层之间应该在物理上隔离，Web
Container处理视图功能、在EJB Container中处理业务逻辑功能、然后也是EBJ
Container控制数据库持久化。这样的层次是很清晰，但是一个很严重的问题是Web Container和EJB
Container毕竟是两个不同的容器，它们之间要通信就得用的是RMI机制和JNDI服务，同样都在服务端，却物理上隔离，而且每次业务请求都要远程调用，有没有必要呢？看来并非隔离都是好的。
<br />
<br />
再看看轻量级和重量级的区别，笔者看过很多种说法，觉得最有道理的是轻量级代表是POJO + IoC，重量级的代表是Container +
Factory。（EJB2.0是典型的重量级组件的技术）我们尽量使用轻量级的Pojo很好理解，意义就在于兼容性和可适应性，移植不需要改变原来的代码。而Ioc与Factory比起来，Ioc的优点是更大的灵活性，通过配置可以控制很多注入的细节，而Factory模式，行为是相对比较封闭固定的，生产一个对象就必须接受它全部的特点，不管是否需要。其实轻量级和重量级都是相对的概念，使用资源更少、运行负载更小的自然就算轻量。
<br />
<br />
话题扯远了，因为Spring框架带来了太多可以探讨的地方。比如它的非侵入性：指的是它提供的框架实现可以让程序员编程却感觉不到框架的存在，这样所写的代码并没有和框架绑定在一起，可以随时抽离出来，这也是Spring设计的目标。Spring是唯一可以做到真正的针对接口编程，处处都是接口，不依赖绑定任何实现类。同时，Spring还设计了自己的事务管理、对象管理和Model2
的MVC框架，还封装了其他J2ee的服务在里面，在实现上基本都在使用依赖注入和AOP的思想。由此我们大概可以看到Spring是一个什么概念上的框架，代表了很多优秀思想，值得深入学习。笔者强调，学习并不是框架，而是框架代表的思想，就像我们当初学Struts一样&#8230;&#8230;
<br />
<br />
1．Spring MVC
<br />
关于IoC和AOP笔者在上篇已经稍微解释过了，这里先通过Spring的MVC框架来给大家探讨一下Spring的特点吧。（毕竟大部分人已经很熟悉Struts了，对比一下吧）
<br />
众所周知MVC的核心是控制器。类似Struts中的ActionServlet，Spring里面前端控制器叫做DispatcherServlet。里面充当Action的组件叫做Controller，返回的视图层对象叫做ModelAndView，提交和返回都可能要经过过滤的组件叫做
Interceptor。 <br />
<br />
让我们看看一个从请求到返回的流程吧： <br />
(1)
前台Jsp或Html通过点击submit，将数据装入了request域 <br />
(2)
请求被Interceptor拦截下来，执行preHandler()方法出前置判断 <br />
(3) 请求到达DispathcerServlet <br />
(4)
DispathcerServlet通过Handler Mapping来决定每个reuqest应该转发给哪个后端控制器Controlle<br />
<br />
<br />
<strong>ORM</strong><br />
其实J2ee的规范指南里面就已经包括了一些对象持久化技术，例如JDO（Java Data
Object）就是Java对象持久化的新规范，一个用于存取某种数据仓库中的对象的标准化API，提供了透明的对象存储，对开发人员来说，存储数据对象完全不需要额外的代码（如JDBC
API的使用）。这些繁琐的工作已经转移到JDO产品提供商身上，使开发人员解脱出来，从而集中时间和精力在业务逻辑上。另外，JDO很灵活，因为它可以在任何数据底层上运行。JDBC只是面向关系数据库（RDBMS）JDO更通用，提供到任何数据底层的存储功能，比如关系数据库、文件、XML以及对象数据库（ODBMS）等等，使得应用可移植性更强。我们如果要理解对象持久化技术，首先要问自己一个问题：为什么传统的JDBC来持久化不再能满足大家的需求了呢？
<br />
<br />
笔者认为最好是能用JDBC真正编写过程序了才能真正体会ORM的好处，同样的道理，真正拿Servlet/Jsp做过项目了才能体会到Struts、
Spring等框架的方便之处。很幸运的是笔者这两者都曾经经历过，用混乱的内嵌Java代码的Jsp加Servlet转发写过完整的Web项目，也用
JDBC搭建过一个完整C/S项目的后台。所以现在接触到新框架才更能体会它们思想和实现的优越之处，回顾从前的代码，真是丑陋不堪啊。^_^
<br />
<br />
回到正题，我们来研究一下为什么要从JDBC发展到ORM。简单来说，传统的JDBC要花大量的重复代码在初始化数据库连接上，每次增删改查都要获得
Connection对象，初始化Statement，执行得到ResultSet再封装成自己的List或者Object，这样造成了在每个数据访问方法中都含有大量冗余重复的代码，考虑到安全性的话，还要加上大量的事务控制和log记录。虽然我们学习了设计模式之后，可以自己定义Factory来帮助减少一部分重复的代码，但是仍然无法避免冗余的问题。其次，随着OO思想深入人心，连典型的过程化语言Perl等都冠冕堂皇的加上了OO的外壳，何况是
Java中繁杂的数据库访问持久化技术呢？强调面向对象编程的结果就是找到一个桥梁，使得关系型数据库存储的数据能准确的映射到Java的对象上，然后针对Java对象来设计对象和方法，如果我们把数据库的Table当作Class，Record当作Instance的话，就可以完全用面向对象的思想来编写数据层的代码。于是乎，Object
Relationship Mapping的概念开始普遍受到重视，尽管很早很早就已经有人提出来了。
<br />
缺点我们已经大概清楚了，那么如何改进呢？对症下药，首先我们要解决的是如何从Data Schema准备完美的映射到Object
Schema，另外要提供对数据库连接对象生命周期的管理，对事务不同粒度的控制和考虑到扩展性后提供对XML、Properties等可配置化的文件的支持。到目前为止，有很多框架和技术在尝试着这样做。例如似乎是封装管理得过了头的EJB、很早就出现目前已经不在开发和升级了的Apache
OJB、首先支持Manual SQL的iBATIS，还有公认非常优秀的Hibernate等等。在分别介绍它们之前，我还想反复强调这些框架都在试图做什么：
<br />
<br />
毕竟Java
Object和数据库的每一条Record还是有很大的区别，就是类型上来说，DB是没有Boolean类型的。而Java也不得不用封装类（Integer、Double等）为了能映射上数据库中为null的情况，毕竟Primitive类型是没有null值的。还有一个比较明显的问题是，数据库有主键和外键，而Java中仍然只能通过基本类型来对应字段值而已，无法规定Unique等特征，更别提外键约束、事务控制和级联操作了。另外，通过Java
Object预设某Field值去取数据库记录，是否在这样的记录也是不能保证的。真的要设计到完全映射的话，Java的Static被所有对象共享的变量怎么办？在数据库中如何表现出来&#8230;&#8230;
<br />
我们能看到大量的问题像一座座大山横在那些框架设计者们面前，他们并不是没有解决办法，而是从不同的角度去考虑，会得到很多不同的解决方案，问题是应该采取哪一种呢？甚至只有等到真正设计出来了投入生产使用了，才能印证出当初的设想是否真的能为项目开发带来更多的益处。笔者引用一份文档中提到一个健壮的持久化框架应该具有的特点：
<br />
A robust persistence layer should support---- <br />
1. Several types of
persistence mechanism <br />
2. Full encapsulation of the persistence mechanism.
<br />
3. Multi-object actions <br />
4. Transactions Control <br />
5. Extensibility
<br />
6. Object identifiers <br />
7. Cursors: logical connection to the persistence
mechanism <br />
8. Proxies: commonly used when the results of a query are to be
displayed in a list <br />
9. Records: avoid the overhead of converting database
records to objects and then back to records <br />
10. Multi architecture <br />
11.
Various database version and/or vendors <br />
12. Multiple connections <br />
13.
Native and non-native drivers <br />
14. Structured query language queries(SQL) <br />
<br />
<font face="Arial ">现在来简短的介绍一下笔者用过的一些持久化框架和技术，之所以前面强调那么多共通的知识，是希望大家不要盲从流行框架，一定要把握它的本质和卓越的思想好在哪里。
<br />
1． Apache OJB <br />
OJB代表Apache Object Relational
Bridge，是Apache开发的一个数据库持久型框架。它是基于J2ee规范指南下的持久型框架技术而设计开发的，例如实现了ODMG
3.0规范的API，实现了JDO规范的API， 核心实现是Persistence Broker API。OJB使用XML文件来实现映射并动态的在Metadata
layer听过一个Meta-Object-Protocol(MOP)来改变底层数据的行为。更高级的特点包括对象缓存机制、锁管理机制、 Virtual
代理、事务隔离性级别等等。举个OJB Mapping的简单例子ojb-repository.xml： <br />
<br />
&lt;class-descriptor
class=&#8221;com.ant.Employee&#8221; table=&#8221;EMPLOYEE&#8221;&gt; <br />
&lt;field-descriptor name=&#8221;id&#8221;
column=&#8221;ID&#8221; <br />
jdbc-type=&#8221;INTEGER&#8221; primarykey=&#8221;true&#8221; autoincrement=&#8221;true&#8221;/&gt;
<br />
<br />
&lt;field-descriptor name=&#8221;name&#8221; column=&#8221;NAME&#8221; jdbc-type=&#8221;VARCHAR&#8221;/&gt;
<br />
&lt;/class-descrptor&gt; <br />
<br />
&lt;class-descriptor
class=&#8221;com.ant.Executive&#8221; table=&#8221;EXECUTIVE&#8221;&gt; <br />
&lt;field-descriptor
name=&#8221;id&#8221; column=&#8221;ID&#8221; <br />
jdbc-type=&#8221;INTEGER&#8221; primarykey=&#8221;true&#8221;
autoincrement=&#8221;true&#8221;/&gt; <br />
<br />
&lt;field-descriptor name=&#8221;department&#8221;
column=&#8221;DEPARTMENT&#8221; jdbc-type=&#8221;VARCHAR&#8221;/&gt; <br />
<br />
&lt;reference-descriptor
name=&#8221;super&#8221; class-ref=&#8221;com.ant.Employee&#8221;&gt; <br />
&lt;foreignkey
field-ref=&#8221;id&#8221;/&gt; <br />
&lt;/reference-descriptor&gt;
<br />
&lt;/class-descrptor&gt; <br />
<br />
2． iBATIS
<br />
iBATIS最大的特点就是允许用户自己定义SQL来组配Bean的属性。因为它的SQL语句是直接写入XML文件中去的，所以可以最大程度上利用到
SQL语法本身能控制的全部特性，同时也能允许你使用特定数据库服务器的额外特性，并不局限于类似SQL92这样的标准，它最大的缺点是不支持枚举类型的持久化，即把枚举类型的几个对象属性拼成与数据库一个字段例如VARCHAR对应的行为。这里也举一个Mapping文件的例子sqlMap.xml：
<br />
&lt;sqlMap&gt; <br />
&lt;typeAlias type=&#8221;com.ant.Test&#8221; alias=&#8221;test&#8221;/&gt;
<br />
<br />
&lt;resultMap class=&#8221;test&#8221; id=&#8221;result&#8221;&gt; <br />
&lt;result
property=&#8221;testId&#8221; column=&#8221;TestId&#8221;/&gt; <br />
&lt;result property=&#8221;name&#8221;
column=&#8221;Name&#8221;/&gt; <br />
&lt;result property=&#8221;date&#8221; column=&#8221;Date&#8221;/&gt;
<br />
&lt;/resultMap&gt; <br />
<br />
&lt;select id=&#8221;getTestById&#8221; resultMap=&#8221;result&#8221;
parameterClass=&#8221;int&#8221;&gt; <br />
select * from Test where TestId=#value#
<br />
&lt;/select&gt; <br />
<br />
&lt;update id=&#8221;updateTest&#8221; parameterClass=&#8221;test&#8221;&gt;
<br />
Update Tests set Name=#name#, Date=&#8221;date&#8221; where TestId=#testId#
<br />
&lt;/update&gt; <br />
&lt;/sqlMap&gt; <br />
<br />
3． Hibernate
<br />
Hibernate无疑是应用最广泛最受欢迎的持久型框架，它生成的SQL语句是非常优秀。虽然一度因为不能支持手工SQL而性能受到局限，但随着新一代
Hibernate
3.x推出，很多缺点都被改进，Hibernate也因此变得更加通用而时尚。同样先看一个Mapping文件的例子customer.hbm.xml来有一个大概印象：
<br />
<br />
&lt;hibernate-mapping&gt; <br />
&lt;class name=&#8221;com.ant.Customer&#8221;
table=&#8221;Customers&#8221;&gt; <br />
&lt;id name=&#8221;customerId&#8221; column=&#8221;CustomerId&#8221;
type=&#8221;int&#8221; unsaved-value=&#8221;0&#8221;&gt; <br />
&lt;generator class=&#8221;sequence&#8221;&gt;
<br />
&lt;param name=&#8221;sequence&#8221;&gt; Customers_CustomerId_Seq &lt;/param&gt;
<br />
&lt;/generator&gt; <br />
&lt;/id&gt; <br />
<br />
&lt;property name=&#8221;firstName&#8221;
column=&#8221;FirstName&#8221;/&gt; <br />
&lt;property name=&#8221;lastName&#8221; column=&#8221;LastName&#8221;/&gt;
<br />
<br />
&lt;set name=&#8221;addresses&#8221; outer-join=&#8221;true&#8221;&gt; <br />
&lt;key
column=&#8221;Customer&#8221;/&gt; <br />
&lt;one-to-many class=&#8221;com.ant.Address&#8221;/&gt;
<br />
&lt;/set&gt; <br />
&lt;/class&gt;<br />
&lt;/hibernate-mapping&gt;
<br />
<br />
Hibernate有很多显著的特性，最突出的就是它有自己的查询语言叫做HQL，在HQL中select
from的不是Table而是类名，一方面更加面向对象，另外一方面通过在hibernate.cfg.xml中配置Dialect为HQL可以使得整个后台与数据库脱离耦合，因为不管用那种数据库我都是基于HQL来查询，Hibernate框架负责帮我最终转换成特定数据库里的SQL语句。另外
Hibernate在Object-Caching这方面也做得相当出色，它同时管理两个级别的缓存，当数据被第一次取出后，真正使用的时候对象被放在一级缓存管理，这个时候任何改动都会影响到数据库；而空闲时候会把对象放在二级缓存管理，虽然这个时候与数据库字段能对应上但未绑定在一起，改动不会影响到数据库的记录，主要目的是为了在重复读取的时候更快的拿到数据而不用再次请求连接对象。其实关于这种缓存的设计建议大家研究一下Oracle的存储机制（原理是相通的），Oracle牺牲了空间换来时间依赖于很健壮的缓存算法来保证最优的企业级数据库访问速率。
<br />
<br />
以上是一些Mapping的例子，真正在Java代码中使用多半是继承各个框架中默认的Dao实现类，然后可以通过Id来查找对象，或者通过
Example来查找，更流行的是更具Criteria查找对象。Criteria是完全封装了SQL条件查询语法的一个工具类，任何一个查询条件都可以在Criteria中找到方法与之对应，这样可以在Java代码级别实现SQL的完全控制。另外，现在许多ORM框架的最新版本随着JDk
5.0加入Annotation特性都开始支持用XDoclet来自动根据Annotation来生成XML配置文件了。 <br />
</font><br />
<br />
<img src ="http://www.blogjava.net/orangelizq/aggbug/292851.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/orangelizq/" target="_blank">桔子汁</a> 2009-08-27 17:09 <a href="http://www.blogjava.net/orangelizq/archive/2009/08/27/292851.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]一个计算机专业学生几年的Java编程经验汇总</title><link>http://www.blogjava.net/orangelizq/archive/2009/08/27/292844.html</link><dc:creator>桔子汁</dc:creator><author>桔子汁</author><pubDate>Thu, 27 Aug 2009 08:52:00 GMT</pubDate><guid>http://www.blogjava.net/orangelizq/archive/2009/08/27/292844.html</guid><wfw:comment>http://www.blogjava.net/orangelizq/comments/292844.html</wfw:comment><comments>http://www.blogjava.net/orangelizq/archive/2009/08/27/292844.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/orangelizq/comments/commentRss/292844.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/orangelizq/services/trackbacks/292844.html</trackback:ping><description><![CDATA[<strong>1．
关于动态加载机制</strong><br />
学习Java比C++更容易理解OOP的思想，毕竟C++还混合了不少面向过程的成分。很多人都能背出来Java语言的特点，所谓的动态加载机制等等。当然概念往往是先记住而后消化的，可有多少人真正去体会过动态加载的机制，试图去寻找过其中的细节呢?
提供大家一个方法：<br />
在命令行窗口运行Java程序的时候，加上这个很有用的参数：<br />
<br />
java ?verbose
*.class<br />
<br />
这样会清晰的打印出被加载的类文件，大部分是jdk自身运行需要的，最后几行会明显的看到自己用到的那几个类文件被加载进来的顺序。即使你声明了一个类对象，不实例化也不会加载，说明只有真正用到那个类的实例即对象的时候，才会执行加载。这样是不是大家稍微能明白一点动态加载了呢？^_^<br />
<br />
<strong>2．
关于寻找class文件原理</strong><br />
建议大家在入门的时候在命令行窗口编译和运行，不要借助JCreator或者Eclipse等IDE去帮助做那些事情。尝试自己这样做：<br />
javac
-classpath yourpath *.java<br />
java -classpath yourpath
*.class<br />
也许很多人都能看懂，设置classpath的目的就是告诉编译器去哪里寻找你的class文件.
不过至少笔者今日才弄懂JVM去查询类的原理，编译器加载类要依靠classloader，
而classloader有3个级别，从高到低分别是BootClassLoader(名字可能不准确) , ExtClassLoader,
AppClassLoader.<br />
<br />
这3个加载器分别对应着编译器去寻找类文件的优先级别和不同的路径：BootClassLoader对应jre/classes路径，是编译器最优先寻找class的地方<br />
ExtClassLoader对应jre/lib/ext路径，是编译器次优先寻找class的地方<br />
AppClassLoader对应当前路径，所以也是编译器默认找class的地方<br />
<br />
其实大家可以自己写个程序简单的测试，对任何class，例如A,
<br />
调用new A().getClass().getClassLoader().toString()
打印出来就可以看到，把class文件放在不同的路径下再次执行，就会看到区别。特别注意的是如果打印出来是null就表示到了最高级 BootClassLoader,
因为它是C++编写的，不存在Java对应的类加载器的名字。<br />
<br />
寻找的顺序是一种向上迂回的思想，即如果本级别找不到，就只能去本级别之上的找，不会向下寻找。不过似乎从Jdk1.4到Jdk1.6这一特点又有改变，没有找到详细资料。所以就不举例子了。告诉大家设计这种体系的是Sun公司曾经的技术核心宫力先生，一个纯种华人哦！^_^<br />
<br />
这样希望大家不至于迷惑为什么总报错找不到类文件，不管是自己写的还是导入的第三方的jar文件（J2ee中经常需要导入的）。<br />
<br />
<strong>3．
关于jdk和jre</strong><br />
大家肯定在安装JDK的时候会有选择是否安装单独的jre，一般都会一起安装，我也建议大家这样做。因为这样更能帮助大家弄清楚它们的区别：<br />
<br />
Jre
是java runtime environment, 是java程序的运行环境。既然是运行，当然要包含jvm，也就是大家熟悉的虚拟机啦，
还有所有java类库的class文件，都在lib目录下打包成了jar。大家可以自己验证。至于在windows上的虚拟机是哪个文件呢？
学过MFC的都知道什么是dll文件吧，那么大家看看jre/bin/client里面是不是有一个jvm.dll呢？那就是虚拟机。<br />
<br />
Jdk 是java
development kit，是java的开发工具包，里面包含了各种类库和工具。当然也包括了另外一个Jre.
那么为什么要包括另外一个Jre呢？而且jdk/jre/bin同时有client和server两个文件夹下都包含一个jvm.dll。
说明是有两个虚拟机的。这一点不知道大家是否注意到了呢？<br />
<br />
相信大家都知道jdk的bin下有各种java程序需要用到的命令，与jre的bin目录最明显的区别就是jdk下才有javac，这一点很好理解，因为
jre只是一个运行环境而已。与开发无关，正因为如此，具备开发功能的jdk自己的jre下才会同时有client性质的jvm和server性质的 jvm，
而仅仅作为运行环境的jre下只需要client性质的jvm.dll就够了。<br />
<br />
记得在环境变量path中设置jdk/bin路径麽？这应该是大家学习Java的第一步吧，
老师会告诉大家不设置的话javac和java是用不了的。确实jdk/bin目录下包含了所有的命令。可是有没有人想过我们用的java命令并不是
jdk/bin目录下的而是jre/bin目录下的呢？不信可以做一个实验，大家可以把jdk/bin目录下的java.exe剪切到别的地方再运行
java程序，发现了什么？一切OK！<br />
<br />
那么有人会问了？我明明没有设置jre/bin目录到环境变量中啊？<br />
<br />
试想一下如果java为了提供给大多数人使用，他们是不需要jdk做开发的，只需要jre能让java程序跑起来就可以了，那么每个客户还需要手动去设置环境变量多麻烦啊？所以安装jre的时候安装程序自动帮你把jre的java.exe添加到了系统变量中，验证的方法很简单，大家看到了系统环境变量的
path最前面有&#8220;%SystemRoot%\system32;%SystemRoot%;&#8221;这样的配置，那么再去Windows/system32下面去看看吧，发现了什么？有一个java.exe。<br />
<br />
如果强行能够把jdk/bin挪到system32变量前面，当然也可以迫使使用jdk/jre里面的java，不过除非有必要，我不建议大家这么做。使用单独的jre跑java程序也算是客户环境下的一种测试。<br />
<br />
这下大家应该更清楚jdk和jre内部的一些联系和区别了吧？<br />
<img src ="http://www.blogjava.net/orangelizq/aggbug/292844.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/orangelizq/" target="_blank">桔子汁</a> 2009-08-27 16:52 <a href="http://www.blogjava.net/orangelizq/archive/2009/08/27/292844.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]UML建模工具-Java开源</title><link>http://www.blogjava.net/orangelizq/archive/2009/08/27/292843.html</link><dc:creator>桔子汁</dc:creator><author>桔子汁</author><pubDate>Thu, 27 Aug 2009 08:46:00 GMT</pubDate><guid>http://www.blogjava.net/orangelizq/archive/2009/08/27/292843.html</guid><wfw:comment>http://www.blogjava.net/orangelizq/comments/292843.html</wfw:comment><comments>http://www.blogjava.net/orangelizq/archive/2009/08/27/292843.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/orangelizq/comments/commentRss/292843.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/orangelizq/services/trackbacks/292843.html</trackback:ping><description><![CDATA[<table align="center" border="0" width="760">
    <tbody>
        <tr valign="top">
            <td colspan="2">
            <table class="content" align="center" border="0" height="3696" width="754">
                <!--dwlayouttable-->
                <tbody>
                    <tr>
                        <td class="content" valign="top">
                        <p><strong>ArgoUML</strong></p>
                        <p>使用java编写的开源UML产品，功能比较全。最受欢迎的UML建模工具。 </p>
                        <p><strong>Alma</strong> </p>
                        <p>Alma是一个软件建模分析的工作平台，它读取几种不同的源代码，帮你设计面向对像的模型，修改结构和源代码，输出新的源代码、文档和图表。</p>
                        <p><strong>UMLet </strong></p>
                        <p>UMLet是一个开放源代码轻量级UML建模工具。UMLet能够让你快速建模，并且能够导出各种格式SVG, JPG, PDF and
                        LaTeX-friendly EPS。</p>
                        <p><strong>UML/Dot </strong></p>
                        <p>UML/Dot这个项目从Java源代码或字节码中生成UML类。使用GraphViz
                        Dot生成图表。用户可以完全控制处理过程，可以隐藏或显示任意提取的元素。需要：JAVA v1.4 或更高版本，GraphViz。 </p>
                        <p><strong>JUG </strong></p>
                        <p>Java UML Generator
                        是用于从Java类文件自动生成UML类图的工具。最初设计为一个命令行工具，将.class/.jar文件转换到.emf/.eps文件，现在它提供了一个可视化环境。
                        </p>
                        <p><strong>Violet </strong></p>
                        <p>Violet是一种轻量级的UML建模工具。易学易用 可以快速绘制类图、对象图、时序图和状态图 跨平台 支持中文 源码开放 </p>
                        <p><strong>UMLGraph</strong></p>
                        <p>UMLGraph支持说明性规约（Declarative Specification),类图(Class Diagram) ,顺序图(Sequence
                        Diagrams).</p>
                        <p><strong>Fujaba Tool Suite</strong> </p>
                        <p>Fujaba Tool Suite结合UML类图与UML行为视图来提供一个强大,易于使用,而且是整齐均称的系统设计与规范语言. 而且Fujaba Tool
                        Suite还支持从整个系统设计生成Java源代码从完美地实现了一个可执行的模型．同样也支持相反操作，因此源代码可以被解析并被表现在UML中．</p>
                        <p><img src="http://www.uml.org.cn/UMLTools/images/Background.gif" height="130" width="400"  alt="" /></p>
                        <p><strong>UniMod </strong></p>
                        <p>UniMod是Executable
                        UML思想的实现。UniMod是以Eclipse插件形式存在。可以通过UniMod提供的一个在线Demo了解更多的详细资料。</p>
                        <p><img src="http://www.uml.org.cn/UMLTools/images/UniMod.gif" height="301" width="400"  alt="" /></p>
                        <p><strong>Taylor MDA </strong></p>
                        <p>Taylor MDA是一个基于Eclipse的UML建模工具。它专注于EJB3企业应用程序的生成。Taylor MDA当前支持生成：</p>
                        <ul>
                            <li>EJB3 Entity Beans
                            </li>
                            <li>EJB3 Stateless Session Beans
                            </li>
                            <li>利用JBoss内置容器的JUnit Tests
                            </li>
                            <li>Maven Project
                            </li>
                            <li>以后将支持生成：
                            </li>
                            <li>用于CRUD Portlets的Seam代码
                            </li>
                            <li>用于商业处理与页面流(page flows)的jBPM/Seam代码 </li>
                        </ul>
                        <p><img src="http://www.uml.org.cn/UMLTools/images/modeling.gif" height="295" width="400"  alt="" /></p>
                        <p><strong>StarUML </strong></p>
                        <p>StarUML是一个运行在Win32上快速，灵活，可扩展，功能强大的UML/MDA平台。开源项目StarUML的目的是提供一个可以用来代替知名商业UML工具比如Rational
                        Rose,Together等的建模工具和平台。</p>
                        <p><img src="http://www.uml.org.cn/UMLTools/images/classdiagram.gif" height="258" width="400"  alt="" /></p>
                        <p><strong>Quick Sequence Diagram Editor </strong></p>
                        <p>这个简单的工具能够利用对像与信息的描述文本来生成UML时序图。它采用Java5开发并打包成一个可执行的Jar文件。</p>
                        <p><img src="http://www.uml.org.cn/UMLTools/images/QuickSequence.gif" height="317" width="400"  alt="" /></p>
                        <p><strong>TinyUML </strong></p>
                        <p>TinyUML是一个能够帮助你快速和轻松地绘制UML2图的开源工具。采用Java5开发。</p>
                        <p><img src="http://www.uml.org.cn/UMLTools/images/TinyUML.gif" height="365" width="400"  alt="" /></p>
                        <p><strong>Papyrus</strong> </p>
                        <p>Papyrus是一个基于Eclipse平台UML2建模工具。遵从Eclipse UML2、支持由OMG规定的UML2标准和DI2 （Diagram
                        Interchange）标准、Papyrus的整个架构是可扩展的允许用户增加新的图样（diagram）和新的代码生成器等、支持UML2
                        Profile开发、嵌套Profile支持等。</p>
                        <p><img src="http://www.uml.org.cn/UMLTools/images/UseCase_PAPYRUS.jpg" height="198" width="292"  alt="" /></p>
                        <p><img src="http://www.uml.org.cn/UMLTools/images/ClassDiag_Reg.jpg" height="198" width="292"  alt="" /></p>
                        <p><img src="http://www.uml.org.cn/UMLTools/images/ComponentDiag.jpg" height="198" width="327"  alt="" /></p>
                        </td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<img src ="http://www.blogjava.net/orangelizq/aggbug/292843.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/orangelizq/" target="_blank">桔子汁</a> 2009-08-27 16:46 <a href="http://www.blogjava.net/orangelizq/archive/2009/08/27/292843.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]与林昊一起探讨OSGi</title><link>http://www.blogjava.net/orangelizq/archive/2009/08/18/291639.html</link><dc:creator>桔子汁</dc:creator><author>桔子汁</author><pubDate>Tue, 18 Aug 2009 07:12:00 GMT</pubDate><guid>http://www.blogjava.net/orangelizq/archive/2009/08/18/291639.html</guid><wfw:comment>http://www.blogjava.net/orangelizq/comments/291639.html</wfw:comment><comments>http://www.blogjava.net/orangelizq/archive/2009/08/18/291639.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/orangelizq/comments/commentRss/291639.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/orangelizq/services/trackbacks/291639.html</trackback:ping><description><![CDATA[在今年5月份的网侠大会上，InfoQ中文站有幸与国内OSGi的先锋林昊（BlueDavy）在一起探讨了OSGi的相关话题，包括它的优势、复杂度以及Java下的实现等等。<br />
<br />
在谈到采用OSGi作为开放服务框架的基础架构能带来好处时，林昊是这么阐述的：<br />
<br />
&nbsp;&nbsp;&nbsp; 相信SOA现在已经是整个业界的焦点话题了。因为现在很多人都开始用OSGi，或者说学习OSGi，可能很多人都会想，OSGi 和SOA是不是有结合点？因为OSGi在R4以后，也就是说从他发行的第四个版本的规范来看，OSGi在R4中引入了面向服务的组建模型，而这个可以说几乎是整个SOA体系中，第一个明确提出的一个实现级的规范。但是由于OSGI是SingleVM的，也就是说他只是在单VM中的规范，这样的话可能跟 SOA有些不同，像SOA通常都是分布式领域的，这样来看的话OSGi可能是有点欠缺的。不过目前OSGi也在这方面不断的做出努力，包括在今年年底，OSGi将会推出RFC 119，那这个规范的话，其实就是OSGi用于分布式领域的规范。<br />
<br />
&nbsp;&nbsp;&nbsp; 我们最近从OSGi联盟了解到的一些消息，OSGi和现在SCA的结合可能会变得更加紧密，相信在Java领域规范中可能会将采用OSGi列入规范。<br />
<br />
&nbsp;&nbsp;&nbsp; 来看OSGi对SOA体系的支持的话，其实主要仍然是他的面向服务的组件模型。在这方面呢，OSGi在面向服务组件模型中明确定义了服务到底是个什么东西。那这个的话，其实在SOA体系中以前可能没有告诉你，你写一个服务，到底应该是什么样的。然后你的组件之间应该怎么样来交互等等，这一系列在OSGi中都定义的非常清楚，OSGi可能现在用于来做SOA的实现还不是很齐全，毕竟它缺少分布式领域里的一些规范，但是OSGi在整个服务模型上的思想是值得我们参考的<br />
<br />
<strong>下面是访谈文字记录：</strong><br />
今天在InfoQ中文站有幸在阿里巴巴举办的第二届中国网络工程师侠客行大会上请到OSGi演讲嘉宾林昊，林昊你好，请向大家介绍一下你自己好吗？<br />
大家好，我是林昊，网名 BlueDavy。现在在淘宝工作。之前先后写了一些OSGi的中文宣传材料，包括OSGi实战、OSGi进阶——这两篇OpenDoc，主要是结合我自己的经验来推广OSGi在中国的应用，我大概也了解到，经过这两篇OpenDoc，中国也有一些公司开始考虑采用OSGi了，这是一件很好的事情。目前，我们主要是在筹办OSGi的中文官方站，这个是得到了OSGi官方认可的，全球第六个国家级别的User Group性质的站点。目前这个站我们还在进行之中，可能近期会全面对外公布，大概是这些。<br />
好。 OSGI是一门存在了很长时间的一门技术。那么但是在近年来，在Java社区这里边，关于它的探讨、实现，然后以及应用已经越来越火热了，尤其在最近宣布的Spring Source Application Server里边更是以OSGI作为他的核心技术。作为国内在OSGI方面的先驱者，你还能不能跟不熟悉OSGI的这些读者介绍一下OSGI到底是什么吗？<br />
是这样的，近来我们可以看到，几乎所有现在的应用服务器都已经宣称基于OSGi或者run on OSGI或者兼容OSGI， 像Spring的话，之前大概花了一两年的时间做Spring DM，但Spring之前一直都是基于他自己的IOC容器的，如果全面迁移到Spring DM的话可能还需要一段时间，但最近推出的Spring Source Application Platform是一个全新的东西，他基本上就已经开始全面采用Spring DM了，这个和以前的Spring的兼容方式是有点不同的。OSGI简单来讲，就像OSGI官方站上的一句话来描述话，OSGI是一个为Java提供的动态模块化的系统，这是一个他非常好的简称。<br />
<br />
然而经过近两年的发展，OSGI已经逐渐在改变他的推广方式了，也就是说从以前的for Java开始不大提这个词，开始提他是全面的、统一的中间件。采用这个名词的话，其实可以看出OSGI的目的是想脱离语言的限制，否则以前的话都是for Java，for Java。从OSGi目前简单的介绍词中，我们可以看到OSGI最重要的就在两个方面，一个是动态化，一个是模块化。在Java体系中模块化一直以来都是比较弱的一点，而OSGI在这方面突出的表现，让它吸引到了现在几乎所有的大公司的关注，在模块化，以及动态化方面呢， OSGI都是从规范角度来做，已经提供了支持，在没有OSGi的情况下通常我们都是自己想各种各样的办法来实现，但毕竟不是官方级的规范，现在OSGI的发展已经影响到了整个业界，包括Sun，经过这么久的斗争还是开始慢慢接受了OSGI，这也是一个很明显的体现。<br />
那采用OSGI作为开放服务框架的基础架构能带来哪些好处呢？<br />
相信SOA现在已经是整个业界的焦点话题了。因为现在很多人都开始用OSGI，或者说学习OSGI，可能很多人都会想，OSGI和SOA是不是有结合点？因为OSGI在R4以后，也就是说从他发行的第四个版本的规范来看，OSGI在R4中引入了面向服务的组建模型，而这个可以说几乎是整个SOA体系中，第一个明确提出的一个实现级的规范。但是由于OSGI是SingleVM的，也就是说他只是在单VM中的规范，这样的话可能跟SOA有些不同，像SOA通常都是分布式领域的，这样来看的话OSGi 可能是有点欠缺的。不过目前OSGI也在这方面不断的做出努力，包括在今年年底，OSGI将会推出RFC 119，那这个规范的话，其实就是OSGI用于分布式领域的规范。<br />
<br />
我们最近从OSGI联盟了解到的一些消息，OSGI和现在SCA的结合可能会变得更加紧密，相信在Java领域规范中可能会将采用OSGI列入规范。<br />
<br />
来看OSGI对SOA体系的支持的话，其实主要仍然是他的面向服务的组件模型。在这方面呢，OSGI在面向服务组件模型中明确定义了服务到底是个什么东西。那这个的话，其实在SOA体系中以前可能没有告诉你，你写一个服务，到底应该是什么样的。然后你的组件之间应该怎么样来交互等等，这一系列在OSGI中都定义的非常清楚，OSGI可能现在用于来做SOA的实现还不是很齐全，毕竟它缺少分布式领域里的一些规范，但是OSGI在整个服务模型上的思想是值得我们参考的。<br />
<br />
Apache Tomcat开发团队和JSR 277的邮件组中都有人质疑过，OSGI是否违背了KISS原则，那么Peter Kriens在博客中对这个观点也进行反驳，请问你对OSGI的重量级以及它的复杂度持有什么观点呢？<br />
这一点其实是这样的，对于了解OSGi规范的人而言，都可以看得出OSGI一直以来都是轻量级的，而且他也是比较简单的，并不是很复杂。因为这个从OSGI的起源可以看得出。OSGI最早的时候是为Smart Home来提供服务的，也就是说他是为家居网关这一块来制定规范的。那在这一块的规范中，他是不可能做得很复杂的，所以OSGI他本身的规范在复杂度这方面应该不会是很大问题的。但OSGI R4的实现Eclipse Equinox，看起来是比较重量级的，如果我们去下这个包的话，大概会在几兆以上，相对来讲，这个看起来会让人觉得OSGI的实现是比较复杂和比较重量级的。如果你再去看更聪明的Spring DM，那就更大了。这些东西可能会让别人产生一定的错觉，这个问题Peter在官方的BLOG上也曾经提到的，他对于Spring目前在OSGI上面的一些做法并不是相当认同。他认为Spring目前已经把OSGI引入一个复杂化的路线，所以这一点Peter也是持否认的观点的，我们其实可以看得出，OSGI的实现像Felix的话，大概在100K左右，从这个数量级我们可以看得出，他本身是个相当小的东西。<br />
<br />
你刚才提到的 Felix 还有Spring DM，目前除了这些框架以外，<strong>在Java下边有哪些OSGI规范的这些实现呢</strong>？他们各自都有哪些特色？<br />
<br />
目前现在Java中真正实现OSGI规范的应该是有三个，最出名的当然是Eclipse Equinox，Spring DM的话，他应该是采用Equinox来做扩展实现的，Felix基本上是自己完全重新实现的一套。其实还有一个可能不是很出名的，是 Newton ，但是Newton的话，是一个SCA的实现，所以我们可能不能完全以OSGI的规范的实现来评判它，不过他是基于OSGI来实现SCA的，所以要算的话他也可以算一个。在这三者当中的话，Equinox名声比较大一点。Equinox毕竟是OSGI第一个官方认可的实现，也是第一个通过了官方验证的实现，他的使用也已经得到了验证。因为Equinox毕竟是 Eclipse的核心，而且现在Equinox已经提升到了 Eclipse 的Top Level的Project，而这一点可以看得出 Eclipse 其实对这个的重视已经越来越高了，之后他可能也会改名成 Eclipse Core Runtime，成为Eclipse的运行核心。<br />
<br />
Equinox整体来讲他的实现是比较完整的，而且他投入的力量也比较大，这基本上是非常值得期待的，可以一直跟随着他。Equinox在OSGI的发展上其实是起到了很大的作用的，包括我们可以看到Equinox之前他起动了一个 Server side的沙箱，那这个的话，对OSGI的发展起到了很明显的推动作用，因为我们目前可以看到现在最新的RFC应该是 66，在66里面其实已经开始提到吸取了现在Equinox在Server side上的一些做法，我想对于了解OSGI的同学而言，应该知道OSGI的Http Services是只支持 servlet以前的老版本。新版本像2.3以上的servlet规范中的像filter，这些都是没法支持的，在RFC 66中则会开始逐步支持这些东西了， Equinox另外一个最大的贡献可能是在扩展方面，因为他引用了Eclipse做的非常成功的扩展点，扩展点现在几乎已经成为了OSGI的非事实性的规范，也就是其实目前OSGI所有的实现中都会提供，因为扩展点对模块的可扩展性方面提供了很大的帮助。以前的话，在OSGI官方规范中是没有这一点的。然后我们可以来看Felix，Felix的话，其实他是Apache后期开始做的，也就是说它比Equinox晚挺多的。Felix的话，我们可以看他基本上是一个非常轻量级的OSGI实现，目前很多采用OSGI的人都开始逐步才用Felix，可能是因为大家觉得Equinox太重量级了。<br />
<br />
Felix 除了轻量级以外，还有一个比较突出的特色，是他把之前Peter一直想做得OBR这一块，就是OSGI的bundle仓库这一块做得非常非常好了，而这一块对于OSGI其实是非常重要的，Bundle仓库这一块大概会在OSGI的R5列入规范，所以Felix在这一块的作用应该是很明显的，我相信OSGI R5的规范会参考他来做。然后 Newton的话，Newton本身是基于OSGI实现的，它带来的最大作用也许是他让所有人认可了OSGI是能够应用于分布式服务领域的，这对于OSGI进军分布式领域是有一定的好处的，也许RFC 119会在Newton的基础上做一定的参考来做规范了。<br />
对于目前Java 7中将支持OSGI的消息有什么看法？JSR 277跟OSGI之间的争论呢？<br />
我想OSGI和JSR 277的争论在整个OSGI业界绝对是一场非常非常漫长的战争，几乎了解的人可能都知道，JSR 277很早就成立了。一直以来，其实最早的时候，277的规范组的成员是没有列入Peter的，而其实大部分人都知道，Peter在模块化以及动态化方面的经验几乎在全世界都是顶尖级的。之前Peter自己也申请过要加入JSR 277，但被拒绝了。在今年Javaone第二天的大会上Sun官方明确的宣布了在Java 7中将会支持OSGI。这一点虽然没有比他说采用OSGI让人激动，因为他毕竟只是兼容而已。但是从这一点可以看到，Sun已经做了比较大的让步了，因为之前其实他从来没有考虑过，他一定是要自己完全做一套的，而我们从Sun在JavaOne上的第二天的一些讲演中可以看出，Sun自己目前也在非常强调模块化这一方面的工作，包括他自己在JavaEE 6以及Java 7上都是明确的说，最重要的一点的，就是说在他的规范中最需要重视的就是模块化的规范这一点，这也说明Sun对JSR 277是非常非常重视的。不过也正因为他对这一块非常非常重视，所以可能很难接纳一个已有的模块化的标准，否则Sun可能在这一块会难以立足。不过我们可以看得出，在JavaOne宣布了以后。Peter在自己的官方博客上透露了一个消息，JSR 277 Leader已经邀请Peter加入JSR 277专家组，那这个的话，可能也证明了JSR 277专家组是认为需要Peter这样的顶尖专家的，不过Peter自己仍然在考虑之中。因为Sun毕竟已经制订了一系列的东西，这也意味着他可能不会完全采用OSGI，这个对Peter来说可能是有点疑问的。<br />
记得上一次在InfoQ中文站的文字访谈中，您说过当时OSGI应用最重要的问题还是落在如何去构建模块化、动态化和可扩展的系统上面。那么近年来OSGI在这方面上取得了什么进展吗？<br />
其实OSGI他本身的规范程度上应该来讲，他在模块化以及动态化还有可扩展性方面都已经有了一定的规范了。包括像模块化的话，是他一直以来的特色，然后动态化方面应该也是支持的一直都比较好，只是在可扩展性方面的话，因为OSGI以前只是借助DS，就是它的R4中的 Declarative Services 来做这方面的支持，那相对来讲比Equinox的扩展点的话，应该是有一定的弱势的。<br />
<br />
不过目前的话OSGI应该也会逐步考虑，就是说在他的R5中可能会考虑Equinox扩展点怎么样嵌进去，来提升他在扩展性这一方面的支持。虽然OSGI从规范中支持了这些（模块化、动态化和可扩展），包括框架的实现上也是可以支持模块化这些特性的，但是我们最关键的仍然还是怎么样去使用OSGI了。因为如果你使用OSGI的时候，不遵循他的这些原则的话，其实最后设计出来的系统仍然是你以前的非模块化，非动态化的系统。<br />
作为OSGI在国内中文社区里边的一个活跃分子，也算是一个领军人物了。那么你觉得目前国内社区这块在OSGI的现状是怎么样子的，今后又是一个怎么样发展方向呢？<br />
<br />
之前呢，其实在国内的社区中应该是没有，就是没有OSGI的集中讨论场所的，包括我们知道可能在JavaEye上面会有OSGI的圈子，但是并不是专栏性质的，或者说不是这种社区，极大的一个集中式的社区性质的。然后OSGI之前的社区更多是在Equinox上面，之前我们在Equinox的maillist上面可能会有一些讨论。然后在中国方面的话，其实一直以来都没有做这方面的工作，不过OSGI中文官方站筹划已经很久了，但是因为要官方认可的话，需要跟官方做一些交互，还有一些协议方面的，因为要得到他们的授权，这个商标必须是拿到允许才能使用的。所以我们跟官方交涉了一段时间，最近应该也是在今年年初的时候，才拿到了OSGI的授权。在拿到授权之后呢，我们现在已经在开始建设我们的OSGI中文官方站了。在OSGI中文社区里面我们已经做了一定的推广，就是已经告诉了大家这个站是怎么样访问，然后大家可以怎么样加入这里来为OSGi做贡献，就是说为整个OSGI的推广做贡献。因为其实在目前，我们OSGI官方站大概的做法主要是翻译官方站的一些东西，包括官方站的一些新闻，这样大家可以了解到整个OSGI业界的最新的发展动向。然后另外的话，我们会翻译一些OSGI官方上的一些精品的 BLOG。那这些BLOG其实会给大家有很高的指导意义。<br />
<br />
另外一方面我们可能会加强包括OSGI中国方面自己的一些原创性质的文章。因为其实以前是很少有原创性质的一些文章的。那这些方面的话，可能在近两年应该会好一些。因为随着OSGI在国内慢慢开始得到应用，大家都会开始在这一块有一定的经验了。在有了经验之后，我们希望有更多人能写出关于OSGI方面深入文章。这对于推广，包括你自己对OSGI的一些想法，我们也会把一些写得比较好的OSGI的原创文章翻译成英文，然后推荐给OSGI官方联盟。这样的话，对于整个OSGI发展也会有一定的好处。<br />
<br />
在中文官方站上，我们可能也会成立一个开源的社区，这里面可能会包括论坛等，另外一方面就是提供一些基于OSGI的开源项目，这些应该是会对推广OSGI起到一定的作用。<br />
<br />
&nbsp;个人简介<br />
林昊，三年前接触OSGi，目睹了OSGi从最初的不够受关注到现在几乎成为了各大应用平台厂商的必选，同时也得到了Sun的官方认可，而自己也随着对于OSGi的应用经验的增长，编写了《OSGi实战》、《OSGi进阶》两篇 Opendoc，这两篇是目前OSGi领域中仅有的中文文档资料，国内不少公司、IT从业人士因为这两篇文档进入了OSGi领域，在去年通过和OSGi官方联盟交涉后拿到了官方联盟的授权，建立了OSGi官方认可的全球第6个User Group<br />
<br />
来自：http://www.infoq.com/cn/interviews/linhao-osgi<br />
<img src ="http://www.blogjava.net/orangelizq/aggbug/291639.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/orangelizq/" target="_blank">桔子汁</a> 2009-08-18 15:12 <a href="http://www.blogjava.net/orangelizq/archive/2009/08/18/291639.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>