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

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

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

    狂奔 lion

    自強(qiáng)不息

    2006年8月17日

    淺談Java中的同步的方法和原理

    Java的內(nèi)存模型中Thread會(huì)附有自己的堆棧,寄存器,必要時(shí)需要和主存即heap之間同步。
    可以使用Synchornized關(guān)鍵字和Concurrent包中的Lock可以保證線程互斥和可見性。

    互斥性體現(xiàn)在類鎖或者對(duì)象鎖上,每個(gè)對(duì)象自身都包含一個(gè)監(jiān)視器,該監(jiān)視器是一個(gè)每次只能被一個(gè)線程所獲取進(jìn)入的臨界區(qū),可以通過wait和notify來退出和準(zhǔn)入臨界區(qū)。可以看出這是一個(gè)生產(chǎn)者-消費(fèi)者的模型。而Concurrent包中的Lock為了能夠獲得更好的性能和更好的擴(kuò)展性,以及不依賴于關(guān)鍵字的可讀代碼,自己實(shí)現(xiàn)了這樣一個(gè)生產(chǎn)消費(fèi)隊(duì)列,也就是AbstractQueuedSynchronizer,被稱為AQS的機(jī)制。每個(gè)Lock都內(nèi)置了一個(gè)AbstractQueuedSynchronizer。需要說明的是AbstractQueuedSynchronizer內(nèi)部實(shí)現(xiàn)采用了CAS機(jī)制,通過getState, setState, compareAndSetState訪問控制一個(gè)32bit int的形式進(jìn)行互斥。

    那么可見性是如何保證的呢?

    對(duì)于關(guān)鍵字的同步機(jī)制,其實(shí)可見性就是線程和主存之間的同步時(shí)機(jī)問題。共有4個(gè)時(shí)間點(diǎn)需要注意:
    1 獲取或釋放類鎖/對(duì)象鎖的時(shí)候。Thread保證reload/flush全部變更
    2 volatile就是flush on write或者reload on read
    3 當(dāng)線程首次訪問共享變量時(shí),可以得到最新的結(jié)果。
    題外:所以在構(gòu)造方法中公布this時(shí)很危險(xiǎn)的。簡(jiǎn)單的說,就是構(gòu)造時(shí)不逃脫任何變量,不開啟新的線程,只做封裝。關(guān)于安全構(gòu)造,請(qǐng)參考
    http://www.ibm.com/developerworks/cn/java/j-jtp0618/#resources
    4 線程結(jié)束時(shí),所有變更會(huì)寫回主存

    關(guān)于Concurrent Lock如何實(shí)現(xiàn)可見性的問題,Doug Lea大俠,只在他的論文中提到,按照J(rèn)SR133,Unsafe在getState, setState, compareAndSetState時(shí)保證了線程的變量的可見性,不需要額外的volatile支持,至于具體這些native做了哪些magic就不得而知了,總之,最后的contract就是保證lock區(qū)間的共享變量可見性。開發(fā)團(tuán)隊(duì)被逼急了就這樣回答:
    There seems to be a real reluctance to explain the dirty details. I think the question was definitely understood on the concurrent interest thread, and the answer is that synchronized and concurrent locking are intended to be interchangable in terms of memory semantics when implemented correctly. The answer to matfud's question seems to be "trust us.”

    不過這個(gè)地方的確是開發(fā)團(tuán)隊(duì)給我們用戶迷惑的地方,在同樣應(yīng)用了CAS機(jī)制的Atomic類中,都內(nèi)嵌了volatile變量,但是再lock塊中,他告訴我們可以保證可見性。

    感興趣的同學(xué)可以下面的兩個(gè)thread和Doug Lea的thesis:
    http://altair.cs.oswego.edu/pipermail/concurrency-interest/2005-June/001587.html
    http://forums.sun.com/thread.jspa?threadID=631014&start=15&tstart=0
    http://gee.cs.oswego.edu/dl/papers/aqs.pdf

    posted @ 2010-07-09 19:49 楊一 閱讀(1860) | 評(píng)論 (0)編輯 收藏

    commons-net FTPClient API存取設(shè)計(jì)

    文件系統(tǒng)無非就是文件的存取和組織結(jié)構(gòu)。
    訪問一個(gè)文件系統(tǒng)的API也應(yīng)該是寫,讀,定位方法(Pathname?/URI?)

    FTPClient針對(duì)文件的保存和獲取各提供了兩個(gè)方法,分別是:

    public boolean storeFile(String remote, InputStream local)
    public OutputStream storeFileStream(String remote)

    public boolean retrieveFile(String remote, OutputStream local)
    public InputStream retrieveFileStream(String remote)

     

    兩個(gè)方法貌似相同,實(shí)際不同,返回流的那個(gè)因?yàn)椴荒荞R上處理流,所以需要用戶手工調(diào)用completePendingCommand,而另一個(gè)傳遞流進(jìn)去的則不需要。可能有同學(xué)已經(jīng)遇到過這個(gè)問題了,讀寫第一個(gè)文件時(shí)總是正確的,當(dāng)相同API讀寫第二個(gè)文件時(shí),block住了。這是因?yàn)镕TPClient要求在進(jìn)行流操作之后執(zhí)行completePendingCommand,以確保流處理完畢,因?yàn)榱魈幚聿皇羌磿r(shí)的,所以也沒有辦法不手工調(diào)用completePendingCommand。問題是開發(fā)者把不返回流的方法末尾加上了completePendingCommand,如果不看代碼可能根本不知道。
    文檔上說:

         * There are a few FTPClient methods that do not complete the
         
    * entire sequence of FTP commands to complete a transaction.  These
         
    * commands require some action by the programmer after the reception
         
    * of a positive intermediate command.  After the programmer's code
         * completes its actions, it must call this method to receive
         
    * the completion reply from the server and verify the success of the
         
    * entire transaction.


    但是這樣仍然還是讓人有點(diǎn)困惑,為什么都是存儲(chǔ)/讀取的方法,有時(shí)候要調(diào)用completePendingCommand,有時(shí)候不調(diào)用?更嚴(yán)重的問題是completePendingCommand調(diào)用了getReply,如果一個(gè)命令通過socket stream傳了過去但是沒有g(shù)etReply,即沒有completePendingCommand,那么下次發(fā)命令時(shí),將會(huì)受到本次返回碼的干擾,得到無效的響應(yīng)。而如果在completePendingCommand之后又進(jìn)行了一次無辜的completePendingCommand,那么因?yàn)镕TP Server上沒有Reply了,就會(huì)block。所以completePendingCommand并不是可以隨意添加的。

    現(xiàn)在出現(xiàn)了兩個(gè)問題:
    1 completePendingCommand很容易多出來或遺漏
    2 顯式調(diào)用completePendingCommand暴露了底層實(shí)現(xiàn),給用戶帶來不便,用戶只想要InputStream或者OutputStream

    為了解決這個(gè)問題,可以對(duì)InputStream進(jìn)行擴(kuò)展,建立一個(gè)ReplyOnCloseInputStream,如下:

    private static ReplyOnCloseInputStream extends InputStream{
      
    //
      public ReplyOnCloseInputStream(InputStream is, FTPClient c){
        
    //
      }

      
    //
      @override
      
    public void close(){
        
    if(c.completePendingCommand){
          is.close();
        }
    else{
          
    //throw Exception
        }

      }

    }
     
    //
    return new ReplyOnCloseInputStream(is, client);


    這樣封裝之后,F(xiàn)TPClient的用戶只需要正常在處理完流之后關(guān)閉即可,而不必暴露實(shí)現(xiàn)細(xì)節(jié)。保存文件也可以用相同的方法封裝OutputStream。

    posted @ 2010-07-07 23:08 楊一 閱讀(3465) | 評(píng)論 (1)編輯 收藏

    關(guān)于ThreadLocal的內(nèi)存泄露

    ThreadLocal是一種confinement,confinement和local及immutable都是線程安全的(如果JVM可信的話)。因?yàn)閷?duì)每個(gè)線程和value之間存在hash表,而線程數(shù)量未知,從表象來看ThreadLocal會(huì)存在內(nèi)存泄露,讀了代碼,發(fā)現(xiàn)實(shí)際上也可能會(huì)內(nèi)存泄露。

    事實(shí)上每個(gè)Thread實(shí)例都具備一個(gè)ThreadLocal的map,以ThreadLocal Instance為key,以綁定的Object為Value。而這個(gè)map不是普通的map,它是在ThreadLocal中定義的,它和普通map的最大區(qū)別就是它的Entry是針對(duì)ThreadLocal弱引用的,即當(dāng)外部ThreadLocal引用為空時(shí),map就可以把ThreadLocal交給GC回收,從而得到一個(gè)null的key。

    這個(gè)threadlocal內(nèi)部的map在Thread實(shí)例內(nèi)部維護(hù)了ThreadLocal Instance和bind value之間的關(guān)系,這個(gè)map有threshold,當(dāng)超過threshold時(shí),map會(huì)首先檢查內(nèi)部的ThreadLocal(前文說過,map是弱引用可以釋放)是否為null,如果存在null,那么釋放引用給gc,這樣保留了位置給新的線程。如果不存在slate threadlocal,那么double threshold。除此之外,還有兩個(gè)機(jī)會(huì)釋放掉已經(jīng)廢棄的threadlocal占用的內(nèi)存,一是當(dāng)hash算法得到的table index剛好是一個(gè)null key的threadlocal時(shí),直接用新的threadlocal替換掉已經(jīng)廢棄的。另外每次在map中新建一個(gè)entry時(shí)(即沒有和用過的或未清理的entry命中時(shí)),會(huì)調(diào)用cleanSomeSlots來遍歷清理空間。此外,當(dāng)Thread本身銷毀時(shí),這個(gè)map也一定被銷毀了(map在Thread之內(nèi)),這樣內(nèi)部所有綁定到該線程的ThreadLocal的Object Value因?yàn)闆]有引用繼續(xù)保持,所以被銷毀。

    從上可以看出Java已經(jīng)充分考慮了時(shí)間和空間的權(quán)衡,但是因?yàn)橹脼閚ull的threadlocal對(duì)應(yīng)的Object Value無法及時(shí)回收。map只有到達(dá)threshold時(shí)或添加entry時(shí)才做檢查,不似gc是定時(shí)檢查,不過我們可以手工輪詢檢查,顯式調(diào)用map的remove方法,及時(shí)的清理廢棄的threadlocal內(nèi)存。需要說明的是,只要不往不用的threadlocal中放入大量數(shù)據(jù),問題不大,畢竟還有回收的機(jī)制。

    綜上,廢棄threadlocal占用的內(nèi)存會(huì)在3中情況下清理:
    1 thread結(jié)束,那么與之相關(guān)的threadlocal value會(huì)被清理
    2 GC后,thread.threadlocals(map) threshold超過最大值時(shí),會(huì)清理
    3 GC后,thread.threadlocals(map) 添加新的Entry時(shí),hash算法沒有命中既有Entry時(shí),會(huì)清理

    那么何時(shí)會(huì)“內(nèi)存泄露”?當(dāng)Thread長(zhǎng)時(shí)間不結(jié)束,存在大量廢棄的ThreadLocal,而又不再添加新的ThreadLocal(或新添加的ThreadLocal恰好和一個(gè)廢棄ThreadLocal在map中命中)時(shí)。

    posted @ 2010-07-02 18:27 楊一 閱讀(2281) | 評(píng)論 (2)編輯 收藏

    關(guān)于軟件文檔,我的看法

    文檔應(yīng)該包括兩大部分,一部分是清晰的代碼結(jié)構(gòu)和注釋,比如Concurrent API就是這樣,還有一部分是文字文檔,包括三個(gè)小部分:一是開發(fā)文檔,應(yīng)該講架構(gòu)和功能;二是索引文檔,詳細(xì)介紹功能和參數(shù),三是用戶文檔,包括安裝和使用說明

    文檔最困難的莫過于版本的一致性,當(dāng)軟件升級(jí)后,一些obsolete的內(nèi)容和新的feature很難同步。要是架構(gòu)發(fā)生了變化,那就更困難了。一般document team都不是太精于技術(shù),所以也會(huì)產(chǎn)生一些問題。

    只能說任何事物永遠(yuǎn)都有改進(jìn)的空間,但是同樣也永遠(yuǎn)沒有達(dá)到完美的程度

    posted @ 2010-06-29 18:26 楊一 閱讀(320) | 評(píng)論 (0)編輯 收藏

    NIO學(xué)習(xí)之Web服務(wù)器示例

         摘要: 1 根據(jù)cpu core數(shù)量確定selector數(shù)量 2 用一個(gè)selector服務(wù)accept,其他selector按照core-1分配線程數(shù)運(yùn)行 3 accept selector作為生產(chǎn)者把獲得的請(qǐng)求放入隊(duì)列 4 某個(gè)selector作為消費(fèi)者從blocking queue中取出請(qǐng)求socket channel,并向自己注冊(cè) 5 當(dāng)獲得read信號(hào)時(shí),selector建立工作...  閱讀全文

    posted @ 2010-06-25 19:19 楊一 閱讀(1967) | 評(píng)論 (0)編輯 收藏

    多線程的知識(shí)

    多線程的優(yōu)點(diǎn):
    1 多核利用
    2 為單個(gè)任務(wù)建模方便
    3 異步處理不同事件,不必盲等
    4 現(xiàn)代的UI也需要它
    風(fēng)險(xiǎn):
    1 同步變量易錯(cuò)誤
    2 因資源限制導(dǎo)致線程活躍性問題
    3 因2導(dǎo)致的性能問題
    用途:
    框架,UI,Backend
    線程安全的本質(zhì)是什么:
    并非是線程和鎖,這些只是基礎(chǔ)結(jié)構(gòu),本質(zhì)是如何控制共享變量訪問的狀態(tài)
    什么是線程安全:
    就是線程之間的執(zhí)行還沒有發(fā)生錯(cuò)誤,就是沒有發(fā)生意外
    一個(gè)線程安全的類本身封裝了對(duì)類內(nèi)部方法和變量的異步請(qǐng)求,調(diào)用方無需考慮線程安全問題
    無狀態(tài)的變量總是線程安全的
    原子性:
    完整執(zhí)行的單元,如不加鎖控制,則會(huì)發(fā)生競(jìng)態(tài)條件,如不加鎖的懶漢單例模式,或者復(fù)合操作。
    鎖,內(nèi)在鎖,重入:
    利用synchronized關(guān)鍵字控制訪問單元,同一線程可以重入鎖內(nèi)部,避免了面向?qū)ο螽a(chǎn)生的問題。同一變量的所有出現(xiàn)場(chǎng)合應(yīng)該使用同一個(gè)鎖來控制。synchronized(lock)。
    即使所有方法都用synchronized控制也不能保證線程安全,它可能在調(diào)用時(shí)編程復(fù)合操作。
    活躍性和性能問題:
    過大的粒度會(huì)導(dǎo)致這個(gè)問題,用鎖進(jìn)行異步控制,導(dǎo)致了線程的順序執(zhí)行。
    簡(jiǎn)單和性能是一對(duì)矛盾,需要適當(dāng)?shù)娜∩帷2荒茉跊]有考慮成熟的情況下,為了性能去犧牲簡(jiǎn)潔性。
    要盡量避免耗時(shí)操作,IO和網(wǎng)絡(luò)操作中使用鎖

    posted @ 2010-06-25 19:17 楊一 閱讀(377) | 評(píng)論 (0)編輯 收藏

    Ext Store Filter的實(shí)現(xiàn)和問題

    Store包含兩個(gè)數(shù)據(jù)緩存 - snapshot和data,grid,combo等控件的顯示全部基于data,而snapshot是數(shù)據(jù)的完整緩存,當(dāng)首次應(yīng)用過濾器時(shí),snapshot從data中備份數(shù)據(jù),當(dāng)應(yīng)用過濾器時(shí),filter從snapshot獲取一份完整的數(shù)據(jù),并在其中進(jìn)行過濾,過濾后的結(jié)果形成了data并傳遞給展示,及data總是過濾后的數(shù)據(jù),而snapshot總是完整的數(shù)據(jù),不過看名字讓人誤以為它們的作用正好相反。
    相應(yīng)地,當(dāng)進(jìn)行store的增刪改時(shí),要同時(shí)維護(hù)兩個(gè)緩存。
    問題
    Store包含兩個(gè)增加Record的方法,即insert和add,其中的insert沒有更新snapshot所以當(dāng)重新應(yīng)用filter時(shí),即data被重新定義時(shí),在data中使用insert新增的記錄是無效的。
    解決方法
    用add不要用insert,如果用insert,記得把數(shù)據(jù)寫進(jìn)snapshot: store.snapshot.addAll(records)

    posted @ 2010-06-25 19:16 楊一 閱讀(1285) | 評(píng)論 (0)編輯 收藏

    Ext中Combo組件的聯(lián)動(dòng)封裝

         摘要: 在Extjs中構(gòu)造N級(jí)聯(lián)動(dòng)下拉的麻煩不少,需定制下拉數(shù)據(jù)并設(shè)定響應(yīng)事件。通過對(duì)Combo集合的封裝,無需自己配置Combo,只需設(shè)定數(shù)據(jù)和關(guān)聯(lián)層級(jí),即可自動(dòng)構(gòu)造出一組支持正向和逆向過濾的聯(lián)動(dòng)下拉并獲取其中某一個(gè)的實(shí)例。 如: 數(shù)據(jù): Ext.test = {};       Ext.test.lcbdata&nb...  閱讀全文

    posted @ 2010-06-25 19:14 楊一 閱讀(1306) | 評(píng)論 (0)編輯 收藏

    前端框架動(dòng)態(tài)組件和代碼生成之間的選擇

    目前主流的SSH開發(fā)架構(gòu)中,為減輕開發(fā)者工作,便于管理開發(fā)過程,往往用到一些公共代碼和組件,或者采用了基于模版的代碼生成機(jī)制,對(duì)于后臺(tái)的DAO,Service等因?yàn)榧軜?gòu)決定,代碼生成必不可少,但是在前端頁面的實(shí)現(xiàn)上,卻可以有兩種不同的思路,一種是把配置信息直接封裝成更高級(jí)別的組建,一種是進(jìn)行代碼生成。請(qǐng)大家討論一下這兩種方案的優(yōu)劣,這里先拋磚引玉了。

    相同點(diǎn):
    配置信息:XML OR 數(shù)據(jù)庫

    控件化:
    優(yōu)點(diǎn):
    1 易于添加公共功能
    2 修改配置數(shù)據(jù)直接生效
    3 代碼結(jié)構(gòu)清晰,對(duì)開發(fā)者友好
    缺點(diǎn):
    1 重組內(nèi)存中對(duì)象結(jié)構(gòu),性能沒有代碼生成好(但渲染時(shí)間相同)
    2 僅能控制組件自身封裝的配置,不支持個(gè)性化修改,如果配置文件不支持的參數(shù),則控件不支持
    3 必須保證每個(gè)控件一個(gè)配置

    代碼生成:
    優(yōu)點(diǎn):
    1 性能較好
    2 易于定制內(nèi)容
    3 可以只配置一個(gè)模版,然后做出多個(gè)簡(jiǎn)單的修改
    缺點(diǎn):
    1 不能針對(duì)多個(gè)頁面同時(shí)添加公共功能
    2 業(yè)務(wù)修改需要重新生成代碼
    3 開發(fā)者需要修改自動(dòng)生成的代碼,并需要了解一些底層的實(shí)現(xiàn)結(jié)構(gòu)

    =====================20091029
    代碼生成并不能提高工作效率,尤其是針對(duì)復(fù)雜的富客戶端開發(fā)
    開發(fā)組件可提提供一種有效的選項(xiàng),但是在運(yùn)行效率和內(nèi)存處理上需要細(xì)心處理

    posted @ 2010-06-25 19:11 楊一 閱讀(454) | 評(píng)論 (0)編輯 收藏

    Javascript工作流引擎代碼及實(shí)例

     

    最近在學(xué)習(xí)jBPMJavascript,所以按照一些相關(guān)概念自己寫了下面的200行代碼的“工作流引擎”,工作流管理系統(tǒng)包含了流程定義,引擎,及應(yīng)用系統(tǒng)三個(gè)主要部分,下面的代碼實(shí)現(xiàn)了流程的分支合并,目前只支持一種環(huán)節(jié)上的遷移。拷貝到html,雙擊就可以跑起來。

     

    var workflowDef = {
             start:{
                       fn:
    "begin"//對(duì)應(yīng)處理方法可以在內(nèi)部定義,也可以在外部定義
                       next:[
    "task1","task2"]
             },
             end:
    "end",
             tasks:[{
                       id:
    "task1",
                       fn:
    function(){
                                alert(
    "執(zhí)行任務(wù)一");
                       },
                       before:
    function(){
                                alert(
    "執(zhí)行任務(wù)一前");
                       },
                       after:
    function(){
                                alert(
    "執(zhí)行任務(wù)一后");
                       },
                       next:[
    "task4","task5"]
             },{
                       id:
    "task2",
                       fn:
    function(){
                                alert(
    "執(zhí)行任務(wù)二");
                       },
                       before:
    function(){
                                alert(
    "執(zhí)行任務(wù)二前");
                       },
                       after:
    function(){
                                alert(
    "執(zhí)行任務(wù)二后");
                       },
                       next:[
    "task3"]
             },{
                       id:
    "task3",
                       fn:
    function(){
                                alert(
    "執(zhí)行任務(wù)三");
                       },
                       before:
    function(){
                                alert(
    "執(zhí)行任務(wù)三前");
                       },
                       after:
    function(){
                                alert(
    "執(zhí)行任務(wù)三后");
                       },
                       
    //定義合并的數(shù)量
                       merge: 
    3,
                       next:
    "EOWF"
             },{
                       id:
    "task4",
                       fn:
    function(){
                                alert(
    "執(zhí)行任務(wù)四");
                       },
                       before:
    function(){
                                alert(
    "執(zhí)行任務(wù)四前");
                       },
                       after:
    function(){
                                alert(
    "執(zhí)行任務(wù)四后");
                       },
                       next:[
    "task3"]
             },{
                       id:
    "task5",
                       fn:
    function(){
                                alert(
    "執(zhí)行任務(wù)五");
                       },
                       before:
    function(){
                                alert(
    "執(zhí)行任務(wù)五前");
                       },
                       after:
    function(){
                                alert(
    "執(zhí)行任務(wù)五后");
                       },
                       next:[
    "task3"]
             }]
    }

     

     

    //////////定義引擎////////////

    Yi 
    = {};
    Yi.Utils 
    = {};
    Yi.Utils.execute 
    = function(o){
             
    if(typeof o != 'function')
                       eval(o)();
             
    else
                       o();
    }
    //工作流類
    Yi.Workflow 
    = function(workflowDef){
             
    this.def = workflowDef;
             
    this.tasks = this.def.tasks;
    }
    //public按照環(huán)節(jié)id查找查找
    Yi.Workflow.prototype.findTask 
    = function(taskId){
             
    for(var i=0;i<this.tasks.length;i++){
                       
    if(this.tasks[i].id == taskId)
                                
    return this.tasks[i];
             }
    }
    //public啟動(dòng)工作流
    Yi.Workflow.prototype.start 
    = function(){
             
    this.currentTasks = [];
             Yi.Utils.execute(
    this.def.start.fn);
             
    for(var i=0;i<this.def.start.next.length;i++){
                       
    this.currentTasks[i] = this.findTask(this.def.start.next[i]);
                       Yi.Utils.execute(
    this.currentTasks[i].before);
             }
    }
    //private
    Yi.Workflow.prototype.findCurrentTaskById 
    = function(taskId){
             
    for(var i=0;i<this.currentTasks.length;i++){
                       
    if(this.currentTasks[i].id == taskId)
                                
    return this.currentTasks[i];
             }
             
    return null;
    }
    //private
    Yi.Workflow.prototype.removeFromCurrentTasks 
    = function(task){
             
    var temp = [];
             
    for(var i=0;i<this.currentTasks.length;i++){
                       
    if(!(this.currentTasks[i] == task))
                                temp.push(
    this.currentTasks[i]); 
             }
             
    this.currentTasks = temp;
             temp 
    = null;
    }
    //public觸發(fā)當(dāng)前環(huán)節(jié)
    Yi.Workflow.prototype.signal 
    = function(taskId){
             
    //只處理當(dāng)前活動(dòng)環(huán)節(jié)
             
    var task = this.findCurrentTaskById(taskId);
             
    if(task == null){
                       alert(
    "工作流未流轉(zhuǎn)到此環(huán)節(jié)!");
                       
    return;
             }
             
    //對(duì)于合并的處理
             
    if(task.merge != undefined){
                       
    if(task.merge != 0){
                                alert(
    "工作流流轉(zhuǎn)條件不充分!");
                                
    return;
                       }
    else{
                                Yi.Utils.execute(task.before);
                       }        
             }
             
    //觸發(fā)當(dāng)前環(huán)節(jié)
             Yi.Utils.execute(task.fn);
             
    //觸發(fā)后動(dòng)作
             Yi.Utils.execute(task.after);
             
    //下一步如果工作流結(jié)束
             
    if(task.next === "EOWF"){
                       Yi.Utils.execute(
    this.def.end);
                       
    delete this.currentTasks;
                       
    return;
             }
             
    //遍歷下一步環(huán)節(jié)
             
    this.removeFromCurrentTasks(task);
             
    for(var i=0;i<task.next.length;i++){
                       
    var tempTask = this.findTask(task.next[i]);
                       
    if(!tempTask.inCurrentTasks)
                                
    this.currentTasks.push(tempTask);
                       
    if(tempTask.merge != undefined){
                                tempTask.merge
    --;
                                tempTask.inCurrentTasks 
    = true;
                       }
                       
    else
                                Yi.Utils.execute(tempTask.before);
             }
    }
    //public獲取當(dāng)前的活動(dòng)環(huán)節(jié)
    Yi.Workflow.prototype.getCurrentTasks 
    = function(){
             
    return this.currentTasks;
    }
    //public獲取流程定義
    Yi.Workflow.prototype.getDef 
    = function(){
             
    return this.def;
    }

     

    ////////應(yīng)用系統(tǒng)///////////////
    var wf = new Yi.Workflow(workflowDef);
    alert(
    "啟動(dòng)工作流");
    wf.start();
    alert(
    "嘗試手工執(zhí)行任務(wù)3,返回工作流沒有流轉(zhuǎn)到這里");
    wf.signal(
    "task3");
    alert(
    "分支開始");
    alert(
    "手工執(zhí)行任務(wù)1");
    wf.signal(
    "task1");
    alert(
    "手工執(zhí)行任務(wù)2");
    wf.signal(
    "task2");
    alert(
    "手工執(zhí)行任務(wù)4");
    wf.signal(
    "task4");
    alert(
    "手工執(zhí)行任務(wù)5");
    wf.signal(
    "task5");
    alert(
    "手工執(zhí)行任務(wù)3");
    wf.signal(
    "task3");
    function begin(){
             alert(
    "流程開始,該函數(shù)在外部定義");
    }
    function end(){
             alert(
    "流程結(jié)束");
    }

    posted @ 2009-03-06 17:39 楊一 閱讀(1992) | 評(píng)論 (1)編輯 收藏

    Spring Security 2 中動(dòng)態(tài)角色權(quán)限的實(shí)現(xiàn)

     

    安全框架的主體包括兩部分即驗(yàn)權(quán)和授權(quán)。Spring Security2可以很好的實(shí)現(xiàn)這兩個(gè)過程。Spring Security2對(duì)其前身acegi最大的改進(jìn)是提供了自定義的配置標(biāo)簽,通過Security的命名空間定義了httpauthentication-provider等標(biāo)簽,這樣做的好處是極大地簡(jiǎn)化了框架的配置,并很好地隱藏了框架實(shí)現(xiàn)的細(xì)節(jié),在配置的表述上也更清晰,總體上提高了框架的易用性。

    然而,該框架默認(rèn)的權(quán)限配置方式在xml中,又因?yàn)樾掳姹倦[藏了實(shí)現(xiàn)細(xì)節(jié),在動(dòng)態(tài)權(quán)限的擴(kuò)展上,能力變小了。在驗(yàn)權(quán)過程中,遇到的問題不多。但在授權(quán)時(shí),如果是acegi,人們可以通過繼承AbstractFilterInvocationDefinitionSource類實(shí)現(xiàn)在授權(quán)(即資源角色和用戶角色的匹配)前,針對(duì)資源的角色的獲取。而新版本因?yàn)橛眯聵?biāo)簽進(jìn)行了整合,這個(gè)過程被默認(rèn)的類實(shí)現(xiàn)隱藏掉了,包括過濾器,資源獲取和角色定義等過程都由框架來實(shí)現(xiàn),于是很多人在使用Spring Security2時(shí)也想通過改動(dòng)DefaultFilterInvocationDefinitionSource對(duì)資源的獲取來實(shí)現(xiàn)數(shù)據(jù)庫或文件中的動(dòng)態(tài)的角色。不過這樣的改動(dòng)侵入性比較高,而且還保留了acegi的痕跡,也違背了開閉的原則。

    其實(shí),我們完全可以通過Spring Security2 accessManager提供的自定義投票機(jī)制來解決這個(gè)問題,這樣既不影響現(xiàn)有的基于URL的配置,還可以加入自己的動(dòng)態(tài)的權(quán)限配置。

             其實(shí)現(xiàn)策略如下:

    1 定義類DynamicRoleVoter實(shí)現(xiàn)AccessDecisionVoter,注入實(shí)現(xiàn)接口DynamicRoleProvider(用來定義獲取角色的方法)的提供動(dòng)態(tài)角色的類

    2 在兩個(gè)supports方法中返回true

    3 vote方法中,有三個(gè)參數(shù)(Authentication authentication, Object object,

    ConfigAttributeDefinition config) 通過第一個(gè)獲取用戶的權(quán)限集合,第二個(gè)可以獲取到資源對(duì)象,進(jìn)而通過DynamicRoleProvider獲取到角色集合進(jìn)行匹配。

    4 在配置文件中加入DynamicRoleVoter,如下:

    <beans:bean id="accessDecisionManager" class="org.springframework.security.vote.AffirmativeBased">
    <beans:property name="decisionVoters">
    <beans:list>
    <beans:bean class="org.springframework.security.vote.RoleVoter" />
    <beans:bean class="org.springframework.security.vote.AuthenticatedVoter" />
    <beans:bean class="DynamicRoleVoter">
        
    <beans:property name="dynamicRoleProvider">
            
    <beans:ref local="dynamicRoleProvider"/>
    </beans:property>
    </beans:bean>
    </beans:list>
    </beans:property>
    </beans:bean>
    <beans:bean id=” dynamicRoleProvider” class=”…”>
        
    ……
    </beans:bean
    >

    posted @ 2009-03-04 12:55 楊一 閱讀(5077) | 評(píng)論 (0)編輯 收藏

    實(shí)現(xiàn)Ext表單對(duì)checkBoxGroup的統(tǒng)一管理

    1 對(duì)于類型是checkboxgroup的數(shù)據(jù),數(shù)據(jù)庫中保存數(shù)據(jù)的格式是value1,value2...valueN,其中1~N的數(shù)據(jù)有可能不存在,如果選中則存在,最后拼接成一個(gè)串。
    在Ext中,通過Record對(duì)象向FormPanel中的內(nèi)置對(duì)象BasicForm加載數(shù)據(jù)時(shí),采用的是setValues方法,而setValues第一步要通過Record中定義的name使用findField方法找到表單元素,遺憾的是,繼承了Field的checkboxgroup組件并不能正確的通過getName返回自身引用,所以,需要對(duì)getName方法進(jìn)行重寫,此外,為了適應(yīng)我們采用的數(shù)據(jù)格式,對(duì)于該組件的setValue(被setValues調(diào)用)和getValue(獲取到已加工的數(shù)據(jù),此事后話)也要進(jìn)行重寫。故而對(duì)于形如:
    {     
       xtype: 'checkboxgroup',   
       name: 'biztype',     
       width: 
    220,   
       columns: 
    3,   
       fieldLabel: '業(yè)務(wù)類別',   
       items: [     
           {boxLabel: '類別1', inputValue: '
    01'},     
           {boxLabel: '類別2', inputValue: '
    02'},     
           {boxLabel: '類別3', inputValue: '
    03'},     
           {boxLabel: '類別4', inputValue: '
    04'}     
           ]     
     }  

    的checkboxgroup定義,需重寫類如下:
     
    Ext.override(Ext.form.CheckboxGroup,{    
        
    //在inputValue中找到定義的內(nèi)容后,設(shè)置到items里的各個(gè)checkbox中    
        setValue : function(value){   
            
    this.items.each(function(f){   
                
    if(value.indexOf(f.inputValue) != -1){   
                    f.setValue(
    true);   
                }
    else{   
                    f.setValue(
    false);   
                }   
            });   
        },   
        
    //以value1,value2的形式拼接group內(nèi)的值   
        getValue : function(){   
            
    var re = "";   
            
    this.items.each(function(f){   
                
    if(f.getValue() == true){   
                    re 
    += f.inputValue + ",";   
                }   
            });   
            
    return re.substr(0,re.length - 1);   
        },   
        
    //在Field類中定義的getName方法不符合CheckBoxGroup中默認(rèn)的定義,因此需要重寫該方法使其可以被BasicForm找到   
        getName : function(){   
            
    return this.name;   
        }   
    });

    2 通過內(nèi)置對(duì)象basicForm的getValues方法可以獲取到一個(gè)form的完整json數(shù)據(jù),但遺憾的事,這里取到的是dom的raw數(shù)據(jù),類似emptyText的數(shù)據(jù)也會(huì)被返回,而Field的getValue方法不存在這個(gè)問題,所以如果想要返回一個(gè)非raw的json集合,可以給formpanel添加如下方法:
    getJsonValue:function(){   
        
    var param = '{';   
        
    this.getForm().items.each(function(f){   
            
    var tmp = '"' + f.getName() + '":"' + f.getValue() + '",';   
            param 
    +=  tmp;   
        });   
        param 
    = param.substr(0,param.length - 1+ '}';   
        
    return param;   
    }  

    這個(gè)方法同樣適用于上面定義的checkboxgroup,如此就可以把前后臺(tái)的數(shù)據(jù)通過json統(tǒng)一起來了

    posted @ 2009-03-04 12:50 楊一 閱讀(2235) | 評(píng)論 (0)編輯 收藏

    富客戶端技術(shù)中的JavaScript腳本國際化

         摘要: 當(dāng)前的富客戶端可以包含兩部分:分別為JSP頁面和通過富客戶端js組件(如extjs)渲染的組件化窗口頁。針對(duì)這兩部分分別做如下處理: 對(duì)于JSP頁面的部分采用JSTL標(biāo)準(zhǔn)庫的fmt標(biāo)簽,如通過: <fmt:message key="page.login.title"/>這樣的形式進(jìn)行展現(xiàn),其中message對(duì)應(yīng)的文本在服務(wù)端配置,并在web.xml中配置資源文件的位置,也可以采用s...  閱讀全文

    posted @ 2008-12-23 12:07 楊一 閱讀(2564) | 評(píng)論 (1)編輯 收藏

    windows中不能雙擊打開jar文件的解決辦法

    看此文前請(qǐng)保證jar包中有至少一個(gè)Main方法入口,及圖形化的界面。
    并保證META-INF/MANIFEST文件中的Main-Class已經(jīng)指向之前實(shí)現(xiàn)的main方法入口。

    最近硬盤壞了,于是重新安裝了OS,發(fā)現(xiàn)拷貝后的jdk或jre(未經(jīng)安裝的版本),不能打開jar文件執(zhí)行(jdk版本1.6_11),
    于是在打開方式中指向了javaw程序,發(fā)現(xiàn)無效,并提示"cannot find main class", 與此同時(shí)windows把jar類型的文件關(guān)聯(lián)到了
    指定的javaw程序上,上網(wǎng)找了一通,沒有人提及這個(gè)問題的解決辦法,而顯然這個(gè)問題又不是由開篇中提到的問題導(dǎo)致的。
    于是在注冊(cè)表中當(dāng)前用戶配置中刪除了當(dāng)前jar類型的定義。但是重新嘗試后依然無效。

    于是重新安裝了jdk,發(fā)現(xiàn)這次可以打開jar文件了,并且這次用來打開的程序從打開方式來看仍然是javaw。
    比較注冊(cè)表中文件類型的定義,并沒有差別。從文件夾選項(xiàng) -> 文件類型來看終于看到了差別,

    高級(jí)里面的open操作定義如下:
    "C:\Program Files\Java\jre6\bin\javaw.exe" -jar "%1" %*
    而如果我們自己選擇javaw,默認(rèn)的open操作是沒有 -jar參數(shù)的,必須手工加進(jìn)去。
    我們知道java啟動(dòng)jar包的參數(shù)是 -jar,但是記得以前javaw是可以直接打開jar的,不知什么時(shí)候起也需要帶有-jar參數(shù)了。

    所以對(duì)于一個(gè)拷貝的綠色jre只要修改一下open操作的定義就可以解決上面的問題了。

    解決了上面的問題,又產(chǎn)生了新的問題,之前選擇打開的javaw程序在打開方式中丟不掉了,比較多余,這個(gè)可以在注冊(cè)表中修改
    在HKEY_CLASSES_ROOT\Applications下面找到響應(yīng)的程序刪除就可以了,原來每次用一個(gè)程序打開一個(gè)類型的文件windows都會(huì)在
    注冊(cè)表中這個(gè)地方留下相關(guān)的記錄

    posted @ 2008-12-22 18:19 楊一 閱讀(3182) | 評(píng)論 (0)編輯 收藏

    關(guān)于文本協(xié)議中二進(jìn)制到文本的轉(zhuǎn)碼

    偶然間注意到一個(gè)困擾了我很久的問題,那就是如果我不通過Socket而通過應(yīng)用層的某種基于文本的協(xié)議,比如SOAP進(jìn)行通信的話,
    如何傳遞二進(jìn)制的數(shù)據(jù)呢?現(xiàn)在SOA,Web Service等很火,應(yīng)該會(huì)遇到這種問題吧?

    現(xiàn)在已知的方法可以通過Base64進(jìn)行編碼,其原理和方法見:
    http://baike.baidu.com/view/469071.htm

    這種方法采用了字節(jié)中的6位進(jìn)行文本轉(zhuǎn)換,并且在其他論壇上也看到了帖子說淘寶的搜索也采用了這種編碼方式進(jìn)行處理。
    但是采用了5位進(jìn)行轉(zhuǎn)換。并且大膽地給出了5位轉(zhuǎn)碼的算法,見:
    http://www.javaeye.com/topic/286240

    不過這種5位的轉(zhuǎn)換會(huì)產(chǎn)生更多多余的字節(jié),6位的轉(zhuǎn)碼充分利用了現(xiàn)今的可讀文本,可是5位卻沒有,因?yàn)?和8的最小公倍數(shù)是40,
    所以當(dāng)每轉(zhuǎn)換40位即5個(gè)字節(jié)的二進(jìn)制數(shù)據(jù)需要8個(gè)字節(jié)來表示,這樣就多產(chǎn)生3個(gè)字節(jié),浪費(fèi)的效率是3/5, 而6位轉(zhuǎn)碼浪費(fèi)的效率是
    1/3。而且隨著字節(jié)增多,轉(zhuǎn)化效率也在下降。可見采用5位轉(zhuǎn)碼是一種既浪費(fèi)空間,又浪費(fèi)效率的解決方案。在不增加url長(zhǎng)度的情況下充分提高效率,6位編碼是最佳的。如果可以任意的餓犧牲url長(zhǎng)度,
    可以把0-9全部拿出來當(dāng)做標(biāo)記位,0-9不會(huì)單獨(dú)出現(xiàn),這樣一共有10*26 + 26 = 286 種可能還不包括小寫字母,
    此外還有=,+,-什么的至少256可以編碼8位的字節(jié)了,這樣處理效率就提高了。

    現(xiàn)在把問題優(yōu)化一下,人類可讀無歧義的文本碼有0-9,A-Z,a-z共62個(gè)
    設(shè)取出x個(gè)作為標(biāo)志位則(62-x) * x + (62 - x) >= 256
    解這個(gè)二元一次方程得到:
    3.366<=X<=57.634
    考慮到編碼的文本長(zhǎng)度,取x的最小值,即 4
    最優(yōu)解:
    用0, 1, 2, 3做為標(biāo)志位
    4-9,A-Z, a-z參與編碼并與標(biāo)志位配合實(shí)現(xiàn)8位字節(jié)的文本化
    可以看到這種方法的轉(zhuǎn)碼效率會(huì)比較高,但是空間冗余大。

    此外其實(shí)可用的文本不知62個(gè),包括感嘆號(hào)等用上后補(bǔ)足64 = 2^6
    它的高位是 00
    那么只要再找到三個(gè)文本符保存其他三個(gè)高位01 10 11就可以了
    這樣的轉(zhuǎn)碼空間可以更小一些。


    想法還很不成熟,歡迎大家批評(píng)

    posted @ 2008-12-04 15:56 楊一 閱讀(1662) | 評(píng)論 (2)編輯 收藏

    JSON通用服務(wù)端處理

         摘要: 最近在學(xué)習(xí)JavaScript,發(fā)現(xiàn)不論是ext還是prototype都很推崇json這種通信協(xié)議的格式,但是這兩個(gè)框架都是比較偏前端的,和dwr不同,dwr是一個(gè)一站式的ajax框架,不僅提供了客戶端的工具方法,也包括服務(wù)端的配置和通信的處理。 而ext和prototype等僅僅設(shè)置好了json的接口并對(duì)ajax通信做了封裝,相對(duì)而言是一種比較“純粹”的AJAX實(shí)現(xiàn),當(dāng)...  閱讀全文

    posted @ 2008-11-24 18:14 楊一 閱讀(2229) | 評(píng)論 (1)編輯 收藏

    軟件開發(fā)平臺(tái)及框架的意義

    學(xué)過軟件工程的都知道,軟件產(chǎn)品的生產(chǎn)周期是一個(gè)經(jīng)歷若干階段的漫長(zhǎng)過程,包括需求獲取 - 設(shè)計(jì) - 開發(fā) - 維護(hù)等等。

    需求階段 - 總想考慮到所有的問題,或是一切按合同辦事。但在現(xiàn)實(shí)中根本不得能,因此很多公司開始提倡“隨需而變”的能力,希望快速的響應(yīng)用戶的需求變化
    維護(hù)階段 - 總希望自己開發(fā)出來的東西一勞永逸,永遠(yuǎn)不要再產(chǎn)生任何麻煩,產(chǎn)生了麻煩也不要找到我。甚至有些項(xiàng)目組的人員開發(fā)出來一大堆不成熟的產(chǎn)品、項(xiàng)目后撒手不管,走人了事,毫無職業(yè)操守,亦是對(duì)自身行業(yè)聲譽(yù)(至少是國內(nèi)IT服務(wù)提供商聲譽(yù))的一個(gè)打擊。真正的項(xiàng)目開發(fā)不應(yīng)該這樣,一定是非常易于維護(hù)的,能夠快速地找出問題的所在,或是新需求切入點(diǎn)的所在,然后解決

     

    很明顯,前面提到的兩個(gè)問題都要也只能通過設(shè)計(jì)和開發(fā)來解決。問題來了,怎樣開發(fā)出的軟件才能快速地響應(yīng)需求,易于維護(hù)?可以有很多不相沖突的說法,比如解耦,比如通過POJO封裝數(shù)據(jù)等等。這些東西流行開來以后,很多人有疑問,為什么我的項(xiàng)目中一定要用這些框架?我不用這些框架也可以快速的開發(fā)出我要的功能,而且更加簡(jiǎn)單,等等。如果孤立地從設(shè)計(jì)和開發(fā)的角度看這些問題,這種說法并沒有錯(cuò)誤,但是如果從整個(gè)軟件開發(fā)的生命周期來看,則不是這樣。當(dāng)然,這里還有一個(gè)是否“過度設(shè)計(jì)”的trade-off在里面,不過那又是另一個(gè)話題了。

    再說說各種各樣的平臺(tái)吧,它們和框架不同,軟件體系結(jié)構(gòu)中有一種架構(gòu)模型即層次模型,我們現(xiàn)在的TCP/IP協(xié)議棧即屬于這種模型,我們的軟件對(duì)于平臺(tái)產(chǎn)品的依賴是一種朝向穩(wěn)定的依賴,就好像我們?cè)谡{(diào)試代碼時(shí)往往不會(huì)去調(diào)試操作系統(tǒng)API的bug一樣,因此在開發(fā)這種平臺(tái)層次級(jí)別的產(chǎn)品時(shí)就沒有必要再去采用那些為了保障“企業(yè)應(yīng)用”Web軟件生命周期中所采用的方法了,完全可以用最基礎(chǔ),最底層的手段。只要能夠做到高效、穩(wěn)定即可。因此,平臺(tái)中間件產(chǎn)品的開發(fā)必須和應(yīng)用軟件產(chǎn)品分開來看,雖然它們可能都在用Java這種編程語言。

    posted @ 2008-10-26 13:24 楊一 閱讀(1635) | 評(píng)論 (0)編輯 收藏

    形式化與自動(dòng)化

    本科讀書時(shí),曾聽過離散數(shù)學(xué)老師一句很精彩的論斷:“只要能夠形式化的東西,就可以自動(dòng)化”。可是今天我不談離散數(shù)學(xué),倒想說說其他不相關(guān)的東西。

    你一定聽到過“一流的企業(yè)賣標(biāo)準(zhǔn),二流的企業(yè)賣品牌,三流的企業(yè)賣產(chǎn)品”。

    什么是形式化?為什么形式化的東西就可以自動(dòng)化呢?撇開數(shù)學(xué)符號(hào)不談,對(duì)企業(yè)來說,形式化的東西可以是一些規(guī)章及做事的方法,生產(chǎn)產(chǎn)品的方法等等。為什么人民幣稍一升值,中國的中小制造型企業(yè)就要痛苦不堪?因?yàn)槲覀兠考葲]有品牌,更沒有標(biāo)準(zhǔn),拿生產(chǎn)DVD機(jī)為例,最初的90年代生產(chǎn)DVD機(jī)賣到歐美很賺,可是現(xiàn)在據(jù)說不賠錢就不錯(cuò)了,因?yàn)橐U納一大筆的專利費(fèi)。中國的大多數(shù)企業(yè)處在整個(gè)產(chǎn)業(yè)鏈的最下端,所得的利潤(rùn)的大多數(shù)被其他企業(yè)剝奪了,因?yàn)槲覀冇玫氖莿e人的品牌,別人的標(biāo)準(zhǔn)。我們的公司在全球經(jīng)濟(jì)中處于“民工”的境地。

    回到我們的問題中來,一流企業(yè)所做的標(biāo)準(zhǔn),是生產(chǎn)一種產(chǎn)品的方式和規(guī)約,這一層面是抽象世界的最高層次,無法對(duì)這層抽象的產(chǎn)生進(jìn)行形式化,所以是一種創(chuàng)造性的勞動(dòng);二流企業(yè)所賣的品牌是對(duì)一種產(chǎn)品具體生產(chǎn)方法的規(guī)約,通過“模板方法模式”的應(yīng)用,這一層次的抽象的模板可以從上一個(gè)層次的形式化中自動(dòng)化,然后只需形式化具體的操作細(xì)節(jié),對(duì)于生產(chǎn)細(xì)節(jié)的形式化,也需要一定的創(chuàng)造性的勞動(dòng);三流的企業(yè)是一部機(jī)器,因?yàn)榈酱藶橹挂磺械臇|西都已經(jīng)形式化了,只需要有時(shí)間和精力的機(jī)器去自動(dòng)完成而已。

    讓我們好好想想在一個(gè)知識(shí)經(jīng)濟(jì)的社會(huì)里,什么事物是創(chuàng)造性的,是只能被形式化而不能被自動(dòng)化的。因?yàn)橹挥腥祟惖膭?chuàng)造性思想不能被機(jī)器所取代,這也是為什么機(jī)器人無法取代人類的原因。

    80年代出生的人應(yīng)該記得歷史教科書中的論述,工業(yè)革命時(shí),一些工人去砸毀機(jī)器,覺得這些機(jī)器剝奪了他們的工作。如果有一天,老板突然來告訴您:你可以離開了,請(qǐng)不要沮喪和懊悔,因?yàn)槟缭撘庾R(shí)到您其實(shí)就是一部機(jī)器。當(dāng)然為了防止上面悲劇的發(fā)生,早點(diǎn)去從事有創(chuàng)造性的工作吧,停止對(duì)于各種軟件自動(dòng)化輔助工具的抱怨和擔(dān)憂,勇敢地迎接明天。

    還記得小時(shí)候常看的電影《神鞭》吧!

    posted @ 2008-09-12 12:49 楊一 閱讀(1490) | 評(píng)論 (1)編輯 收藏

    也談普元

    偶然間看到下面有一個(gè)網(wǎng)友慨嘆普元的強(qiáng)大,而開發(fā)人員的渺小。
    小弟剛剛參加工作,也在項(xiàng)目中接觸到了普元的EOS。普元的這個(gè)東西怎么說呢,就是亂用XML然后Spring沒做好就變成那個(gè)樣子的,同時(shí)失去了類型的表述,一部機(jī)器要進(jìn)行裝配需要組件和零件,軟件應(yīng)該自上而下,分而治之,這是上個(gè)世紀(jì)70年代,學(xué)者們就達(dá)成的共識(shí),所以關(guān)于“銀彈”神話的唯一結(jié)論就是——“沒有銀彈”。
    為什么說EOS是沒有做好的Spring?
    Spring簡(jiǎn)化了對(duì)象的裝配,強(qiáng)調(diào)重用,是建立在面向?qū)ο蠡A(chǔ)上的,是建立在敏捷測(cè)試基礎(chǔ)上的,是建立在強(qiáng)類型基礎(chǔ)上的;
    而EOS則是建立在面向過程的基礎(chǔ)上的,建立在不可測(cè)試的基礎(chǔ)上的,建立在毫無類型基礎(chǔ)上的(全是String)
    然而EOS也有很多的優(yōu)點(diǎn)(據(jù)小弟不完全發(fā)現(xiàn)):
    1)EOS固化的開發(fā)流程強(qiáng)制一個(gè)team從一種易于維護(hù)的結(jié)構(gòu)組織Web,包括頁面,表示層,邏輯層等等。否則的話就需要一個(gè)架構(gòu)師來做出規(guī)約,但仍不易于管理;
    2)EOS的畫圖功能讓人耳目一新,從“代碼即文檔”的哲學(xué)出發(fā),這些畫圖很好地詮釋了代碼表述的內(nèi)容和結(jié)構(gòu),給程序的維護(hù)帶來便利。
    3)相對(duì)于OO和J2EE傳統(tǒng)開發(fā),EOS易于上手,學(xué)習(xí)曲線較短。但是這一點(diǎn)有爭(zhēng)議,EOS的知識(shí)不具備通用性。
    綜上,根據(jù)2-8的關(guān)系法則,在某些領(lǐng)域EOS的確有其優(yōu)點(diǎn),但是認(rèn)為EOS完全“解放”了程序員,則是不負(fù)責(zé)任的說法。
    這只是我的個(gè)人看法,歡迎大家就此話題討論。

    posted @ 2008-09-04 15:41 楊一 閱讀(2336) | 評(píng)論 (10)編輯 收藏

    標(biāo)準(zhǔn)化與非標(biāo)準(zhǔn)化

    聯(lián)合國是國家間的標(biāo)準(zhǔn)化組織,可惜一超多強(qiáng)們只把它當(dāng)作是一個(gè)道具,需要時(shí)拿來用一下,不需要時(shí)完全可以踢到一邊。
    歷史上,每個(gè)朝代都認(rèn)識(shí)到失敗的教訓(xùn),卻最終都迎來了相似的結(jié)局。

    有人說,軟件行業(yè)是一個(gè)天生的壟斷行業(yè),其特質(zhì)是,產(chǎn)品研發(fā)的過程異常的復(fù)雜,但產(chǎn)品一旦出爐,就可以瘋狂而不計(jì)成本地生產(chǎn)。只有NRE Cost,眼下的軟件行業(yè)也出現(xiàn)了群雄逐鹿的場(chǎng)面,上游產(chǎn)業(yè)被幾家大公司所瓜分,這些大公司如果能互相牽制,則會(huì)坐在一起,成立一個(gè)組織。如果一家獨(dú)大,則我行我素,稱王稱霸。

     

    看看他們的一路成長(zhǎng):

    初始:

    他們想占有你,最初都會(huì)很乖。就像女孩在成為家庭主婦之前總能收到男孩的禮物。

    成長(zhǎng):

    大公司們也漸漸從規(guī)范的參與者,變成規(guī)范+的樹立者,比如IE,Office,再比如Oracle的特性等等。

    稱霸:

    市場(chǎng)占有的差不多了,可以不顧客戶的意志做自己喜歡的事情,反正你已經(jīng)離不開我。

    消亡:

    客戶們?cè)孤曒d道,新的“符合規(guī)范”或簡(jiǎn)潔明了的產(chǎn)品出現(xiàn)市場(chǎng)。


    希望這些大軟件廠商們能夠吸取教訓(xùn),也希望小軟件廠商們將來不要走入歷史的怪圈。

    posted @ 2008-09-03 18:54 楊一 閱讀(189) | 評(píng)論 (0)編輯 收藏

    OA的殺手級(jí)應(yīng)用

    在遠(yuǎn)古時(shí)期人們靠結(jié)繩紀(jì)事,據(jù)說美洲的瑪雅文明在覆滅之前都一直沒有自己的文字,而采用這種古老的方法。
    后來我們的祖先發(fā)明了文字,在竹簡(jiǎn)上,布帛上書寫文字,竹簡(jiǎn)和布帛就是信息的載體,這樣的載體造價(jià)不菲,所以我們的文言和白話就有這么大的差距,留下的論語也要微言大義。再后來我們的祖先發(fā)明了紙張,嚴(yán)重地降低了承載信息的開銷,于是人類的文明得以更好地記錄和更快地發(fā)展。今天,我們的信息載體又有了新的變化,一張光盤,一個(gè)硬盤都可以承載無數(shù)的學(xué)問。
    信息有了載體,隨之產(chǎn)生了信息管理的問題:
    如何對(duì)信息進(jìn)行增刪改查的操作?如何處理附加在信息上的工作流?如何管理權(quán)限?
    在IT系統(tǒng)出現(xiàn)之前,人們通過圖書館管理圖書,通過搬運(yùn)工進(jìn)行信息流動(dòng),通過鑰匙和鎖頭管理權(quán)限。
    在IT系統(tǒng)出現(xiàn)之后,人類可以通過計(jì)算機(jī)來完成這些操作。這其中數(shù)據(jù)庫系統(tǒng),工作流系統(tǒng)幫了我們大忙。
    IT系統(tǒng)處理信息的過程是:
    多樣式的文檔(抽象為XML)-> 內(nèi)存數(shù)據(jù) -> 持久化(文件數(shù)據(jù)庫)->內(nèi)存數(shù)據(jù) -> 多樣式的文檔(抽象為XML)
    我們讓用戶在我們?cè)O(shè)定的UI窗口進(jìn)行輸入,然后通過報(bào)表的形式產(chǎn)生各種各樣的輸出。中間一個(gè)步驟一個(gè)步驟,一個(gè)環(huán)節(jié)一個(gè)環(huán)節(jié)的走下去。
    這其中,我們把很大一部分精力消耗在,如何讓用戶舒服的輸入,和產(chǎn)生用戶所需要的輸出上。
    于是人們就要思考,難道不可以直接編輯一種全世界認(rèn)可的文檔形式(大家現(xiàn)在正在和MS爭(zhēng)吵的東西)通過網(wǎng)絡(luò)流轉(zhuǎn),然后獲得結(jié)果嗎?為什么要從程序員的角度加給用戶數(shù)據(jù)庫,工作流,錄入界面這些繁雜的東西?
    從這點(diǎn)意義上說,我推崇Sharepoint或者Google sites。
    就拿google docs來說吧,在線編輯word,每個(gè)環(huán)節(jié)通過分享的形式進(jìn)行編輯,授權(quán)這部分可以通過歷史記錄來找到,隨時(shí)恢復(fù)到歷史版本,因此也不怕誤操作和無權(quán)限操作,真正的所見即所得,支持50人同時(shí)在線編輯。這難道不是OA的殺手級(jí)應(yīng)用嗎?

    posted @ 2008-03-05 13:31 楊一 閱讀(1262) | 評(píng)論 (1)編輯 收藏

    如何學(xué)習(xí)spring

    學(xué)習(xí)這些框架技術(shù),我覺得歸根結(jié)底就是做什么的,為什么做,如何做
    前人說讀書有三個(gè)層次,我看這大概可以總結(jié)為是新的三個(gè)層次:)
    因?yàn)闆]有搞清楚為什么要用,就會(huì)誤用,用了還不如沒用。其實(shí)我覺得學(xué)spring讀讀rod那個(gè)原著挺好的,比單純學(xué)spring有幫助,最好自己有體會(huì)。比如你開發(fā)網(wǎng)站很熟練了,自然就知道為什么要用spring了。等完全領(lǐng)會(huì)了他那兩本書后,再讀讀他們的reference book應(yīng)該差不多了。
    這個(gè)過程其實(shí)就是做什么->為什么->怎么做的過程

    posted @ 2008-01-16 10:19 楊一 閱讀(1027) | 評(píng)論 (1)編輯 收藏

    系統(tǒng)模型及系統(tǒng)故障日志的思考

    最近在研究關(guān)于系統(tǒng)的基于日志的故障恢復(fù),無意間在網(wǎng)上發(fā)現(xiàn)一篇論文中對(duì)于系統(tǒng)日志模型的精彩論述,翻譯過來并附上我的思路:

    一個(gè)系統(tǒng)是一個(gè)具有明顯的邊界的實(shí)體,它根據(jù)一定的輸入,自身運(yùn)行邏輯及系統(tǒng)的內(nèi)部時(shí)鐘變化來產(chǎn)生相應(yīng)的輸出。
    所謂“明顯的邊界”是指系統(tǒng)所產(chǎn)生的輸出是明確而無二義性的。我們稱這個(gè)邊界為系統(tǒng)的設(shè)計(jì)規(guī)范(specification)。一個(gè)系統(tǒng)通過與其所處環(huán)境進(jìn)行交互,從而獲取輸入并產(chǎn)生輸出。一個(gè)系統(tǒng)可以被拆解為不同的子系統(tǒng)。這些子系統(tǒng)通常被稱為系統(tǒng)模塊(system components),每個(gè)模塊又獨(dú)立地成為一個(gè)系統(tǒng),作為一個(gè)系統(tǒng),這個(gè)模塊又會(huì)和它的相關(guān)環(huán)境進(jìn)行交互(比如,一個(gè)更大的系統(tǒng)中的其他的模塊組件)來獲取輸入并產(chǎn)生輸出,這些模塊還可以繼續(xù)被分解為更小的子系統(tǒng)。
    一個(gè)系統(tǒng)可以被建模為一個(gè)狀態(tài)機(jī)(state machine),其中的狀態(tài)包含了系統(tǒng)所持有并處理的數(shù)據(jù)。這些狀態(tài)的遷移被分為兩大類:由系統(tǒng)內(nèi)部邏輯所觸發(fā)且對(duì)外部環(huán)境透明的遷移和直接與外部環(huán)境相接觸的遷移。前者的例子如內(nèi)存數(shù)據(jù)和寄存器數(shù)據(jù)的轉(zhuǎn)換,內(nèi)存中數(shù)據(jù)結(jié)構(gòu)的重組。第二種遷移的例子包含了各種各樣的系統(tǒng)和環(huán)境之間的交互,一般來說,如果這個(gè)過程能被建模成系統(tǒng)的I/O操作,則應(yīng)屬于這一類別。因此,一個(gè)消息內(nèi)容的形成是一個(gè)或多個(gè)第一類別狀態(tài)遷移的結(jié)果,但將消息輸出到系統(tǒng)的環(huán)境則是屬于第二類遷移。
    第二類別的狀態(tài)遷移可以捕獲交互事件(interaction events),或者簡(jiǎn)單的事件(events)。這些事件可以由系統(tǒng)外部的觀察者(observer)來獲取。顯然,這里的事件是消息、信號(hào)、數(shù)據(jù)及其內(nèi)容以及一切系統(tǒng)和其環(huán)境交互(如機(jī)器人運(yùn)動(dòng)手腳,報(bào)警器報(bào)警,打印機(jī)打印等等)的發(fā)送和接受的模型。此外事件還可以用來描述系統(tǒng)缺乏交互的時(shí)間,比如一個(gè)計(jì)時(shí)器在日志中輸出系統(tǒng)的空閑時(shí)間等。
    當(dāng)一個(gè)大的系統(tǒng)被拆分成多個(gè)模塊時(shí),每個(gè)模塊都被賦予了整個(gè)系統(tǒng)所處理數(shù)據(jù)的一部分,正因?yàn)槟K和模塊間的接口銜接和數(shù)據(jù)感知,一些原來屬于第一類別的狀態(tài)轉(zhuǎn)換,因?yàn)橄到y(tǒng)的拆分在更低的層次上變成了第二類別,成為系統(tǒng)和環(huán)境之間的交互。
    對(duì)于一個(gè)特定的系統(tǒng),他對(duì)于輸入的形式和獲取時(shí)間是不可預(yù)知的,但是這個(gè)系統(tǒng)卻應(yīng)該能夠做到根據(jù)一個(gè)特定的輸入以及系統(tǒng)當(dāng)前的特定狀態(tài)獲取一個(gè)特定的輸出。因此系統(tǒng)的執(zhí)行可以被建模為狀態(tài)轉(zhuǎn)換序列,每個(gè)狀態(tài)的輸入是一個(gè)不確定性事件。為了記錄日志并做到故障恢復(fù),我們還應(yīng)做到能夠在環(huán)境中捕獲這個(gè)不確定性事件輸入。
    此外,在系統(tǒng)與系統(tǒng)間進(jìn)行交互式,事件的傳遞時(shí)間也應(yīng)該是不確定性的。



    怎樣用日志來預(yù)防系統(tǒng)崩潰,在崩潰后如何還原系統(tǒng),我想關(guān)鍵問題就是怎么做好內(nèi)存的快照,這樣,在斷電重啟后可以通過日志來還原內(nèi)存的信息這樣第一步就是確認(rèn)內(nèi)存中的數(shù)據(jù)結(jié)構(gòu),哪些是必不可少的。確定系統(tǒng)恢復(fù)的粒度,按照子系統(tǒng)的分割和事件的記錄來進(jìn)行replay,根據(jù)子系統(tǒng)的劃分,可以找出每個(gè)子系統(tǒng)中第二類別的事件進(jìn)行記錄。
    以向數(shù)據(jù)庫系統(tǒng)提交作業(yè)為例,實(shí)際上在整個(gè)作業(yè)提交的過程中,每個(gè)層次都要做到可以在失敗的情況下重現(xiàn),這個(gè)功能在完善的數(shù)據(jù)庫系統(tǒng)和集群批處理系統(tǒng)中當(dāng)然已經(jīng)很完善。但如果是針對(duì)web系統(tǒng)的作業(yè)提交,則需要針對(duì)Web的作業(yè)持久方案,做一個(gè)日志恢復(fù)處理。需要特別指出的是,對(duì)于數(shù)據(jù)的查詢是不需要做備份的。
    在具體實(shí)現(xiàn)上,我想應(yīng)該包括:日志記錄,故障檢測(cè),日志持久三個(gè)部分。一份日志就是一個(gè)對(duì)于系統(tǒng)檢查點(diǎn)(checkpoint)的連續(xù)記錄。日志記錄者負(fù)責(zé)記錄日志到日志持久者,故障檢測(cè)器隨時(shí)監(jiān)控系統(tǒng),發(fā)現(xiàn)故障后,從日志持久者中讀取日志,進(jìn)行replay.

    posted @ 2008-01-07 14:44 楊一 閱讀(995) | 評(píng)論 (0)編輯 收藏

    如何實(shí)現(xiàn)包含插件功能的Applet Web界面

    不知諸位有沒有想過用Applet來組織Web的程序界面?小弟最近整理了一些雜碎的思路,思想完全開放,歡迎批評(píng)。
    先說一下可能遇到的問題:
    1 安全性:Applet對(duì)本地資源的操作需要相應(yīng)的安全許可;
    2 庫資源的下載:如何下載及管理支持本地Applet的庫資源;
    3 通信:Applet如何與后臺(tái)的Servlet進(jìn)行通信;
    4 圖形的加載:如何利用Applet動(dòng)態(tài)的實(shí)例化并展現(xiàn)界面。

    下面一一展開討論

    (一)保障安全性

    安全性的主要解決方案是利用Java提供的keytool生成一個(gè)keystore,并利用這個(gè)keystore對(duì)jar包進(jìn)行signjar的操作。
    整個(gè)對(duì)Java文件的編譯,打包和signjar過程可以利用Ant來完成,比如下面的Ant腳本片段就是用來處理signjar的,大家也可以通過相應(yīng)的Java命令直接處理:

    < target  name ="signjar"  depends ="jar" >
     
    < signjar  jar ="example.jar"
      keystore
    ="${basedir}/yangyi.keystore"  storepass ="mypassword"  alias ="mykey" ></ signjar >
    </ target >

    如果直接用命令,則其形式為:
    jarsigner [ options ] jar-file alias
    具體的操作方法可以參考下面的鏈接:
    http://java.sun.com/j2se/1.5.0/docs/tooldocs/windows/jarsigner.html
    通過這個(gè)signjar的操作,我們就給這個(gè)包中的類進(jìn)行了一次數(shù)字簽名,這樣,當(dāng)Applet進(jìn)行默認(rèn)許可之外的操作時(shí),窗口將彈出這個(gè)數(shù)字簽名要求本地用戶進(jìn)行確認(rèn),只有在確認(rèn)后,用戶才可以繼續(xù)進(jìn)行操作。

    這樣我們可以在第一次用戶運(yùn)行Applet程序時(shí),在用戶的許可下動(dòng)態(tài)地在用戶的$user.home/.java.policy下生成一個(gè)授權(quán)文件,以后就可以執(zhí)行需要的操作了,為保證客戶端的安全性,僅賦予用戶執(zhí)行特定文件夾權(quán)限的權(quán)利,如(僅作為例子,可以根據(jù)需要自己配置文件和Socket訪問權(quán)限):
    grant codeBase "file:/home/yiyang/test/×" {
     java.security.AllPermission;
    };

    (二)下載并管理庫支持

    這個(gè)過程可以通過Java的URL類提供的openConnection方法來獲取一個(gè)InputStream從而獲取到遠(yuǎn)程的資源(包括支持庫和配置文件兩部分)
    1)對(duì)于配置文件,因?yàn)槠鋬?nèi)容都比較少,而且比較簡(jiǎn)單,可以直接通過輸入流來獲取,這是沒有異議的;
    2)對(duì)于庫文件,在下載之前先到我們管理的庫的目錄下找到版本索引文件(我們?cè)O(shè)定一個(gè)版本索引文件來管理升級(jí)),這個(gè)版本索引文件如下所示:

    time={資源獲取的時(shí)間戳}
    lib1.jar=1.0
    lib2.jar=1.1

    其中,服務(wù)器端也保留有一份這樣的版本文件,當(dāng)下載庫文件時(shí),首先對(duì)客戶端和服務(wù)端的庫的總時(shí)間戳進(jìn)行比較,如果客戶端大于或等于服務(wù)端,則不需下載,否則,如果客戶端對(duì)應(yīng)項(xiàng)目為空或者其總的時(shí)間戳小于服務(wù)端,則進(jìn)一步比較內(nèi)部庫文件的版本,發(fā)現(xiàn)版本低的庫或在客戶端不存在的庫后,自動(dòng)到服務(wù)器上進(jìn)行下載,在下載成功后,更新客戶端的索引文件。

    (三)通信

    這個(gè)問題小弟曾在以往的blog中有過詳細(xì)的討論,可以到http://yangyi.blogjava.net中的相應(yīng)隨筆中找到答案。總的來說,在類型協(xié)議并不復(fù)雜,且客戶端,服務(wù)端均為Java開發(fā)的情況下,應(yīng)用Hessian是一個(gè)好的解決方案,需要指出的是Hessian中的代碼對(duì)客戶端來說并不是全部必須的,大家可以根據(jù)客戶端的使用情況對(duì)這個(gè)庫進(jìn)行瘦身。只保留作為客戶端必要的類即可。

    (四)動(dòng)態(tài)的實(shí)例化及插件結(jié)構(gòu)

    我們要實(shí)現(xiàn)用戶界面的集成,從根本上說要解決下面的幾個(gè)問題:
    1)菜單集成
    2)支持庫集成
    3)集成點(diǎn)
    4)輸出變量
    對(duì)于客戶端為Applet開發(fā)的插件,我們把上面的四項(xiàng)配置統(tǒng)一在XML文件中進(jìn)行描述定義。
    這里需要注意的是菜單要提供名稱,支持庫要提供下載路徑或者本地路徑,集成點(diǎn)我們希望是一個(gè)JPanel。
    在定義好XML后,可以到網(wǎng)址:http://www.flame-ware.com/xml2xsd/去獲得一個(gè)對(duì)應(yīng)的schema,利用這個(gè)schema和JAXB提供的xjc工具,我們就可以生成對(duì)應(yīng)的XML操作類,來對(duì)配置進(jìn)行處理。
    對(duì)于菜單的集成可以動(dòng)態(tài)地在JMenu中添加MenuItem(表示插件的功能)
    根據(jù)配置的支持庫的位置,我們可以通過Java的URLClassLoader對(duì)庫進(jìn)行動(dòng)態(tài)的加載,然后根據(jù)相應(yīng)的集成點(diǎn),獲取實(shí)例,這個(gè)過程的示例代碼如下所示:

    File f  =   new  File( " a.jar " );  // a.jar是我們從配置文件中讀取的支持庫
    URL url  =   null ;
    Class lib 
    =   null ;
    try   {
     url 
    =  f.toURI().toURL();
     lib 
    =  Class.forName( " Lib " true new  URLClassLoader(
       
    new  URL[]  { url } ));  // Lib是我們從配置文件中讀取的集成點(diǎn)
     JPanel plugin_panel  =  (JPanel)lib.newInstance();
     
    return  plugin_panel;
    }
      catch  (Exception e)  {
     e.printStackTrace();
    }

    對(duì)于輸出變量,其主要作用是用戶各個(gè)插件之間的信息交互,我們可以通過一個(gè)總的HashMap來實(shí)現(xiàn),為避免變量值出現(xiàn)沖突,在變量名前自動(dòng)加上插件名的前綴。
    如plug_in1的變量var1,其系統(tǒng)名稱為:plug_in1__var1.

    解決了上面的四個(gè)障礙,我們就可以把精力投入到具體的功能實(shí)現(xiàn)上了。

    posted @ 2008-01-02 15:07 楊一 閱讀(1734) | 評(píng)論 (4)編輯 收藏

    好好學(xué)習(xí),天天向上

    總算找到了工作. 我會(huì)好好努力的. 此時(shí)此刻,更加明白,以往的一切榮與辱都成為過去. 又要踏上新的征程.

    posted @ 2007-12-30 12:56 楊一 閱讀(295) | 評(píng)論 (0)編輯 收藏

    myeclipse

    剛看了myeclipse,eclipse是一個(gè)很可怕的東西,它試圖讓所有的開發(fā)人員一打開電腦就不能夠離開它,還要在里面完成所有的工作。人們不至于反感它的原因是它是開源的,不受商業(yè)控制的。如果我們對(duì)于myeclipse過度依賴,必然最終走向?qū)ξ④泧?yán)重依賴的老路。我不反對(duì)利用軟件盈利。但是自由的精神不應(yīng)被改變。
    微軟和我們是原始的獵人與獵物之間的關(guān)系,虎與倀的關(guān)系,最終極的占有。我們這才生是MS的人,死是MS的鬼。

    posted @ 2007-12-28 11:39 楊一 閱讀(318) | 評(píng)論 (0)編輯 收藏

    利用JAAS及JNI實(shí)現(xiàn)在Java環(huán)境下的Unix/Linux權(quán)限認(rèn)證

         摘要: 這篇隨筆談一談如何在Java環(huán)境下利用Unix/Linux的用戶名和密碼對(duì)用戶的權(quán)限作出過濾。為方便大家學(xué)習(xí)交流,本文中給出了源代碼,借此拋磚引玉,歡迎大家對(duì)這個(gè)簡(jiǎn)單的登錄模型做出改進(jìn)或者設(shè)計(jì)出自己的技術(shù)方案。
    由標(biāo)題我們不難看出,與本文相關(guān)的知識(shí)點(diǎn)主要有3個(gè):
    1 JAAS這個(gè)解耦設(shè)計(jì)的多層驗(yàn)證方法(1.4后已歸入Java核心庫中)
    2 應(yīng)用JNI訪問底層代碼,及JNI中簡(jiǎn)單的類型匹配
    3 在shadow模式下,Unix/Linux系統(tǒng)的用戶驗(yàn)證  閱讀全文

    posted @ 2007-12-12 16:50 楊一 閱讀(1472) | 評(píng)論 (0)編輯 收藏

    延遲加載技術(shù)及其在iBATIS中的實(shí)現(xiàn)

    O/R映射框架的延遲加載技術(shù)實(shí)現(xiàn)大體上有這么4種(參看Martin Fowler的意見):
    (http://www.martinfowler.com/eaaCatalog/lazyLoad.html)

    There are four main varieties of lazy load. Lazy Initialization uses a special marker value (usually null) to indicate a field isn't loaded. Every access to the field checks the field for the marker value and if unloaded, loads it. Virtual Proxy is an object with the same interface as the real object. The first time one of its methods are called it loads the real the object and then delegates. Value Holder is an object with a getValue method. Clients call getValue to get the real object, the first call triggers the load. A ghost is the real object without any data. The first time you call a method the ghost loads the full data into its fields.

    通過閱讀源代碼,發(fā)現(xiàn)iBATIS中的延遲加載是用上述方式中的虛擬代理實(shí)現(xiàn)的.

    在動(dòng)態(tài)代理的實(shí)現(xiàn)上, iBATIS有Java動(dòng)態(tài)代理和CGLIB兩種實(shí)現(xiàn)方案,iBATIS把用CGLIB實(shí)現(xiàn)的方案稱為Enhanced的方案,可見CGLIB的效率會(huì)比java的動(dòng)態(tài)代理效率要高.
    在iBATIS首先判斷是否定義了延遲加載,如果定義了,則利用Lazy的Loader來提取數(shù)據(jù)(返回一個(gè)Proxy).如沒有執(zhí)行對(duì)這個(gè)的任何操作,或者只是不再使用(finalize),則不做處理,否者就加載真正的對(duì)象.

    可以通過閱讀類
    com.ibatis.sqlmap.engine.mapping.result.loader.LazyResultLoader
    的源碼獲取更多的細(xì)節(jié).

    posted @ 2007-12-09 19:17 楊一 閱讀(2052) | 評(píng)論 (0)編輯 收藏

    淺談Java中的通信機(jī)制及與C/C++ API的集成(下)

    接著上次的話題,今天我們聊聊gSOAP這個(gè)框架,我們把用C寫的舊有系統(tǒng)用gSOAP改造一下,通過SOA的形式發(fā)布出去。
    上文提到,利用gSOAP可以做到以下3點(diǎn):
    1 一個(gè)Stand-alone的服務(wù)器外殼
    2 一個(gè)根據(jù)API程序自動(dòng)生成的Web Services服務(wù)
    3 一個(gè)WSDL描述符文件

    客戶根據(jù) WSDL 描述文檔,會(huì)生成一個(gè) SOAP 請(qǐng)求消息。Web Services 都是放在Web服務(wù)器后面,客戶生成的SOAP請(qǐng)求會(huì)被嵌入在一個(gè)HTTP POST請(qǐng)求中,發(fā)送到 Web 服務(wù)器來。Web 服務(wù)器再把這些請(qǐng)求轉(zhuǎn)發(fā)給 Web Services 請(qǐng)求處理器。請(qǐng)求處理器的作用在于,解析收到的 SOAP 請(qǐng)求,調(diào)用 Web Services,然后再生成相應(yīng)的 SOAP 應(yīng)答。Web 服務(wù)器得到 SOAP 應(yīng)答后,會(huì)再通過 HTTP應(yīng)答的方式把信息送回到客戶端。
    WSDL是Web服務(wù)中客戶端和服務(wù)端溝通的橋梁,描述了對(duì)象提供的方法。SOAP幫我們制定了一份被官方認(rèn)可的對(duì)象的封裝方法。有了WSDL,客戶端只關(guān)心如何把參數(shù)用Soap封裝起來發(fā)出去,并獲取結(jié)果。服務(wù)端只關(guān)心如何對(duì)Soap進(jìn)行拆包->服務(wù)->封包。gSOAP可以幫我們實(shí)現(xiàn)上述過程中的拆包和封包,而我們可以只關(guān)心服務(wù)的實(shí)現(xiàn)。

    言歸正傳,在這里我們以一個(gè)簡(jiǎn)單的實(shí)現(xiàn)加、減、開放的Web Services的服務(wù)為例子,介紹gSOAP的使用:
    為了發(fā)布這個(gè)Web服務(wù),首先我們需要把服務(wù)的接口定義好,這個(gè)服務(wù)可能是一個(gè)現(xiàn)有服務(wù)的Adapter,為此我們定義頭文件
    calc.h:
    typedef double xsd__double;
    int ns__add(xsd__double a, xsd__double b, xsd__double &result);
    int ns__sub(xsd__double a, xsd__double b, xsd__double &result);
    int ns__sqrt(xsd__double a, xsd__double &result); 
    注意到這里面我們把double定義成了xsd__double(兩個(gè)下劃線),這是為了告訴gSOAP,我們需要的soap格式和WSDL格式是基于Document/literal的而非rpc/encoded.為了不把事情搞復(fù)雜,在這里我只能說,Java1.6自帶的Web Services工具只支持Document/literal格式的WSDL,所以我們生成這種格式的WSDL。至于這兩種格式之間選擇和他們的long story,大家可以參考下面的文章:
    http://www.ibm.com/developerworks/webservices/library/ws-whichwsdl/
    編寫好頭文件后,我們就可以利用gSOAP提供的工具進(jìn)行生成了:
    /usr/lib/gsoap-2.7/bin/soapcpp2 -S -2 calc.h
    生成的主要文件詳見附件。
    下面我們實(shí)現(xiàn)calc.h中定義的函數(shù):
    // Contents of file "calc.cpp": 
    #include "soapH.h" 
    #include 
    "ns.nsmap" 
    #include 
    <math.h> 
    int main()
    {
       struct soap soap;
       
    int m, s; // master and slave sockets
       soap_init(&soap);
       m 
    = soap_bind(&soap, "localhost"9999100);
       
    if (m < 0)
          soap_print_fault(
    &soap, stderr);
       
    else
       {
          fprintf(stderr, 
    "Socket connection successful: master socket = %d\n", m);
          
    for (int i = 1; ; i++)
          {
             s 
    = soap_accept(&soap);
             
    if (s < 0)
             {
                soap_print_fault(
    &soap, stderr);
                
    break;
             }
             fprintf(stderr, 
    "%d: accepted connection from IP=%d.%d.%d.%d socket=%d", i,
                (soap.ip 
    >> 24)&0xFF, (soap.ip >> 16)&0xFF, (soap.ip >> 8)&0xFF, soap.ip&0xFF, s);
             
    if (soap_serve(&soap) != SOAP_OK) // process RPC request
                soap_print_fault(&soap, stderr); // print error
             fprintf(stderr, "request served\n");
             soap_destroy(
    &soap); // clean up class instances
             soap_end(&soap); // clean up everything and close socket
          }
       }
       soap_done(
    &soap); // close master socket and detach environment
    }
    // Implementation of the "add" remote method: 
    int ns__add(struct soap *soap, double a, double b, double &result) 

       result 
    = a + b; 
       
    return SOAP_OK; 

    // Implementation of the "sub" remote method: 
    int ns__sub(struct soap *soap, double a, double b, double &result) 

       result 
    = a - b; 
       
    return SOAP_OK; 

    // Implementation of the "sqrt" remote method: 
    int ns__sqrt(struct soap *soap, double a, double &result) 

       
    if (a >= 0
       { 
          result 
    = sqrt(a); 
          
    return SOAP_OK; 
       } 
       
    else
       { 
          
    return soap_sender_fault(soap, "Square root of negative value""I can only compute the square root of a non-negative value");
       } 
    前文提到過,我們不希望為了發(fā)布基于Web Services的C語言的API而開發(fā)或應(yīng)用一個(gè)大的Web服務(wù)器。我們代碼中的main函數(shù)實(shí)現(xiàn)了一個(gè)最簡(jiǎn)單的Web Server(基于Socket).這個(gè)Server利用gSOAP生成的API來提供針對(duì)SOAP的處理。
    下面我們把這個(gè)嵌入式的web server編譯,編譯的時(shí)候注意stdsoap2.cpp這個(gè)文件是從gSOAP包中拷貝而來,不是自動(dòng)生成的,大家下載gSOAP后直接就能找到這個(gè)文件及其頭文件。
    g++ -o calcServer calc.cpp soapC.cpp soapServer.cpp stdsoap2.cpp
    一個(gè)以Web Servers形式提供的C API誕生了。
    在server端執(zhí)行./calcServer

    下面討論如何用Java1.6的自帶工具生成一個(gè)客戶端stub:
    把gSOAP生成的WSDL拷貝到我們的Java開發(fā)環(huán)境中來,按照Web Services Server中定義的端口和服務(wù)器,配置參數(shù)生成客戶端Web Services代碼:
    /usr/lib/jvm/jdk1.6.0_03/bin/wsimport -extension -httpproxy:localhost:9999 -verbose ns.wsdl

    生成后,把這個(gè)環(huán)境添加到eclipse的編譯環(huán)境中來,然后在eclipse中建一個(gè)新的類:
    class Test {
        
    public static void main(String args[]) {
            Service service 
    = new Service();
            
    double h = service.getService().sub(200001);
            System.out.println(h);
        }
    }
    運(yùn)行后得到結(jié)果19999.0

    總結(jié):當(dāng)集成Java和C兩種平臺(tái)時(shí),我們可以有多種解決方案,但首先我們應(yīng)該想到gSOAP因?yàn)樗軌蚝艹錾赝瓿扇蝿?wù)。
    文中相關(guān)代碼:
    http://www.tkk7.com/Files/yangyi/gsoap.zip
    廣告:本人明年畢業(yè),正在找工作,個(gè)人簡(jiǎn)歷:
    http://www.tkk7.com/Files/yangyi/My%20Resume.zip

    posted @ 2007-12-06 12:19 楊一 閱讀(1777) | 評(píng)論 (2)編輯 收藏

    淺談Java中的通信機(jī)制及與C/C++ API的集成(上)

    背景:
    對(duì)于舊有系統(tǒng)的改造和升級(jí),最苦惱的莫過于跨平臺(tái),跨語言。我的一個(gè)朋友最近從Java專向了專攻.NET——因?yàn)?NET的CLR既有類似Java虛擬機(jī)概念這種已經(jīng)被證明很成功的底層托管能力。又對(duì)于Windows的就有桌面應(yīng)用提供了良好的兼容。
    最近我的一個(gè)個(gè)人項(xiàng)目也面臨著這樣的需求。一個(gè)C語言開發(fā)的中間件,通過API暴露給二次開發(fā)及插件應(yīng)用。現(xiàn)在由于對(duì)其應(yīng)用的需求變得日趨復(fù)雜,而且正在脫離Unix的管理環(huán)境,走向基于JWS這樣的BCS管理。有朋友推薦我用JNI,但這樣一是增加了耦合度,二是讓Java睡在JNI感覺不太安穩(wěn)。在認(rèn)知了上下兩層的系統(tǒng)平臺(tái)后,問題變得明朗起來:如何在HTTP協(xié)議下實(shí)現(xiàn)Java和C之間的交互?
    思路:
    本人對(duì)Java比較熟悉,先從Java的角度入手,Java間的通信方法:
    1 通過URL,Applet/JWS訪問被影射到URL的動(dòng)態(tài)資源(Servlet)
    2 通過URL,Applet/JWS訪問共享的靜態(tài)資源(Server定期更新靜態(tài)資源)
    3 通過序列化和反序列化,實(shí)現(xiàn)簡(jiǎn)單對(duì)象的傳輸(比如Resin的Hessian框架就提供了這種通信的方式)
    4 通過一些工具做代碼生成,利用Web Services實(shí)現(xiàn)客戶端和服務(wù)端的交互
    此外脫離HTTP,還可以做RMI,socket編程

    現(xiàn)在問題是通信的一端由Java變成了C/C++, 于是, 解決方案1需要把動(dòng)態(tài)資源由CGI來定義,而方案3變得不再適用。于是方案有:
    1 通過URL,Applet/JWS訪問被影射到URL的動(dòng)態(tài)資源(CGI)
    2 通過URL,Applet/JWS訪問共享的靜態(tài)資源(Server定期更新靜態(tài)資源)
    3 通過一些工具做代碼生成,利用Web Services實(shí)現(xiàn)客戶端和服務(wù)端的交互(×××這是我們討論的重點(diǎn)×××)

    解決方案:
    現(xiàn)在針對(duì)上文提出的3中通信方式中的1和3談一談實(shí)現(xiàn)的方法,2的實(shí)現(xiàn)方案比較靈活,需要發(fā)揮大家的想象力了:)
    針對(duì)CGI:
    首先CGI可以配置在各種主流的服務(wù)器中作為后端的腳本運(yùn)行。大家可能對(duì)Servlet更熟悉一些。
    CGI可以用腳本寫,也可以用C來實(shí)現(xiàn)。CGI被觸發(fā)后,通過系統(tǒng)的環(huán)境變量來獲得輸入,在處理完畢后向標(biāo)準(zhǔn)輸出中輸出結(jié)果。
    由此可以想見,Web服務(wù)器在接受到來自HTTP協(xié)議的請(qǐng)求后,首先把請(qǐng)求的參數(shù)獲取到,然后設(shè)置到環(huán)境變量里。
    根據(jù)對(duì)訪問的URL的解析和服務(wù)器自身的配置,找到服務(wù)于請(qǐng)求的CGI程序的位置,然后執(zhí)行這個(gè)程序。
    這個(gè)程序被執(zhí)行后通過環(huán)境變量得到了服務(wù)器先前設(shè)置在環(huán)境變量中的參數(shù)。在經(jīng)過一些復(fù)雜的邏輯操作后,向標(biāo)準(zhǔn)輸出輸出結(jié)果。
    這個(gè)輸出又被Web服務(wù)器所捕獲,轉(zhuǎn)而傳遞回請(qǐng)求的客戶端。
    更多關(guān)于CGI的知識(shí)和理解,大家可以通過google來尋找答案

    上述CGI的方式可以讓我們直接獲取到結(jié)果,但是方案比較原始和基礎(chǔ)。其缺點(diǎn)有:
    1 需要自己制定類型傳輸協(xié)議,做封裝和拆封,否則只支持字符串
    2 我們不會(huì)為了要用C的API就給它裝一個(gè)或者自己實(shí)現(xiàn)一個(gè)Web服務(wù)器的,這讓我們的底層程序顯得蠢笨而冗余。我們希望能有一個(gè)超薄的Server外殼,
    在對(duì)API封裝后,通過某個(gè)端口進(jìn)行開放即可。

    針對(duì)Web Servcies:
    Based on上面的兩個(gè)不足,我們只能把希望寄托在Web Services身上了,
    筆者在這里推薦給大家的是在C/C++很著名的Web Services工具gSOAP。大家可以到http://gsoap2.sourceforge.net/上去下載這個(gè)工具。
    通過這個(gè)工具,我們可以做到:
    1 一個(gè)Stand-alone的服務(wù)器外殼
    2 一個(gè)根據(jù)API程序自動(dòng)生成的Web Services服務(wù)
    3 一個(gè)WSDL描述符文件

    有關(guān)基于gSOAP的Web Services C服務(wù)端和Java客戶端的運(yùn)行機(jī)理,及通過Java客戶端訪問gSOAP的Web Services的過程中需要注意的問題(筆者費(fèi)了一天周折才搞清楚),將在下一篇中描述

    廣告時(shí)間:
    本人是哈工大的研究生,明年7月畢業(yè)。正在找工作,如果有工作機(jī)會(huì),別忘了通知小弟哦(contactyang@163.com)

    posted @ 2007-12-04 17:33 楊一 閱讀(2040) | 評(píng)論 (0)編輯 收藏

    好久沒有更新了

    好久沒有更新了,昨天在VMware上安裝了一個(gè)虛擬的局域網(wǎng),并在其上 配置了NFS和NIS,以及公司的集群產(chǎn)品LSF


    posted @ 2007-10-11 18:02 楊一 閱讀(256) | 評(píng)論 (1)編輯 收藏

    建了一個(gè)工具類,送給需要拼接插入字符串的朋友們:)


    import  java.sql.Date;

    /**
     * 這個(gè)類用來對(duì)數(shù)據(jù)庫做插入操作時(shí)采用
     * 
    @author  yangyi
     *
     
    */


    public   class  InsertTool  {
        
    private  String tableName;

        
    private  StringBuffer sbColumnName;

        
    private  StringBuffer sbColumnContent;

        
    public  InsertTool(String tableName)  {
            
    this .tableName  =  tableName;
            sbColumnName 
    =   new  StringBuffer();
            sbColumnContent 
    =   new  StringBuffer();
        }


        
    public   void  add(String columnName, Object columnContent)  {
            insertColumnName(columnName);
            
    if  (columnContent  instanceof  Date)  {
                sbColumnContent.append(
    " , "   +  columnContent);
            }
      else
                sbColumnContent.append(
    " ,' "   +  columnContent  +   " ' " );
        }


        
    public   void  add(String columnName,  int  columnContent)  {
            insertColumnName(columnName);
            sbColumnContent.append(
    " , " + columnContent);
        }


        
    private   void  insertColumnName(String columnName)  {
            sbColumnName.append(
    " , "   +  columnName);
        }


        
    public  String getInsertSql()  {
            StringBuffer sb 
    =   new  StringBuffer();
            sb.append(
    " INSERT INTO  " );
            sb.append(tableName);
            sb.append(
    " ( " );
            sb.append(sbColumnName.substring(
    1 ));
            sb.append(
    " ) VALUES( " );
            sb.append(sbColumnContent.substring(
    1 ));
            sb.append(
    " ) " );
            
    return  sb.toString();
        }

        
        
    public   static   void  main(String args[]) {
            InsertTool it 
    =   new  InsertTool( " aa " );
            it.add(
    " a " , " d " );
            it.add(
    " b " , 10 );
            it.add(
    " c " , 1 );
            System.out.println(it.getInsertSql());
        }

    }

    使用方法非常簡(jiǎn)單,看看Main就知道啦

    posted @ 2007-06-14 12:41 楊一 閱讀(873) | 評(píng)論 (1)編輯 收藏

    Are you a coder or a programmer?

    Are you trying to build software that is composed by software components provided by large companies, and still name it a system?
    Are you doing the job anybody can do if given enough time to read the technical handbooks and rebuild the system or you have created something?
    If you are in the same situation, you are probably a coder instead of a programmer.

    posted @ 2007-06-13 19:47 楊一 閱讀(301) | 評(píng)論 (1)編輯 收藏

    My Attitude Toward Linux Shell

    I must be an extremely patient user of Linux, for I have been trying to install all versions of Linux distributions lately, and getting used to the shell commands.

    I also read some books on the subject. To be honest, it is true that the command lines are more efficient, and this can be verified by the following calculation:

    Suppose a mouse have 3 keys, and the keyboard ten times more. The three key mouse can generate actions 3^2 when clicked 2 times, while the keyborad 30^2. Come on, no matter we clicked the keyboard or the mouse, we just clicked 2 times.

    posted @ 2007-05-31 23:08 楊一 閱讀(300) | 評(píng)論 (0)編輯 收藏

    [譯]JDBC4.0具有哪些新特性?

         摘要: 在 Java SE 6 所提供的諸多新特性和改進(jìn)中,值得一提的是為 Java 程序提供數(shù)據(jù)庫訪問機(jī)制的 JDBC 版本升級(jí)到了 4.0, 這個(gè)以 JSR-221 為代號(hào)的版本 , 提供了更加便利的代碼編寫機(jī)制及柔性 , 并且支持更多的數(shù)據(jù)類型 . 在本文中,我們將從編碼的易用性及柔性的角度探討 JDBC 4.0 所帶來的新特性及改進(jìn)。
    JDBC 4.0 的新特性

    JDBC 4.0 文檔列舉了 20 個(gè)改進(jìn)及新特性 , 大小不等 . 本文無法做到盡述其詳 , 為此筆者根據(jù)其功能特點(diǎn)及應(yīng)用領(lǐng)域?qū)⑵浞譃橄率鏊念悾?

    1. 驅(qū)動(dòng)及連接管理

    2. 異常處理

    3. 數(shù)據(jù)類型支持

    4. API 的變化

    本文按照上述四類展開詳述
      閱讀全文

    posted @ 2007-04-24 16:25 楊一 閱讀(3381) | 評(píng)論 (2)編輯 收藏

    Zarar Siddiqi: JSP是不是應(yīng)該退出歷史舞臺(tái)了?(譯自theServerSide.com)

    Zarar Siddiqi寫了一篇題為"Are JSPs Dead?,"的文章,文中不無夸張地建議,JSP技術(shù)應(yīng)該也許根本不該出現(xiàn)在JavaEE開發(fā)的前沿陣地上,或許僅僅是ASP的原因吧.他說:
    JSP給Java的應(yīng)用的重用所帶來的阻礙是巨大的, J2EE中并沒有提供這種機(jī)制.而如果你非要這么做的話,則必然以犧牲其他模塊或應(yīng)用的更大的可重用性為代價(jià)。對(duì)于容器的高度依賴導(dǎo)致了對(duì)SE的重用不可實(shí)現(xiàn),同時(shí)測(cè)試工作也變得舉步維艱,您或許不得不建立一些Mock對(duì)象來觀察結(jié)果.JSP和Servlet一對(duì)一的綁定,對(duì)我來說也不是什么有趣的事情,后臺(tái)對(duì)JSP編譯為Java類的處理也毫無意義. 既然可以通過Servlet為網(wǎng)頁直接服務(wù),為什么還要多余的推出一種混合的技術(shù)呢?

    如果您還在考慮用JSP做您的MVC模型中的V部分來開發(fā)哪怕是一個(gè)中等大小的應(yīng)用,您已經(jīng)在犯嚴(yán)重的錯(cuò)誤了。特別是,如果您的JSP僅僅作為視圖顯示的時(shí)候(頁面中沒有實(shí)際代碼,只有taglibs),因?yàn)椋踔吝B它僅有的“優(yōu)點(diǎn)”——內(nèi)嵌Java代碼都沒有應(yīng)用。如果您是那種認(rèn)為標(biāo)簽庫沒有想象中那么糟的人,那么您還是可以使用頁面腳本,以此來生產(chǎn)您認(rèn)為合格的軟件。您已經(jīng)無藥可救了。
    Zarar建議使用Freemarker, Velocity, 以及AJAX 來替換JSP.

    這實(shí)在是種有趣的想法, 因?yàn)椴徽撐覀兿矚g與否 (Zarar顯然屬于“否”的行列) JSPs是Java EE中默認(rèn)的顯示技術(shù). JSP是否稱職呢? 是否還有其他的可以成為標(biāo)準(zhǔn)的技術(shù)呢? 您又在應(yīng)用何種技術(shù)呢? 為什么? (那些還被迫夾在陳舊的項(xiàng)目的中的,仍在使用Struts 1.1和JSPs的“可憐”的朋友們呢?)

    posted @ 2007-04-22 15:31 楊一 閱讀(2017) | 評(píng)論 (5)編輯 收藏

    用代碼一步步學(xué)習(xí)Spring:IoC,AOP

         摘要: 本文通過幾段可以運(yùn)行的代碼示例,讓大家在20分鐘之內(nèi)掌握Spring的IoC,AOP這些不易理解的概念  閱讀全文

    posted @ 2006-12-11 22:55 楊一 閱讀(2558) | 評(píng)論 (1)編輯 收藏

    一點(diǎn)想法

    最近學(xué)業(yè)太過緊張,都沒有時(shí)間更新blog了,等忙完了這一陣吧。

    現(xiàn)在我學(xué)習(xí)的主打有兩個(gè)截然不同的方向。一個(gè)是工作流技術(shù),一個(gè)是移動(dòng)計(jì)算技術(shù)。

    前一個(gè)是我從本科起就一直在搞得東西,想一直鉆研下去,多翻譯一些,原創(chuàng)一些這方面的文章。

    另一方面先在,移動(dòng)計(jì)算方興未艾,可以預(yù)見在不遠(yuǎn)的將來必定是移動(dòng)計(jì)算的世界。

    其實(shí),這兩個(gè)方向到也是不矛盾的,一個(gè)客戶端,一個(gè)服務(wù)器。

    posted @ 2006-11-29 15:31 楊一 閱讀(466) | 評(píng)論 (0)編輯 收藏

    學(xué)習(xí)Linux有感

    記得很久以前,曾經(jīng)看過一篇帖子說,“完全使用 Linux ,脫離 Windows ”,在最近的一個(gè)月時(shí)間里,我嘗試了這種做法。結(jié)論讓我不得不說: Linux 如果作為桌面來使用的話,還遠(yuǎn)遠(yuǎn)沒有到達(dá)實(shí)用的程度。

    作為開發(fā)環(huán)境和服務(wù)器倒是非常不錯(cuò)的,因此我把 Linux 配置成了一個(gè)開發(fā)工具,而用 Windows 來娛樂。

    vi nano emacs anjuta eclipse都是非常好的編輯開發(fā)工具。

    posted @ 2006-11-06 10:20 楊一 閱讀(654) | 評(píng)論 (3)編輯 收藏

    您不得不關(guān)注的成長(zhǎng)群體

    現(xiàn)在Java技術(shù)在全世界很流行,Java的一個(gè)優(yōu)點(diǎn)是程序員很不容易被一種技術(shù)所束縛,而技術(shù)的成長(zhǎng)在與經(jīng)驗(yàn)的交流和不斷的學(xué)習(xí)。
    歡迎高手和未來的高手,有志于實(shí)現(xiàn)四個(gè)現(xiàn)代化的青壯年加入技術(shù)討論群:26839664。
    我們討論: Java,Python,Unix/ linux下的C/C++,PHP, Perl,SOA,Web Services,架構(gòu),模式,框架,DB,Workflow... 

    posted @ 2006-10-25 22:31 楊一 閱讀(650) | 評(píng)論 (1)編輯 收藏

    編程的6個(gè)原則

         摘要: 原作:Joseph Ottinger, 來自近日的theServerSide,本文是譯文。

    原作網(wǎng)址:http://www.theserverside.com/news/thread.tss?thread_id=42598


    Empathy Box在blog中介紹了編程應(yīng)該注意的5個(gè)問題,這篇文章實(shí)際表述了編程時(shí)應(yīng)引起注意的很重要的6個(gè)思想  閱讀全文

    posted @ 2006-10-13 22:03 楊一 閱讀(1612) | 評(píng)論 (2)編輯 收藏

    數(shù)字驗(yàn)證碼小圖生成程序

         摘要: 做了一個(gè)登陸驗(yàn)證碼的生成小程序,或許對(duì)大家有用。支持背景圖和文字旋轉(zhuǎn)  閱讀全文

    posted @ 2006-09-21 20:13 楊一 閱讀(1434) | 評(píng)論 (2)編輯 收藏

    開源軟件優(yōu)于商業(yè)軟件嗎?

         摘要: 本文是TheServerSide首頁的文章,本文是譯文,本文基于一個(gè)調(diào)查,結(jié)合關(guān)于開源軟件質(zhì)量的文章,發(fā)表了作者關(guān)于開源軟件質(zhì)量的一些看法  閱讀全文

    posted @ 2006-09-16 18:07 楊一 閱讀(1407) | 評(píng)論 (1)編輯 收藏

    值得借鑒的SWT shell構(gòu)造方法的編程模式

    SWT shell的構(gòu)造方法影響深遠(yuǎn),是值得我們借鑒的編程模式,采用了如下的形式:
    new MyClass(MyClass.A | MyClass.B | MyClass.C)
    其中,對(duì)于MyClass.A定義為 1<<1,MyClass.B 定義為 1<<2 以此類推。
    在我們都知道,在java中整形是4個(gè)字節(jié),那么除去符號(hào)位,還可以有31bit用來加入各種各樣的開關(guān),
    當(dāng)31個(gè)條件都滿足時(shí),將得到Integer.MAX_VALUE.這樣保證了傳入的是一個(gè)整型的數(shù),而在構(gòu)造方法內(nèi)部可以這樣判斷:

    public MyClass(int types){
      
    if(types & MyClass.A != 0){
        
    //表示在A條件被設(shè)定時(shí)的情況
        
      }
    }

    這種模式主要用來配置當(dāng)一個(gè)類中的多個(gè)屬性都是“開關(guān)型”的變量 —— 即位布爾型時(shí)的情況,從用

    戶接口的角度,增加了利用接口開發(fā)程序人員所編寫程序的可讀性,因此當(dāng)所編寫的程序僅供自己使用

    時(shí),我個(gè)人不推薦這種方法;而對(duì)于相反的情況,則強(qiáng)烈推薦。另一方面來說,這種編程模式提高了程

    序的運(yùn)行效率。

    posted @ 2006-09-10 14:00 楊一 閱讀(546) | 評(píng)論 (0)編輯 收藏

    Spring Ioc值得注意的兩個(gè)特性

    1 Spring支持生命周期的回調(diào),通過在bean配置屬性中增加init-method來做一些初始化的工作,隨之而產(chǎn)生了一個(gè)疑問:property設(shè)值注入和init-method哪個(gè)在先呢?結(jié)論是前者!這樣最大的好處是,我們不必再為第三方的框架代碼編寫單獨(dú)的適配器,僅僅通過在本類中property設(shè)置,然后在init-method中初始化即可;
    2 設(shè)值注入時(shí),在setXX方法中可以不僅僅是簡(jiǎn)單的this.xX = xX;而可以對(duì)xX做一些加工,如:
    setXX(int xX){
    if(xX > 10){
     
    this.xX = xX/2;
    }
    else
     
    this.xX = xX;
    }
    這兩個(gè)小技巧還停留在使用軟件而不是開發(fā)軟件的淺層次上,然而隨著Spring的日益流行,他們也許能給站在巨人肩膀上的您的開發(fā)帶來莫大的便利。

    posted @ 2006-08-24 01:03 楊一 閱讀(1002) | 評(píng)論 (0)編輯 收藏

    關(guān)于一些java框架“中文問題”的看法

         摘要: 今天上blogjava,發(fā)現(xiàn)首頁技術(shù)區(qū)突然多了好幾篇關(guān)于中文問題的文章。作者一出手便洋洋灑灑不下千言,而且好像言語中充滿了對(duì)spring支持者的不屑。在這里僅從技術(shù)角度發(fā)表一下我的個(gè)人看法,有說得不對(duì)的地方,歡迎批評(píng)指正。  閱讀全文

    posted @ 2006-08-21 14:07 楊一 閱讀(1766) | 評(píng)論 (11)編輯 收藏

    如何用java做數(shù)組亂序?

    用java做了一個(gè)數(shù)組亂序,首先建立快速排序算法,排序的依據(jù)是根據(jù)序列中隨機(jī)產(chǎn)生的序列號(hào),序列號(hào)利用map保證在每次排序過程中只產(chǎn)生一次,不知道有沒有效率更高的方法,大家咚咚腦筋哈

        
    public static void randomList(List list) {
            Collections.sort(list, 
    new Comparator(){
                HashMap map 
    = new HashMap();
                
    public int compare(Object v1, Object v2) {
                    init(v1);
                    init(v2);
                    
                    
    double n1 = ((Double)map.get(v1)).doubleValue();
                    
    double n2 = ((Double)map.get(v2)).doubleValue();
                    
    if(n1 > n2)
                        
    return 1;
                    
    else if(n1 < n2)
                        
    return -1;
                    
    return 0;
                }
                
    private void init(Object v){
                    
    if(map.get(v) == null){
                        map.put(v, 
    new Double(Math.random()));
                    }
                }
                
    protected void finalize() throws Throwable {
                    map 
    = null;
                }
            });
        }

    posted @ 2006-08-20 11:58 楊一 閱讀(2481) | 評(píng)論 (1)編輯 收藏

    如何利用apache, war包發(fā)布你的網(wǎng)站

        首先說明war包和jar包,zip包沒有什么區(qū)別,都是zip格式的文件壓縮流。因此在制作時(shí)除了利用sun jdk中的jar命令,完全可以直接用winrar之類的工具進(jìn)行zip格式壓縮,只要注意好擴(kuò)展名就好了。
        在發(fā)布war包時(shí),注意到$tomcat_home/webapps/ROOT下面是我們剛剛安裝tomcat后的測(cè)試頁面,也是我們部署的根位置所在.把這個(gè)文件夾備份到其他位置,或更改名稱.然后把你要部署的war包,改名為ROOT.war,注意這里是大小寫敏感的,一定要大寫.登陸http://localhost:8080,怎么樣,可以了吧?
        想利用apache更安全的發(fā)布你的網(wǎng)站?好,下載apache2.0,和tomcat調(diào)用模塊mod_jk.so,放到安裝好的apache2modules文件夾下,在$apache_home/conf/httpd.conf配置文件中加入如下內(nèi)容:
    <VirtualHost *:80>
        #你的電子郵箱
        ServerAdmin contactyang@163.com
        #DocumentRoot C:/Program Files/tomcat/webapps/ROOT
        #有域名嗎
        ServerName localhost
        #Load module of mod_jk apache tomcat connecter
        LoadModule jk_module modules/mod_jk.so
        JkWorkersFile conf/workers.properties
        JkLogFile     logs/mod_jk.log
        JkMount  /*.jsp ajp13

        #Load jk2 apache tomcat connecter end
    </VirtualHost>

    在$apache_home/conf目錄下建立workers.properties文件,加入如下內(nèi)容:

    workers.tomcat_home="c:\program files\tomcat"
    #讓mod_jk模塊知道Tomcat的安裝路徑
    workers.java_home=C:\Program Files\Java\jdk1.5.0
    #讓mod_jk模塊知道jdk路徑
    ps=\
    worker.list=ajp13
    #這里是關(guān)鍵,名字要和httpd.conf的一致。如果這里改了httpd.conf也要改。
    worker.ajp13.port=8009
    #工作端口,tomcat的jk監(jiān)聽端口,可以查看Tomcat 的Server.xml中有port="8009" protocolHandlerClassName="org.apache.jk.server.JkCoyoteHandler"這樣的Connector
    worker.ajp13.host=localhost
    #Tomcat所在機(jī)器,如果安裝在與apache不同的機(jī)器則需要設(shè)置IP
    worker.ajp13.type=ajp13
    #類型,Apache與Tomcat之間傳遞使用的協(xié)議
    worker.ajp13.lbfactor=1

    登陸http://localhost/

    怎么樣?有了吧

    posted @ 2006-08-20 09:35 楊一 閱讀(6046) | 評(píng)論 (0)編輯 收藏

    關(guān)于SOA與Web Services的疑問

        今天忽然想到一個(gè)問題,Web Service未來的發(fā)展趨勢(shì)是什么?為什么近兩年聽到的聲音越來越少了? 記得04年的時(shí)候,WS還是比較火的,不僅在課堂上學(xué)習(xí),還做過一些java和.net的應(yīng)用,以后就不怎么用了,也許是分布式理論受到了挑戰(zhàn)吧 (Rod果然站在時(shí)代的前沿)。
        許多人說,現(xiàn)在最火的SOA里面用到的技術(shù)就是Web Service,可是SOA是個(gè)概念而已,大廠商主導(dǎo)的東西不一定經(jīng)得起推敲的,正如WS一樣。

    網(wǎng)上一篇介紹SOA的文章如是說:

    面向服務(wù)架構(gòu)(SOA)的原則

    Web service已經(jīng)不再是新婚的娘子。眾多企業(yè)都已經(jīng)創(chuàng)建各種實(shí)驗(yàn)性Web Services 項(xiàng)目,事實(shí)證明,這項(xiàng)新興的分布式計(jì)算技術(shù)確實(shí)能夠降低集成和開發(fā)的成本。另外,一些關(guān)鍵的Web Services標(biāo)準(zhǔn)紛紛制定,強(qiáng)安全(robust security)和管理方面的產(chǎn)品也陸續(xù)問世。對(duì)于志向遠(yuǎn)大的企業(yè)來說,他們已經(jīng)在考慮下一步了。

    對(duì)大多數(shù)公司來說,下一步要考慮的不再是點(diǎn)對(duì)點(diǎn)的應(yīng)用,而是Web services在企業(yè)間以及業(yè)務(wù)伙伴間更為寬廣的應(yīng)用。這種技術(shù)的變遷需要更松散耦合、面向基于標(biāo)準(zhǔn)的服務(wù)的架構(gòu)。這樣一個(gè)架構(gòu)要求對(duì)IT在組織中的角色有新的觀點(diǎn)和認(rèn)識(shí),而不僅僅是一種實(shí)現(xiàn)方法。通過對(duì)業(yè)務(wù)的敏捷反應(yīng),企業(yè)可以得到實(shí)實(shí)在在的回報(bào),而要達(dá)到這一點(diǎn),面向服務(wù)架構(gòu)設(shè)計(jì)師的角色非常關(guān)鍵。除此之外,潛在的回報(bào)更是不可勝數(shù)-分布計(jì)算技術(shù)能夠保證對(duì)業(yè)務(wù)需求足夠靈活的反應(yīng),而這種業(yè)務(wù)上的敏捷正是各公司夢(mèng)寐以求而目前還遙不可及的。

    分布式計(jì)算將網(wǎng)絡(luò)上分布的軟件資源看作是各種服務(wù)。面向服務(wù)架構(gòu)是一種不錯(cuò)的解決方案。但這種架構(gòu)不是什么新思想;CORBA和DCOM就很類似,但是,這些過去的面向服務(wù)架構(gòu)都受到一些難題的困擾:首先,它們是緊密耦合的,這就意味著如分布計(jì)算連接的兩端都必須遵循同樣API的約束。打比方說,如果一個(gè)COM對(duì)象的代碼有了更改,那么訪問該對(duì)象的代碼也必須作出相應(yīng)更改。其二,這些面向服務(wù)架構(gòu)受到廠商的約束。Microsoft控制DCOM自不必說,CORBA也只是一個(gè)偽裝的標(biāo)準(zhǔn)化努力,事實(shí)上,實(shí)現(xiàn)一個(gè)CORBA架構(gòu),經(jīng)常都是在某個(gè)廠商對(duì)規(guī)范的實(shí)現(xiàn)上進(jìn)行工作。

    Web services是在改進(jìn)DCOM和CORBA缺點(diǎn)上的努力。今天應(yīng)用Web services的面向服務(wù)架構(gòu)與過去不同的特點(diǎn)就在于它們是基于標(biāo)準(zhǔn)以及松散耦合的。廣泛接受的標(biāo)準(zhǔn)(如XML和SOAP)提供了在各不同廠商解決方案之間的交互性。而松散耦合將分布計(jì)算中的參與者隔離開來,交互兩邊某一方的改動(dòng)并不會(huì)影響到另一方。這兩者的結(jié)合意味著公司可以實(shí)現(xiàn)某些Web services而不用對(duì)使用這些Web services的客戶端的知識(shí)有任何了解。我們將這種基于標(biāo)準(zhǔn)的、松散耦合的面向服務(wù)的架構(gòu)簡(jiǎn)稱為SOA。

     
        這和當(dāng)年的宣傳WS并沒有什么不同,僅僅多了個(gè)SOA而已, 試問今天的架構(gòu)師,哪位應(yīng)用了WS,哪位涉及了SOA? 有多少成功的案例?哪位知道這項(xiàng)技術(shù)在美國的發(fā)展情況,有很廣泛的應(yīng)用嗎,還是僅限于SOA?
        真正項(xiàng)目中需要SOA思想的那種跨國財(cái)團(tuán)有幾個(gè)?對(duì)于在國內(nèi)最多的中小型應(yīng)用,暴露服務(wù)倒是極危險(xiǎn)的事情。不過作為程序員,學(xué)習(xí)新技術(shù),新概念實(shí)屬無奈之舉 。有些不必要的復(fù)雜性干擾人的思維,讓你無法干凈利落地做事。

    posted @ 2006-08-18 17:51 楊一 閱讀(455) | 評(píng)論 (0)編輯 收藏

    也談多層架構(gòu)

    敏捷開發(fā)中一個(gè)經(jīng)典的原則YAGNI原則,就是通過重構(gòu)提取公因式當(dāng)出現(xiàn)一次時(shí),不分層,以后業(yè)務(wù)復(fù)雜了,馬上抽象出一個(gè)層次來,分層是依賴倒置原則和模版方法模式的應(yīng)用。談到時(shí)候應(yīng)該分層,我想:如果只是一個(gè)非常簡(jiǎn)單的網(wǎng)站,3、5個(gè)頁面,7、8張表如果在這種需求下去分層,無異于自己折磨自己,添加系統(tǒng)不必要的復(fù)雜性。

    posted @ 2006-08-18 17:35 楊一 閱讀(335) | 評(píng)論 (0)編輯 收藏

    關(guān)于敏捷開發(fā)的疑問

    學(xué)習(xí)了很多人捧為經(jīng)典的ppp之后,我開始考慮在所參與的團(tuán)隊(duì)中采用敏捷開發(fā)的方式,除了結(jié)對(duì)編程,基本采用XP編程的方式。跌代計(jì)劃,TDD,重構(gòu),積極溝通。然而在此過程中卻遇到很多尷尬的問題,一個(gè)是團(tuán)隊(duì)中的人員經(jīng)常流動(dòng),導(dǎo)致剛剛熟悉的開發(fā)環(huán)境,又要找新人代替;一個(gè)是團(tuán)隊(duì)中的成員水平參差不齊,難以達(dá)成一致的良好設(shè)計(jì)規(guī)范,也許又是不得不做一些硬性的規(guī)定。
    這里最大的問題是:XP強(qiáng)調(diào)代碼即設(shè)計(jì),那就要求每個(gè)人都對(duì)代碼的編寫非常熟練,對(duì)團(tuán)隊(duì)中每個(gè)成員的編程水平要求很高,然而這和相對(duì)較少的項(xiàng)目經(jīng)費(fèi),及短暫的項(xiàng)目周期難以協(xié)調(diào)。
    更為可怕的是,項(xiàng)目中的人員職責(zé)不明,沒有明確的負(fù)責(zé)人,而由沒有軟件開發(fā)和管理經(jīng)驗(yàn)的人主導(dǎo)。

    posted @ 2006-08-17 12:43 楊一 閱讀(256) | 評(píng)論 (0)編輯 收藏

    <2006年8月>
    303112345
    6789101112
    13141516171819
    20212223242526
    272829303112
    3456789

    導(dǎo)航

    公告

    本人在blogjava上發(fā)表的文章及隨筆除特別聲明外均為原創(chuàng)或翻譯,作品受知識(shí)產(chǎn)權(quán)法保護(hù)并被授權(quán)遵從 知識(shí)分享協(xié)議:署名-非商業(yè)性使用-相同方式共享 歡迎轉(zhuǎn)載,請(qǐng)?jiān)谵D(zhuǎn)載時(shí)注明作者姓名(楊一)及出處(www.tkk7.com/yangyi)
    /////////////////////////////////////////
    我的訪問者

    常用鏈接

    留言簿(5)

    隨筆分類(55)

    隨筆檔案(55)

    相冊(cè)

    Java

    其他技術(shù)

    生活

    最新隨筆

    搜索

    積分與排名

    最新評(píng)論

    閱讀排行榜

    評(píng)論排行榜

    自強(qiáng)不息


    用心 - 珍惜時(shí)間,勇于創(chuàng)造
    主站蜘蛛池模板: 国产久爱免费精品视频| 中文文字幕文字幕亚洲色| 亚洲精品成人在线| 亚洲AV无码成人精品区大在线| 亚洲一区二区三区乱码A| 亚洲理论片在线观看| 亚洲熟女乱色一区二区三区| 免费一区二区三区在线视频| 国产成人精品免费久久久久| 久久WWW免费人成人片| 亚洲人成网站观看在线播放| 免费精品国自产拍在线播放 | 国产亚洲综合成人91精品 | 亚洲大成色www永久网址| 精品乱子伦一区二区三区高清免费播放 | 久久亚洲精品人成综合网| 亚洲av永久无码一区二区三区| 日韩免费高清播放器| 成人午夜性A级毛片免费| 亚洲AV无码乱码国产麻豆穿越| 亚洲熟妇无码AV不卡在线播放| 免费观看男人免费桶女人视频| 亚洲av综合色区| 在线永久看片免费的视频| 亚洲中文字幕不卡无码| 亚洲av无码一区二区三区四区| 美女内射无套日韩免费播放| 国产又粗又猛又爽又黄的免费视频 | 18级成人毛片免费观看| 亚洲深深色噜噜狠狠爱网站| 男男黄GAY片免费网站WWW| 成人在线免费看片| 久久无码av亚洲精品色午夜| 久久久久亚洲av成人无码电影| 国产精品久久亚洲一区二区| 国产亚洲成av人片在线观看| 国内精品乱码卡1卡2卡3免费| 亚洲日韩乱码中文无码蜜桃臀| 无码囯产精品一区二区免费| 亚洲AV日韩AV永久无码久久| 免费观看91视频|