<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Java Votary

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
      48 隨筆 :: 1 文章 :: 80 評論 :: 0 Trackbacks

    2005年12月20日 #

    ThreadLocal是什么

    早在JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal為解決多線程程序的并發問題提供了一種新的思路。使用這個工具類可以很簡潔地編寫出優美的多線程程序。

    ThreadLocal很容易讓人望文生義,想當然地認為是一個“本地線程”。其實,ThreadLocal并不是一個Thread,而是Thread的局部變量,也許把它命名為ThreadLocalVariable更容易讓人理解一些。

    當使用ThreadLocal維護變量時,ThreadLocal為每個使用該變量的線程提供獨立的變量副本,所以每一個線程都可以獨立地改變自己的副本,而不會影響其它線程所對應的副本。

    從線程的角度看,目標變量就象是線程的本地變量,這也是類名中“Local”所要表達的意思。

    線程局部變量并不是Java的新發明,很多語言(如IBM IBM XL FORTRAN)在語法層面就提供線程局部變量。在Java中沒有提供在語言級支持,而是變相地通過ThreadLocal的類提供支持。

    所以,在Java中編寫線程局部變量的代碼相對來說要笨拙一些,因此造成線程局部變量沒有在Java開發者中得到很好的普及。

    ThreadLocal的接口方法

    ThreadLocal類接口很簡單,只有4個方法,我們先來了解一下:

    • void set(Object value)

    設置當前線程的線程局部變量的值。

    • public Object get()

    該方法返回當前線程所對應的線程局部變量。

    • public void remove()

    將當前線程局部變量的值刪除,目的是為了減少內存的占用,該方法是JDK 5.0新增的方法。需要指出的是,當線程結束后,對應該線程的局部變量將自動被垃圾回收,所以顯式調用該方法清除線程的局部變量并不是必須的操作,但它可以加快內存回收的速度。

    • protected Object initialValue()

    返回該線程局部變量的初始值,該方法是一個protected的方法,顯然是為了讓子類覆蓋而設計的。這個方法是一個延遲調用方法,在線程第1次調用get()或set(Object)時才執行,并且僅執行1次。ThreadLocal中的缺省實現直接返回一個null。

    值得一提的是,在JDK5.0中,ThreadLocal已經支持泛型,該類的類名已經變為ThreadLocal<T>。API方法 也相應進行了調整,新版本的API方法分別是void set(T value)、T get()以及T initialValue()。

    ThreadLocal是如何做到為每一個線程維護變量的副本的呢?其實實現的思路很簡單:在ThreadLocal類中有一個Map,用于存儲每一個線程的變量副本,Map中元素的鍵為線程對象,而值對應線程的變量副本。我們自己就可以提供一個簡單的實現版本:

    代碼清單1 SimpleThreadLocal

    public class SimpleThreadLocal {

    private Map valueMap = Collections.synchronizedMap(new HashMap());

    public void set(Object newValue) {

    valueMap.put(Thread.currentThread(), newValue);①鍵為線程對象,值為本線程的變量副本

    }

    public Object get() {

    Thread currentThread = Thread.currentThread();

    Object o = valueMap.get(currentThread);②返回本線程對應的變量

    if (o == null && !valueMap.containsKey(currentThread)) {③如果在Map中不存在,放到Map

    中保存起來。

    o = initialValue();

    valueMap.put(currentThread, o);

    }

    return o;

    }

    public void remove() {

    valueMap.remove(Thread.currentThread());

    }

    public Object initialValue() {

    return null;

    }

    }

    雖然代碼清單9?3這個ThreadLocal實現版本顯得比較幼稚,但它和JDK所提供的ThreadLocal類在實現思路上是相近的。

    一個TheadLocal實例

    下面,我們通過一個具體的實例了解一下ThreadLocal的具體使用方法。

    代碼清單2 SequenceNumber

    package com.baobaotao.basic;

    public class SequenceNumber {

    通過匿名內部類覆蓋ThreadLocalinitialValue()方法,指定初始值

    private static ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>(){

    public Integer initialValue(){

    return 0;

    }

    };

    獲取下一個序列值

    public int getNextNum(){

    seqNum.set(seqNum.get()+1);

    return seqNum.get();

    }

    public static void main(String[] args)

    {

    SequenceNumber sn = new SequenceNumber();

    3個線程共享sn,各自產生序列號

    TestClient t1 = new TestClient(sn);

    TestClient t2 = new TestClient(sn);

    TestClient t3 = new TestClient(sn);

    t1.start();

    t2.start();

    t3.start();

    }

    private static class TestClient extends Thread

    {

    private SequenceNumber sn;

    public TestClient(SequenceNumber sn) {

    this.sn = sn;

    }

    public void run()

    {

    for (int i = 0; i < 3; i++) {④每個線程打出3個序列值

    System.out.println("thread["+Thread.currentThread().getName()+

    "] sn["+sn.getNextNum()+"]");

    }

    }

    }

    }

     

    通常我們通過匿名內部類的方式定義ThreadLocal的子類,提供初始的變量值,如例子中①處所示。TestClient線程產生一組序列號, 在③處,我們生成3個TestClient,它們共享同一個SequenceNumber實例。運行以上代碼,在控制臺上輸出以下的結果:

    thread[Thread-2] sn[1]

    thread[Thread-0] sn[1]

    thread[Thread-1] sn[1]

    thread[Thread-2] sn[2]

    thread[Thread-0] sn[2]

    thread[Thread-1] sn[2]

    thread[Thread-2] sn[3]

    thread[Thread-0] sn[3]

    thread[Thread-1] sn[3]

    考察輸出的結果信息,我們發現每個線程所產生的序號雖然都共享同一個SequenceNumber實例,但它們并沒有發生相互干擾的情況,而是各自產生獨立的序列號,這是因為我們通過ThreadLocal為每一個線程提供了單獨的副本。

    Thread同步機制的比較

    ThreadLocal和線程同步機制相比有什么優勢呢?ThreadLocal和線程同步機制都是為了解決多線程中相同變量的訪問沖突問題。

    在同步機制中,通過對象的鎖機制保證同一時間只有一個線程訪問變量。這時該變量是多個線程共享的,使用同步機制要求程序慎密地分析什么時候對變量進行讀寫,什么時候需要鎖定某個對象,什么時候釋放對象鎖等繁雜的問題,程序設計和編寫難度相對較大。

    而ThreadLocal則從另一個角度來解決多線程的并發訪問。ThreadLocal會為每一個線程提供一個獨立的變量副本,從而隔離了多個線 程對數據的訪問沖突。因為每一個線程都擁有自己的變量副本,從而也就沒有必要對該變量進行同步了。ThreadLocal提供了線程安全的共享對象,在編 寫多線程代碼時,可以把不安全的變量封裝進ThreadLocal。

    由于ThreadLocal中可以持有任何類型的對象,低版本JDK所提供的get()返回的是Object對象,需要強制類型轉換。但JDK 5.0通過泛型很好的解決了這個問題,在一定程度地簡化ThreadLocal的使用,代碼清單 9 2就使用了JDK 5.0新的ThreadLocal<T>版本。

    概括起來說,對于多線程資源共享的問題,同步機制采用了“以時間換空間”的方式,而ThreadLocal采用了“以空間換時間”的方式。前者僅提供一份變量,讓不同的線程排隊訪問,而后者為每一個線程都提供了一份變量,因此可以同時訪問而互不影響。

    Spring使用ThreadLocal解決線程安全問題

    我們知道在一般情況下,只有無狀態的Bean才可以在多線程環境下共享,在Spring中,絕大部分Bean都可以聲明為singleton作用 域。就是因為Spring對一些Bean(如RequestContextHolder、 TransactionSynchronizationManager、LocaleContextHolder等)中非線程安全狀態采用 ThreadLocal進行處理,讓它們也成為線程安全的狀態,因為有狀態的Bean就可以在多線程中共享了。

    一般的Web應用劃分為展現層、服務層和持久層三個層次,在不同的層中編寫對應的邏輯,下層通過接口向上層開放功能調用。在一般情況下,從接收請求到返回響應所經過的所有程序調用都同屬于一個線程,如圖9?2所示:

    通通透透理解ThreadLocal

    1同一線程貫通三層

    這樣你就可以根據需要,將一些非線程安全的變量以ThreadLocal存放,在同一次請求響應的調用線程中,所有關聯的對象引用到的都是同一個變量。

    下面的實例能夠體現Spring對有狀態Bean的改造思路:

    代碼清單3 TopicDao:非線程安全

    public class TopicDao {

    private Connection conn;一個非線程安全的變量

    public void addTopic(){

    Statement stat = conn.createStatement();引用非線程安全變量

    }

    }

    由于①處的conn是成員變量,因為addTopic()方法是非線程安全的,必須在使用時創建一個新TopicDao實例(非singleton)。下面使用ThreadLocal對conn這個非線程安全的“狀態”進行改造:

    代碼清單4 TopicDao:線程安全

    import java.sql.Connection;

    import java.sql.Statement;

    public class TopicDao {

    ①使用ThreadLocal保存Connection變量

    private static ThreadLocal<Connection> connThreadLocal = new ThreadLocal<Connection>();

    public static Connection getConnection(){

    ②如果connThreadLocal沒有本線程對應的Connection創建一個新的Connection,

    并將其保存到線程本地變量中。

    if (connThreadLocal.get() == null) {

    Connection conn = ConnectionManager.getConnection();

    connThreadLocal.set(conn);

    return conn;

    }else{

    return connThreadLocal.get();③直接返回線程本地變量

    }

    }

    public void addTopic() {

    ④從ThreadLocal中獲取線程對應的Connection

    Statement stat = getConnection().createStatement();

    }

    }

    不同的線程在使用TopicDao時,先判斷connThreadLocal.get()是否是null,如果是null,則說明當前線程還沒有對 應的Connection對象,這時創建一個Connection對象并添加到本地線程變量中;如果不為null,則說明當前的線程已經擁有了 Connection對象,直接使用就可以了。這樣,就保證了不同的線程使用線程相關的Connection,而不會使用其它線程的 Connection。因此,這個TopicDao就可以做到singleton共享了。

    當然,這個例子本身很粗糙,將Connection的ThreadLocal直接放在DAO只能做到本DAO的多個方法共享Connection時 不發生線程安全問題,但無法和其它DAO共用同一個Connection,要做到同一事務多DAO共享同一Connection,必須在一個共同的外部類 使用ThreadLocal保存Connection。

    小結

    ThreadLocal是解決線程安全問題一個很好的思路,它通過為每個線程提供一個獨立的變量副本解決了變量并發訪問的沖突問題。在很多情況 下,ThreadLocal比直接使用synchronized同步機制解決線程安全問題更簡單,更方便,且結果程序擁有更高的并發性。

    posted @ 2009-07-01 12:15 Dion 閱讀(344) | 評論 (0)編輯 收藏

         摘要: 題記世界是事實的總體,而不是事物的總體。世界為諸事實所規定,為它們既是全部事實所規定。——路德維希·維特根斯坦,《邏輯哲學論》The answer, please?"請回答我..."The stern voice startles you. 一個嚴厲的聲音把你嚇個半死.You were dozing in Mrs. Rosencrantz's high school math class agai...  閱讀全文
    posted @ 2006-03-11 10:02 Dion 閱讀(2111) | 評論 (0)編輯 收藏

    前幾天跟著寫了一個簡單的例子.
    覺得Drools的配置也沒有什么.
    今天在運行house的例子的時候, 無論怎么樣, 總是異常: 沒有定義的SMF.
    顯然沒有找到我定義的drools.config文件.
    官方網站上是這樣寫地:
    String droolsConfigProp = System.getProperty( "drools.conf" );

    if ( droolsConfigProp != null )
    {
        loadConfig( droolsConfigProp );
    }

    ClassLoader cl = Thread.currentThread( ).getContextClassLoader( ); if ( cl == null )
    {
        cl = getClass( ).getClassLoader( );
    }

    Enumeration configUrls = cl.getResources( "META-INF/drools.conf" );

    if ( !configUrls.hasMoreElements( ) )
    {
        cl = getClass( ).getClassLoader( );
        configUrls = cl.getResources( "META-INF/drools.conf" );
    }

    if ( !configUrls.hasMoreElements( ) )
    {
        cl = ClassLoader.getSystemClassLoader( );
        configUrls = cl.getResources( "META-INF/drools.conf" );
    }

    this.classLoader = cl;
    while ( configUrls.hasMoreElements( ) )
    {
        URL configUrl = (URL) configUrls.nextElement( );
        loadConfig( configUrl );
    }

    好像每一個旮旯里面都找了, 為什么沒有找到我的呢?
    System.getProperty指向的位置并不一定和loadFromUrl位置一樣.呵呵.
    posted @ 2006-03-11 10:00 Dion 閱讀(1640) | 評論 (0)編輯 收藏

    內容提要
           在本文的第一部分,我將討論規則引擎如何幫助你從軟件的應用邏輯中分離出商業規則邏輯,以實現商業應用的靈活性。另外,我還將介紹JSR-94規則引擎 API,及其開源實現Drools項目,它是這一新技術的先驅。在第二部分,我們將介紹一個規則引擎例子,并深入地研究Drools引擎及其JSR-94 擴展的復雜性。

    為什么使用規則引擎
           商業世界充滿了關于變化的陳詞濫調,如任何事物都會改變,唯一不變的是變化等等。而在技術領域里,情況正好相反。我們仍然在試圖解決30年前軟件業中同樣 的一堆問題--也許比30年前還要多的問題。在過去的十年,IT從業人員淹沒在軟件方法學的大量文獻中,如快速軟件開發,極限編程,敏捷軟件開發等,它們 無一例外地強調靈活和變化的重要性。
           但商業通常比開發團隊所依賴的軟件過程和技術改變得更加迅速。當商業策劃人員試圖重整IT部門,以支持新的業務轉型時,仍然覺得很費勁。

    Lost in Translation
           雖然IT團隊反應迅速,但他們通常帶來"電話效應"――IT給商業計劃的執行帶來的阻力和它帶來的利益一樣多。不幸的是,在開發團隊完全理解商業決策規則 并實現之前,規則已經改變了。在軟件進入市場前,它已經過時了,需要進行重構以滿足新的業務需求。如果你是一個開發人員,你會知道我在說什么。再也沒有比 在需求變動的情況下構造軟件讓開發人員更沮喪的事情了。作為軟件開發人員,你必須比業務人員更了解業務,有時還要了解更多。
           試想一下你是一位商業決策者。假如公司的成功依賴于你對于市場趨勢敏銳的洞察力,它常常幫助你領先于競爭者利用變化的市場環境獲利。每天你都會得到更多更 好的市場信息,但并不要緊。完成新產品開發可能需要6-9個月,在此期間,對于市場大膽和敏銳的洞察和信息優勢可能已經浪費了。而且,當產品發布時,有這 樣幾種可能:產品沒有什么吸引人的特性,預算超支,過了產品的最佳發布期限,或三者兼而有之。
           情況可能還會更糟,在完成產品開發時,市場環境和規劃產品開發時相比,已經發生了根本變化。現在你必須要遵守新的規則,你已經喪失了你的邊際優勢,而且設 計軟件的五人中的三人已經離開了公司。你必須給接手的新人重新講解復雜的業務。如果事情不順利,你可能發現自己要對付一個缺少文檔,并且你完全不了解的遺 留應用。
           你的戰略在哪出現了問題?你在哪里應該可以做到更好?最近的輕量級軟件過程,如極限編程,敏捷軟件開發等都在強調自動單元測試和軟件功能優先級的重要性。 除此之外,還有其他的原則,你的開發團隊可能也很熟悉,這些原則可以幫助他們對需求的變動作出迅速反應并縮短項目的開發周期。這些原則的大多數,如系統分 解,多年前就已經出現,并得到了Java平臺的支持(如JMX等),還有如面向對象和角色建模,已經內建在Java語言中。
           但Java仍然是一門相當年輕的語言,而且Java平臺遠遠還沒有完備。當前在Java社區,一個引人注目的新技術是,分離商業決策者的商業決策邏輯和應 用開發者的技術決策,并把這些商業決策放在中心數據庫,讓它們能在運行時(即商務時間)可以動態地管理和修改。這是一個你值得考慮的策略。
           為什么你的開發團隊不得不象商業經理人一樣,在代碼中包含復雜微妙的商業決策邏輯呢?你怎樣才能向他們解釋決策推理的微妙之處呢?你這樣做是否謹慎呢?可 能不是。象bottom line一樣,某些東西在解釋的過程中丟失了。為什么要冒這樣的風險,讓應用代碼或測試代碼錯誤地表達你的商業決策邏輯呢?如果這樣做的話,你怎樣檢查它 們的正確性呢――難道你自己想學習如何編程和編寫測試代碼,或者你的客戶會為你測試軟件?你一方面要應付市場,一方面要應付軟件代碼,這實在太困難了。
           如果能將這些商業決策規則集中地放在一個地方,以一種你可以理解的格式定義,讓你可以直接管理,而不是散落在代碼的各個角落,那該有多好。如果你能把商業 決策規則獨立于你的軟件代碼,讓開發團隊作出技術決策,你將會獲得更多好處。你的項目開發周期會更短,軟件對于變動的需求更靈活。

    規則引擎標準Java API
           2003年11月,Java社區通過了Java Rule Engine API規范(JSR-94)的最后草案。這個新的API讓開發人員在運行時訪問和執行規則有了統一的標準方式。隨著新規范產品實現的成熟和推向市場,開發 團隊將可以從應用代碼中抽取出商業決策邏輯。
           這就需要新一代的管理工具,幫助商務經理人可以定義和細化軟件系統的行為。不必通過開發過程來修改應用,并假定可以得到正確的結果,經理人將可以隨時根據需要修改決策規則,并進行測試。
           但這將需要開發人員在設計系統時作出某些改變,并可以得到合適的開發工具。

    分離商務和技術的關注點
           這是一個非常簡單的例子,從經理人的角度,說明如何分離商務和技術的關注點。
           你管理著一個反向投資基金。你公司計算機系統的一部分用于分析股票價格,收益和每股凈資產,并在需要時向你提出預警。這個計算機系統的工作是,識別出PE比率比市場平均值低的股票,并標記出來以便進一步的檢查。
           你的IT部門擁有一大堆數據,并開發了一系列你可以在規則中引用的簡單數據對象。現在,為簡單起見,假設你是一名受過良好教育的,了解技術的管理人,你了解XML的基本知識,可以讓你編寫和修改簡單的XML規則文件。
           你的第一個規則是,給道瓊斯所有的股票估值,并剔除P/E比率大于10的股票(這有點過分簡化,但這里只作為一個例子)。保留下來的股票用來生產一系列報表。對于這個簡單的例子,你的規則文件看起來如下(我們將會過頭來討論這個文件的結構):

    <stock:overvalued>
        <stock:index> DJIA </stock:index>
        <stock:pe> over 10.0 </stock:pe>
    </stock:overvalued>

           一個月后,你接到一家巴西分析師公司的電話,雇傭你的公司生成一系列巴西股市的報表,但他們有更嚴格的標準。而目前在巴西,P/E比率市場平均值是個位 數,因此你用來評估被市場低股票的閾值需要改變。除了較低的P/E比率,你的新客戶還要求以Price-to-Book比率作為參考標準。
           你啟動規則編輯器,并修改規則以匹配新的評估條件。現在,規則引擎剔除巴西股市中P/E比率大于6.5,以及Price to Book 比率小于等于1的股票。完成規則文件修改后,看起來如下:

    <stock:overvalued>
        <stock:index> Brazil </stock:index>
        <stock:pe> over 6.5 </stock:pe>
        <stock:pb> over 1.0 </stock:pb>
    </stock:overvalued>

           你無需為此向開發團隊作任何解釋。你無需等待他們開發或測試程序。如果你的規則引擎的語義足夠強大,讓你描述工作數據,你可以隨時按需修改商業規則。
           如果限制因素是規則的定義語言和數據模型,你可以確信這兩者將會標準化,并出現先進的編輯器和工具,以簡化規則的定義,保存和維護。
           現在,我希望你已經清楚以下的原則:在這個例子中,哪只股票是否被選擇是一個商務決策,而不是技術決策。決定將哪只股票交給你的分析師是經理人的邏輯 ――"logic of the bottom line"。經理人作出這些決策,并可以按需定制應用。這些規則因此變成了一種控制界面,一種新的商業系統用戶界面。

    使用Rule開發
           如果在這個應用場景中,你是一個開發人員,你的工作會稍微輕松一些。一旦你擁有了一種用于分析股票的規則語言,你可以取出數據對象并交給規則引擎執行。我們將會到規則語言的討論,但現在我們繼續剛才的例子。
           你的系統將一系列的stock bean輸入規則引擎。當規則執行后,你可以選出符合條件的股票并可以對它們作進一步處理。也許是把它們輸入報表生成系統。分析師使用這些報表幫助他們分 析股市。同時,老板也可能讓你使用新的技術分析工具,并用Dow理論預測股市的底部和頂部。
           規則引擎可以讓你的系統變得更簡單,因為你無需在代碼中編寫商務邏輯,如怎樣選擇股票,選擇股票過程中奇怪的條件組合等。這些邏輯不再進入你的代碼。你將可以專注于數據模型。
           現在可以這么認為,通過從應用代碼中剝離出易變的商業邏輯,你的效率會更高。但凡是總有例外――簡單應用可能并不能從規則系統中獲益。但如果你開發一個大型系統,有很多易變的商業邏輯,你可以考慮在應用中集成規則引擎。
           除了從應用代碼中剝離出商業決策邏輯外,規則引擎還有其他用處。有時候你需要應用成百上千的規則進行決策,并且有上千個對象和這些規則一起使用。很難想象 有什么先進的人工智能引擎可以處理這種情況。遇到這種情況,你需要一個極快的決策算法或是大型機。大型機并不便宜,但你可以非常便宜的得到效率和可伸縮性 最好的算法。

    Bob McWhirter的Drools項目
           現在,我要介紹Drools項目,Charles Forgy Rete算法的一個增強的Java語言實現。Drools是一個Bob McWhirter開發的開源項目,放在The Codehaus上。在我寫這篇文章時,Drools發表了2.0-beata-14版。在CVS中,已完整地實現了JSR94 Rule Engine API并提供了單元測試代碼。
           Rete算法是Charles Forgy在1979年發明的,是目前用于生產系統的效率最高的算法(除了私有的Rete II)。Rete是唯一的,效率與執行規則數目無關的決策支持算法。For the uninitiated, that means it can scale to incorporate and execute hundreds of thousands of rules in a manner which is an order of magnitude more efficient then the next best algorithm。Rete應用于生產系統已經有很多年了,但在Java開源軟件中并沒有得到廣泛應用(討論Rete算法的文檔參見http://herzberg.ca.sandia.gov/jess/docs/61/rete.html。)。
           除了應用了Rete核心算法,開源軟件License和100%的Java實現之外,Drools還提供了很多有用的特性。其中包括實現了JSR94 API和創新的規則語義系統,這個語義系統可用來編寫描述規則的語言。目前,Drools提供了三種語義模塊――Python模塊,Java模塊和 Groovy模塊。本文余下部分集中討論JSR94 API,我將在第二篇文章中討論語義系統。
           作為使用javax.rules API的開發人員,你的目標是構造一個RuleExecutionSet對象,并在運行時通過它獲得一個RuleSession對象。為了簡化這個過程, 我編寫了一個規則引擎API的fa?ade,可以用來解釋代表Drools的DRL文件的InputStream,并構造一個 RuleExecutionSet對象。
           在上面提到了Drools的三種語義模塊,我接下來使用它們重新編寫上面的例子XML規則文件。這個例子中我選擇Java模塊。使用Java模塊重新編寫的規則文件如下:

    <rule-set name="StockFlagger"
          xmlns="http://drools.org/rules"
          xmlns:java="http://drools.org/semantics/java">
      <rule name="FlagAsUndervalued">
        <parameter identifier="stock">
          <java:class>org.codehaus.drools.example.Stock</java:class>
        </parameter>
        <java:condition>stock.getIndexName().equals("DJIA");</java:condition>
        <java:condition>stock.getPE() > 10 </java:condition>
        <java:consequence>
          removeObject(stock);   ( 譯注:應該是retractObject(stock) )
        </java:consequence>
      </rule>
    </rule-set>

           現在的規則文件并沒有上面的簡潔明了。別擔心,我們將在下一篇文章討論語義模塊。現在,請注意觀察XML文件的結構。其中一個rule-set元素包含了 一個或多個rule元素,rule元素又包含了parameter,condition和consequence元素。Condition和 consequence元素包含的內容和Java很象。注意,在這些元素中,有些事你可以做,有些事你不能做。目前,Drools使用 BeanShell2.0b1作為它的Java解釋器。我在這里并不想詳細的討論DRL文件和Java語義模塊的語法。我們的目標是解釋如何使用 Drools的JSR94 API。
           在Drools項目CVS的drools-jsr94模塊中,單元測試代碼包含了一個ExampleRuleEngineFacade對象,它基于 Brian Topping的Dentaku項目。這個fa?ade對象通過javax.rules API,創建了供RuleExecutionSet和RuleSession使用的一系列對象。它并沒有完全包括了Drools引擎API的所有特性和細 微差別,但可以作為新手使用API的一個簡單例子。
          下面的代碼片斷顯示如何使用規則引擎的facade構造一個RuleExecutionSet對象,并通過它獲得一個RuleSession對象。
     
    import java.io.InputStream;
    import javax.rules.*;
    import org.drools.jsr94.rules.ExampleRuleEngineFacade;
    public class Example {
        private ExampleRuleEngineFacade engine;
        private StatelessRuleSession statelessSession;
        /* place the rule file in the same package as this class */
        private String bindUri = "myRuleFile.drl"
        public Example() {
            /* get your engine facade */
            engine = new ExampleRuleEngineFacade();
            /* get your input stream */
            InputStream inputStream =
                    Example.class.getResourceAsStream(bindUri);
            /* build a RuleExecutionSet to the engine */
            engine.addRuleExecutionSet(bindUri, inputStream);
            /* don't forget to close your InputStream! */
            inputStream.close();
            /* get your runtime session */
            this.statelessSession = engine.getStatelessRuleSession(bindUri);
        }
        ...
    }

           在以上的例子代碼中,你需要處理InputStream的IOException例外,這里為了簡單起見省略了。你要做的只是構建InputStream 對象,并把它輸入ExampleRuleEngineFacade,用來創建一個RuleExecutionSet對象。然后,你可以得到一個 StatelessRuleSession,并用它來執行所有的規則。使用StatelessRuleSession相對簡單。我們可以給上面的類添加一 個方法,用來對一個對象列表執行規則:

    public List getUndervalued(List stocks) {
        return statelessSession.executeRules(stocks);
    }

           該方法輸入一個stock對象列表給規則引擎,然后使用規則評估輸入的股票對象,并剔除那些不符合價值低估標準的股票。它是個簡單的例子,但足以說明問題。
           在ExampleRuleEngineFacade類中,代碼會稍微有些復雜。ExampleRuleEngineFacade類創建了一個 RuleServiceProvider對象,并用它創建RuleAdministrator,RuleExecutionSetProvider和 RuleRuntime對象。RuleExecutionSetProvider負責解釋InputStream,并創建一個 RuleExecutionSet對象。RuleRuntime對象用來得到一個session,RuleAdministrator用來管理所有的對 象。在往下是Drools核心API,它的核心是Rete算法實現。我在這里不打算詳細討論,但你可以看看 ExampleRuleEngineFacade的代碼。
           現在你已經看到了在商業和科研方面使用規則引擎的一些例子,并對Drools項目有了基本的了解。在下一篇文章里,我將討論DRL文件的結構和Java語 義模塊,讓你可以編寫自己的DRL文件。還將向你解釋如何編寫你自己的語義模塊,討論salience和working memory的概念。

    資源
    · Drools Project
    · JSR-94 Specification
     
    作者
          N. Alex Rupp is a freelance software architect and developer from Minneapolis, and the current JSR94 Lead for the Drools project.
    posted @ 2006-03-11 10:00 Dion 閱讀(1750) | 評論 (0)編輯 收藏

    一般情況下, 只顯式引用:

    • drools-all-2.0.jar
    • antlr-2.7.5.jar
    • xercesImpl-2.6.2.jar

    就可以了.當然ClassPath下也要用一些其他的jar.
    下載位置: http://dist.codehaus.org/drools/distributions/drools-2.0-bin-withdeps.zip

    如果, 在DRL文件中定義了Java Function, 這時候就要顯式的引用:

    • janino-2.3.2.jar

    這時候, 引擎是需要janino把DRL中的java function描述轉換成可執行的二進制代碼(?)的.

    posted @ 2006-03-11 09:59 Dion 閱讀(962) | 評論 (0)編輯 收藏

    Drools and Mandarax

    兩個項目做了兩件不同的事情: 一個是Forward Chaining,另一個是 backward chaining. Drools 是forward chaining的,  意味著 它對assert的對象反應, 事件驅動的. Mandarax 是 backward chaining的, 像 prologue一樣, 你問它問題, 它試圖給你它知道的答案. 舉例來說, 在使用Drools的時候, 你可能會先assert 給它今天的日期, 如果它發現有匹配的規則的手,它會用事件的方式通知你"今天是你的生日". 在 backward chaining 的系統, 你可能先問 "今天是我的生日嘛?" 系統會搜索它知道的, 然后告訴你答案.
    For an excellent explanation of forward and backward chaining read Charles Forgey's recent articles at http://rulespower.com/ - Forward and Backward Chaining:
    Parts 1, 2 and 3.
    posted @ 2006-03-11 09:58 Dion 閱讀(1173) | 評論 (0)編輯 收藏

    Open Source Rule Engines Written In Java

    • Drools The drools engine uses a modified form of the Rete algorithm called the Rete-OO algorithm. Internally it operates using the same concepts and methods as Forgy's original but adds some node types required for seemless integration with an object-oriented language.
    • OFBiz Rule Engine Backward chaining is supported. Original code base from "Building Parsers in Java" by Steven John Metsker.
    • Mandarax Based on backward reasoning. The easy integration of all kinds of data sources. E.g., database records can be easily integrated as sets of facts and reflection is used in order to integrate functionality available in the object model.
    • Algernon Efficient and concise KB traversal and retrieval. Straightforward access to ontology classes and instances. Supports both forward and backward chaining.
    • TyRuBa TyRuBa supports higher order logic programming: variables and compound terms are allowed everywhere in queries and rules, also in the position of a functor- or predicate-name. TyRuBa speeds up execution by making specialized copies of the rule-base for each query in the program. It does so incrementally while executing a logic program and builds an index for fast access to rules and facts in the rule base, tuned to the program that is running. The indexing techniques works also for higher-order logic. TyRuBa does 'tabling' of query results.
    • JTP Java Theorem Prover is based on a very simple and general reasoning architecture. The modular character of the architecture makes it easy to extend the system by adding new reasoning modules (reasoners), or by customizing or rearranging existing ones.
    • JEOPS JEOPS adds forward chaining, first-order production rules to Java through a set of classes designed to provide this language with some kind of declarative programming.
    • InfoSapient Semantics of business rules expressed using fuzzy logic.
    • JShop Simple Hierarchical Ordered Planner (SHOP) written in Java.
    • RDFExpert RDF-driven expert system shell. The RDFExpert software uses Brian McBride's JENA API and parser. A simple expert system shell that uses RDF for all of its input: knowledge base, inference rules and elements of the resolution strategy employed. It supports forward and backward chaining.
    • Jena 2 - Jena is a Java framework for writing Semantic Web applications. Jena2 has a reasoner subsystem which includes a generic rule based inference engine together with configured rule sets for RDFS and for the OWL/Lite subset of OWL Full. These reasoners can be used to construct inference models which show the RDF statements entailed by the data being reasoned over. The subsystem is designed to be extensible so that it should be possible to plug a range of external reasoners into Jena, though worked examples of doing so are left to a future release.
    • JLisa - JLisa is a powerful framework for building business rules accessible to Java and it is compatible with JSR-94. JLisa is more powerful than Clips because it has the expanded benefit of having all the features from common lisp available. These features are essential for multi-paradigm software development
    • Euler - Euler is a backward-chaining reasoner enhanced with Euler path detection and will tell you whether a given set of facts and rules supports a given conclusion. Things are described in N3.
    • JLog - JLog is an implementation of a Prolog interpreter, written in Java. It includes built-in source editor, query panels, online help, animation primitives, and a GUI debugger.
    • Pellet OWL Reasoner - Pellet is an open-source Java based OWL DL reasoner. It can be used in conjunction with either Jena or OWL API libraries. Pellet API provides functionalities to see the species validation, check consistency of ontologies, classify the taxonomy, check entailments and answer a subset of RDQL queries (known as ABox queries in DL terminology). Pellet is an OWL DL reasoner based on the tableaux algorithms developed for expressive Description Logics.
    • Prova - Prova is derived from Mandarax Java-based inference system developed by Jens Dietrich. Prova extends Mandarax by providing a proper language syntax, native syntax integration with Java, and agent messaging and reaction rules. The development of this language was supported by the grant provided within the EU project GeneStream. In the project, the language is used as a rules-based backbone for distributed web applications in biomedical data integration.
    posted @ 2006-03-11 09:58 Dion 閱讀(1342) | 評論 (0)編輯 收藏

    始終會用上的Common BeanUtils

    Beanutils用了魔術般的反射技術,實現了很多夸張有用的功能,都是C/C++時代不敢想的。無論誰的項目,始終一天都會用得上它。我算是后知后覺了,第一回看到它的時候居然錯過。

    1.屬性的動態getter、setter

    在這框架滿天飛的年代,不能事事都保證執行getter,setter函數了,有時候屬性是要根據名字動態取得的,就像這樣:  
    BeanUtils.getProperty(myBean,"code");
    而Common BeanUtils的更強功能在于可以直接訪問內嵌對象的屬性,只要使用點號分隔。
    BeanUtils.getProperty(orderBean, "address.city");
    相比之下其他類庫的BeanUtils通常都很簡單,不能訪問內嵌的對象,所以有時要用Commons BeanUtils來替換它們。

    BeanUtils還支持List和Map類型的屬性,如下面的語法即可取得Order的顧客列表中第一個顧客的名字
    BeanUtils.getProperty(orderBean, "customers[1].name");
    其中BeanUtils會使用ConvertUtils類把字符串轉為Bean屬性的真正類型,方便從HttpServletRequest等對象中提取bean,或者把bean輸出到頁面。
    而PropertyUtils就會原色的保留Bean原來的類型。

    2.BeanCompartor 動態排序

    還是通過反射,動態設定Bean按照哪個屬性來排序,而不再需要在實現bean的Compare接口進行復雜的條件判斷。
    List peoples = ...; // Person對象的列表
    Collections.sort(peoples, new BeanComparator("age"));

    如果要支持多個屬性的復合排序,如"Order By lastName,firstName"

    ArrayList sortFields = new ArrayList();
    sortFields.add(new BeanComparator("lastName"));
    sortFields.add(new BeanComparator("firstName"));
    ComparatorChain multiSort = new ComparatorChain(sortFields);
    Collections.sort(rows,multiSort);

    其中ComparatorChain屬于jakata commons-collections包。
    如果age屬性不是普通類型,構造函數需要再傳入一個comparator對象為age變量排序。
    另外, BeanCompartor本身的ComparebleComparator, 遇到屬性為null就會拋出異常, 也不能設定升序還是降序。這個時候又要借助commons-collections包的ComparatorUtils.

       Comparator mycmp = ComparableComparator.getInstance();
       mycmp = ComparatorUtils.nullLowComparator(mycmp);  //允許null
       mycmp = ComparatorUtils.reversedComparator(mycmp); //逆序
       Comparator cmp = new BeanComparator(sortColumn, mycmp);
    3.Converter 把Request或ResultSet中的字符串綁定到對象的屬性

       經常要從request,resultSet等對象取出值來賦入bean中,如果不用MVC框架的綁定功能的話,下面的代碼誰都寫膩了。

       String a = request.getParameter("a");
    bean.setA(a);
    String b = ....
    bean.setB(b);
    ......

    不妨寫一個Binder自動綁定所有屬性:

        MyBean bean = ...;
    HashMap map = new HashMap();
    Enumeration names = request.getParameterNames();
    while (names.hasMoreElements())
    {
    String name = (String) names.nextElement();
    map.put(name, request.getParameterValues(name));
    }
    BeanUtils.populate(bean, map);

        其中BeanUtils的populate方法或者getProperty,setProperty方法其實都會調用convert進行轉換。
         但Converter只支持一些基本的類型,甚至連java.util.Date類型也不支持。而且它比較笨的一個地方是當遇到不認識的類型時,居然會拋 出異常來。 對于Date類型,我參考它的sqldate類型實現了一個Converter,而且添加了一個設置日期格式的函數。
    要把這個Converter注冊,需要如下語句:

        ConvertUtilsBean convertUtils = new ConvertUtilsBean();
       DateConverter dateConverter = new DateConverter();
       convertUtils.register(dateConverter,Date.class);



    //因為要注冊converter,所以不能再使用BeanUtils的靜態方法了,必須創建BeanUtilsBean實例
    BeanUtilsBean beanUtils = new BeanUtilsBean(convertUtils,new PropertyUtilsBean());
    beanUtils.setProperty(bean, name, value);
    4 其他功能
    4.1 ConstructorUtils,動態創建對象
         public static Object invokeConstructor(Class klass, Object arg)
    4.2 MethodUtils,動態調用方法
        MethodUtils.invokeMethod(bean, methodName, parameter);

    4.3 PropertyUtils,當屬性為Collection,Map時的動態讀取:
    Collection: 提供index
       BeanUtils.getIndexedProperty(orderBean,"items",1);
    或者
      BeanUtils.getIndexedProperty(orderBean,"items[1]");
    Map: 提供Key Value
      BeanUtils.getMappedProperty(orderBean, "items","111");//key-value goods_no=111 
    或者
      BeanUtils.getMappedProperty(orderBean, "items(111)") 

    4.4 PropertyUtils,直接獲取屬性的Class類型
         public static Class getPropertyType(Object bean, String name)
    4.5 動態Bean 用DynaBean減除不必要的VO和FormBean 
    posted @ 2006-01-15 20:20 Dion 閱讀(5093) | 評論 (2)編輯 收藏

         摘要: Migrate apps from Internet Explorer to MozillaHow to make Internet Explorer-specific Web applications work in Mozilla-based browsersDocument options Print this page'); //--> Print this page E-ma...  閱讀全文
    posted @ 2006-01-04 19:18 Dion 閱讀(1490) | 評論 (1)編輯 收藏

    以下以 IE 代替 Internet Explorer,以 MF 代替 Mozzila Firefox

    1. document.form.item 問題
        (1)現有問題:
            現有代碼中存在許多 document.formName.item("itemName") 這樣的語句,不能在 MF 下運行
        (2)解決方法:
            改用 document.formName.elements["elementName"]
        (3)其它
            參見 2

    2. 集合類對象問題
        (1)現有問題:
            現有代碼中許多集合類對象取用時使用 (),IE 能接受,MF 不能。
        (2)解決方法:
            改用 [] 作為下標運算。如:document.forms("formName") 改為 document.forms["formName"]。
            又如:document.getElementsByName("inputName")(1) 改為 document.getElementsByName("inputName")[1]
        (3)其它

    3. window.event
        (1)現有問題:
            使用 window.event 無法在 MF 上運行
        (2)解決方法:
            MF 的 event 只能在事件發生的現場使用,此問題暫無法解決。可以這樣變通:
            原代碼(可在IE中運行):
                <input type="button" name="someButton" value="提交" onclick="javascript:gotoSubmit()"/>
                ...
                <script language="javascript">
                    function gotoSubmit() {
                        ...
                        alert(window.event);    // use window.event
                        ...
                    }
                </script>

            新代碼(可在IE和MF中運行):
                <input type="button" name="someButton" value="提交" onclick="javascript:gotoSubmit(event)"/>
                ...
                <script language="javascript">
                    function gotoSubmit(evt) {
                        evt = evt ? evt : (window.event ? window.event : null);
                        ...
                        alert(evt);             // use evt
                        ...
                    }
                </script>
            此外,如果新代碼中第一行不改,與老代碼一樣的話(即 gotoSubmit 調用沒有給參數),則仍然只能在IE中運行,但不會出錯。所以,這種方案 tpl 部分仍與老代碼兼容。

    4. HTML 對象的 id 作為對象名的問題
        (1)現有問題
            在 IE 中,HTML 對象的 ID 可以作為 document 的下屬對象變量名直接使用。在 MF 中不能。
        (2)解決方法
            用 getElementById("idName") 代替 idName 作為對象變量使用。

    5. 用idName字符串取得對象的問題
        (1)現有問題
            在IE中,利用 eval(idName) 可以取得 id 為 idName 的 HTML 對象,在MF 中不能。
        (2)解決方法
            用 getElementById(idName) 代替 eval(idName)。

    6. 變量名與某 HTML 對象 id 相同的問題
        (1)現有問題
            在 MF 中,因為對象 id 不作為 HTML 對象的名稱,所以可以使用與 HTML 對象 id 相同的變量名,IE 中不能。
        (2)解決方法
            在聲明變量時,一律加上 var ,以避免歧義,這樣在 IE 中亦可正常運行。
            此外,最好不要取與 HTML 對象 id 相同的變量名,以減少錯誤。
        (3)其它
            參見 問題4

    7. event.x 與 event.y 問題
        (1)現有問題
            在IE 中,event 對象有 x, y 屬性,MF中沒有。
        (2)解決方法
            在MF中,與event.x 等效的是 event.pageX。但event.pageX IE中沒有。
            故采用 event.clientX 代替 event.x。在IE 中也有這個變量。
            event.clientX 與 event.pageX 有微妙的差別(當整個頁面有滾動條的時候),不過大多數時候是等效的。

            如果要完全一樣,可以稍麻煩些:
            mX = event.x ? event.x : event.pageX;
            然后用 mX 代替 event.x
        (3)其它
            event.layerX 在 IE 與 MF 中都有,具體意義有無差別尚未試驗。


    8. 關于frame
       (1)現有問題
             在 IE中 可以用window.testFrame取得該frame,mf中不行
       (2)解決方法
             在frame的使用方面mf和ie的最主要的區別是:
    如果在frame標簽中書寫了以下屬性:
    <frame src="xx.htm" id="frameId" name="frameName" />
    那么ie可以通過id或者name訪問這個frame對應的window對象
    而mf只可以通過name來訪問這個frame對應的window對象
    例如如果上述frame標簽寫在最上層的window里面的htm里面,那么可以這樣訪問
    ie: window.top.frameId或者window.top.frameName來訪問這個window對象
    mf: 只能這樣window.top.frameName來訪問這個window對象

    另外,在mf和ie中都可以使用window.top.document.getElementById("frameId")來訪問frame標簽
    并且可以通過window.top.document.getElementById("testFrame").src = 'xx.htm'來切換frame的內容
    也都可以通過window.top.frameName.location = 'xx.htm'來切換frame的內容
    關于frame和window的描述可以參見bbs的‘window與frame’文章
    以及/test/js/test_frame/目錄下面的測試
    ----adun 2004.12.09修改

    9. 在mf中,自己定義的屬性必須getAttribute()取得
    10.在mf中沒有  parentElement parement.children  而用
                   parentNode parentNode.childNodes
       childNodes的下標的含義在IE和MF中不同,MF使用DOM規范,childNodes中會插入空白文本節點。
      一般可以通過node.getElementsByTagName()來回避這個問題。
       當html中節點缺失時,IE和MF對parentNode的解釋不同,例如
       <form>
       <table>
            <input/>
       </table>
       </form>
       MF中input.parentNode的值為form, 而IE中input.parentNode的值為空節點

      MF中節點沒有removeNode方法,必須使用如下方法 node.parentNode.removeChild(node)

    11.const 問題
      (1)現有問題:
         在 IE 中不能使用 const 關鍵字。如 const constVar = 32; 在IE中這是語法錯誤。
      (2)解決方法:
         不使用 const ,以 var 代替。

    12. body 對象
       MF的body在body標簽沒有被瀏覽器完全讀入之前就存在,而IE則必須在body完全被讀入之后才存在

    13. url encoding
    在js中如果書寫url就直接寫&不要寫&amp;例如var url = 'xx.jsp?objectName=xx&amp;objectEvent=xxx';
    frm.action = url那么很有可能url不會被正常顯示以至于參數沒有正確的傳到服務器
    一般會服務器報錯參數沒有找到
    當然如果是在tpl中例外,因為tpl中符合xml規范,要求&書寫為&amp;
    一般MF無法識別js中的&amp;


    14. nodeName 和 tagName 問題
      (1)現有問題:
         在MF中,所有節點均有 nodeName 值,但 textNode 沒有 tagName 值。在 IE 中,nodeName 的使用好象
         有問題(具體情況沒有測試,但我的IE已經死了好幾次)。
      (2)解決方法:
         使用 tagName,但應檢測其是否為空。

    15. 元素屬性
       IE下 input.type屬性為只讀,但是MF下可以修改


    16. document.getElementsByName() 和 document.all[name] 的問題
      (1)現有問題:
         在 IE 中,getElementsByName()、document.all[name] 均不能用來取得 div 元素(是否還有其它不能取的元素還不知道)。
    posted @ 2005-12-31 17:55 Dion 閱讀(934) | 評論 (1)編輯 收藏

    這里說說我的經歷吧。大學前以及大學前面三年的經歷就不說了,因為大學前的高中就是好好學習,大學前三年就是混過來的。

        我上的學校還算可以,雖然不是北大清華這樣第一流名牌大學,但至少也算中國的第二流名牌大學了。大學中前面三年都陪伴著游戲過去,所學到的只是些計算機基 礎知識。到大四后我突然發現就業的問題就在眼前,而自己似乎什么也不會,于是開始看書。最一開始重點看的是C++,可是后來自從看了一本J2ME的書以后 被Java所吸引。當時雖然學校上過Java課程,但是自己也只是學了很少的皮毛,也就只會寫寫Hello World和什么加減法之類很簡單的程序,連API都知道沒有幾個,比如說字符串長度的API我都不知道。所以剛開始自己學J2ME的時候屢屢受挫,自己 也明白自己的缺點,決定從J2SE開始好好補上。

        剛開始為了熟悉Java開發環境,買了本JBuilder開發的教程,并且在自己的本本上安裝了JBuilder進行演練。當時的我連JavaDoc都不 知道,每次究竟什么API能做什么事情一點頭緒都沒有,還不知道哪里去查,后來同學告訴我有個JavaDoc這個東西,我還興奮不已,覺得自己被從黑暗中 拉回來了。一開始使用JBuilder的時候,馬上為之所吸引,有兩個原因,第一是因為它自動標出語法錯誤,邊寫代碼邊提示你什么地方語法出錯,記得以前 使用VC++的時候,每次程序寫好后先編譯,然后再Build,再運行,這其中每個步驟都會出不少錯誤。特別是在編譯的時候,寫個200多行的程序一次編 譯下來就有100多個錯誤,結果每次花在這上面的工夫都要好長時間。而JBuilder使用了即時語法分析,所以基本上程序寫完,就可以省略調試語法錯誤 的步驟了。第二個原因是可以自動提示代碼,這個功能可以讓你迅速熟悉API,免得每次去查幫助文檔那么麻煩,我就是這么很快掌握了許多API的。

    可能大家會問我為什么一開始不學習《Java編程思想》,的確這本書我們宿舍就有好幾本,不過大家普遍反映效果不好,到最后都不知道說的是什么,所以我也沒敢看。

        經過20天左右的學習,對Java有了更進一步的了解,熟悉了不少API函數,由于在那本書上寫開發SWING占了不少篇幅,所以也對Swing的開發了 解了不少。看完以后因為同學說Java的靈魂就是多線程編程,所以開始看Oreilly的《Java線程》。記得在大學中操作系統這門課我們就提到過線程 的知識。并且課本上就是用Java實現的,當時有了一點點概念,但這次看這本專門說線程的書后才發現我原來了解的那些根本是什么都不算(當然,現在回想起 來,我那時看書學到的也只是很簡單的皮毛而已)。看完這本書后我自己學會在我的JBuilder下開發很簡單的多線程程序,并且模擬線程沖突,等待等情 況。當時看著自己寫的一兩百行程序可以順利執行,那種興奮勁就別提了。這本書我看得也很快,大概就花了3個星期看完。

        經過上面的學習,自己相比以前來說提升了不少,這時候自己也找到了工作,是做J2EE對日外包的,所以更加堅定了努力學習Java的信心。

        在上面寫的程序中,我自己寫程序沒有規范性,在代碼編寫的時候自己的盲點特別多,還容易犯低級失誤。同學有一個《Effective Java》中文版,可是我看了幾頁發現自己根本看不懂,里面什么靜態工廠啊,什么單例模式什么的根本不知道什么東東。我知道自己目前的水平還不夠,所以決 定放下這本書,去尋找別的適合我的書看。這個時候我看到了候捷先生翻譯的《Practical Java》一書,當時是剛剛上的書架。這本書我在書店翻了下目錄后就感覺如獲至寶,馬上買回家,在回家的公車上就貪婪地讀起來。這本書不算很厚,但是自己 看得卻很認真很仔細,也明白了不少東西,比如Java中等號和equals()方法的區別,究竟什么時候用什么。還有Exception處理機制,以前不 知道什么叫Exception,只是JBuilder提示我要我拋出Exception我再拋出Exception,自己覺得這東西基本沒什么用呢。但是 看了這本書后我改變了看法,我發現Exception是個很好的東西,可以迅速把程序從正常狀態和異常狀態區分開來,即使而準確地在指定位置得到處理。那 時自己也有了以后寫程序的時候注意編寫異常處理部分的想法。《Practical Java》這本書雖然不厚,但是我卻非常仔細地去看了,大概花了1個月時間,我把這本書完全消化了下去。

        當時聽說Java在網絡上的應用非常廣,我也不知道究竟是什么應用,我于是買了Oreilly的《Java網絡編程》這本書。這本書雖然很厚,其實前半部 分內容不是很復雜,后半部分寫什么RMI的東西我也看不大懂,只能理解個概念。通過這本書,我了解了HTTP協議究竟是什么一個東西,在它上面利用 Java傳輸數據該如何做,知道了什么是Request,什么是Response。這也為以后開始我的J2EE之旅打下了很好的基礎。當時自己依然是邊看 書邊自己寫代碼來驗證,自己寫了個服務器端Socket和客戶端Socket,成功進行了通信,又在上面加上了安全Socket內容,實現了SSL通信。 當時我把寫的這個又套上了Swing的外殼,還和同學拿這個傳文件呢。不過當時也沒有考慮過什么校驗碼之類的東西,所以傳傳小文件還是可以的,文件稍微一 大一點,傳過去的文件總是不對頭,和我原來的文件經常會出一些差異,導致文件打不開。

        《Java網絡編程》這本書看了不少時間,因為書比較厚,東西也比較多,不過除了后面的一些知識以外,其他的還是容易理解的。大概花了2個月左右的時間看 完。看完后,時間也到了2004年的3月。我也輪到開始我畢業設計的時候了。我們的畢業設計導師都還不錯,給你自己選個課題,我選的是一個B/S結構的在 線簡歷處理系統,正好和我所學和下面所工作的東西是一條路上的了。這時我覺得我應該往B/S結構上轉了,當時在選擇先看Servlet還是先看JSP上猶 豫不決。最終決定先看Servlet,后來也證明了我的決定是對的,我在熟悉了Servlet后再學JSP是非常容易的,基本上根本沒有遇到什么難點。

    可 能有人會覺得我看了好多Oreilly的書,雖然我不能說Oreilly本本都是好書,不過相對來說,好書的概率總超過許多其他的出版社,而且體系比較齊 全。我看得幾本書我都覺得還不錯。現說說下面這本我學Servlet時候看的《Java Servlet編程》來說吧,很不錯的一本書,讓我迅速知道了什么是Servlet,然后通過最簡單的實例,讓你知道了Servlet如何運行的,跟 HTTP協議是如何配合的,如何返回HTML形式的文本,XML配置符該如何寫,究竟每個元素是什么意思等等。由于我原來有一定的XML基礎(知道XML 語法各種格式的含義而已),所以掌握起來還算比較快。通過這本書,我知道了如何動態生成HTML文檔,知道如何把一個Servlet映射到一個虛擬的地 址。在后半部分寫到了數據庫操作部分,我對數據庫的了解其實也僅限于原來大學課本上的《數據庫系統原理》,如何從程序和數據庫交互是一竅不通。通過數據庫 操作這章,我知道了如何使用JDBC語句如何編寫,大家不要笑,對于當初一個新手來說,這個真是一個全新的領域,做什么事情都需要Sample來對照,跟 著依葫蘆畫瓢吧,其實現在的軟件開發也是這樣,我想現在大家誰能直接手寫Struts或者Hibernate的配置文件都很難吧。閑話少說,大概這個時 候,我對畢業設計的雛形有了點思想上的概念。看完了《Java Servlet編程》后緊接著就又看Oreilly的《JSP設計》,由于有了Servlet的基礎,學起JSP特別快。當時沒有著重看Tag的自定義設 計,光看了JSP的其他東西,終于在五一節后把畢業設計都寫完了,當時總代碼量是2000多行,第一次寫這么多代碼的程序覺得很有成就感。現在看起來那時 做的是標準垃圾,但是當時覺得還是很不錯。用了Servlet + JSP。其實Servlet也不是用來當控制器的,而是和JSP做的差不多功能,都是作view的功能的。很快,畢業設計交差過去了,寫寫畢業論文,準備 答辯。在這個過程中,我又一次考慮自己下面該看什么書。

    這次我又看中了侯捷翻譯的一本巨著,也就是鼎鼎大名的Martin Fowler寫的《重構——改善既有代碼的設計》這本書。剛開始聽見重構這個名字,總覺得非常高深,加上都評論說重構是和設計模式齊名的東東,感覺更加高 深恐怖了。大概在6月初我開始看了重構,剛開始看的時候雖然抱著試試看的心態,不過還是非常認真的。但是,讓我頗感意外的是重構并不是很難,至少這本書中 說的非常通俗易懂,通過大量的實例讓你覺得重構是種很簡單很基本的技術。雖然我看完了重構以后在真實的代碼編寫中很少直接按照上面代碼所說的方法進行重構 代碼,基本上都是通過IDE來重構代碼,但是卻大大提升了自己編程思維,從此以后寫代碼就很少瞻前顧后了,因為我擁有了重構這個工具。這本書有點厚,再加 上中間有答辯,拍畢業照,以及畢業手續等等,這本書我花了一個半月看完。我看書的速度也不算快,不過我看書比較有恒心,不像有部分人看幾天就不想看了,我 能堅持天天看,所以總的來說還是不慢的。我計算過,如果我每天看10頁書,堅持下去,那一年就是3650頁書,平均一本書365頁來算,1年就是10本。 如果這10本書中有8本不屬于垃圾書籍,那么你這年就能有非常大的提高了。

    看重構這本書中間我也抽了一段時間看了兩本其他的書,第一本是 《Java夜未眠》,挺不錯的一本書,雖然是散文,但是還是能讓你明白不少道理,受益匪淺。另外一本就是李維的《Borland傳奇》,由于自己當時最喜 歡用的工具就是JBuilder,所以也對Borland公司非常敬仰,特別對安德森,簡直就頂禮膜拜啊,哈哈。這本書寫得很精彩,寫了Borland公 司二十年來的血淚史,寫了如何跟微軟斗爭,如何在微軟和IBM的夾縫中生存。當然,也有很多的對于技術方面作者李維自己的見解,看了會有不少同感的。就這 樣,磨磨蹭蹭地把重構看完了。

        當看完了《重構》這本書之后,我也開始去公司報到上班了。可以看出來,我當時工作的時候水平也很有限,但總比一年前要好不少,至少很多東西都已經知道了。 那時外面極限編程聽的比較多,自己也去書店買了本《Java極限編程》回來看,現在想想算是我看得第一本垃圾書籍了。不過也是有收獲的,這本書極限編程也 就說了點概念,然后就寫了不少工具的使用方法。在看《重構》中對JUnit有了點認識,不過只是皮毛中的皮毛。看了這本《Java極限編程》后對 JUnit的使用又了解了不少皮毛,對于Cactus有了點了解,對Ant了解了不少,至少可以自己寫出自己需要的配置文件了,并且可以結合JUnit生 成測試Report。由于我去的是日企,做對日外包的,所以公司開始培訓日本語,用的是《標準日本語》這套教材。我于是邊學日語邊看技術,大概2個星期左 右我把那本《Java極限編程》初步看完后就扔在了家里。這時的我已經開始會用Ant了,覺得是步入J2EE的重要一步。

        很快啃掉那本垃圾書以后又看了本和Java不是非常有關的書:《程序員修煉之道——從小工到專家》,原因其實很簡單,大學同學都說這本書是經典書,看書這 東西,別人的評價還是能起不少作用的。這本書字數不是很多,不過排版的時候比較分散,導致書本有點厚,呵呵,可能也算出版社賺錢的一種方法吧。不過總的來 說,我覺得出版社紙張質量最好的是電子工業出版社,其次是中國電力出版社,最爛的恐怕就是機械工業出版社了,機械工業出版社有少量書紙張還能說過去,但有 不少簡直讓人不得不有脾氣啊,紙張薄得感覺和寫毛筆字的宣紙都差不多了。這本電子工業出版社的書紙張質量的確不錯,不過也許是因為我功力尚淺,所以這本書 雖然都看懂了,但是深有感觸并且銘記于心的沒有幾個,現在再回想,也只記得軟件模塊設計時要正交等等少數幾點了。這本書由于內容不是非常多,所以我就看了 半個月不到搞定。這時的我開發IDE已經轉移到了Eclipse上,畢竟商業開發用D版有點說不過去,而且公司也怕查,所以不允許用JBuilder,鼓 勵大家用Eclipse。我用了一段時間的Eclipse后,從一開始的不適應到后來覺得Eclipse很方便使用,JBuilder比Eclipse多 的就是一些根據不同類型開發的模版而已,而這些可以由Eclipse的插件來彌補。到了這時,我覺得我的Java基礎應該算還可以的了,API也熟悉了非 常多。我覺得看《Effective Java》的時機成熟了。

        由于大學已經畢業了,所以也不會有同學的《Effective Java》放在邊上讓我看這樣的好事出現,老老實實地去了書店買了本《Effective Java》中文版回來研讀。呵呵,大家也許會問我為什么不買本E文的看,雖然我大學早早也把英語4級過了,而且大學中不少計算機專業課程教材也是E文的, 當時為了考試也認真讀了。但是畢竟英語不是我們的母語,看起來速度上明顯比中文版的慢一截。當然,如果是那種垃圾翻譯者用機器翻譯出來的中文版,看那些垃 圾中文版速度肯定比不上直接看英文原版的。這時的我看《Effective Java》已經不再是當初的那么感覺很陌生了,覺得上面說的那些要點自己想想還都是可以理解的。我個人覺得提高自身編程習慣以及水平最多的還是看類似于 《Practical Java》和《Effective Java》的這種按照條目來進行說明的書,能把你自己平時容易忽略的地方按照重點一個個揪出來進行修正。比如《Effective Java》中的第一條,使用靜態工廠來代替構造函數,自己原來在進行開發的時候,從來不怎么會主動想到建立一個靜態工廠,總覺得使用構造函數來新建一個對 象是天經地義的事情。但看完這個條目后,我的看法也隨之改變,發現靜態工廠還是非常好的,當然,也不是什么地方用靜態工廠都很好。上面也寫到了靜態工廠的 優缺點,比如在什么地方適合使用,什么場合最好不要使用等等。這本書我覺得翻譯的也不錯,絕對值,強烈向有一定開發經驗的人推薦。我大概看了3周半的樣子 把這本書看完,這時的時間也到了2004年的9月初,新員工入司培訓也不再是第一個月純粹的日語培訓,而是技術培訓和日語培訓一起開展,技術上培訓 Java,Web開發,數據庫開發這三門課程,日語則開始進行日本語國際三級的培訓。公司的日語培訓和技術培訓都還不錯,技術培訓純粹把大家當作什么都不 懂的人,在Java上從最原始的Hello World開始培訓,Web開發上從HTML頁面開始培訓,數據庫開發則從Oracle的安裝,SQL語句的編寫開始培訓。當然,在培訓的過程中我也不會 閑著,而是又開始尋找自己要啃的書本,這次,我選中了Oreilly新出版不久的《Java與XML》第二版。

        由于XML表達數據的自由性以及強大型,所以XML特別適合于做配置文件以及數據信息文件,在Java中XML的使用可謂是多如牛毛。在J2EE中,從 Web Application的web.xml開始就是XML文件,到下面的Framework配置等等,沒有一個沒有XML的身影,而且XML都起到了舉足輕 重的作用。雖然我原來也懂一點XML,不過也僅限于XML的語法以及結構等等,那些深入下去的東西基本還是盲點,關于Java中如何處理XML更是一竅不 通。為了更好的學習J2EE,XML是必須征服得一座山峰。這次,我依然又再一次信任了Oreilly出版社,買了本當時出版不久的《Java與XML》 中文第二版。這本書剛開始并沒有過多介紹XML本身過多的東西,只是為了怕某些讀者并不了解XML而對XML語法結構等做了非常簡要的介紹,不過也非常到 位的介紹。介紹完了這些XML基礎知識后就開始了SAX——〉DOM——〉JDOM——〉JAXP——〉Web Service的歷程。不過我現在覺得如果能介紹DOM4J就更好了,因為我現在覺得DOM4J是Java中最好用而且性能也不錯的XML處理工具。剛開 始的我其實什么是SAX,什么是DOM都不知道,對JAXP更是一無所知。這本書英文版據說很受好評,中文版我只能說一般,因為有些地方估計譯者并不擅長 這一塊,所以翻譯得很生硬,以至于部分段落難于理解。總體來說,書的絕大多數內容還是可以看懂,由于沒有具體實際操作的經驗,所以很多也就是把概念理解 了,直到幾個月后做正式項目開始應用這些XML處理工具進行開發的時候才達到了熟練運用的能力。在這本書中學會了JDOM的使用方法,JDOM也還是比較 好用的,學會了JDOM,以后操縱XML也方便了許多。這本書我的建議就是,可以一口氣讀到第十章JAXP部分,后面的Cocoon以及SOAP等等部分 那本書介紹的并不是很好。Cocoon我是看了官方專門的幫助文檔以后才感覺入了門。而SOAP是經過別的書籍加上項目中的實際運用才真正學會的。

    這 時到我剛進公司已經兩個月過去了,時間已經到了9月中旬的樣子,還有一個月我們公司新員工入司培訓就要結束,也意味著還有一個多月我們就要開始接觸正式項 目。這時的我寫B/S程序僅僅是JSP + JavaBean的水平,連JSP中的TAG都不會自定義,看見別人網上的程序自己還自己定義Tag很是羨慕,于是決定把那本《JSP設計》認真看完,把 自定義Tag的功能實現。后來看了以后發現原來那本《JSP設計》的精華都在最后的150頁內,最后那部分先是介紹了自定義Tag的定義方法以及Tag定 義所帶來的一些好處。自從學會了如何自定義Tag,在后來公司的項目中自己也根據項目的特點定義了一些共通的Tag,大大方便了不少項目中的開發人員,提 高了生產力。這本書而且也說了一下B/S開發的兩種Web Module。在這里,我第一次知道了Web開發可以用一個Servlet作為控制器,用JSP僅僅作用于表現層,這也為以后掌握MVC打下了很好的基 礎。

    9月中下旬掃完了《JSP設計》的尾巴后,有一次跟公司給我們培訓的老師在閑聊時談到了項目開發,我詢問他項目是不是用JSP和 JavaBean來開發,他笑著和我說不是這樣的,而是基于Framework來進行開發。比如Struts就是公司的常用Framework。 Struts這東西以前也好像聽說過,不過從來也只是聽說而已,并沒有看過。得到這個信息的我,為了能盡快熟悉實際項目的開發環境,便決心盡快學會 Struts。當時的市場上講解Struts的書只有一本,也就是Oreilly的《Jakarta Struts編程》,不像現在連《Struts in Action》的中文版也有了。我去了書店買來開始回家看,剛開始看的時候覺得如同云里霧里一般,因為這本書歸納總結性的東西很多,比較適合當參考手冊, 而真正帶領新手入門這一塊做的并不好。所以當我把這本書都看完了以后,還是不會用Struts編寫一個程序,只是感覺自己朦朦朧朧懂了一些概念,比如 MVC什么的。在公司我們的培訓也結束了,通知在國慶節過來以后的第一個星期——大概是10月10日左右進行考試,最后根據培訓考核情況來調整薪水。當時 跟我一起培訓的新員工基本上沒有人會Struts,其實這個時候連會用JSP + JavaBean寫一個最簡單的登錄畫面的人也沒有多少個,大部分人還是模模糊糊懂一點,但是具體做東西還是做不來的那種水平。國慶節大概10月5號的我 去了趟書店,突然發現書架上新上了一本書,就是孫衛琴編寫的《精通Struts》這本書。孫衛琴的書我倒是聽說過,就是在這之前出的一本關于Tomcat 以及Web App開發的書,據說挺容易上手的。我翻看了這本書的目錄結構,覺得可以值得一讀,于是雖然價格不菲,仍然買回家當天就研讀起來。憑我的讀后感覺來說,這 本書也許學術價值并不高,說得深入的東西基本沒有,但是特別適合初學者,通過Hello World這種例子迅速讓你手把手編寫出第一個Struts程序。就這樣,在這本書買回來的第二天,我自己就用Struts寫了一個很簡單的登錄畫面程 序,當時的感覺別提多興奮了,就感覺自己入了門,以后的道路一片光明。在這里,我要由衷地感謝孫衛琴女士,寫了這么一本適合初學者的書,同時也建議沒有學 過Struts但又想掌握Struts的Java程序員們買這本書回來看(不知道我是不是有書托之嫌,我只是說我自己的心里想法)。

        國慶的假期放完了,我也回到了公司準備考核,上午是筆試,下午是上機考試。筆試分為了4塊,分別是Java,Web開發,Oracle數據庫,以及 CMMI規約。這四門除了Oracle數據庫我一向不是很擅長,只考了個中等分數以外,其他三門分數都名列前茅。不過CMMI規約老實說我也不怎么會,不 過碰巧考的很多都是我知道的東西。下午是上機考試,題目給出來了,我一看題目,原來是一個最簡易的成績查詢系統,也就是數據庫里面已經有一些學生成績,我 們寫一個檢索頁面,可以輸入或者選擇檢索條件,把符合我們檢索條件的數據輸出并顯示在畫面中。我于是拿剛學會不久的Struts進行編寫,在3個小時內把 整個頁面都寫好了,并且還自定義了一個Tag來顯示數據信息。考完以后我才知道總共也就五六個人程序可以運行,而且只有我一個人用的是Struts,其他 人基本都是最簡單的JSP + JavaBean,有的人連JavaBean都沒有,數據庫操作全部寫在了JSP頁面中。毫無疑問,這次上機考試我得到了好評,給了最高分。在全部的培訓 成績中我也居前兩名,我們部門新員工我排第一名。帶著這個成績,我們的入司培訓基本結束,開始進入部門做實習項目。

        雖然說我們正式進了部門,不過試用期還沒有結束,我們試用期最后一個月的任務就是做一個實習項目,當然,每天還是要進行日語培訓,因為要參加12月份的國 際日語三級考試。公司也象征性得給大家培訓了三節課的技術,第一節是Struts培訓,第二節是Web App的MVC結構的培訓,第三節是Log4j培訓,這幾次培訓下來,大部分人感覺好象云里霧里一樣,基本什么都沒聽懂,不過我由于有了點Struts的 基本知識,所以感覺收獲比較大,特別是MVC的培訓中我真正明白了視圖——控制器——模型這三層每層應該怎么處理,知道了一個Web App中如何分Java Package比較好,明白了專門有一個DAO層來處理數據庫所帶來的便捷,明白了Log在Web開發中的重要地位,這為以后的開發帶來了很大的好處。實 習項目的課題很快就下來了,要我們做一個電子相冊的B/S系統,要求有圖片上傳,圖片檢索,圖片顯示以及要用Struts來構建,這些是基本的要求,其他 功能可以自由擴張。我們部門的新員工分為兩個小Group,都是一樣的課題,互相促進和學習,每個Group還配備了一個老員工,作為督促我們的進度,防 止我們有過大的偏差等等,不過具體做東西上原則上要求是不會給我們什么幫助。首先每個小Group要選出一個Leader,結果我被大家一致選為我們 Group的Leader。在小組討論中我們先進行需求分析,大家的討論很是熱烈,主意也很多,不過基本上組員們也都是點子多,具體實現上面還都沒有想 過。對于他們的那些建議,絕大多數我決定都作為我們要實現的目標,但也有少部分我覺得目前以我們的水平還無法實現的,就先否決了。會議開完后,當天回家以 后我就開始排開發計劃和個人的進度,第二天寫畫面的基本設計,第三天把組員拉過來開始Review基本設計,我們組的速度還算比較快。從星期二公布課題, 到星期五就和幾個組員一起把DEMO畫面設計出來了。原來的計劃是第二個星期一開始Coding,大概花一個星期完成。不過其余組員似乎還是不怎么會 Struts,于是我回家星期六星期天基本全天都在看書寫代碼學習,花了兩天把項目基本Coding完畢。其中Web頁面部分也不再使用一開始使用 Frame的做法,而是采用了Tiles框架。Tiles的使用過后我感覺是非常好的東西,經過簡單的配置可以完成大批網頁中類似部分的構建,而且生成的 屬于一個頁面,這樣就省去了以前寫Frame時提交頁面總是要考慮設置Target以及在引用對象的時候大批Parent或者top對象使用的麻煩事了。 在開發過程中我使用了Log4j,這為我的調試程序帶來了極大的方便,呵呵,可以想象,沒有Log來調試一個Web程序真是不可想象的。

    這 段時間我是邊開發邊翻查那本《精通Struts》的,這樣,迅速把Struts中提供的許多Tag弄熟練了,為以后具體的項目開發帶來了便捷。也許是一向 以來公司的實習項目完成效果都不是很理想吧,這次我們的迅速完成比較出乎Leader的意料,綜合三個月的試用培訓,由于我在日語和技術以及實習項目中表 現都還不錯,所以定工資級別時也是同一批進公司的新員工中最高的,隨著轉正會議的結束,我也在10月底成為了公司的正式員工。大概剛剛進入11月份,我們 Group便開動一個項目,項目不是很大。當時老員工們許多都在做項目的詳細設計,我便跟著公司一位技術專家(也是當初給我們入司培訓的其中一位老師)做 起項目的Framework構建工作。當時的我才進公司,第一資歷尚淺,第二我的確也并不是很會什么東西,所以給我的任務很多都是一些模塊的 Utility的設計。比如通用的Check方法啊,CSV以及定長文件的讀取解析什么的啊,還有某些在IE中可以實現的效果如何在Netscape中也 能實現同樣的效果等等。雖然這些東西在現在看來并不是很復雜,但是當時自己的確隨著做這些東西而學到了很多很多。比如使用JDOM對XML文件的解析啊, 很多Check方法的小技巧啊,IE和Netscape究竟有什么地方不一致,該如何解決等等,這些都在這幾天內了解了很多。在這幾天中,我通過網上查找 資料,臨場迅速學習了Java反射的使用方法,并且自己邊學邊寫實例,實現了各種情況下的反射案例。我個人覺得掌握Java反射技術是非常重要的,這讓你 可以寫一些通用的工具。如果不會反射技術的話,也許你永遠只能寫一些針對特定情況下的解決方法。而會使用反射以后,你可以寫一些代碼,這些代碼可以用在許 多地方,達到自己擴展甚至構建Framework的效果。在這個項目中,我使用了自定義Tag和Java反射技術,定義了些項目中比較需要的通用的 Tag,方便了大家。

        后來聽老員工說新員工進公司就開始做Framework是以前從來都沒有過的事情,因為我們Leader對我希望比較大,所以想盡可能培養我,讓我早點挑 起項目大梁,所以給我的成長提供了一次又一次的機遇。11月中旬以后,項目開始進入編碼階段,我也第一次看到了正式的項目設計書。第一次看到設計書的時候 我都覺得自己腦子有點懵,一大堆日語什么含義自己不是很清楚,而且感覺根本無從下手,不知道從哪里開始看比較好。項目擔當耐心得和我說了設計書的格式以及 究竟什么地方是什么一個含義,以及Coding的時候按照什么個思路來看設計書。再加上項目中有老員工先寫了個Sample,讓大家看了標準的一個流程, 所以我們就依葫蘆畫瓢,慢慢得把一個畫面一個畫面Coding完畢。當然了,后來也有測試員來測試我們的畫面,發現bug后就發Bug Report給我,那一個月就是在Coding,修正Bug中渡過的,這個項目是用Struts做的,因為不大。所以也沒有再用其他的 Framework,數據庫操作那里只有個非常簡單的單表操作DAO層,其余的DB操作都是自己通過JDBC操作語句來完成的。在這第一個自己接觸的真正 項目中,我自己學到了很多B/S設計的技巧,感覺很充實。不過書本學習方面我也沒有閑著,我為了能夠深入了解Java,大概在11月中旬左右開始看《深入 Java虛擬機》這本書,由于內容比較深入,所以看得也有點吃力。書翻譯得和寫得都還不錯,值得一看,我一直看了前八章,看到Java程序運行細節后就沒 再看了,大概看到了12月底的樣子吧,呵呵,有時間的話決定把后面的部分也看完。這本書看完后收獲就是了解了Class文件的實質,Java的安全模型, 虛擬機是如何工作的。這些知識對后來調試程序Bug或者Exception的時候非常有好處,可以把以前自己覺得莫名其妙的錯誤的原因找出來,不像以前遇 到很古怪的Exception的時候怎么死的都不知道,從讀完這本書以后,在以后的調試異常中很少再有不知所以然的感覺了。

        2004年12月底的時候,我的第一個項目也做完了,由于我空閑著,Leader便在星期三的時候把一個公司內部開發的Source統計的小工具讓我進行 修改,使得添加一個比較有用的功能。東西給我的時候基本沒有任何文檔,在我手上的就是一堆源代碼而已,界面是用Swing制作的,因為沒有專門在UI上進 行精心設計,所以說不上好看,典型的Java編寫的圖形界面的程序的樣子。軟件不是非常大,估計在1萬行源代碼以內,不過對于只有一個人修改來說,也比較 夠嗆了。還好我在剛學Java的時候用JBuilder寫了一些Swing的程序,現在還是對Swing有概念的,所以拿到手上以后經過仔細分析,逐漸理 清了頭緒。經過修改和自己測試完畢后,覺得還比較滿意,達到了預期的目標,于是在星期五的時候提交給了Leader。通過這次,對Swing的開發又加深 了印象,自然,在有的細節技巧方面受益匪淺。

    元旦很快來臨了,在年底以前,公司覺得有必要學習下Hibernate,雖然我們目前的項目中 還沒有用過Hibernate,而是用另外一個公司內部開發的ORM工具,不過幾名技術專家初步對Hibernate感覺后覺得Hibernate的功能 要強大的多,而且是開源的,不斷有人在推動,升級,所以有必要我們要學Hibernate。這次的學習采用學習小組的形式,也就是公司內部先抽幾名員工 (主要是技術部門的,當然,開發部門如果有興趣的話也可以考慮)來進行深入學習,然后定期開會交流互相學習,達到短時間內先行的幾名成員迅速深入掌握 Hibernate的形式。由于我第一處于空閑狀態,第二也比較有興趣,而且跟技術部門的專家們也比較談得來,所以我也加入了其中,成為幾名學習小組中成 員的一部分。我們學習資料主要就是《Hibernate in Action》英文版一書以及官方的幫助手冊。我負責其中對象操作,Transaction和Cache,還有高級Mapping關系的設置幾個部分的學 習。由于資料都是全英文的,所以看書速度并不是很快,不過還是初步得到掌握了。大概學習了半個多月的樣子,我們各自基本學習完畢,互相交流后并且寫下了讀 書筆記,用來后面具體項目開發時候參考用。通過這大半個月的學習,我個人覺得提高了非常多,在這之前,我只知道有ORM這種東西,但是從來沒有使用過,也 從來沒有看過。自從學過了以后,我不僅對Hibernate在代碼編寫時的使用比較熟悉了,而且對Hibernate的配置以及許多底層的知識有了很清楚 的認識,讓自己在數據持久化方面的認識提高了大大的一步。

        元旦過后,雖然一邊在學習Hibernate,不過由于下面項目的需要,Leader跟我說要我學一下Unix下的Shell編程,因為 項目中許多批處理會用Shell來啟動。UNIX命令在學校時候學過的,不過這個時候已經忘記了很多,只是翻閱資料的時候還能回想起來不少命令。 Shell并不難,如果有了編程基礎,學習Shell編程也很快的,總體感覺就是編程語言大同小異,從基本語法來說,不外乎賦值、條件、循環這幾種類型。 只要迅速掌握這幾種類型在這種編程語言中的編碼格式,那么你就可以迅速掌握這門語言最基本的編程能力。Shell經過一周的學習后覺得感覺不錯,不僅可以 順利看懂別人寫的Shell程序,而且自己可以在Linux下順利寫出符合自己需求的Shell程序并能順利執行。但是突發事件總是有的,那個項目突然決 定延后兩個月,所以前一個星期的學得Shell等于暫時派不上用場了。不過嘛,多學一樣技能總是沒有害處的,而且又復習了那么多Unix命令啦,感覺還是 很不錯的。于是我又進入了不在項目中的真空期了。

        但是好景不長啊,好日子還沒有過上兩個星期,公司去年做的一個比較大的項目開始了2期開發,我也被一下拖入了項目中。說起那個項目,公司好多人還心有余 悸,據說去年那個項目開發的時候,大概50多號人干了好幾個月,每天都是11點以后才有可能回家,周六是鐵定加班,周日是看情況,晚上就算加班加到凌晨3 點也不是什么奇怪的事情。當時大家都說多來幾個這種項目大家就要死了,這次這個項目的2期過來了,大家精神又一次緊張起來咯。一開始照例是項目會議,聽完 項目經理描述以后,大家也放心了不少,這次雖然說是二期,不過規模不大,只需要15個人左右干一個月就能搞定。主要是把項目一期里面一些地方進行改修,當 然也有需要新的畫面的開發,不過相對于去年的那塊不是很多而已。對我來說這次是個很大的考驗,因為項目是二期,項目組內除了我,其他的人都做過1期開發, 所以對項目結構都很清楚。這次項目開始并沒有什么培訓,所以我只能單獨看1期的源代碼來熟悉項目結構什么的。這個時候項目經理把我叫去要我辦理護照,準備 這個項目派遣我去東京現場維護。

    這個項目是個比較全面比較大的項目,服務器采取了集群的方式,數據量也是千萬乃至上億級別的,所以性能要求 特別高。在技術方面用到了很多,使用EJB來控制Transaction,使用了ORM工具來操縱DB數據等等等等。而且由于比較龐大,所以服務器初始化 的那塊為了Load上去大批配置信息,代碼量極其龐大,在權限控制的那塊地方,代碼非常難以讀懂。這也給我一開始的學習代碼帶來了很大的一塊麻煩。不過總 算靜下心來后把整個項目框架以及實現手法基本摸清楚了,這個時候覺得非常開心,而且對Web應用程序的構造心里面也非常充實,覺得自己已經具備寫 Framework的初步能力了。

    項目是緊張的,基本上每天晚上都要加班到11點,然后打車回家,哈哈,公司報銷。而且臨近過年,這么加班 也一點都感覺不到過年的氣息。不過我也不能因此放松了自己的學習。我覺得自己的基礎應該算比較好了,便開始啃起另外一本大部頭——《Java與模式》。一 直以來我對設計模式的感覺就是一些已經成型的,久經考驗的代碼框架,具有非常好的可擴展能力以及非常好的代碼健壯性。不過初學者最好不要看設計模式,因為 你接觸的代碼不多,如果貿然看設計模式的話,會造成不明白為什么這種設計模式好,究竟好在什么地方的情況下就在代碼中亂套設計模式,對自己的以后編碼發展 帶來不利的影響。每一種設計模式都有每一種設計模式的特點,自然也有他們自身的適用范圍,比如拿最基本的單例模式(Singleton)來說,適合于做配 置信息讀取器,主鍵產生器等全局唯一的東西。如果初學者不明白這些,拿單例模式亂套,什么都用單例模式,比如把普通傳遞數據用的JavaBean也做成了 單例模式,帶來的惡果就嚴重了。這本《Java與模式》我是從頭到尾認認真真看了,每看完一個模式都會仔細回想以前看的代碼哪里用到過這個模式,總會自己 想想這些模式適用于哪些地方。因為這個時候我自己編寫的代碼行數也已經很多了,所以看見這些模式就會特別有感覺。經過50多天的認真研讀,所有模式都被我 消化了下去,并且使得我的對程序開發上面的認識提升了非常大的一步。順路說一句,這本書寫得非常好,例子很多,但是不復雜,有一定代碼編寫經驗的人就可以 看懂了。不過看懂并不是最重要的,重要的是消化下去,用來理解以前看過的代碼的精華,這樣自己才能得到提高。

        這個項目雖然很緊張很忙,不過我還是適應了下來,而且對整個項目結構什么的都有了比較好的整體的把握。項目橫跨了整個過年期間,所以在過年的那幾天都必須 開著手機,怕有什么突發事件要求去加班。簽證在2月4日左右送過去簽,Leader跟我說因為在過年期間,所以簽證可能會比較緩慢,比較難簽,不過一般情 況下1個月應該足夠了。原計劃我是跟另外兩個同事3月6日去東京,這樣算算也差不多。不過中國有句話叫好事多磨,呵呵,用在我身上的確不過分,我的簽證3 月3日日本領事館才簽,三月四日送到南京。3月5日和3月6日是雙休日,所以3月7日簽證才送到我手上。由于計劃是3月6日派人去東京,所以只好派另外一 個身上有簽證還沒有過期的人代替我過去,這次的機會就算泡湯咯。不過我并不是很在意,因為公司這里去東京出差的機會狠多,特別對于開發人員,據說工作幾年 后一聽到去日本出差就不樂意,畢竟也背井離鄉么。

        在這個項目的途中,大概在2005年1月底2月初的時候公司也開始進行了制作詳細設計的培訓,我雖然在項目中,不過也成為了其中一員。這次培訓總共大概6 次課,每次2個多小時,雖然時間不長,不過把詳細設計的要點以及思路和容易出錯的地方都說了出來,感覺很是不錯,這幾次課的培訓后,雖然可能要我立即進行 詳細設計編寫還有點困難,不過心里面已經有了不少底,我覺得經過一段時間后的鍛煉,我應該可以有進行詳細設計的能力了。

        3月初這個大項目結束后,本以為可以休整下,不過很快通知我3月7日加入另外一個項目,其實也不算一個正式的項目,屬于公司知識庫的一個信息查詢模塊。由 公司的一個技術專家負責,那人也就是我進公司時候第一個項目中帶著我的那個技術專家,說起來我和他還真有緣,現在我這個項目還是跟著他,而且公司里面唯一 一個和我同月同日生的人,真是很巧的巧合呢。他人挺好,很熱心,所以我也從他那學到了很多東西。這次由于不是正式項目,所以并沒有什么基本設計書,而是他 給我們開會議的時候大致說了下項目的內容,每個畫面的具體功能以及數據庫表格的設計。由于這次項目規模很小,總共就12個畫面的量,所以不采取 Struts等Framework,而是采用比較原始的JSP + JavaBeans的構造。我們每個人根據他所跟我們講解得功能寫每個人自己分配到的畫面的詳細設計,其實也不算真正的詳細設計,就是每個人把自己操作的 那塊的具體邏輯設計寫出來,然后和他一起review一次,再開始編寫代碼。詳細設計這里我做的很快,當天下午就把自己分配到的兩個畫面業務邏輯什么的都 寫好了,星期一布置得任務,我星期三的時候全部編碼自測完畢提交,所以我的感覺就好像這個小項目一瞬間就結束了。

    日本每年財務結算是在3月 份,所以我們歷來的習慣就是每年1月和2月很忙,3月開始清閑,一直可以到5月左右會接到個大項目昨。所以接下來就真正到了我的空閑時期,沒有項目的壓 力,我可以自由學我自己喜歡的東西。很久以前買了本《精通EJB》第二版,可是一直以來我覺得自己功力尚淺,所以沒有看,這次我想認真學學EJB。雖然大 家公認EJB并不是很好,不過歷來受到批評的都是EJB中的Entity Bean部分,這部分我覺得可以借助Hibernate來彌補,而會話Bean和消息驅動Bean則還是挺不錯的。這次也當學一門技術,學習其好的東西, 不是很好的東西就當作以后開發時候的借鑒。《精通EJB》這本書我的感覺是書質量比較好,不過翻譯的水平稍微差了點,特別是有不少錯誤,而且很低級的錯誤 居然校對的時候都沒有發現,不能不說是個比較大的瑕疵。但是它不失為一本EJB的好教材。從一開始的JNDI開始,然后講解了對象序列化,RMI- IIOP等等。這些以前都模模糊糊,或者是看過了但是還不知道究竟有什么用。但是經過這次的學習以后,對這些分布式系統比較需要的東西有了進一步的了解, 感覺頭腦中比較清晰,究竟RMI是什么樣的工作原理,怎樣實現一個遠程方法調用等等。接下來的EJB學習,自己用Eclipse + Weblogic邊看書邊動手,寫了一個個自己的學習小程序。我個人感覺看書最好就是邊看邊自己動手寫小學習程序,這樣比光看不練能學到多得多的東西。學 了EJB后覺得腦子又清晰了很多,看見一個案例后頭腦中就會有好幾種如何解決的方法,幾種方法互相在頭腦中自己比較,經過這樣,大大提高了自己的思維活躍 性。

        3月中旬開始由于公司比較清閑,大部分人處于沒有項目的狀態,所以公司舉辦了第一屆全公司范圍的編程競賽。公司只指定了題目為一個日歷系統,要求具有日程 記事等功能,其余功能自由發揮。這次不再采用團隊形式了,而是采取各自為戰的策略。自從培訓過詳細設計以后,我頭腦一直有如何寫詳細設計的思路,這次我自 己首先指定了開發計劃,保證自己控制自己的進度。接著進行了需求分析,確定了我有哪些功能。然后在自己的基本設計中開始進行數據庫結構設計。這次我決定采 用Hibernate+Struts的結構進行編寫,這樣我的數據持久層操作大大簡化,而且功能上也增強了許多。DB設計好以后我開始DEMO畫面的制 作。說實話,我美工水平實在不怎么樣,可以說雖然一般網頁的效果我都會自己做出來,不過具體網頁設計成什么樣我還真是一竅不通。還好 Dreamweaver我還算算是比較熟練,自己搗鼓搗鼓也想摸象樣把DEMO畫面給設計出來了,不過美觀不美觀我就覺得不怎么樣了,只是我能力有限,也 沒辦法設計的更好看,這個時候我感受到了一個項目中美工是多么重要啊。下面的詳細設計自己寫得很開心,把需要的功能都用文字反映了出來,這也算我寫成詳細 設計樣子的第一份詳細設計了,做完挺有成就感的。接下來首先構筑自己這個小項目的Framework,經過公司兩個正式項目的洗禮后,那兩個項目的 Framework我都認真研讀過源代碼的,所以我自己有了自己心里一套Framework的構造方法,特別是如何把Struts和Hibernate結 合起來的結構,自己有自己的一些想法。在這次Framework構造中,我沒有復制任何公司以前的代碼段,都是憑著自己對以前看的代碼理解后寫出來的。這 次項目我覺得對自己的提高也很大,首先鍛煉了自己詳細設計的能力。其次,自己雖然學習過Hibernate,不過從來沒有這么樣應用過 Hibernate,這次讓自己大大提升了實踐運用的經驗。公司由于知道這時也沒有一個真正的項目使用Hibernate,所以這時的我也算公司內部 Hibernate使用經驗最豐富的人了,這也為了后來我協助別的使用了Hibernate的項目解決問題的原因。再次,我這次自己寫了 Framework,特別在批處理方面,運用了許多剛學會理解掉的設計模式,這些模式讓我的程序更具有健壯性和可擴展性,讓我在設計方面的能力大大提升 了。

    這次的編程競賽我寫得比較認真,代碼量的確也很大,總代碼行數超過了3萬行,有效代碼行數也在1萬行以上。經過公司專家們的評定后,我 得到了第一名,雖然沒有什么獎品,不過肯定了我這段時間以來的努力,我還是很開心的。而且這次的編程競賽讓我大大增加了編碼的熟練度,而且也在其中演練了 許多自己想出來的編程技巧,為以后的發展帶來很大的好處。

        從4月份開始,公司由于比較清閑,所以部門內部開始進行各種培訓。我們部門開展了3項培訓,第一項就是編程能力培訓,第二項是Oracle數據庫技術培 訓,第三項是測試技巧培訓。在編程能力培訓中,主要就是把原來沒有注意的細節采取大家討論,輪流講課的方式進行的,雖然其中很多東西我原來都是知道的,不 過也有原來不清楚的地方。而且經過了這次互相討論,更加加深了印象。在Oracle培訓中我覺得收獲很大,這個Oracle培訓采取了傳統的上課的模式, 由我們開發小組中一個取得OCM的老員工給我們講解。對于Oracle,我原來基本上就只會寫寫SQL語句,具體Oracle有什么特別的功能,可以做什 么我也不是很清楚。但是這次上課從Oracle的啟動原理開始,讓我知道Oracle中究竟有什么,Oracle數據庫各部分在磁盤上是如何存放的, Control File,Redo File究竟是什么意思,在數據庫中起什么作用,數據庫是怎么依賴他們運行的,還有如何對Oracle進行系統管理員級別的管理,如何在不停止數據庫運行 的情況下進行數據庫的更新、升級、備份等等。這些東西雖然非常有用,但在平時的開發是學不到的,這次趁著這個機會大大提升了自己Oracle的水平,感覺 非常開心。數據庫一向是我的弱項,在上大學的時候我SQL語句能力只是一般,數據庫管理配置什么基本一點都不懂,通過這次集中的培訓,我覺得自己的能力又 進一步增強了,弱項也在慢慢退卻。在三項培訓中最后進行的測試培訓我承認我沒有怎么認真去學,所以學會的也就是些測試概念,具體的測試技巧什么的還是不怎 么會。現在開發和測試的結合性越來越高,看來要下下功夫,以免給淘汰咯。

        提了這段時間在公司的進展,還沒說自己的學習呢,這段時間正好看見中文版的《JUnit in Action》出版了,在書的背后寫著“如果沒有看過這本書,就不要對J2EE進行單元測試”這句話。我早在去年就了解了JUnit的強大功能,再加上 Ant的話對于回歸測試是非常便利的。趁有時間,我便于3月底4月初的時候開始看這本書。當時的我看《精通EJB》第二版看了一半,發現其中錯誤越來越 多,而且文字也有些地方不知所云了,所以扔下不再浪費時間看那本書,專心攻讀《JUnit In Action》。憑良心說,Manning的這套In Action叢書的確很不錯,從我先前看的《Hibernate In Action》英文版就能看出來,其中對代碼的編排非常方便讀者,感覺可以很順利的看到你所想看到的代碼片斷。這套《JUnit In Action》也是一樣,博文視點的紙張還是很好的,排版使用了Manning的風格,閱讀起來很舒服,所以我讀得很快,大概就兩個多星期就讀完了這本 400多頁的書。感覺的確收獲不淺,首先,原來的自動化配置工具中只會使用一個Ant,其他的基本沒聽說過,在這本書上詳細介紹了Maven。聽過書中的 講解以及自己的試驗,的確覺得Maven功能很強大,不過感覺起來配置比Ant要麻煩,所以我自己的感覺是Ant在項目中還是會廣泛應用,不過Maven 在大型項目,特別是整個Site中有很大的用武之地,對于我們來說,使用的方法都是很簡單的,掌握如何編寫配置文件才是我們的關鍵。

    書對 JUnit與Cactus在J2EE的測試手法上給了大量的事例,給人的感覺非常好,In Action這套叢書最大的優點就在這里,用實例代碼片斷讓你迅速了解一樣東西。在實際工作中其實JUnit應用也是比較廣泛的,特別如果采取測試驅動開 發的話,JUnit是必不可少的一部分。在TagLib測試,JSP單體測試,數據庫測試和EJB測試都是我以前根本沒有看過的東西。其實這次雖然學是學 會了,不過真正做的時候還是要有個代碼例子依葫蘆畫瓢。我想大家肯定也都有這種感覺,寫程序的時候先找一段有點相似的代碼片斷Copy過來,然后看看要修 改什么地方,真正從頭到尾自己用手寫的代碼片斷是不多的,除非你已經爛熟于心。不過這本書快看完的時候,項目又來了。

        這次做一個企業的MIS系統,與以往不同的是,這次客戶給了一個比較龐大的基盤,封裝了近100個Tag,基本上把各種各樣有可能遇到的操作都封裝到 Tag里面了。而且所有的畫面顯示等信息都是放在數據庫的Table中,所以這次要求不寫任何程序代碼,只是學會使用好這些Tag,然后利用這些Tag寫 出Jsp頁面。一開始的時候還真是頭疼,這些Tag一個都不明白,而且文檔不是非常齊全,Tag的Source中注釋也比較少,學習起來不是很方便。我們 一共3個人投入到這個項目的前期準備中,在第一個星期的學習中大家互相分配好個人學習的模塊,隨時互相交流。在后來的深入中發現這個項目的業務邏輯操作會 使用PL/SQL以及存儲過程來進行,對于我來說,PL/SQL是從來沒有做過的東西,就叫做一竅不通,于是我需要從頭開始學習PL/SQL,以及如何編 寫存儲過程。我從網上下了一個PL/SQL的電子書籍,然后在公司花了一天時間進行學習,個人用的是Toad來調試PL/SQL的,雖然別人喜歡用 PL/SQL Developer來進行開發,不過我還是比較鐘愛Toad,而且Toad的確功能也很強大,使用起來也很方便就是了。經過第一天的PL/SQL的學習, 基本掌握了全部語法以及存儲過程的書寫格式等等,開始能夠寫寫非常簡單的PL/SQL。接下來的兩三天不斷鞏固熟練,客戶那里也發過來幾本詳細設計讓我們 練習著做一下。有了實際的詳細設計,再加上我們之間互相交流,我們提高的都很快,大概過了三四天,大家就把基本詳細設計代碼編寫完畢了,而且經過實際鍛 煉,我的PL/SQL編寫存儲過程的水平也大大提升,已經可以滿足開發中的需要了。

    這個項目因為如果我們一開始做的能讓客戶滿意的話,后續 的項目將會比較龐大,所以Leader決定把我們Group比較空閑的其他人也先培訓一下,讓他們有點感覺,到以后正式開發的時候也能迅速進入狀態,負責 給他們培訓的任務也就交給了我。說起來是培訓,其實也就是把大概流程以及方法通過一次會議的形式告訴他們,然后把我前面已經作好的那個畫面作為他們的作 業,要他們看著設計書自己把畫面制作出來。這個時候也要放勞動節了,黃金周可以休息一個星期,想想就覺得很Happy。勞動節的時候基本沒有怎么學習,只 是先把XML-RPC仔細看了下,學會了如何去寫一個XML-RPC的應用,接著稍微看了點SOAP,看得也不錯,只是些簡單的SOAP的例子而已,那些 SOAP的復雜東西都沒有看。

        很快就五一黃金周七天放假放完,八號開始上班,上班后就開始正式做節前就定好的那個項目,這次性質屬于試做,也就是人家先發一批設計書過來,我們然后開始 Coding,大概做了一周后,我自己害了急性結膜炎,只能回家休息,這次可真的是只能休息了,眼睛覺得特別漲,不要說電腦了,連書都不能看,看了眼睛就 疼。所以在家就只能睡大覺,過了一周眼睛大概才復原,可以去公司上班了。回到公司以后,Leader通知我說我不用去做上次那個項目了,要我加入我們 Group的一個新的項目,這個項目比較大,當時還處于東京剛剛做好基本設計,我們從東京把任務接下來,準備發回來做詳細設計。我進去的時候項目才開始三 四天,基本上還沒有做什么,這次我進入了詳細設計制作小組,開始進行這個項目的詳細設計的制作。

        由于我屬于第一次在正式的項目中參與詳細設計,所以很多東西都不明白,特別是業務上面的東西,許多日語中的業務術語我根本不明白,比如什么賣切,切替,仕 入什么的。看著基本設計書,感覺跟以前看詳細設計書有很大的不同。具體的東西寫的少了,業務流程邏輯框架什么的比較多,所以需要首先把業務內容都熟悉了, 才可能寫出詳細設計來。這次的詳細設計我也不是孤軍奮戰,而是有一個進公司4年的老員工帶著我一起做,我的任務很輕,不過重點是學會如何去寫詳細設計,也 許下次再有一個比較大的項目,就沒有別人再帶著我,而是我自己一個人去完成詳細設計了。大概詳細設計寫了20天左右,我被通知當天把手上的一份詳細設計寫 完,第二天進入方式設計小組進行方式的設計。

    進入方式小組以后,接到的任務就是好幾個編寫DB操作方面的代碼自動化生成工具。由于這次DB 方面并沒有非常強制性的那種規約,所以SQL語句的編寫可以說比較隨意,這就給我工具的編寫帶來了很大的難度和挑戰。這次負責管理方式小組的人仍然是進公 司以后經常帶著我的那位技術專家,所以也真算很巧呢。寫工具其實很對自身代碼編寫的提高也很有好處,因為首先客戶那里資料會不斷修改,這些工具你為了以后 客戶更新資料后你能順利更新工具,你需要設計一個優良的Framework,不一定需要多么復雜的Framework,不過一定要盡量把程序各方面的耦合 度盡量降低,這樣才有利于自己對工具進行擴展。緊接著很快,項目代碼編寫開始了,我的任務算中等偏上,有2個畫面和一個批處理需要編寫,復雜度還算比較繁 一點。這次項目需要編寫JUnit程序,每天都要進行回歸測試,保證代碼Method的正確性。JUnit雖然自己會用,但是從來沒有在真正的項目中使 用,所以在真正用的時候感覺有點手足無措。以前做JUnit從來都是覺得給個參數,檢測一個返回值就好了,其實不是那么回事,業務邏輯復雜了,自己需要做 大量的Stub來模擬真實的Class的返回值。設計一個好的Stub是比較困難的,特別在數據庫內容比較豐富的時候,一張數據庫Table就有上百個 域,工作量可見一斑了。項目要到05年9月中旬才會結束,所以現在還在緊張的開發階段。我寫了JUnit的感覺就是難點不在如何去寫JUnit程序,而是 如何去設計測試用例。對于我們這樣不是以測試出身的程序員來說,設計測試用例是很痛苦而且很艱難的事情,估計有過相似經驗的人肯定會表示贊同。

        當然我一邊在緊張的做項目,對于書本的學習也沒有閑著。這段時間抓緊把侯捷的Word排版藝術掃了一遍,看完覺得收獲頗豐。雖然我以前覺得我在Word上 用得挺不錯,日常的一些操作什么的我都會,不過看這本書的中間我發現我還是有很多地方不會的,也學到了不少東西,在以后的Word排版中會很受到好處。由 于項目用到了Spring知識,所以我也看了網絡上那個流傳廣泛的Spring開發指南的PDF看了一遍,感覺長了見識,對IOC以及DI有了進一步的了 解,也理解了為什么需要采用IOC以及DI。不過這個也沒有深入下去仔細看,以后等項目稍微空閑一點的時候一定再把Hibernate和Spring好好 看一下,學習人家的設計理念,提高自己能力。對了,也許最重要的是我最近在看一本書,就是《J2EE核心模式》的第二版,我當時原來準備看電子版的這本 《Core J2EE Patterns》的,不過突然在書店發現這本書的中文版出來了,而且譯者有熊節的名字,也就是跟侯捷一起翻譯《重構——改善既有代碼的設計》的那個譯 者,我比較相信他翻譯的水平,于是買回來看,雖然項目非常緊張,我一個月算上周末需要加班在100個小時左右的樣子,但是我相信時間是海綿里的水,只要去 擠,肯定會有的。所以我到現在大概看了2周的樣子,已經看了300多頁,而且感覺自己的設計視野也開闊了許多,這本書的確很好,把J2EE中常用的一些模 塊原理都說了出來,說明了為什么這么做好,這么做如何減少了耦合性,提高了可維護性等等,總之,有1年以上J2EE開發經驗而且覺得自己對J2EE有了比 較好的了解的開發人員我強烈推薦看這本書。看了這本書以后我都在回想以前設計的一些框架,一些模塊,覺得自己有很多地方當時設計的時候覺得很精巧,不過卻 屬于弄巧成拙,加大了模塊的耦合性,所以在修改的時候比較難于下手。

    posted @ 2005-12-26 21:43 Dion 閱讀(2592) | 評論 (8)編輯 收藏

         摘要: 華為軟件編程規范和范例 document.title="華為軟件編程規范和范例 - "+document.title 目  錄1 排版62 注釋113 標識符命名184 可讀性205 變量、結構226 函數、過程287 可測性368 程序效率409 質量保證4410 代碼編輯、編譯、審查5011 代碼測試、維護5212 宏531 排版11-1:程序塊要采...  閱讀全文
    posted @ 2005-12-20 08:59 Dion 閱讀(2982) | 評論 (3)編輯 收藏

    主站蜘蛛池模板: 亚洲黄色在线网站| 久久亚洲中文字幕精品一区四| 亚洲香蕉网久久综合影视| 亚洲欧美成aⅴ人在线观看| 日韩亚洲国产高清免费视频| 亚洲网红精品大秀在线观看| 99在线热视频只有精品免费| 亚洲AV乱码久久精品蜜桃| 一区二区免费视频| 色拍自拍亚洲综合图区| 午夜免费福利视频| 亚洲美女aⅴ久久久91| 无码国产精品一区二区免费式直播| 久久久久亚洲AV片无码下载蜜桃 | 狠狠热精品免费观看| 夜色阁亚洲一区二区三区| 美女扒开尿口给男人爽免费视频| 啊灬啊灬别停啊灬用力啊免费看| 国产亚洲蜜芽精品久久| 亚洲成AV人在线观看网址| 皇色在线免费视频| 人人狠狠综合久久亚洲88| 99久热只有精品视频免费观看17| 亚洲欧洲日产韩国在线| 四虎成人免费网址在线| 免费国产草莓视频在线观看黄| 亚洲自偷自偷偷色无码中文| 三年片在线观看免费观看大全动漫| 亚洲一区二区三区首页| 最近的免费中文字幕视频| 国产精品国产亚洲区艳妇糸列短篇 | 亚洲成av人片不卡无码| 99re热免费精品视频观看 | 免费人人潮人人爽一区二区| 91麻豆精品国产自产在线观看亚洲 | 日本免费人成黄页在线观看视频 | 久久精品国产亚洲Aⅴ蜜臀色欲| 女同免费毛片在线播放| 亚洲免费福利在线视频| 国产亚洲精品免费视频播放| 91短视频免费在线观看|