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

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

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

    莊周夢蝶

    生活、程序、未來
       :: 首頁 ::  ::  :: 聚合  :: 管理

    官方消息:http://labs.adobe.com/wiki/index.php/Flex:Open_Source

    Flex向微軟WPF開戰的新起點。正如預期的那樣,Adobe決定flex在Mozilla Public License (MPL)協議下納入開源社區,flex的前景很值的期待。

    posted @ 2007-04-26 17:02 dennis 閱讀(2209) | 評論 (7)編輯 收藏

        這兩天一直在讀spring1.2的AOP實現源碼,AOP實現原理說起來很簡單,對于實現業務接口的對象使用java代理機制實現,而對于一般的類使用cglib庫實現,但spring的實現還是比較復雜的,不過抓住了本質去看代碼就容易多了。發現一篇04年寫的《spring源碼分析:實現AOP》,倒是不用自己再寫了,04年的時候已經有很多人研讀過spring的源碼,而那時的我還在學校,對java半懂不懂的狀態,就算到現在也不敢說真的懂了,繼續學習、努力。文章如下:

       
    我的問題
           為了完成公司應用開發平臺的設計,這幾天一直在研究Spring的擴展機制。Spring的核心無疑是BeanFactory, ApplicationContext和AOP。在“Spring AOP編程”教程的例子中,是由ProxyFactoryBean來實現的。問題來了,普通的bean和FactoryBean的配置完全是一樣的。那 么,BeanFactory是如何區分普通的Bean和用作Proxy的FactoryBean的?ProxyFactoryBean又是怎樣實現AOP 功能的?(本文還很不完善,我會繼續修改。)
     
    FactoryBean的職責
            FactoryBean在Spring中被當成一種特殊的bean,通過實現FactoryBean接口進行擴展。FactoryBean的職責是:
            l.封裝了創建對象或查找對象的邏輯。
           2.提供了一個中間層,用于支持AOP。

           我們來看一個LocalStatelessSessionProxyFactoryBean的例子。首先,定義Stateless EJB的代理,id為ejbServiceProxy:
           <bean id="ejbServiceProxy" class="LocalStatelessSessionProxyFactoryBean">
               <property name="jndiName">     
                  <value>myEjb</value>
               </property>
               <property name="businessInterface">
                  <value>com.mycompany.MyBusinessInterface</value>
               </property>
          </bean>
     
          然后,再將這個業務邏輯服務對象注入客戶程序:
         <bean id="myAction" class = "samples.myAction">
             <property name="myService">
                 <ref bean="ejbServiceProxy"/>
             </property>
         </bean>

         這樣,客戶程序并不知道myService的實現細節,Spring使用FactoryBean完成了兩者之間的解耦。
     
    準備代碼分析環境
         1. 安裝Eclipse和Spring IDE。
         2. 下載Spring framework源代碼,并導入Eclipse。
         3. 在類路徑創建log4j.properties配置文件,設置如下:
                 log4j.rootLogger=DEBUG, stdout
                 log4j.appender.stdout=org.apache.log4j.ConsoleAppender
                 log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
                 log4j.appender.stdout.layout.ConversionPattern=%d{SSS} %p %c{2} - %m%n
         4. 編寫TestCase,跟蹤Console窗口的debug信息。

    FactoryBean源代碼分析
           如果bean實現了FactoryBean接口,BeanFactory將把它作為一個bean工廠,而不是直接作為普通的bean。正常情況下, BeanFactory的getBean("bean")返回FactoryBean生產的bean實例,如果要返回FactoryBean本身的實例, 使用getBean("&bean")的調用方式。
           在分析ProxyFactoryBean之前,我們先分析BeanFactory,它是Spring Framework的基礎。我們看看它是如何分別處理普通的Bean和FactoryBean的。
     
      BeanFactory分析
     
         BeanFactory類圖
     
           如以上的類圖所示,XmlBeanFactory繼承了AbstactBeanFactory抽象類。AbstactBeanFactory類中使用了 Template Method設計模式,其中的模板方法為getBeanDefinition()和createBean()兩個抽象方法。其中 AbstractAutowireCapableBeanFactory類實現了getBeanDefinition()方法, DefaultAutowireCapableBeanFactory類實現了getBeanDefinition()方法。當調用getBean()方 法時,AbstractBeanFactory類定義的邏輯分別調用了這兩個模板方法。

         BeanFactory類的調用順序
           我們暫時不使用ApplicationContext,以簡化分析過程。我在這里使用了“Spring AOP編程”的例子,請參照該教程閱讀。首先,編寫測試用例,代碼如下:

                public class AopTest extends TestCase {
                      XmlBeanFactory factory = null;
                      protected void setUp() throws Exception {
                           super.setUp();
                           InputStream is = new FileInputStream("testaop.xml");
                           factory = new XmlBeanFactory(is);
                      }
                      public void testGetBean() {
                           Bean bean = (Bean)factory.getBean("bean");
                           assertNotNull(bean);
                           bean.theMethod();
                      }
                }
     
           1. 首先,XmlBeanFactory使用XmlBeanDefinitionReader讀入testaop.xml配置文件,后者用 XmlBeanDefinitionParser和DefaultXmlBeanDefinitionParser進行分析,從中得到 BeanDefinition的信息,并保存在XmlBeanDefinitionReader的BeanDefinitionRegistry變量里。
           2. 客戶程序調用getBean方法時,AbstractBeanFactory首先使用transFormedBeanName方法分析傳入的Bean名稱,判斷客戶程序需要FactoryBean本身,還是它所創建的Bean對象。
           3. 接下來,如果bean被定義為singleton模式,AbstractBeanFactory調用createBean方法根據 BeanDefinition信息實例化bean類,然后將該bean實例傳給getObjectForSharedInstance方法并返回 getObjectForSharedInstance的返回對象。GetObjectForSharedInstance方法摘要如類圖所示,首先判斷 bean是否繼承了FactoryBean。如果是,返回FactoryBean的getObject方法(下節我將詳細分析使用 ProxyFactoryBean如何實現AOP);如果不是,返回bean對象。
           4. 如果bean被定義為prototype模式,每次客戶程序請求都會生成新的bean實例,因此,createBean方法直接實例化bean對象并返回。
     
      ProxyFactoryBean如何實現AOP

         ProxyFactoryBean類圖
           FactoryBean接口如下圖所示,共有三個方法getObject,getObjectType,和isSingleton。ProxyFactoryBean實現了FactoryBean接口,它的相關類圖如下:
     

     
         實現AOP的過程
           如上圖所示,ProxyFactoryBean類繼承了AdvisedSupport類,后者繼承了ProxyConfig類并定義了操作advisor 和interceptor的接口,以支持AOP。當BeanFactory實例化ProxyFactoryBean時,根據配置文件的定義將關于 advice,pointcut,advisor,所代理的接口和接口實現類的所有信息傳給ProxyFactoryBean。
           當客戶程序調用BeanFactory的getBean方法時,ProxyFactory使用JdkDynamicAopProxy實例化 BeanImpl類,并用JdkDynamicAopProxy的invoke方法執行advice。至于執行advice的時機,由 ProxyFactoryBean調用RegexpMethodPointcutAdvisor進行判斷。


    posted @ 2007-04-24 09:37 dennis 閱讀(7541) | 評論 (0)編輯 收藏

        今日上午10時左右,在蓋茨參加北大舉行的“2007創新盛會”活動時,一位開源軟件人士沖到臺上抗議,并大呼“我們需要開源軟件,需要自由!”。這個報道一開始聽到的時候還是有點詫異,然后是釋然,蓋茨同學被人扔過雞蛋了,更何況這么一句口號。而王開源做為一名公民,有權利去表達自己的觀點。這樣的抗議示威舉動很正常,也應該被正常對待,社會各階層的人士都有權利發出自己的聲音。我可以不贊成你的觀點,但我尊重你表達觀點的權利。
        可后來看到很多的評論,對開源社區的謾罵,對王開源本人的人身攻擊比比皆是,我不由地奇怪,微軟在中國有這么多粉絲嗎?也許答案是肯定的,在中國盜版猖獗,就像我親愛的老婆以為電腦就是windows一樣的人絕對不少。可作為業內的IT人的表現就有點說不過去了,我們不去抗議中國電信、國有銀行壟斷是因為我們不是那個行業的人,而作為軟件業的一分子,人們有權利去抗議微軟利用操作系統壟斷帶來的負面影響,人們有權利去表達支持開源事業,只要手段合法。

       國內的軟件業處于國際軟件生態鏈的最底端,在操作系統、編譯器、程序設計語言、數據庫等等核心技術全部掌握在國外大公司的手中,很多人以為軟件設計就是C#,就是java,就是oracle、db2,而為了某個陣營可以對同為中國人的同胞罵的淋漓盡致,比如java VS C#, ruby VS java等等。這樣的場景想想其實很搞笑。

       這件事情引申開來,其實從對待這件事情的態度上,也可以看到一個人接受的教育:是在威權主義影響下的犬儒人士,還是有自主思考能力的公民。也許王開源受到特殊對待的是那句“需要自由!”的口號吧,做到獨立思考,從來不是件容易的事情。
      

    posted @ 2007-04-21 13:06 dennis 閱讀(604) | 評論 (2)編輯 收藏

    最近項目的websphere經常當機,運行一段時間后變慢然后當掉。查找了下網上的資料,盡管不是我在負責服務器,但是也是個學習的機會。

    主要針對的癥狀:  
            平臺:was5.1   base,http   server   1.3.28,oracle   8i,9i  
            癥狀:用戶響應突然變慢,然后并連接不上80端口,重啟后正常,一段時間后反復  
            解決方式:調整服務器參數,增加服務器的處理能力  
       
            1,更改http   server的配置文件參數KeepAlive。  
          原因:這個值說明是否保持客戶與HTTP   SERVER的連接,如果設置為ON,則請求數到達MaxKeepAliveRequests設定值時請求將排隊,導致響應變慢。  
          方法:打開ibm   http   server安裝目錄,打開文件夾conf,打開文件httpd.conf,查找KeepAlive值,改ON為OFF,其默認為ON  
       
      2,更改http   server的配置文件參數ThreadsPerChild值到更大數目,默認為50  
          原因:服務器響應線程的數量  
          方法:打開ibm   http   server安裝目錄,打開文件夾conf,打開文件httpd.conf,查找ThreadsPerChild值,默認為50,改到更大數目,視用戶數 多少而定,一般改到客戶機數量的1.1倍,如200臺,則設為220  
       
      3,關閉http   server日志紀錄  
              原因:http   server的日志IO影響性能  
              方法:打開ibm   http   server安裝目錄,打開文件夾conf,打開文件httpd.conf,查找CustomLog值,找到沒有注釋的那行(行的開頭沒有符號"#"), 將那行用符號"#"注釋掉,以關閉日志紀錄,提高處理性能。  
       
      4,更改Websphere的服務器處理線程數  
              原因:線程的數量影響同時并發的請求數量  
              方法:打開管理控制臺,依次打開目錄樹,服務器->server1->web容器->線程池,修改"最大大小"的值,默認是50,改到 更大數目,具體視總用戶數量和機器的配置而定,一般設置其等于或小于http   server設置的MaxKeepAliveRequests的值。

        根據上面的建議,查看了下我們的服務器配置情況,倒是沒什么不同,實際上導致服務相應變慢到停止,一般是由兩個原因導致的  
      1,數據庫操作時間過長(如查詢),導致占用連結時間過長,然后后續請求無法及時取得連結響應請求  
      2,代碼中一定要確保連結關閉,尤其在jsp中。后臺程序要在finally中關閉
        由此,我查看了System.out的日志,發現每次在當機前都有報“連接郵件服務器失敗”類似的錯誤,我們的郵件服務器是ibm的Lotus Domino,最近的網絡狀況很有問題,個人懷疑是因為連接郵件服務器時間過長,導致了這種情況的發生,有待證實。   

    posted @ 2007-04-20 13:06 dennis 閱讀(3783) | 評論 (0)編輯 收藏

         摘要:     spring IOC容器的實現,一開始我被復雜的接口和類所掩埋,看不清整體的思路和設計,踟躕于代碼叢林中,摸不清前進的方向。一開始我就決定只研讀以xml文件做配置文件的XmlFactoryBean的具體實現為主要目標,漸漸地有了點感覺,用UML把spring中的bean工廠體系展現出來之后就更清晰了,讓你不得不感嘆設計的精巧和復雜。本文只是我個人對spring...  閱讀全文

    posted @ 2007-04-20 11:59 dennis 閱讀(15533) | 評論 (12)編輯 收藏

         摘要:     一直使用prototype.js,因為prototype的風格與ruby相似,用起來很舒服;這兩天抽空看看jQuery,也是個很優秀的js基礎庫,特別是在選擇器方面,相當實用。轉自:http://www.cnblogs.com/skylaugh/archive/2006/12/18/595563.html 翻譯整理:Young.J官方網站:http://jq...  閱讀全文

    posted @ 2007-04-19 13:51 dennis 閱讀(8476) | 評論 (2)編輯 收藏

        這個包的說明是說主要是包括用于操作JavaBean的類和接口,將被大部分spring包使用。在讀這個包的代碼前,我特意將JavaBean規范讀了一遍。JavaBean規范不僅僅是getter、setter,定義了一個完整的輕量級組件模型,事件、方法、屬性、持久化等等支持均包含在內。JavaBean規范很明顯是學習Delphi的組件模型,sun希望通過它來形成一個java組件的市場,可惜結果不如人意,JavaBean在GUI方面并未形成一個類似delphi控件市場;隨著spring等輕量級框架的流行,而EJB重量級的組件模型被越來越多的人放棄,JavaBean反而在服務端模型方面占據了主流 。廢話不提,這個包的核心接口和類就是BeanWrapper和BeanWrapperImpl,顧名思義,這個接口就是用于包裝JavaBean的行為,諸如設置和獲取屬性,設置屬性編輯器等(PropertyEditor)。看下這個包的核心類圖:

    BeanWrapper接口繼承了PropertyAccessor(用于屬性訪問和設置)和PropertyEditorRegistry(屬性編輯器的獲取和設置),而BeanWrapperImpl除了實現BeanWrapper接口外還繼承自PropertyEditorRegistrySupport 類。在PropertyEditorRegistrySupport 類中可以看到spring默認設置的一系列自定義PropertyEditor。比如:
    protected void registerDefaultEditors() {
            
    this.defaultEditors = new HashMap(32);

            
    // Simple editors, without parameterization capabilities.
            
    // The JDK does not contain a default editor for any of these target types.
            this.defaultEditors.put(Class.classnew ClassEditor());
            
    this.defaultEditors.put(File.classnew FileEditor());
            
    this.defaultEditors.put(InputStream.classnew InputStreamEditor());
            
    this.defaultEditors.put(Locale.classnew LocaleEditor());
            
    this.defaultEditors.put(Properties.classnew PropertiesEditor());
            
    this.defaultEditors.put(Resource[].classnew ResourceArrayPropertyEditor());
            
    this.defaultEditors.put(String[].classnew StringArrayPropertyEditor());
            
    this.defaultEditors.put(URL.classnew URLEditor());

    。。。。。。。

        PropertyEditor的概念就是屬性編輯器,或者說屬性轉換器,比如我們在spring的配置文件中設置某個bean的class,這是一個字符串,怎么轉換為一個Class對象呢?通過上面注冊的ClassEditor,看看這個類是怎么實現的:

    public class ClassEditor extends PropertyEditorSupport {

        
    private final ClassLoader classLoader;

        /**
         * Create a default ClassEditor, using the given ClassLoader.
         * 
    @param classLoader the ClassLoader to use
         * (or <code>null</code> for the thread context ClassLoader)
         
    */
        
    public ClassEditor(ClassLoader classLoader) {
            
    this.classLoader =
                    (classLoader 
    != null ? classLoader : Thread.currentThread().getContextClassLoader());
        }


        
    public void setAsText(String text) throws IllegalArgumentException {
            
    if (StringUtils.hasText(text)) {
                
    try {
                    //調用輔助類,得到Class對象
                    setValue(ClassUtils.forName(text.trim(), 
    this.classLoader));
                }
                
    catch (ClassNotFoundException ex) {
                    
    throw new IllegalArgumentException("Class not found: " + ex.getMessage());
                }
            }
            
    else {
                setValue(
    null);
            }
        }

        
    public String getAsText() {
            Class clazz 
    = (Class) getValue();
            
    if (clazz == null) {
                
    return "";
            }
            
    if (clazz.isArray()) {
                
    return clazz.getComponentType().getName() + ClassUtils.ARRAY_SUFFIX;
            }
            
    else {
                
    return clazz.getName();
            }
        }

    }
        代碼已經解釋了一切,繼承javabean的PropertyEditorSupport,自己實現轉換即可。這個包另外就是定義了一個完整的異常體系,值的我們參考。另外一個值的注意的地方是CachedIntrospectionResults類的實現,這個類使用了單例模式,它的作用在于緩存JavaBean反省(Introspect)得到的信息,因為每次使用Introspector對獲取JavaBean信息是個不小的性能開支。緩存使用的是WeakHashMap,而不是HashMap,看看spring的解釋:
    /**
         * Map keyed by class containing CachedIntrospectionResults.
         * Needs to be a WeakHashMap with WeakReferences as values to allow
         * for proper garbage collection in case of multiple class loaders.
         
    */
        
    private static final Map classCache = Collections.synchronizedMap(new WeakHashMap());

    因為緩存使用的key是bean的Class對象(以保證唯一性),因此在應用存在多個class loaders的時候,為了保證垃圾收集的進行,不出現內存泄露而采用WeakHashMap,為了理解這一點,我用JProfiler測試了自定義ClassLoader情況下,內存堆的使用情況,從快照上看。在使用HashMap的情況下,因為測試的bean的Class對象被載入它的ClassLoader以及java.beans.BeanInfo,java.beans.PropertyDescriptor,java.lang.reflect.Method這四個對象強引用,而導致不可回收。而在使用WeakHashMap時,判斷當載入bean的ClassLoader和載入CachedIntrospectionResults的ClassLoader是不同的時候,使用弱引用包裝緩存對象,當垃圾收集起發現弱引用時將馬上清除弱引用對象,該弱引用也將加入一個隊列,而WeakHashMap將定時檢查這個隊列,當有新的弱引用達到時(意味著已經被回收)就清除相應的鍵值。請看:
    private static boolean isCacheSafe(Class clazz) {
            
    //CachedIntrospectionResults的ClassLoader
            ClassLoader cur = CachedIntrospectionResults.class.getClassLoader();
            
    //載入bean的ClassLoader
            ClassLoader target = clazz.getClassLoader();
            
    if (target == null || cur == target) {
                
    return true;
            }
            
    while (cur != null) {
                cur 
    = cur.getParent();
                
    if (cur == target) {
                    
    return true;
                }
            }
            
    return false;
        }

    public static CachedIntrospectionResults forClass(Class beanClass) throws BeansException {

       
       
    boolean cacheSafe = isCacheSafe(beanClass);
       
    if (cacheSafe) {
                    classCache.put(beanClass, results);
                }
                
    else {
               //弱引用   
                classCache.put(beanClass, new WeakReference(results));

                }
       

        不知道我的理解是否有誤,如果有誤,請不吝指出,謝謝。

    posted @ 2007-04-16 10:23 dennis 閱讀(4080) | 評論 (1)編輯 收藏

        好了,我終于買了《算法導論》和《計算機程序的構造與解釋》,這半年不準備再追逐“時尚的技術”,潛心讀這兩本,相信自己一定能夠做到。《Programming Ruby》這兩天讀完了,翻譯的很好,盡管還是有很少的一些翻譯和文字校驗上的瑕疵,但比起某些翻譯的跟天書似的已經好上很多,看的出來譯者是很用心的。昨天讀《Duck Typing》那章,動態語言的特色顯示的淋漓盡致,不由拍案叫絕。而《類與對象》也深入闡述了ruby的OO模型,對于我準備讀xruby的源碼也有不小的幫助,當然,如果結合dreamhead的《管窺ruby系列》來讀應該更有感觸。
        錢真是個頭痛的問題,工作一年半,銀行里還是沒存幾個錢,殘念,努力,努力。順手給老婆買了只熊熊,哈哈,特價商品,可不能讓她知道




    posted @ 2007-04-15 11:02 dennis 閱讀(900) | 評論 (0)編輯 收藏

        RubyGems是一個庫和程序的標準化打包以及安裝框架,它使定位、安裝、升級和卸載Ruby包變的很容易。rails以及它的大部分插件都是以gem形式發布的。本文描述一個自己創建ruby Gems的過程。
        假設你今天用ruby實現了一個stack結構,你想發布到網上讓別人可以共享,OK,工作開始了。首先你的程序當然要先寫好了:
    #stacklike.rb
    module Stacklike
     attr_reader:stack
     
    def initialize
        @stack
    =Array.new
     end
     
    def add_to_stack(obj)
        @stack.push(obj)
     end 
     
    def take_from_stack
        @stack.pop
     end
     
    def size
        @stack.length
     end
     alias length size
     
     
    def clear
       @stack.clear
     end
    end      

    然后就是我們的Stack類,引入這個Module,請注意,我們這里只是特意這樣做,增加點復雜度:
    #stack.rb
    require 
    'stacklike'
    class Stack
     include Stacklike
    end

     

    作為一個要被大眾使用的小程序,一定要有完備的測試代碼,OK,ruby內置了單元測試庫,我們來寫個單元測試來測試Stack:
    require 'stack'
    require 
    'test/unit'
    class TestStack <Test::Unit::TestCase
      
    def testStack
        stack
    =Stack.new
        assert_equal(0,stack.size)
        assert_equal(stack.length,stack.size) 
        stack.add_to_stack(
    1)
        assert_equal(
    1,stack.length)
        assert_equal(
    1,stack.take_from_stack)
        
        stack.clear
        assert_equal(0,stack.length)
        assert_nil(stack.take_from_stack)
        
        
    10.times{|i| stack.add_to_stack(i)}
        assert_equal(
    10,stack.size)
        assert_equal(stack.length,stack.size)
        
    9.downto(4){|i| assert_equal(i,stack.take_from_stack)} 
        
        assert_equal(
    4,stack.length)
        assert_equal(
    3,stack.take_from_stack)
        assert_equal(
    3,stack.length)
        
        stack.clear
        assert_equal(0,stack.length)
        assert_nil(stack.take_from_stack)
      end
    end

    如果你使用radrails或者RDT運行這段代碼,你將看到讓人舒服的greenbar,一切正常。程序寫好了,接下來就是關鍵步驟了,怎么發布成ruby Gems呢?

    第一步,寫Gems規范文件
       gemspec是ruby或者YAML形式的元數據集,用來提供這個gem的關鍵信息,我們創建一個文件夾就叫stack,然后在下面建立2個目錄兩個文件:
    lib目錄:用于存放庫的源代碼,比如這個例子中的stack.rb,stacklike.rb
    test目錄:用于存放單元測試代碼。
    README文件:描述你的庫的基本信息和版權許可證等
    stack.gemspec:gems規范文件,用以生成gem
    當然,也可以有docs目錄用以存放rdoc文檔和ext目錄用以存放ruby擴展,我們這個簡單例子就免了。
    看看我們的規范文件:
    #stack.spec
    require 
    'rubygems'
    SPEC
    =Gem::Specification.new do |s|
      s.name
    ="Stack"
      s.version
    ='0.01'
      s.author
    ='dennis zane'
      s.email
    ="killme2008@gmail.com"
      s.homepage
    ="http://www.rubyeye.net"
      s.platform
    =Gem::Platform::RUBY
      s.summary
    ="ruby實現的Stack"
      condidates 
    =Dir.glob("{bin,lib,docs,test}/**/*")
      s.files
    =condidates.delete_if do |item|
        item.include?(
    "CVS")|| item.include?("rdoc")
      end
      s.require_path
    ="lib"
      s.autorequire
    ='stack,stacklike'
      s.test_file
    ="test/ts_stack.rb"
      s.has_rdoc
    =false
      s.extra_rdoc_files
    =["README"]
    end  

    很明顯,規范文件也是ruby程序(也可以用YAML描述),設置了這個gem的主要關鍵信息:名稱、作者信息、平臺,需要注意的就是files數組過濾掉了cvs和rdoc文件,require_path和auto_require讓你指定了require_gem裝入gem時會被添加到$LOAS_PATH(ruby查找庫的路徑)中的目錄(也就是我們源代碼存放的lib),auto_require指定了裝載的文件名,我們沒有rdoc,所有設置has_rdoc為false,附帶文檔就是README。

    第二步 修改單元測試文件引用路徑
    過去我們假設ts_stack.rb與stack.rb、stacklike.rb在同一個目錄下,可是我們現在將它們分別放在lib和test目錄,TestStack 怎么引用測試的類呢?答案是在ts_stack.rb開頭加上一行:
    $:.unshift File.join(File.dirname(__FILE__),"..","lib")

    最后一步 構建gem
    在stack目錄執行下列命令:
    ruby stack.gemspec
     
    或者:
    gem build stack.gemspec
    將生成一個文件,你可以將這個文件共享給朋友們咯。你的朋友只要下載這個文件,執行:
    gem install Stack.0.01.gem
    將在他們的ruby環境中安裝你寫的stack,比較遺憾的是,你這個stack確實太簡陋了,哈哈。



    posted @ 2007-04-12 20:38 dennis 閱讀(2218) | 評論 (0)編輯 收藏

        這個包按照說明是:Interfaces and classes for type-safe enum support on JDK >= 1.3。提供類型安全的枚舉類型。代碼也是相當簡單,枚舉類型又分為靜態類型和通用類型。靜態類型其實跟jdk1.5引進的enum類型類似,都是以int類型做code,比如聲明一個Dog類型:
    public static class Dog extends StaticLabeledEnum {

           
    private Dog(int code, String name) {
                
    super(code, name);
            }
        }

    然后就可以這樣聲明枚舉類型了:

    public static final Dog BORDER_COLLIE = new Dog(13"Border Collie");

    public static final Dog WHIPPET = new Dog(14"Whippet");

    public static final Dog GOLDEN_RETRIEVER = new Dog(11null) {
                
    // must set type to be recognized as a "Dog"
                public Class getType() {
                    
    return Dog.class;
                }

                
    public String getLabel() {
                    
    return "Golden Retriever";
                }
            };

    同時有一個靜態枚舉類型的處理類用于提取信息:StaticLabeledEnumResolver ——這個類繼承自抽象類AbstractCachingLabeledEnumResolver,而抽象類實現了接口LabeledEnumResovler,看看這個接口就知道所謂處理類是干什么的了:
    public interface LabeledEnumResolver {

        
    //獲取某個類中聲明的枚舉類型,這些類型   //必須是LabeledEnum的子類
        public Set getLabeledEnumSet(Class type) throws IllegalArgumentException;

        
    public Map getLabeledEnumMap(Class type) throws IllegalArgumentException;
       
        //根據code獲取枚舉
        
    public LabeledEnum getLabeledEnumByCode(Class type, Comparable code) throws IllegalArgumentException;

        //根據lable獲取枚舉
        
    public LabeledEnum getLabeledEnumByLabel(Class type, String label) throws IllegalArgumentException;

    }

    StaticLabeledEnumResolver 使用了單例模式,同時AbstractCachingLabeledEnumResolver定義了一個模板法方法并使用:
    protected abstract Set findLabeledEnums(Class type);
    也是一個Template Method模式應用的例子。

    所謂通用性的枚舉類型,是指不定義成static,并且可以靈活使用其他類型做code的枚舉,比如spring已經內置的3種:ShortCodedLabeledEnum ,StringCodeLabeledEnum和LetterCodeLabeledEnum,這些類都繼承自AbstractLabeledEnum,類名已經顯示了它們的用途,不再細說。這個包完整的類圖如下:
     

    posted @ 2007-04-11 15:57 dennis 閱讀(1697) | 評論 (0)編輯 收藏

    僅列出標題
    共56頁: First 上一頁 41 42 43 44 45 46 47 48 49 下一頁 Last 
    主站蜘蛛池模板: 91成人免费观看在线观看| 4399好看日本在线电影免费| 亚洲日韩精品一区二区三区| 99久久人妻精品免费一区| 亚洲人成电影网站色www| 久久影院亚洲一区| 免费专区丝袜脚调教视频| 久久亚洲AV成人无码国产最大| 国产亚洲精品xxx| 处破痛哭A√18成年片免费| 成在线人视频免费视频| 亚洲伊人精品综合在合线| 亚洲国产日韩在线观频| 在线视频精品免费| aa毛片免费全部播放完整| 国产午夜亚洲精品| 无码欧精品亚洲日韩一区| 国产乱人免费视频| 免费看片在线观看| 成在线人视频免费视频| 亚洲第一se情网站| 亚洲日本乱码一区二区在线二产线 | 四虎影视永久免费观看网址 | 吃奶摸下高潮60分钟免费视频| 日韩免费人妻AV无码专区蜜桃 | 成人免费乱码大片A毛片| 亚洲人成网站999久久久综合| 亚洲人成网站在线播放vr| 在线成人a毛片免费播放 | 亚洲精品tv久久久久久久久| 在线免费观看污网站| 免费无码中文字幕A级毛片| 黄色网址免费在线| 亚洲国产精品久久网午夜| 久久精品国产亚洲网站| 四虎影永久在线高清免费| 麻豆最新国产剧情AV原创免费| 美女在线视频观看影院免费天天看| 污污免费在线观看| 亚洲av色香蕉一区二区三区| 亚洲国产午夜精品理论片|