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

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

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

    2006年9月3日

    struts2 基礎

    1. action extends ActionSupport abstract class, because it already provide some default operation(input, createErrorMessage).
    2. property is set by reflect to action, and pass to jsp(jsp is filled with these properties, jsp is a servlet, what it returned to user is HTML file)
    3. static validate happened in action method(override ActionSupport method), dynamic validation happened in action layer.
    4. change dynamic property file value in this way : thankyou=Thank you for registerling %{personBean.firstName}, Resource file can be deployed in action layer, package layer and global layer
    5. exception can be configured in bellow way:  <global-exception-mappings>
       <exception-mapping exception="org.apache.struts.register.exceptions.SecurityBreachException" result="securityerror" />
        <exception-mapping exception="java.lang.Exception" result="error" />
         </global-exception-mappings>
       
        <global-results>
              <result name="securityerror">/securityerror.jsp</result>
         <result name="error">/error.jsp</result>
         </global-results>
    6. Wildcard Method Selection: flexible but not useful(<action name="*Person" class="org.apache.struts.tutorials.wildcardmethod.action.PersonAction" method="{1}">)
    7. integrate spring & struts 2 way: use spring plugin, main point is who to maintain action creation(spring || action), better choice is spring, you can enjoy great function of spring.
    8. Add Convention Plugin to so that you can use annotation
    9. intercepter can be configured in action level and package level.

    posted @ 2011-03-29 12:07 Sheldon Sun 閱讀(238) | 評論 (0)編輯 收藏

    轉:用Spring快速開發jms應用(JBOSS服務器)

    異步進程通信是面向服務架構(SOA)一個重要的組成部分,因為企業里很多系統通信,特別是與外部組織間的通信,實質上都是異步的。Java消息服務(JMS)是用于編寫使用異步消息傳遞的JEE應用程序的API。傳統的使用JMS API進行消息傳遞的實現包括多個步驟,例如JNDI查詢隊列連接工廠和Queue資源,在實際發送和接收消息前創建一個JMS會話。

       Spring框架則簡化了使用JEE組件(包括JMS)的任務。它提供的模板機制隱藏了典型的JMS實現的細節,這樣開發人員可以集中精力放在處理消息的實際工作中,而不用擔心如何去創建,訪問或清除JMS資源。

       本文將對Spring JMS API作一個概述,并通過一個運行在JBoss MQ服務器上的web例程來介紹如何使用Spring JMS API來異步處理(發送和接收)消息。我將通過傳統JMS實現和Spring JMS實現兩者間的比較,來展示使用Spring JMS處理消息是如何的簡單和靈活。

    異步消息傳遞和面向服務架構

      在現實中,大多數web請求都是同步處理的。例如,當用戶要登入一個網站,首先輸入用戶名和密碼,然后服務器驗證登錄合法性。如果驗證成功,程序將允許該用戶進入網站。這里,登錄請求在從客戶端接收以后被即時處理了。信用卡驗證是另一個同步處理的例子;只有服務器證實輸入的信用卡號是有效的,同時客戶在帳戶上有足夠的存款,客戶才被允許繼續操作。但是讓我們思考一下在順序處理系統上的支付結算步驟。一旦系統證實該用戶信用卡的信息是準確的,并且在帳戶上有足夠的資金,就不必等到所有的支付細節落實、轉賬完成。支付結算可以異步方式進行,這樣客戶可以繼續進行核查操作。

       需要比典型同步請求耗費更長時間的請求,可以使用異步處理。另一個異步處理的例子是,在本地貸款處理程序中,提交至自動承銷系統(AUS)的信用請求處理過程。當借方提交貸款申請后,抵押公司會向AUS發送請求,以獲取信用歷史記錄。由于這個請求要求得到全面而又詳細的信用報告,包括借方現今和過去的帳戶,最近的付款和其他財務資料,服務器需要耗費較長的時間(幾小時或著有時甚至是幾天)來對這些請求作出響應。客戶端程序(應用)要與服務器連接并耗費如此長的時間來等待結果,這是毫無意義的。因此通信應該是異步發生的;也就是,一旦請求被提交,它就被放置在隊列中,同時客戶端與服務器斷開連接。然后AUS服務從指定的隊列中選出請求進行處理,并將處理得到的消息放置在另一個消息隊列里。最后,客戶端程序從這個隊列中選出處理結果,緊接著處理這個信用歷史數據。

    JMS

       如果您使用過JMS代碼,您會發現它與JDBC或JCA很像。它所包含的樣本代碼創建或JMS資源對象回溯,使得每一次您需要寫一個新類來發送和接收消息時,都具有更好的代碼密集性和重復性。以下序列顯示了傳統JMS實現所包括的步驟:

    1. 創建JNDI初始上下文(context)。
    2. 從JNDI上下文獲取一個隊列連接工廠。
    3. 從隊列連接工廠中獲取一個Quene。
    4. 創建一個Session對象。
    5. 創建一個發送者(sender)或接收者(receiver)對象。
    6. 使用步驟5創建的發送者或接收者對象發送或接收消息。
    7. 處理完消息后,關閉所有JMS資源。

    您可以看到,步驟6是處理消息的唯一地方。其他步驟都只是管理與實際業務要求無關的JMS資源,但是開發人員必須編寫并維護這些額外步驟的代碼。

    Spring JMS

       Spring框架提供了一個模板機制來隱藏Java APIs的細節。JEE開發人員可以使用JDBCTemplate和JNDITemplate類來分別訪問后臺數據庫和JEE資源(數據源,連接池)。JMS也不例外。Spring提供JMSTemplate類,因此開發人員不用為一個JMS實現去編寫樣本代碼。接下來是在開發JMS應用程序時Spring所具有一些的優勢。

    1. 提供JMS抽象API,簡化了訪問目標(隊列或主題)和向指定目標發布消息時JMS的使用。
    2. JEE開發人員不需要關心JMS不同版本(例如JMS 1.0.2與JMS 1.1)之間的差異。
    3. 開發人員不必專門處理JMS異常,因為Spring為所有JMS異常提供了一個未經檢查的異常,并在JMS代碼中重新拋出。

    示例程序

            說明:因為只是為了演示如何使用spring編寫jms的應用,所以本例沒有什么實際用途。

            程序功能:MessageProducer.java根據一用戶信息產生一個消息發送到 JMS Provider;由MessageConsumer.java接收。

    1.在Jboss里配置XML文件創建一個新的JMS provider。
    打開位于%JBOSS_HOME%server\default\deploy\jms文件夾下的jbossmq-destinations-service.xml文件,加入以下代碼片斷:
     <!--  Register User Send/Receive Queue  -->
     <mbean code="org.jboss.mq.server.jmx.Queue"
       name="jboss.mq.destination:service=Queue,name=registerUserQueue">
       <depends optional-attribute-name="DestinationManager">jboss.mq:service=DestinationManager</depends>
     </mbean>
     <!--  Register User Send/Receive Topic  -->
     <mbean code="org.jboss.mq.server.jmx.Topic"
      name="jboss.mq.destination:service=Topic,name=registerUserTopic">
       <depends optional-attribute-name="DestinationManager">jboss.mq:service=DestinationManager</depends>
     </mbean>
    2.在spring的配置文件中配置JMS組件的具體細節。
     (1)JNDI上下文是取得JMS資源的起始位置,因此首先我們要配置JNDI模板:
        <!-- JNDI上下文(它是取得JMS資源的起始位置) -->
       <bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
        <property name="environment">
         <props>
          <prop key="java.naming.factory.initial">
           org.jnp.interfaces.NamingContextFactory
          </prop>
          <prop key="java.naming.provider.url">localhost</prop>
          <prop key="java.naming.factory.url.pkgs">
           org.jnp.interfaces:org.jboss.naming
          </prop>
         </props>
        </property>
       </bean>
       注意:此JNDI模板用到了org.jnp.interfaces.NamingContextFactory所以要把%JBOSS_HOME%\client下的jbossall-client.jar加到你的項目的classpath中。
    (2)配置連接工廠:
       <!-- JMS連接工廠 -->
         <bean id="jmsConnectionFactory"class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiTemplate">
         <ref bean="jndiTemplate" />
        </property>
        <property name="jndiName">
         <value>XAConnectionFactory</value>
        </property>
       </bean>
       注意:XAConnectionFactory這個JNDI名字是在%JBOSS_HOME%server\default\deploy\jms文件夾下的jms-ds.xml中定義的(它是由JBoss指定的)。
     (3)配置JmsTemplate組件。在例程中我們使用JmsTemplate102。同時使用defaultDestination屬性來指定JMS目標。
      <!-- JMS模板配置 -->
      <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate102">
       <property name="connectionFactory" ref="jmsConnectionFactory" />
       <property name="defaultDestination" ref="destination" />
       <property name="pubSubDomain">
        <value>true</value>
       </property>
       <!-- 等待消息的時間(ms) -->
       <property name="receiveTimeout">
             <value>30000</value>
          </property>
      </bean>
      注意:如果使用topic-subscribe(主題訂閱)模式,該模板的pubSubDomain屬性值為true;若使用PToP(點對點)模式,pubSubDomain屬性值為false或不配置該屬性。
     (4)定義一個JMS目標來發送和接收消息:
      <bean id="destination" class="org.springframework.jndi.JndiObjectFactoryBean">
       <property name="jndiTemplate">
        <ref bean="jndiTemplate" />
       </property>
       <property name="jndiName">
        <value>topic/registerUserTopic</value>
       </property>
      </bean>
     (5)配置發送者和接收者組件:
      <!-- 消息發布者 -->
      <bean id="msgProducer" class="com.boco.jms.MessageProducer">
       <property name="jmsTemplate" ref="jmsTemplate" />
      </bean>
      <!-- 消息接收者 -->
      <bean id="msgConsumer" class="com.boco.jms.MessageConsumer">
       <property name="jmsTemplate" ref="jmsTemplate" />
      </bean>
    3.相應的類:
     (1). User對象。
       /**
       *  User.java
       *  created on Jul 2, 2006
       *  Copyrights 2006 BOCO,Inc. All rights reserved.
       */
      package com.boco.dto;
      
      import java.io.Serializable;
      
      /**
       * desc: 用戶信息 Bean
       * @author qiujy
       */
      public class User {
       private int id;
       private String username;
       private String password;
       private String email;
       
       public User(){}
       
       //以下為Getter,setter方法略
       ......
      }
      
     (2).消息生產者:
       /**
       *  MessageProducer.java
       *  created on Jul 22, 2006
       *  Copyrights 2006 BOCO,Inc. All rights reserved.
       */
      package com.boco.jms;
      
      import javax.jms.JMSException;
      import javax.jms.MapMessage;
      import javax.jms.Message;
      import javax.jms.Session;
      
      import org.springframework.jms.core.JmsTemplate;
      import org.springframework.jms.core.MessageCreator;
      
      import com.boco.dto.User;
      
      /**
       * desc:消息生產者
       * @author qiujy
       *
       */
      public class MessageProducer {
       /** JMS模板 */
       private JmsTemplate jmsTemplate;
       
       public void setJmsTemplate(JmsTemplate jmsTemplate){
        this.jmsTemplate = jmsTemplate;
       }
       
       public void sendMessage(final User user){
        //調用模板的send來發送消息
        jmsTemplate.send(new MessageCreator(){
      
         public Message createMessage(Session session) throws JMSException {
          //構造一個要發送的消息
          MapMessage message = session.createMapMessage();
           message.setInt("id", user.getId());
           message.setString("username", user.getUsername());
           message.setString("password", user.getPassword());
           message.setString("email", user.getEmail());
          System.out.println("send success!!");
          return message;
         }
        });
       }
      }
      
     (3).消息消費者:
      /**
       *  MessageConsumer.java
       *  created on Jul 22, 2006
       *  Copyrights 2006 BOCO,Inc. All rights reserved.
       */
      package com.boco.jms;
      
      import javax.jms.JMSException;
      import javax.jms.MapMessage;
      
      import org.springframework.jms.core.JmsTemplate;
      
      import com.boco.dto.User;
      
      /**
       * desc:消息消費者
       * @author qiujy
       *
       */
      public class MessageConsumer {
       /** JMS模板 */
       private JmsTemplate jmsTemplate;
       
       public void setJmsTemplate(JmsTemplate jmsTemplate){
        this.jmsTemplate = jmsTemplate;
       }
       
       public User receiveMessage(){
        //參數為Destination的JNDI名字去掉前面的模式類型標識
        //MapMessage msg = (MapMessage)jmsTemplate.receive("registerUserQueue");
        MapMessage msg = (MapMessage)jmsTemplate.receive("registerUserTopic");
        User user = new User();
        
        try {
         user.setId(msg.getInt("id"));
         user.setUsername(msg.getString("username"));
         user.setPassword(msg.getString("password"));
         user.setEmail(msg.getString("email"));
        } catch (JMSException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
        }
        
        return user;
       }
      }

     (4).測試用例:
       //======== 生產者測試用例 ===============
       /**
       *  TestMsgProducer.java
       *  created on Jul 22, 2006
       *  Copyrights 2006 BOCO,Inc. All rights reserved.
       */
      package com.boco.jms;
      
      import junit.framework.TestCase;
      
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      import com.boco.dto.User;
      
      /**
       * desc:
       * @author qiujy
       *
       */
      public class TestMsgProducer extends TestCase {
      
       private ApplicationContext context;
       /**
        * @param arg0
        */
       public TestMsgProducer(String arg0) {
        super(arg0);
        context = new ClassPathXmlApplicationContext("applicationContext_jms.xml");
       }
      
       /* (non-Javadoc)
        * @see junit.framework.TestCase#setUp()
        */
       protected void setUp() throws Exception {
        super.setUp();
       }
      
       /* (non-Javadoc)
        * @see junit.framework.TestCase#tearDown()
        */
       protected void tearDown() throws Exception {
        super.tearDown();
       }
      
       /**
        * Test method for {@link com.boco.jms.MessageProducer#sendMessage(com.boco.dto.User)}.
        */
       public void testSendMessage() {
        User user = new User();
        user.setId(132);
        user.setUsername("JMSTest");
        user.setPassword("password");
        user.setEmail("support@boco.com.cn");
        
        MessageProducer producer = (MessageProducer)context.getBean("msgProducer");
        
        producer.sendMessage(user);
        
       }
      
      }

      //============ 消費者測試用例 ===============
      /**
       *  TestMsgConsumer.java
       *  created on Jul 22, 2006
       *  Copyrights 2006 BOCO,Inc. All rights reserved.
       */
      package com.boco.jms;
      
      import junit.framework.TestCase;
      
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      import com.boco.dto.User;
      
      /**
       * desc:
       * @author qiujy
       *
       */
      public class TestMsgConsumer extends TestCase {
       private ApplicationContext context;
       /**
        * @param arg0
        */
       public TestMsgConsumer(String arg0) {
        super(arg0);
        context = new ClassPathXmlApplicationContext("applicationContext_jms.xml");
       }
      
       /* (non-Javadoc)
        * @see junit.framework.TestCase#setUp()
        */
       protected void setUp() throws Exception {
        super.setUp();
       }
      
       /* (non-Javadoc)
        * @see junit.framework.TestCase#tearDown()
        */
       protected void tearDown() throws Exception {
        super.tearDown();
       }
      
       /**
        * Test method for {@link com.boco.jms.MessageConsumer#receiveMessage()}.
        */
       public void testReceiveMessage() {
        MessageConsumer consumer = (MessageConsumer)context.getBean("msgConsumer");
        User user = consumer.receiveMessage();
        assertNotNull(user);
        System.out.println( "id========" + user.getId()
            + "\nname======" + user.getUsername()
            + "\npassword==" + user.getPassword()
            + "\nemail=====" + user.getEmail());
       }
      
      }

    posted @ 2011-03-23 14:49 Sheldon Sun 閱讀(269) | 評論 (0)編輯 收藏

    concurrent

    AVA后臺程序設計及UTIL.CONCURRENT包的應用


    摘要 : 在很多軟件項目中,JAVA語言常常被用來開發后臺服務程序。線程池技術是提高這類程序性能的一個重要手段。在實踐中,該技術已經被廣泛的使用。本文首先 對設計后臺服務程序通常需要考慮的問題進行了基本的論述,隨后介紹了JAVA線程池的原理、使用和其他一些相關問題,最后對功能強大的JAVA開放源碼線 程池包util.concurrent 在實際編程中的應用進行了詳細介紹。
    關鍵字: JAVA;線程池;后臺服務程序;util.concurrent



    1 引言
    在軟件項目開發中,許多后臺服務程序的處理動作流程都具有一個相同點,就是:接受客戶端發來的請求,對請求進行一些相關的處理,最后將處理結果返回給客戶 端。這些請求的來源和方式可能會各不相同,但是它們常常都有一個共同點:數量巨大,處理時間短。這類服務器在實際應用中具有較大的普遍性,如web服務 器,短信服務器,DNS服務器等等。因此,研究如何提高此類后臺程序的性能,如何保證服務器的穩定性以及安全性都具有重要的實用價值。

    2 后臺服務程序設計
    2.1 關于設計原型
    構建服務器應用程序的一個簡單的模型是:啟動一個無限循環,循環里放一個監聽線程監聽某個地址端口。每當一個請求到達就創建一個新線程,然后新線程為請求服務,監聽線程返回繼續監聽。
    簡單舉例如下:
    import java.net.*;
    public class MyServer extends Thread{
    public void run(){
    try{
    ServerSocket server=null;
    Socket clientconnection=null;
    server = new ServerSocket(8008);//監聽某地址端口對
    while(true){進入無限循環
    clientconnection =server.accept();//收取請求
    new ServeRequest(clientconnection).start();//啟動一個新服務線程進行服務
    ……
    }
    }catch(Exception e){
    System.err.println("Unable to start serve listen:"+e.getMessage());
    e.printStackTrace();
    }
    }
    }
    實際上,這只是個簡單的原型,如果試圖部署以這種方式運行的服務器應用程序,那么這種方法的嚴重不足就很明顯。
    首先,為每個請求創建一個新線程的開銷很大,為每個請求創建新線程的服務器在創建和銷毀線程上花費的時間和消耗的系統資源, 往往有時候要比花在處理實際的用戶請求的時間和資源更多。在Java中更是如此,虛擬機將試圖跟蹤每一個對象,以便能夠在對象銷毀后進行垃圾回收。所以提 高服務程序效率的一個手段就是盡可能減少創建和銷毀對象的次數。這樣綜合看來,系統的性能瓶頸就在于線程的創建開銷。
    其次,除了創建和銷毀線程的開銷之外,活動的線程也消耗系統資源。在一個 JVM 里創建太多的線程可能會導致系統由于過度消耗內存而用完內存或“切換過度”。為了防止資源不足,服務器應用程序需要一些辦法來限制任何給定時刻運行的處理 線程數目,以防止服務器被“壓死”的情況發生。所以在設計后臺程序的時候,一般需要提前根據服務器的內存、CPU等硬件情況設定一個線程數量的上限值。
    如果創建和銷毀線程的時間相對于服務時間占用的比例較大,那末假設在一個較短的時間內有成千上萬的請求到達,想象一下,服務器的時間和資源將會大量的花在 創建和銷毀線程上,而真正用于處理請求的時間卻相對較少,這種情況下,服務器性能瓶頸就在于創建和銷毀線程的時間。按照這個模型寫一個簡單的程序測試一下 即可看出,由于篇幅關系,此處略。如果把(服務時間/創建和銷毀線程的時間)作為衡量服務器性能的一個參數,那末這個比值越大,服務器的性能就越高。
    應此,解決此類問題的實質就是盡量減少創建和銷毀線程的時間,把服務器的資源盡可能多地用到處理請求上來,從而發揮多線程的優點(并發),避免多線程的缺點(創建和銷毀的時空開銷)。
    線程池為線程生命周期開銷問題和資源不足問題提供了解決方案。通過對多個任務重用線程,線程創建的開銷被分攤到了多個任務上。其好處是,因為在請求到達時 線程已經存在,所以無意中也消除了線程創建所帶來的延遲。這樣,就可以立即為請求服務,使應用程序響應更快。而且,通過適當地調整線程池中的線程數目,也 就是當請求的數目超過某個閾值時,就強制其它任何新到的請求一直等待,直到獲得一個線程來處理為止,從而可以防止資源不足。

    3    JAVA線程池原理
    3.1 原理以及實現
    在實踐中,關于線程池的實現常常有不同的方法,但是它們的基本思路大都是相似的:服務器預先存放一定數目的“熱”的線程,并發程序需要使用線程的時候,從 服務器取用一條已經創建好的線程(如果線程池為空則等待),使用該線程對請求服務,使用結束后,該線程并不刪除,而是返回線程池中,以備復用,這樣可以避 免對每一個請求都生成和刪除線程的昂貴操作。
    一個比較簡單的線程池至少應包含線程池管理器、工作線程、任務隊列、任務接口等部分。其中線程池管理器(ThreadPool Manager)的作用是創建、銷毀并管理線程池,將工作線程放入線程池中;工作線程是一個可以循環執行任務的線程,在沒有任務時進行等待;任務隊列的作 用是提供一種緩沖機制,將沒有處理的任務放在任務隊列中;任務接口是每個任務必須實現的接口,主要用來規定任務的入口、任務執行完后的收尾工作、任務的執 行狀態等,工作線程通過該接口調度任務的執行。下面的代碼實現了創建一個線程池:
    public class ThreadPool
    { 
    private Stack threadpool = new Stack();
    private int poolSize;
    private int currSize=0;
    public void setSize(int n)
    { 
    poolSize = n;
    }
    public void run()
    {
    for(int i=0;i

    (發帖時間:2003-11-30 11:55:56) 
    ---岑心 J

    回復(1): 

    4.2    框架與結構
    下面讓我們來看看util.concurrent的框架結構。關于這個工具包概述的e文原版鏈接地址是http: //gee.cs.oswego.edu/dl/cpjslides/util.pdf。該工具包主要包括三大部分:同步、通道和線程池執行器。第一部分 主要是用來定制鎖,資源管理,其他的同步用途;通道則主要是為緩沖和隊列服務的;線程池執行器則提供了一組完善的復雜的線程池實現。
    --主要的結構如下圖所示

    4.2.1 Sync
    acquire/release協議的主要接口
    - 用來定制鎖,資源管理,其他的同步用途
    - 高層抽象接口
    - 沒有區分不同的加鎖用法

    實現
    -Mutex, ReentrantLock, Latch, CountDown,Semaphore, WaiterPreferenceSemaphore, FIFOSemaphore, PrioritySemaphore
    還有,有幾個簡單的實現,例如ObservableSync, LayeredSync

    舉例:如果我們要在程序中獲得一獨占鎖,可以用如下簡單方式:
    try {
    lock.acquire();
    try {
    action();
    }
    finally {
    lock.release();
    }
    }catch(Exception e){
    }

    程序中,使用lock對象的acquire()方法獲得一獨占鎖,然后執行您的操作,鎖用完后,使用release()方法釋放之即可。呵呵,簡單吧,想 想看,如果您親自撰寫獨占鎖,大概會考慮到哪些問題?如果關鍵的鎖得不到怎末辦?用起來是不是會復雜很多?而現在,以往的很多細節和特殊異常情況在這里都 無需多考慮,您盡可以把精力花在解決您的應用問題上去。

    4.2.2 通道(Channel)
    為緩沖,隊列等服務的主接口

    具體實現
    LinkedQueue, BoundedLinkedQueue,BoundedBuffer, BoundedPriorityQueue, SynchronousChannel, Slot

    通道例子
    class Service { // ...
    final Channel msgQ = new LinkedQueue();
    public void serve() throws InterruptedException {
    String status = doService();
    msgQ.put(status);
    }
    public Service() { // start background thread
    Runnable logger = new Runnable() {
    public void run() {
    try {
    for(;;)
    System.out.println(msqQ.take());
    }
    catch(InterruptedException ie) {} }
    };
    new Thread(logger).start();
    }
    }
    在后臺服務器中,緩沖和隊列都是最常用到的。試想,如果對所有遠端的請求不排個隊列,讓它們一擁而上的去爭奪cpu、內存、資源,那服務器瞬間不當掉才怪。而在這里,成熟的隊列和緩沖實現已經提供,您只需要對其進行正確初始化并使用即可,大大縮短了開發時間。

    4.2.3執行器(Executor)
    Executor是這里最重要、也是我們往往最終寫程序要用到的,下面重點對其進行介紹。
    類似線程的類的主接口
    - 線程池
    - 輕量級運行框架
    - 可以定制調度算法

    只需要支持execute(Runnable r)
    - 同Thread.start類似

    實現
    - PooledExecutor, ThreadedExecutor, QueuedExecutor, FJTaskRunnerGroup

    PooledExecutor(線程池執行器)是個最常用到的類,以它為例:
    可修改得屬性如下:
    - 任務隊列的類型
    - 最大線程數
    - 最小線程數
    - 預熱(預分配)和立即(分配)線程
    - 保持活躍直到工作線程結束
    -- 以后如果需要可能被一個新的代替
    - 飽和(Saturation)協議
    -- 阻塞,丟棄,生產者運行,等等

    可不要小看上面這數條屬性,對這些屬性的設置完全可以等同于您自己撰寫的線程池的成百上千行代碼。下面以筆者撰寫過得一個GIS服務器為例:
    該GIS服務器是一個典型的“請求-服務”類型的服務器,遵循后端程序設計的一般框架。首先對所有的請求按照先來先服務排入一個請求隊列,如果瞬間到達的 請求超過了請求隊列的容量,則將溢出的請求轉移至一個臨時隊列。如果臨時隊列也排滿了,則對以后達到的請求給予一個“服務器忙”的提示后將其簡單拋棄。這 個就夠忙活一陣的了。
    然后,結合鏈表結構實現一個線程池,給池一個初始容量。如果該池滿,以x2的策略將池的容量動態增加一倍,依此類推,直到總線程數服務達到系統能力上限, 之后線程池容量不在增加,所有請求將等待一個空余的返回線程。每從池中得到一個線程,該線程就開始最請求進行GIS信息的服務,如取坐標、取地圖,等等。 服務完成后,該線程返回線程池繼續為請求隊列離地后續請求服務,周而復始。當時用矢量鏈表來暫存請求,用wait()、 notify() 和 synchronized等原語結合矢量鏈表實現線程池,總共約600行程序,而且在運行時間較長的情況下服務器不穩定,線程池被取用的線程有異常消失的 情況發生。而使用util.concurrent相關類之后,僅用了幾十行程序就完成了相同的工作而且服務器運行穩定,線程池沒有丟失線程的情況發生。由 此可見util.concurrent包極大的提高了開發效率,為項目節省了大量的時間。
    使用PooledExecutor例子
    import java.net.*;
    /**
    *

    Title:


    *

    Description: 負責初始化線程池以及啟動服務器


    *

    Copyright: Copyright (c) 2003


    *

    Company:


    * @author not attributable
    * @version 1.0
    */
    public class MainServer {
    //初始化常量
    public static final int MAX_CLIENT=100; //系統最大同時服務客戶數
    //初始化線程池
    public static final PooledExecutor pool =
    new PooledExecutor(new BoundedBuffer(10), MAX_CLIENT); //chanel容量為10,
    //在這里為線程池初始化了一個
    //長度為10的任務緩沖隊列。

    public MainServer() {
    //設置線程池運行參數
    pool.setMinimumPoolSize(5); //設置線程池初始容量為5個線程
    pool.discardOldestWhenBlocked();//對于超出隊列的請求,使用了拋棄策略。
    pool.createThreads(2); //在線程池啟動的時候,初始化了具有一定生命周期的2個“熱”線程
    }

    public static void main(String[] args) {
    MainServer MainServer1 = new MainServer();
    new HTTPListener().start();//啟動服務器監聽和處理線程
    new manageServer().start();//啟動管理線程
    }
    }

    類HTTPListener
    import java.net.*;
    /**
    *

    Title:


    *

    Description: 負責監聽端口以及將任務交給線程池處理


    *

    Copyright: Copyright (c) 2003


    *

    Company:


    * @author not attributable
    * @version 1.0
    */

    public class HTTPListener extends Thread{
    public HTTPListener() {
    }
    public void run(){
    try{
    ServerSocket server=null;
    Socket clientconnection=null;
    server = new ServerSocket(8008);//服務套接字監聽某地址端口對
    while(true){//無限循環
    clientconnection =server.accept();
    System.out.println("Client connected in!");
    //使用線程池啟動服務
    MainServer.pool.execute(new HTTPRequest(clientconnection));//如果收到一個請求,則從線程池中取一個線程進行服務,任務完成后,該線程自動返還線程池
    }
    }catch(Exception e){
    System.err.println("Unable to start serve listen:"+e.getMessage());
    e.printStackTrace();
    }
    }
    }

    關于util.concurrent工具包就有選擇的介紹到這,更詳細的信息可以閱讀這些java源代碼的API文檔。Doug Lea是個很具有“open”精神的作者,他將util.concurrent工具包的java源代碼全部公布出來,有興趣的讀者可以下載這些源代碼并細 細品味。 

    5    結束語
    以上內容介紹了線程池基本原理以及設計后臺服務程序應考慮到的問題,并結合實例詳細介紹了重要的多線程開發工具包util.concurrent的構架和使用。結合使用已有完善的開發包,后端服務程序的開發周期將大大縮短,同時程序性能也有了保障。

    posted @ 2011-03-23 13:25 Sheldon Sun 閱讀(248) | 評論 (0)編輯 收藏

    JAVA事務,JTA,JDBC,JDO,DAO,JNDI概念

    引用http://dyldragon.javaeye.com/blog/789374

    一、什么是Java事務

    通常的觀念認為,事務僅與數據庫相關。 
    事務必須服從ISO/IEC所制定的ACID原則。

    ACID是原子性(atomicity)、一致性(consistency)、隔離性(isolation)和持久性(durability)的縮寫。

    事務的原子性表示事務執行過程中的任何失敗都將導致事務所做的任何修改失效。

    一致性表示當事務執行失敗時,所有被該事務影響的數據都應該恢復到事務執行前的狀態。

    隔離性表示在事務執行過程中對數據的修改,在事務提交之前對其他事務不可見。

    持久性表示已提交的數據在事務執行失敗時,數據的狀態都應該正確。


         
    通俗的理解,事務是一組原子操作單元,從數據庫角度說,就是一組SQL指令,要么全部執行成功,若因為某個原因其中一條指令執行有錯誤,則撤銷先前執行過的所有指令。更簡答的說就是:要么全部執行成功,要么撤銷不執行。


    既然事務的概念從數據庫而來,那Java事務是什么?之間有什么聯系?  實際上,一個Java應用系統,如果要操作數據庫,則通過JDBC來實現的。增加、修改、刪除都是通過相應方法間接來實現的,事務的控制也相應轉移到Java程序代碼中。因此,數據庫操作的事務習慣上就稱為Java事務。


    二、為什么需要事務

    事務是為解決數據安全操作提出的,事務控制實際上就是控制數據的安全訪問。具一個簡單例子:比如銀行轉帳業務,賬戶A要將自己賬戶上的1000 元轉到B賬戶下面,A賬戶余額首先要減去1000元,然后B賬戶要增加1000元。假如在中間網絡出現了問題,A賬戶減去1000元已經結束,B因為網絡中斷而操作失敗,那么整個業務失敗,必須做出控制,要求A賬戶轉帳業務撤銷。這才能保證業務的正確性,完成這個操走就需要事務,將A賬戶資金減少和B賬戶資金增加方到一個事務里面,要么全部執行成功,要么操作全部撤銷,這樣就保持了數據的安全性。


    三、Java事務的類型 
        Java 
    事務的類型有三種:JDBC事務、JTA(Java Transaction API)事務、容器事務。 
    1
    JDBC事務 
    JDBC 
    事務是用 Connection 對象控制的。JDBC Connection 接口( java.sql.Connection )提供了兩種事務模式:自動提交和手工提交。 java.sql.Connection 提供了以下控制事務的方法:

    public void setAutoCommit(boolean) 
    public boolean getAutoCommit() 
    public void commit() 
    public void rollback() 
    使用 JDBC 事務界定時,您可以將多個 SQL 語句結合到一個事務中。JDBC 事務的一個缺點是事務的范圍局限于一個數據庫連接。一個 JDBC 事務不能跨越多個數據庫。 
    2
    JTA(Java Transaction API)事務 
        JTA 
    是一種高層的,與實現無關的,與協議無關的API,應用程序和應用服務器可以使用JTA來訪問事務。 
    JTA
    允許應用程序執行分布式事務處理--在兩個或多個網絡計算機資源上訪問并且更新數據,這些數據可以分布在多個數據庫上。JDBC驅動程序的JTA支持極大地增強了數據訪問能力。 
    如果計劃用 JTA 界定事務,那么就需要有一個實現 javax.sql.XADataSource  javax.sql.XAConnection  javax.sql.XAResource接口的 JDBC 驅動程序。一個實現了這些接口的驅動程序將可以參與 JTA 事務。一個 XADataSource 對象就是一個XAConnection 對象的工廠。 XAConnection s 是參與 JTA 事務的 JDBC 連接。 
    您將需要用應用服務器的管理工具設置 XADataSource 。從應用服務器和 JDBC 驅動程序的文檔中可以了解到相關的指導。 
    J2EE 
    應用程序用 JNDI 查詢數據源。一旦應用程序找到了數據源對象,它就調用 javax.sql.DataSource.getConnection() 以獲得到數據庫的連接。 
         XA 
    連接與非 XA 連接不同。一定要記住 XA 連接參與了 JTA 事務。這意味著 XA 連接不支持 JDBC 的自動提交功能。同時,應用程序一定不要對 XA 連接調用 java.sql.Connection.commit() 或者 java.sql.Connection.rollback() 。相反,應用程序應該使用 UserTransaction.begin() UserTransaction.commit()  serTransaction.rollback() 

    3、容器事務 
         
    容器事務主要是J2EE應用服務器提供的,容器事務大多是基于JTA完成,這是一個基于JNDI的,相當復雜的API實現。相對編碼實現JTA 事務管理,我們可以通過EJB容器提供的容器事務管理機制(CMT)完成同一個功能,這項功能由J2EE應用服務器提供。這使得我們可以簡單的指定將哪個方法加入事務,一旦指定,容器將負責事務管理任務。這是我們土建的解決方式,因為通過這種方式我們可以將事務代碼排除在邏輯編碼之外,同時將所有困難交給 J2EE容器去解決。使用EJB CMT的另外一個好處就是程序員無需關心JTA API的編碼,不過,理論上我們必須使用EJB 
    四、三種事務差異 
    1
    JDBC事務控制的局限性在一個數據庫連接內,但是其使用簡單。 
    2
    JTA事務的功能強大,事務可以跨越多個數據庫或多個DAO,使用也比較復雜。 
    3
    、容器事務,主要指的是J2EE應用服務器提供的事務管理,局限于EJB應用使用。 


    JTA

    Java事務API(JTA;Java Transaction API)和它的同胞Java事務服務(JTS;Java Transaction Service),為J2EE平臺提供了分布式事務服務。一個分布式事務(distributed transaction)包括一個事務管理器(transaction manager)和一個或多個資源管理器(resource manager)。一個資源管理器(resource manager)是任意類型的持久化數據存儲。事務管理器(transaction manager)承擔著所有事務參與單元者的相互通訊的責任。下圖顯示了事務管理器和資源管理的間的關系。


    JTA事務比JDBC事務更強大。一個JTA事務可以有多個參與者,而一個JDBC事務則被限定在一個單一的數據庫連接。下列任一個Java平臺的組件都可以參與到一個JTA事務中:

    JDBC連接

    • JDO PersistenceManager 對象
    • JMS 隊列
    • JMS 主題
    • 企業JavaBeans(EJB)
    • 一個用J2EE Connector Architecture 規范編譯的資源分配器。


    DAO

    DAO是Data Access Object數據訪問接口,數據訪問:顧名思義就是與數據庫打交道。夾在業務邏輯與數據庫資源中間。對數據庫進行CURD(增刪查改操作)。

     

      在核心J2EE模式中是這樣介紹DAO模式的:為了建立一個健壯的J2EE應用,應該將所有對數據源的訪問操作抽象封裝在一個公共API中。用程序設計的語言來說,就是建立一個接口,接口中定義了此應用程序中將會用到的所有事務方法。在這個應用程序中,當需要和數據源進行交互的時候則使用這個接口,并且編寫一個單獨的類來實現這個接口在邏輯上對應這個特定的數據存儲。


    JDBC

    JDBC(Java Data Base Connectivity,java數據庫連接)是一種用于執行SQL語句的Java API,可以為多種關系數據庫提供統一訪問,它由一組用Java語言編寫的類和接口組成。JDBC為工具/數據庫開發人員提供了一個標準的API,據此可以構建更高級的工具和接口,使數據庫開發人員能夠用純 Java API 編寫數據庫應用程序,同時,JDBC也是個商標名。

     

    有了JDBC,向各種關系數據發送SQL語句就是一件很容易的事。換言之,有了JDBC API,就不必為訪問Sybase數據庫專門寫一個程序,為訪問Oracle數據庫又專門寫一個程序,或為訪問Informix數據庫又編寫另一個程序等等,程序員只需用JDBC API寫一個程序就夠了,它可向相應數據庫發送SQL調用。同時,將Java語言和JDBC結合起來使程序員不必為不同的平臺編寫不同的應用程序,只須寫一遍程序就可以讓它在任何平臺上運行,這也是Java語言“編寫一次,處處運行”的優勢。


    簡單地說,JDBC 可做三件事:與數據庫建立連接、發送 操作數據庫的語句并處理結果。


    JDO

    JDO(Java Data Object )是一個JAVA用于存取某種數據倉庫中的對象的標準化API。JDO提供了透明的對象存儲,因此對開發人員來說,存儲數據對象完全不需要額外的代碼(如JDBC API的使用)。這些繁瑣的例行工作已經轉移到JDO產品提供商身上,使開發人員解脫出來,從而集中時間和精力在業務邏輯上。另外,JDO很靈活,因為它可以在任何數據底層上運行。JDBC只是面向關系數據庫(RDBMS)JDO更通用,提供到任何數據底層的存儲功能,比如關系數據庫、文件、XML以及對象數據庫(ODBMS)等等,使得應用可移植性更強。


    JNDI

    英文全稱是:Java Naming and Directory Interface

    術語解釋:一組幫助做多個命名和目錄服務接口的API。

    JNDI(Java Naming and Directory Interface)是SUN公司提供的一種標準的Java命名系統接口,JNDI提供統一的客戶端API,通過不同的訪問提供者接口JNDI SPI的實現,由管理者將JNDI API映射為特定的命名服務和目錄系統,使得Java應用程序可以和這些命名服務和目錄服務之間進行交互。集群JNDI實現了高可靠性JNDI[8],通過服務器的集群,保證了JNDI的負載平衡和錯誤恢復。在全局共享的方式下,集群中的一個應用服務器保證本地JNDI樹的獨立性,并擁有全局的JNDI樹。每個應用服務器在把部署的服務對象綁定到自己本地的JNDI樹的同時,還綁定到一個共享的全局JNDI樹,實現全局JNDI和自身JNDI的聯系。


     

    JNDI(Java Naming and Directory Interface)是一個應用程序設計的API,為開發人員提供了查找和訪問各種

     

    命名和目錄服務的通用、統一的接口,類似JDBC都是構建在抽象層上。

     

    JNDI可訪問的現有的目錄及服務有:DNS、XNam 、Novell目錄服務、LDAP(Lightweight Directory Access Protocol 輕型目錄訪問協議)、 CORBA對象服務、文件系統、Windows XP/2000/NT/Me/9x的注冊表、RMI、

     


     

    DSML v1&v2、NIS。

     


    JNDI與JDBC

    JNDI提供了一種統一的方式,可以用在網絡上查找和訪問服務。通過指定一個資源名稱,該名稱對應于數據庫或命名服務中的一個記錄,同時返回數據庫連接建立所必須的信息。

    JNDI主要有兩部分組成:應用程序編輯接口和服務供應商接口。應用程序編程接口提供了Java應用程序訪問各種命名和目錄服務的功能,服務供應商接口提供了任意一種服務的供應商使用的功能。

     

     

    Java代碼  收藏代碼
    1. try{  
    2.   Context cntxt = new InitialContext();  
    3.   DataSource ds = (DataSource) cntxt.lookup("jdbc/dpt");  
    4. }  
    5.   catch(NamingException ne){  
    6.   ...  
    7. }  

    posted @ 2011-03-22 17:35 Sheldon Sun 閱讀(1130) | 評論 (1)編輯 收藏

    Restart

    From now, i will restart my blog , try to record sth of my life, including some thoughts and research results of technology, the only little hope is that the blog can leave my memory of life, as time flying, when i open it , i can get something.

    Technology - Hibernate collection:
    Maybe i used to write sth related before.
    Several points as follows:
    1. Define interface as property, for Hibernate will use its own implementation during runtime.
    2. <key> element is used to identiry foreign key for specified table.
    3. <element> and <composite-element> is used for value type definition while <one-to-many> and <many-to-many> is used for entities type.
    4. indexed-collections contain : map, list, index is used to record position for certain record in the container.<map-key> for map while <index-list> for list.
    Next two items is for bidirection:
    5. inverse can be set in either sides for many-to-many relation.
    6. For one-to-many,  many sides will mantain relationship between object. exception happened when many side is index container.in this situation, it is not a completely "bidirectoinal".

    7. Sort is done in memory while order by is down in DB.
    8. <Bag> is used when property is defined as list, but <index-list> is not welcome.
    9. <idbag> is a list which can generate an id for primary key.

    posted @ 2008-06-11 18:27 Sheldon Sun 閱讀(507) | 評論 (0)編輯 收藏

    Interpret and command pattern

    解釋器模式:
    編譯器用的比較多。
    針對某一特定語法的分析, 解釋, 并進行處理!
    E.g: Expression = expression1 | expression2 | repeatableExpresson|Literal
    針對整個Expression, 分析出其每個組成的expresion1, expression2, 對每個分析出的結果, 都有相應的處理類! 并初始化出處理類的實例進行處理!
    Literal代表元數據 !
    如果對一個汽車組件的各個生產廠商進行解釋器模式分析的話: 汽車 = 輪胎 + 發動機 + 框架 那么首先建立一個分析程序,分析汽車的組成, 并針對每個部件初始化一個不見對應的對象, 來匹配該部件! 并調用部件的特有方法, 處理部件, 返回生產廠家的名稱!

    這個例子好失敗, Interpret 模式優點在表達式的租成有很多模塊, 每個模塊重復的包含其他模塊的情況下, 達到代碼重用的目的! 所以除了正則表達式, 編譯器以外, 暫時想不出什么好的例子來!

    命令行模式:
    Struts 應用是典型的命令行模式。
    1。 把請求參數話。
    2。 對每個請求配置相應的處理類。處理類有統一的接口。
    3。 配置請求與處理類的對應關系。
    4。 調用處理類統一接口。

    沒什么好說的!




    今天比較凡, 感覺自己職業發展已經到達了一個瓶頸, 不知道怎么發展才好!
    感覺自己交流能力比較差, 大家在一起的時候都是聽別人說! 自己很少發言, 做編碼已經感覺沒有太大意思了, 因為現在的公司只注重結果, 不看中代碼的質量,開發出來很容易, 但開發好的代碼很難! 周圍的同事開發出來代碼的水平比我都差很多, 也一樣通過, 搞得自己想提高自己都沒有動力!
    想提高一下交流能力, 不知道轉行做QA會不會有點改善, 或者還家公司?
    比較迷茫!

    posted @ 2007-11-22 16:56 Sheldon Sun 閱讀(302) | 評論 (0)編輯 收藏

    Chain of responsibility

    剛才看了看職責鏈模式, 沒什么概念, 腦袋還是比較混亂! 把思路寫出來!

    職責鏈主要是為了一個請求, 可能有很多個處理者, 這些處理者數目并不固定而設計的!

    對每種處理, 都會有一個處理類來對應! 沒個具體的處理類都會有一個后繼: succor, 這個后繼比處理類更廣泛! 如果當前的處理類可以處理改請求, 則處理,否則使用后繼的處理方法!

    感覺最關鍵的一點就是對后繼者的定義, 那為什么不用繼承機制呢???

    posted @ 2007-11-21 16:49 Sheldon Sun 閱讀(339) | 評論 (1)編輯 收藏

    Validate xml

    package testSchema;

    import java.io.IOException;
    import java.io.InputStream;
    import java.io.Serializable;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;

    import org.apache.commons.codec.binary.Base64;
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.dom4j.Document;
    import org.dom4j.DocumentException;
    import org.dom4j.DocumentHelper;
    import org.dom4j.Element;
    import org.dom4j.Namespace;
    import org.dom4j.io.SAXReader;
    import org.dom4j.tree.DefaultNamespace;

    import org.iso_relax.verifier.Schema;
    import org.iso_relax.verifier.Verifier;
    import org.iso_relax.verifier.VerifierConfigurationException;
    import org.iso_relax.verifier.VerifierFactory;
    import org.iso_relax.verifier.VerifierFilter;
    import org.xml.sax.EntityResolver;
    import org.xml.sax.ErrorHandler;
    import org.xml.sax.InputSource;
    import org.xml.sax.SAXException;
    import org.xml.sax.SAXParseException;

    import com.sun.msv.verifier.jarv.TheFactoryImpl;

    public class ValidateXML {
       
        public Document validate(InputStream stream, String xsdName) throws IOException{
       
        Document result = null;
        InputStream xmlStream = stream;
        InputStream schemaStream = this.getClass().getResourceAsStream(xsdName);
        SAXReader reader;
        try {
            reader = createSAXReader(schemaStream);
            result = reader.read(xmlStream);
            xmlStream.close();
            schemaStream.close();
        } catch (DocumentException e) {
            System.out.println("Validate failed !");
            e.printStackTrace();           
        } catch(IOException e) {
            System.out.println("Xsd file does not exist !");
            e.printStackTrace();           
        }
        catch (Exception e) {
            System.out.println("Xsd file format error !");
            e.printStackTrace();
        }
       
        return result;
    }

    private SAXReader createSAXReader(InputStream xsdStream) throws VerifierConfigurationException, SAXException, IOException {
        VerifierFactory factory = new TheFactoryImpl();
    Schema schema = factory.compileSchema(xsdStream);

    Verifier verifier = schema.newVerifier();
    verifier.setErrorHandler(new ErrorHandler() {
        public void error(SAXParseException e) {
        System.out.println("ERROR: " + e);
        }

        public void fatalError(SAXParseException e) {
        System.out.println("FATAL: " + e);
        }

        public void warning(SAXParseException e) {
        System.out.println("WARNING: " + e);
        }
    });

    // now install the verifying filter
    VerifierFilter filter = verifier.getVerifierFilter();
    SAXReader reader = new SAXReader();
    reader.setXMLFilter(filter);
    return reader;
    }


    public static void main(String[] args) throws IOException {
        ValidateXML validateXML = new ValidateXML();
    //    InputStream schemaStream = validateXML.getClass().getResourceAsStream("Response.xml");
    //    validateXML.validate(schemaStream, "BAK-Response.xsd");
        validateXML.validateByDtd("hibernate-configuration-3.0.dtd", "src\\testSchema\\hibernate.cfg.xml");
    }

    public Document validateByDtd(String dtdFile, String xmlFile) {
        List errors = new ArrayList();
        SAXReader saxReader = new SAXReader();
        saxReader.setEntityResolver(new DTDEntityResolver(dtdFile));
        saxReader.setErrorHandler(new ErrorLogger(xmlFile, errors));
        saxReader.setValidation(true);
        Document doc = null;
        try {
        doc = saxReader.read(xmlFile);
        } catch (DocumentException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        }
       
        return doc;
    }

    public static class ErrorLogger implements ErrorHandler {
        private String file;
        private List errors;
        ErrorLogger(String file, List errors) {
            this.file=file;
            this.errors = errors;
        }
        public void error(SAXParseException error) {
            System.err.println( "Error parsing XML: " + file + '(' + error.getLineNumber() + ") " + error.getMessage() );
            errors.add(error);
        }
        public void fatalError(SAXParseException error) {
            System.err.println(error);
        }
        public void warning(SAXParseException warn) {
            System.err.println( "Warning parsing XML: " + file + '(' + warn.getLineNumber() + ") " + warn.getMessage() );
        }
    }


    public static class DTDEntityResolver implements EntityResolver, Serializable {

        private static final Log log = LogFactory.getLog( DTDEntityResolver.class );

       
        private String dtdFile;
        public DTDEntityResolver(String dtdFile) {
            this.dtdFile = dtdFile;
        }
        public InputSource resolveEntity(String publicId, String systemId) {
            if ( systemId != null ) {
                InputStream dtdStream = this.getClass().getResourceAsStream(dtdFile);
                InputSource source = new InputSource( dtdStream );
                source.setPublicId( publicId );
                source.setSystemId( systemId );
                       
                return source;
            }
            // use default behavior
            return null;
        }

    }

    }

    posted @ 2007-08-08 09:53 Sheldon Sun 閱讀(579) | 評論 (0)編輯 收藏

    Hibernate - Component

    1. Component is value type, can not shared between entities, dont own identifier!
    2. Declaration for mapping under component element.
    3. When storing in set(or other collection type), use composite-element.
    4. When using as primary key, use composite-id.
    5. Dynamic component.



    posted @ 2007-06-19 09:31 Sheldon Sun 閱讀(302) | 評論 (0)編輯 收藏

    Hibernate - Persistent class

    1. Hibernate recommand persisten class as a standard javabean naming convention, but not required, Hibernate can access fileds directory too.
    But a no-argument constuctor is requeried for hibernate to instiante an object of the class by refection.

    2. Indentifier property if optional too, but needed if we want to use the full feature set of hibernate, for hibernate will distinguish object by identifiers while some special operation. e.g:  merge(), saveOrUpdate.

    3. Equals() and hasdCode() mehtod is recommanded to implenent when you want to store persisntent class in a Set or manipulate object span sessions.

    4. There are other 2 ways to define enity object except java class, Map and xml, the defect maybe can not do compile check, metrit is more flexisble than java.

    5. Tuplizier!!!!

    Hibernate integrated with J2EE infrastructure:
    Two main point:
    1. Hidden Configuration.config().buildSessionFacotory operation.
    2. Bound session factory to jndi namespace through many way. e.g: MBean
     

    posted @ 2007-06-14 11:12 Sheldon Sun 閱讀(558) | 評論 (0)編輯 收藏

    Inheritance strategy

    There are three kinds of basic strategies for inheritence mapping:
    1. table per hierarchy.
    2. table per subclass.
    3. table per concreteclass.

    Table structure maybe the root reason to determine which kind strategy will be used.

    Table per hierarchy:
    With subclass element.
    A discriminator column will be used to distinguish subclass.
    Limitation: no not null constraint on sub class's property.
    Fault: redandance data will be generated.

    Table per subclass:
    With joined-class elment.
    There are tables for super class and each subclass, for every subclass, key elemnt is used to referenced to super class's primary key, and all common properties will be stored in super table. The relation between super table and sub table is one-to-one.
    Fault: complex table structure.


    Table per concrete class:
    With union-class elemnt.
    Super class responsible for genrate id and all common properties wich will stored in sub table.
    Fault: redandance data will be generated.
    Limitation: all common column should used the same column name for the properties are defined in super class.

    posted @ 2007-06-01 10:55 Sheldon Sun 閱讀(255) | 評論 (0)編輯 收藏

    HbmBinder

    Walks an XML mapping document and produces the Hibernate configuration-time metamodel (the classes in the mapping package)


     

    1. parse "extend" attribute of subclass, unionclass, joinedclass which defined under <hibernate-mapping> element.

    2. parse "meta" data element.

    3. parse other subclass of root element.

    posted @ 2007-05-30 12:57 Sheldon Sun 閱讀(153) | 評論 (0)編輯 收藏

    Hibernate filter

    1. Hibernate filter is used to give a definition condition in xml mapping files.
    2. Ever session want to use it must enable the filter with name first.
    3. filter is defined in xml with elment <filter-def> under <hibernate-mapping>, used <filter> element under <class> element.
    4. give certain sql condition attribute either in <filter-def> or <filter>.
    5. Support value to filter parameters in application.



    The main purpose is to support global filter.

    posted @ 2007-05-24 13:20 Sheldon Sun 閱讀(436) | 評論 (0)編輯 收藏

    Hibernate query

    1. session.createSqlQuery(), in purpose to increase performance, execute sql directly. addScalar() method is used to sepcify type of columns, add entity to return certain entity instance.
    2. session.getNamedQuery(), execute query defined in mapping files with <sql-query> element, the query can be a defined sql sentence or a procedure, property type and entity type can also be specifid by certain elment.
    3. update, detelet, insert sql can be defined in xml mapping files also.


    The finaly purpose of the query is to enchance performance.

    posted @ 2007-05-24 12:51 Sheldon Sun 閱讀(333) | 評論 (0)編輯 收藏

    Hibernate Criteria

    1. Usage org.hibernage.Criteria interface is to compose criterians included in org.hibernate.criteria package.
    2. Criteria interface inherit org.hibernate.criteria.CriterianSpecification, which only defined some mode value, e.g: flushmode, cach mode, maybe not a good implemnt.
    3. Criterian was implemnt by org.hibernate.impl.criteriaImpl and created by org.hibernate.impl.SessionImplementor, translate class name and sesson to criterian.
    4. Typical usage: session.createCriteria(class).add(Restriction.xx()).list;
    5. Restriction is factory of org.hibernate.criteria.Criteriaon implementation.

    Architecture : Define top level interface to compose low lever sub interface, easy to extense and maintain.

    posted @ 2007-05-24 10:55 Sheldon Sun 閱讀(277) | 評論 (0)編輯 收藏

    Hibernate - Environment

    There are 2 kinds of factory : factory level and System level, factory responsible for every factory instance, System for all facotrys, (only 2 system factory property).
    Evironment got properties for /hibernate.properties first, and then from System.getProperties() to ovrride old one!

    Totally, Evironment represents properties.

    posted @ 2007-05-22 13:57 Sheldon Sun 閱讀(111) | 評論 (0)編輯 收藏

    Collection mappings

    1. Use interface type.
    2. Ordered type collection has index sub-element.
    3. Key element indicates the foreign key referred to entity own the collection.
    4. "element" or "composite element" element is used to specify value type contained in collection.
    5. "many-to-many" or "one-to-many" elmeent is used to sepcify referred type contained in collection.
    6. one-to-many need not an intervening table.(foreign key)

    posted @ 2007-05-22 11:12 Sheldon Sun 閱讀(111) | 評論 (0)編輯 收藏

    Persisitent object

    Hard requirenment:
    1. No-argument construct , package visiblity, usde instantiate object by Constructor.newInstance().

    Option requirement:
    1. Pojo.
    2. Implement hashCode and equals for two resons :
        1) Object will be store in a set property.
        2) Instance span to sesssion scope, make a detached object persistent again, will call equals, for java indentify(==) and db indentify(pk) is not available for the condition(object doest not have identify before persistent),

    Note: hashCode generation should not use indentify proeprty  of object.

    posted @ 2007-05-17 08:51 Sheldon Sun 閱讀(240) | 評論 (0)編輯 收藏

    Hibernate configuration

    Hibernate configuration object is the core and starttime class , initiate it and call its config() method to initial sessionFactory.
    Configuration get properties, mapping , etc information through two ways:
    1. Config file: hibernate.propeties, system, hibernate.cfg.xml(optional, name changed Configuration.doConfig(*.cfg.xml)).
    2. Method: Configuration.addSource, addProperties...

    So config files is only a way of configuration to get config info.



    posted @ 2007-05-16 15:00 Sheldon Sun 閱讀(232) | 評論 (0)編輯 收藏

    0516_2

    Configuration: the class instantiate a sessionng factory, it works as follow:
    1. Get properties for Enviroment.java. Environment get properties from hibernate.properties and System, System propertie is prior to hibernate.properties when name is equal.
    2. Configuration.config will read hibernate.cfg.xml to get more properties and mapping files.


    During last two steps, it will some util class in org.hibernate.util to help handle file.

    3. Generate ConnectionProvider by its all properties.


    posted @ 2007-05-16 09:17 Sheldon Sun 閱讀(122) | 評論 (0)編輯 收藏

    0516_1

    1. Update make a detached object persistent.
    2. Config mapping relating in mapping files make query as object oriented.
    3. For many-to-many relation relationship, middle table store link to two tables.
    4. Key element is identify the column of middle table.
    5. Db operation happend at the end of a unit work ---- session flush.
    6. For value type, "element" will replace "many-to-many" in set element(acturally, for all java object, hibernate take it as a value type), value type can not shared by more than one instance.
    7. All bi-directional associations need one side as inverse. bi-direction means both sides of mapping mentain relations of middle table, inverse side is a mirror of the other side, during save or update, the other side will handle.

    posted @ 2007-05-16 08:52 Sheldon Sun 閱讀(166) | 評論 (0)編輯 收藏

    session

    1. batch insert/update session.flush session.clear
    2. statlesssession

    posted @ 2007-05-15 13:34 Sheldon Sun 閱讀(80) | 評論 (0)編輯 收藏

    Mapping for inheritance

    There are three main kinds of mapping for inheritance:
    1. table per class hirachy, for each subclass, use discriminator to distinguish different data, subclass specific property can not be null, only one table.
    2. table per subclass, there is a common table for super class, subclass table reference to super table through primary key, add relationship between tables.
    3. table per concrete class, generate too much redandance data, pk was generated by super class.


    some mix mapping is available.



    posted @ 2007-05-14 13:41 Sheldon Sun 閱讀(133) | 評論 (0)編輯 收藏

    hibernate ref1

    1. Entity name: can be used query.
    2. Way of define mapping: xml, xdoclet, annotation.
    3. Gerated properties: timestamp, version, and property can be generated. Types as follows :
    never: default value.
    always: generated when insert and update.
    insert: only geneated when create data, won't change when updated it later.
    4. Create db schema can be written in xml file.

    posted @ 2007-05-14 10:20 Sheldon Sun 閱讀(112) | 評論 (0)編輯 收藏

    Hibernate reference

    1. lite archetecture: application handle connection and transaction, use niminum hibernate api.
    2. full scream architecture: application will ingore underlying jdbc, jta apis, hibernate hold it.
    3. Persistent object stats: persistence, transient and detached.
    4. Session factory: a cache of compiled configuration files for single db, thread-safed, factory of session and client of connectionProvider, an optional cache of data for process, cluster layer.
    5. Session: represent a conversation between application and db, factory of transaction. wrapped conncetion.
    6. Transatcion: specify automic unit of work.
    7. Context session: hibernateUtil class, for certain application, the scope of current is different, have different context concept. (need more research!)
    8. Configration: store xml to java, can got it through specify xml, java class and proeprties.
    9. Hibernate mapping: mapping java type to SQL type.
    10. Custome mapping type: implement UserType or CompsiteUserType, can define short name, chould get certain value of property by key value.(useless)
    11. Entity and Value: entity can be shared by more than one persistent class as reference.


    posted @ 2007-05-14 09:45 Sheldon Sun 閱讀(247) | 評論 (0)編輯 收藏

    再論Singleton模式

    Singleton模式可能是應用最廣泛的模式之一了, 但有些錯誤的應用。
    ?Singleton的實現: 有兩種方式, 如下:
    1. class Test { public static final Test instance = new Test(); private Test() {} }
    ?2. class Test { private static final Test instance = new Test(); private Test() {} public static Test getInstance() { return instance; } } 這兩種方法都要求構造器是私有的, 這樣就可以防止該類外的對象創建新的TEST對象。 但相對而言, 推薦使用第二種方法, 因為其更具有靈活性,當我們改變創建對象的方式的時候, 不需要改動客戶代碼。 第一種方法較第二種有一點完全可以忽略不計的效率的提高。
    ?但應避免如下代碼實現Singleton: class Test { private static Test singleton = null; private Test() {} public Test getSingleton() { if(singleton == null) { singleton = new Test(); } return singleton; } } 因為嚴格上講, 這并不能完全實現Singleton模式,而且會導致程序出錯, 這同著名的線程問題--DCL實效的原理是完全一樣的:
    JVM創建對象的過程可以分為幾個步驟:創建空間, 把所有的變量賦值位默認值, 初始化。。。 當有兩個線程A和B同事進入該方法, A先執行, A創建Test實例的空間, 這時,因為CPU的指令流機制,時間片段正好輪到B線程, 這時B判斷singleton是否為NULL, 因為A已經為Test的實例分配了空間, 所以JVM認為實例已經創建了, B繼續執行, 更糟糕的是B調用了singleton, 這時因為他并沒有初始化完全, 所以拋出NullPointerException, 太糟糕了!

    posted @ 2006-10-30 14:10 Sheldon Sun 閱讀(188) | 評論 (0)編輯 收藏

    Bridge模式 和Composite模式

    Bridge:主要實現的原理就是把接口 和實現分離開來, 保證他們再兩個不同的類層次結構。

    用Bridge而不是直接繼承實現主要有兩個好處:
    1。 二進制兼容。 假設我們的應用程序需要用到format功能, 我們可能有要引用兩個第三方JAR包, formatInterface.JAR And formatImp.jar, 我們程序可能只引用了formatInterface.jar中的接口, 而formatImpl.jar里是什么我們根本不需要關心, 因為他是formatInterface的實現, 所以當他改變的時候, 我們的應用程序完全不用重新修改代碼, 編譯。可能我在LINUX下用LINUXFormatImpl.jar, 再WINDOW下use WindowFormatImpl.jar, but Application will never care about it.
    ?2. 接口與實現的分離, 實現不一定實現接口的內容, 就是說實現同接口之間不是一一對應的, 實現可能完成最原子的操作, 而接口通過持有一個實現的應用, 組裝這些操作來實現接口。 比如說接口是createRectangle(), 實現可能只完成了createLine的操作, 然后有接口來組裝。


    ?Composite模式則要從全局的角度考慮對象之間的關系是否滿足“樹枝” 與 “樹葉”的關系, 如果滿足, 則需要定義一個樹枝與樹葉的集合接口Tree, 既包含樹枝接口add(tree)和樹葉接口getColor()。

    posted @ 2006-10-26 19:46 Sheldon Sun 閱讀(155) | 評論 (0)編輯 收藏

    Synchronize 與 JAVA 內存模型

    每個JAVA對象都有一把所, 當有多個線程同時訪問共享資源的時候, 需要Synchronize 來控制安全性, synchronize 分 synchronize 方法 和synchronize快,使用synchronize塊時, 一定要顯示的獲得該對象的鎖(如synchronize(object))而方法則不需要。

    ?JAVA 的內存模型是對每一個進程有一個主內存, 每個線程有自己的內存, 他們從主內存中取數據, 然后計算, 再存入主內存中。

    ?并發問題如下:如果多個線程同事操作同一數據, A線程從主內存中取的I的值為1, 然后進行加1操作, 這時B線程也取I的值, 進行加2操作, 然后A存入2到主內存中, B也存入, 這樣就覆蓋了A的值(同數據庫中的并發問題一樣)。 解決辦法是用synchronize, 如用synchronized(I)。被synchronize 修飾的方法(塊)把以下三步操作當成一個原子操作:取數據, 操作數據, 存數據。 我們知道原子操作是不可以被打斷的, 所以其保證了數據一致性, 這樣同一時間只有一個線程再執行, 對性能有一定的影響。這也是synchronize的第二個作用:保證統一時間只有一個線程再運行。 當實現SOCKET連接的時候經常用到.

    ?JAVA中規定對非FLOAT, LONG的原始類型的取和存操作為原子操作。 其實就是對一個字(32位)的取,存位原始操作, 因為FLOAT, LONG為兩個字節的長度, 所以其取, 存為非原子操作。 如果想把他們也變為原子操作, 可以用VOLATILE關鍵字來修飾。

    posted @ 2006-10-26 19:19 Sheldon Sun 閱讀(411) | 評論 (0)編輯 收藏

    java seriliazable

    1. serializable default serialize all field and object net.
    2. Externalizable default deserialize all fields and use writeExternal and readExternal to serialize object. should provide public construct.
    3. serializable interface use private writeObject and private readOjbect to implemnets the same fucntion as Extenalizable interface. (writeDefautObject and readDefaultObject).
    4. Externalizable extends serializable

    posted @ 2006-10-23 20:09 Sheldon Sun 閱讀(163) | 評論 (0)編輯 收藏

    從學習JAVA看學習語言

    學習java也有幾年的時間了, 大學開始就一直沒有斷過, 工作后有專門學習了java。 由于對原理型的知識比較看重, 所以JAVA基礎學的比較多, 至今精通不敢說, 但至少也應該算是熟悉了吧! 我認為語言的學習最簡單的就是文法學習, 估計一般學習一周 到兩周就可以使用這種語言編寫程序, 對于初級程序員這樣也就足夠了, 但要對語言有很深的了解:就是對這個語言的特性的了解, 把JAVA做例子, 他的所有類繼承自OBJECT(他的所有方法用途, 作用等等), CLONABLE接口, SERIALIZABEL接口改變了方法的行為,synchronized等等, 這些都是JAVA語言定義的自己的特征, 包括JAVA的性能, 要能高效率的運用JAVA, 必須對對這些特性有比較深的了解, 還要對其主要的庫有一定的了解,比如說容器庫, 輸入輸出流。。如果了解這些的話最少也要花費1--2年的學習, 還不一定掌握精髓。 估計掌握這些知識的人怎么也應該是高級程序員了。 JAVA學習的最高境界應該是對其類庫的無比熟悉, 能清楚其內在的實現, 如容器類散列桶的實現方法等等, 以及他們實現的優劣。 能達到這個程度的人應該寥寥無幾, 這樣的人一般是有10年JAVA工作經驗的資深JAVA程序員了。 個人認為學習語言也不過這三個階段:熟悉語法, 熟悉語言的特性, 精通類庫。一個語言成熟與否的標志就是他是否有一個設計良好的全面的類庫。

    posted @ 2006-10-23 11:24 Sheldon Sun 閱讀(198) | 評論 (0)編輯 收藏

    迭代化開發新問題

    http://blog.csdn.net/fuchunyi/archive/2006/10/22/1345708.aspx 這周去拜訪一個客戶,他們正在實施RUP,問及效果如何,聽到了一些關于迭代化開發的新問題。 這位客戶是一家集成商,主要為甲方開發應用軟件系統。實施迭代化開發的主要目的是控制項目風險,應用項目的最大風險一般都在于需求,采用迭代化可以通過迭代產生的原型系統來收集甲方客戶的反饋,從而及早修正對于客戶需求的誤解。但是開發團隊并沒有象預想中那樣收集到甲方的反饋,甲方還是習慣于用傳統的瀑布模型來評價、驗收系統,他們并沒有對項目過程中交付的原型系統進行認真的確認,所以也沒有太多的意見反饋給開發團隊,很多需求的變更還是要到系統正式驗收時才被提出來。因為在甲方的觀念中,他們還不太認可項目結束之前所提交的中間結果。 另外,項目的合同是按照瀑布模型的階段來簽的,需求分析、概要設計、詳細設計、編碼完成、驗收測試是項目回款的里程碑。采用迭代化開發之后,在原定的概要設計交付時間點上,可能需求分析和概要設計都只完成了部分的工作,比原定計劃要晚一些;而詳細設計和編碼工作都已經開始了一部分,比原定計劃要提前一些。這樣就不能按照原定時間點來要求甲方就需求分析和概要設計那部分工作量付款,對于中國的集成商而言,項目回款是比合同簽定都要重要的工作。 這些問題給我們的經驗教訓是應用項目開發采用迭代化開發流程,也需要讓客戶理解這一點,項目工作說明書中的工作單元內容也需要跟迭代化開發流程來符合。軟件開發流程關系到所有的涉眾(Stakeholder),僅僅是開發團隊理解并實施這一流程是不夠的。 還有一個反饋來自于很多項目團隊,認為迭代化開發概念上聽起來很有道理,但在項目中實施后往往感覺不到采用這處方法后對項目有什么太大的幫助。迭代化開發的主要目的在于控制項目風險,常見的項目風險如技術架構、客戶需求等等。但是日常工作中的項目往往沒有太多的風險,我們開發的往往是重復性的項目,電信事業部做的就是不同運營商的BOSS項目,社保事業部就是為不同省份開發社保系統,雖然有特殊需求,但系統架構和基本需求完全一樣;更多的項目是對現有系統的維護性開發,實現客戶提出的變更請求和改正軟件缺陷,一般不會涉及到系統架構的改動。在這種類型的項目中,迭代化開發體現的不是對風險的控制,而是系統增量式開發而不斷給涉眾所帶來的信心和鼓舞,開發人員可以在較斷的時間周期內看到自己所開發的系統可以“跑”起來了,客戶則可以看到整個項目在不斷地往前推進。

    posted @ 2006-10-23 08:58 Sheldon Sun 閱讀(174) | 評論 (0)編輯 收藏

    現在的公務員...

    媽的, 想起來就有氣, 現在的公務員一個比一個牛, 本來應該為人民服務, 態度卻一個比一個差....

    最近想辦居住證續辦, 想打個電話咨詢一下, 試了N多個, 有的 還好借了告訴你個號碼, 讓你去打, 但一直戰線, 更有的那起來就掛掉, 拿起來就掛,,,,,,

    TNND!!!!

    posted @ 2006-10-19 22:49 Sheldon Sun 閱讀(222) | 評論 (1)編輯 收藏

    一個技術牛人的悲慘遭遇

    http://www.bcb-tools.com/AuthorNotes.htm

    posted @ 2006-10-16 08:56 Sheldon Sun 閱讀(149) | 評論 (0)編輯 收藏

    鮑爾默: 軟件互聯界線模糊 Web服務離不開PC

    http://dotnet.csdn.net/n/20061011/95958.html 微軟首席執行官鮑爾默表示,提前部署(on-premise)軟件與通過互聯網發布的服務之間的界線在日益模糊,微軟正在順應這一業界趨勢。 鮑爾默在Gartner 的Symposium/ITxpo 會議上接受了Gartner分析師史密斯和伊馮的采訪。鮑爾默在采訪中說,許多網站可以被稱作“點擊運行”,服務通過網站發布,但在PC上運行。 他表示,我認為我們正處于一種轉型中,軟件正在由前互聯網時代發展到我們所謂的“Live時代”,網站提供了“點擊運行”能力,但軟件仍然需要在PC上運行。 由于有大量的臺式機和服務器軟件產品,與Salesforce.com或Google相比,微軟對托管服務的態度還不夠積極。 據鮑爾默稱,微軟計劃推出面向消費者和企業客戶的服務化軟件,提供通過互聯網的服務和企業防火墻后面的服務器。 去年,微軟將Windows 和開發者工具部門與負責MSN Web 服務的部門進行了整合,它目前正在開發一系列名為Live的托管服務,其中一些服務旨在補充現有的“提前安裝”軟件。 鮑爾默表示,軟件+ 服務與服務化軟件之間的差別在于人們是否想利用手機、PC的處理能力。甚至考查一下目前的互聯網服務,它們也都使用了客戶端的處理能力,例如AJAX、即時通訊服務。 鮑爾默表示,在這一服務化大潮中,盡管不能永遠保持第一,但微軟不會放棄。他說,我們或許不是第一,但我們在不斷努力。在搜索方面也是一樣,我們不會輕言放棄。

    posted @ 2006-10-12 08:27 Sheldon Sun 閱讀(116) | 評論 (0)編輯 收藏

    將女友升級為老婆的時候發生的

    親愛的技術支持: 我急需您的幫助。我最近將"女朋友7.0"升級到"妻子1.0",發現這個新程序意外地啟動了孩子生產程序,而且占用了大量的空間和珍貴的資源。這在產品的使用手冊中沒有提到。 此外"妻子1.0"自動將自己安裝到其他的所有的程序中,它隨系統同時啟動,監控整個系統的狀態。 "男人夜出2.5"和"高爾夫5.3"無法再運行,一旦運行該程序系統即行崩潰。試圖運行 "周日足球6.3"經常失敗,而"周六購物7.1"卻代之運行。看來我無法保留"妻子1.0",因為它和我喜歡運行的任何程序都不相容。我打算回到"女朋友7.0",可是這個程序又無法卸載。 請您幫幫我吧! 喬 給喬的回信: 親愛的喬:這是個很普通的問題,產生于你對基本原理的不了解。很多的男人健"女朋友7.0"升級到"妻子1.0",以為"妻子1.0"是一個"實用與娛樂程序"。然而"妻子1.0"卻是個操作系統,是被設計用來運行所有程序的。你不可能清除"妻子1.0",也不可能回到"女朋友7.0",因為"妻子1.0"的設計中不具有這個功能,無論是卸載、刪除或是清除已經安裝在系統中的這些程序文件,都是不可能的。 有些人曾試圖安裝"女朋友8.0"或者"妻子2.0",結果是產生了更多的問題(參見手冊中的贍養費/孩子的養育/律師費用)。我安裝過"妻子1.0",我建議你保持現在的安裝狀態,妥善解決遇到的困難。 當任何錯誤或問題出現的時候,不論你認為是什么原因引起的,你必須運行"C:\我道歉"程序,并且避免使用"退出鍵"。必要時可能需要運行"C:\我道歉"多次,希望最終能使操作系統恢復到初始狀獺。 "妻子1.0"雖然是一個需要高保養的程序,但同時對人可能是非常有益的。要想充分地利用它,需要買些額外的軟件比如"鮮花2.0"和"巧克力5.0"。不要在任何情況下安裝"秘書(短裙版)",因為"妻子1.0"不支持這種程序,而且系統多數時候肯定會崩潰。 祝你好運!

    posted @ 2006-09-29 16:45 Sheldon Sun 閱讀(137) | 評論 (0)編輯 收藏

    About life

    Life like a long run contest e.g 3000 meters. sb abort it at 1000 meters. sb abort at 2000 but only ones who finished running are sucessfully. But who will became these ones???

    posted @ 2006-09-29 09:01 Sheldon Sun 閱讀(126) | 評論 (0)編輯 收藏

    如何在Web應用中啟動后臺任務

    http://www.javaresearch.org/article/showarticle.jsp?column=2&thread=32387 摘要 我們常常在Web應用中需要啟動一個自己寫的服務,本文的目的是給你提供一個解決方案。 原理 本方案的原理是寫一個實現了ServletContextListener接口的類,該類中有兩個方法: public void contextInitialized(ServletContextEvent sce),它是在應用啟動時調用;另一個方法是:public void contextDestroyed(ServletContextEvent sce),該方法是在應用結束時調用。把我們要啟動的后臺應用邏輯放在contextInitialized方法中實現;把釋放后臺應用占用資源的工作放在contextDestroyed來處理。但我們啟動的后臺任務常常是有要求的,比如時間,頻率等,我在這里使用了一個開源組件:quartz。 步驟 1.寫業務調用類: // DumbJob.java import org.quartz.*; import java.util.*; public class DumbJob implements Job { public DumbJob() { } public void execute(JobExecutionContext context) throws JobExecutionException { //在這里寫業務處理代碼。什么,你不知道?那你別問我!!:-< } } 本類的主要功能是由quartz中調度類按照指定的規則進行調用執行必要的業務邏輯。 2.寫調度類 // TestShedule.java import org.quartz.*; import java.util.*; public class TestShedule{ static SchedulerFactory schedFact = new org.quartz.impl.StdSchedulerFactory(); static Scheduler sched; public static void run()throws Exception{ sched = schedFact.getScheduler(); //獲取調度管理器 JobDetail jobDetail = new JobDetail("myJob", sched.DEFAULT_GROUP, DumbJob.class);//創建工作 CronTrigger trigger = new CronTrigger("myTrigger","test","0/10 * * * * ?");//創建觸發器 sched.scheduleJob(jobDetail, trigger); //添加到調度管理器中 sched.start();//啟動調度管理器 } public static void stop()throws Exception{ sched.shutdown(); } } 本類的目的是設置調用規則,在這里我用了“0/10 * * * * ?”表示每10秒鐘就執行一次,有關表達式的說明請參閱quartz的api文檔。 3.編寫服務啟動類: //ServiceLoader.java import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; public class ServiceLoader implements ServletContextListener { public void contextInitialized(ServletContextEvent sce) { try{ TestShedule.run(); }catch(Exception ex){ System.out.println(ex.getMessage()); } } public void contextDestroyed(ServletContextEvent sce) { try{ TestShedule.stop(); }catch(Exception ex){ System.out.println(ex.getMessage()); } } } 在contextInitialized中調用TestShedule.run()啟動后臺任務;在contextDestroyed中調用TestShedule.stop()停止后臺任務。 4.部署服務啟動類 在web.xml文件中增加如下一行配置: rootServiceLoader index.html 5.啟動web服務即可。 總結 其實實現這個功能的方法很多,我在這里是應用了ServletContextListener接口和開源api quartz,希望能對你的開發有所幫助。 資源 quartz: http://www.opensymphony.com/quartz ServletContextListener在javax.servlet包中

    posted @ 2006-09-27 16:52 Sheldon Sun 閱讀(239) | 評論 (0)編輯 收藏

    動態語言,別再說不

    http://blog.csdn.net/myan/archive/2006/09/25/1281151.aspx 相信很多人都聽過一個禪宗故事,說是兩個僧人趕路,趟過一條小河的時候,看到一個漂亮的少婦困于其中,向他們呼救。其中一個有心施以援手,但想到佛家的色戒,便猶豫起來,不知如何是好。可另一個和尚卻大大咧咧地沖過去,抱起少婦,趟過小河。于是前者的心里就很不舒服,一路上悶悶不語,后來實在忍不住,就問自己的同伴,既然身為佛門中人,怎能不顧清規戒律,如此輕薄。然而那位和尚卻回過頭來,淡淡地說:“我已經把她放下了,你還抱著呢?” 也許不太貼切,但是這幾天中外豪杰們圍繞Ruby和Rail爆發的口水戰,讓我不由得想起這個小故事。 前幾天著名大嘴Joel Spolsky在自己的一畝三分地里對Ruby進行了FUD性的攻擊,引發互聯網上一片口水戰,Ruby之父matz和Rails之父DHH都卷入其中。似乎是要與此相呼應,在國內技術論壇上,這幾天圍繞Ruby的爭論也突然攀登新高峰了。國外的大氣候和國內的小氣候都有共同特點,就是站在傳統技術立場上的人對于RoR的火爆看不下去了,首先站出來發難,從而引發Ruby支持者們的回擊,然后雙方廝殺在一起,連帶旁邊相干不相干的看熱鬧的、拉架的、含沙射影的、慷慨激昂的,瞬間就浩浩蕩蕩,橫無際涯了。而爭論來爭論去,無非還是Ruby的性能問題、可用性問題、前景問題,等等等等。 可能是老生常談了,但倒R派的觀點讓我想起多年前我們這些C++ fans對Java的鄙視言論。那個時候C++程序員們說,Java只能用來在頁面上用applet作一些可笑的小動畫,Java只能對對火柴棍排序,Java慢得像牛車,Java有內存泄露,Java狂耗內存,Java愚蠢的弱類型容器可以把鯨魚裝進一個筆筒,Java居然沒有指針,Java做不了系統程序設計,Java寫不了操作系統,Java解決不了我手頭的超超級復雜的巨牛無比的難題,諸如此類,不一而足。冠冕堂皇的理由可以找出一大籮筐,但大皮襖下面無非就是一個“私”字而已。骨子里的想法是,我費了好大的牛勁才混了個C++三品頂戴,你Java一鬧騰,就把我的似錦前程給攪黃了,怎能不妒火中燒,羞憤交加? 可是這些年過去了,當時我們吐那點酸水起了什么作用了嗎?Java統治了企業計算,統治了手機應用開發,統治了大學教育。不但如此,Java在開源領域里也如日中天,接Eclipse之威在桌面應用中也占了一座大山頭。一些傳統上屬于系統程序的項目,比如編譯器、語法分析器、高性能的服務器軟件等等,也大量轉用Java開發。不錯,Java還是不能用來寫F-22戰斗機的火控系統,但是這跟我們這些坐在cubic里寫民用軟件的家伙有個鬼的關系!人們對于簡單、標準化和生產率的要求不可阻遏地突破了早期對Java筑起的FUD防線。面對Java的空前絕后的成功,我們這些當年曾經對革命力量翻白眼吐舌頭的家伙,在沉默的面對現實之后,已經完成了一次觀念上的滌蕩。我們已經認識到,技術的發展趨勢是不以個人利益為轉移的,干這行就要有順應技術大潮的勇氣,要有不斷破舊立新的魄力。我覺得我已經放下了曾經有的那種盲目的固執和一廂情愿。 然而時間沒過多久,隨著Java成長和騰達起來的一代人(其實不少也就是我的同齡人),又開始重蹈覆轍。面對以Ruby為代表的新興動態語言的蓬勃發展,他們也有點坐不住了。靠革命起家的人最怕革命,當年的下里巴人翻身做主了,搖身一變成闊佬了,就開始對新的革命力量擺譜使臉色,甚至以FUD戰術加以彈壓了。與當年如出一轍,手段還是以攻為守,情緒還是慷慨激昂,筆法還是義正言辭,什么Ruby未經驗證啦,什么Ruby性能低劣啦,什么Rails可擴展性不佳啦,什么Ruby不能解決“大型的”、“復雜的”、“企業級的”、“高性能的”問題啦。最要命的是,哪怕自己90%的時間不過是在字符串處理,這些闊佬們也還是一致宣稱自己做著世界一流的、大型的、復雜的、企業級的、非Java不可、沒Java不行、沒Java就要上吊抹脖子跳樓挖坑的巨牛無比的大項目,聽著讓人心驚肉跳兼之無比崇敬。你說Java還能火幾年?我說怎么也得5年!5年?那是上升期!少說十年,后面還有平臺期。你還別不服,反正我退休之前Java說什么也別想涼下來,誰也別想威脅我的頂戴花翎。企業級啊,架構師啊,經驗啊,高手啊,我混成這樣我容易嗎我?誰冒出來我就跟誰急,我就用口水淹死他! 可惜,這些大話對于我這種記性不幸沒那么差勁的人來說,太似曾相識了,讓我一眼就看出這言論背后的“私”字來。想來也真是輪回,當年我們C++這一批人放下的東西,原來你們Java這一批人還抱著呢。不過,技術的大潮真的是后浪推前浪,往后看吧,我相信,當年C++擋不住的東西,今天Java也擋不住。大趨勢已經擺在這了,接不接受、什么時候接受,那是個人的問題,但是總體的發展是無可逆轉的。 Ruby的興起,其實只不過是一個積累了幾十年的技術趨勢的能量釋放。世界上第二個程序設計語言Lisp及其后續家族成員都是最最動態的語言。早在七十年代,伴隨著圖形界面的出現,Smalltalk就以其純粹的面向對象和純粹的動態性獲得有識之士的認可。自1986年代Perl出現以來,大量開發者就認識到,動態語言開發效率高,限制少,能夠自由的表達思想,輕松完成在傳統語言中非常困難的工作。很多人都預言動態語言遲早會成為主流。然而在整個1990年代,無論是計算機硬件條件還是軟件工程的水平,都還不夠成熟,再加上Perl自身存在一些問題,動態語言始終只是作為主流語言的一種有力的補充而存在。2000年之后,PHP大流行,在Web開發領域三分天下有其一。但是PHP本身完全是為Web而做,當擴展到其他領域時,就凸顯出先天不足的劣勢,因此地主穩坐,霸業難成。直到現在,無論是硬件條件、軟件開發的方法,還是客觀應用環境都逐漸成熟,在這個時候,Ruby借Rails框架贏得廣泛關注,當然不是偶然的現象。在TIOBE全球程序設計語言排名表中,Ruby排名一年間跳升15位,而根據O’Reilly公司對于圖書市場的統計,Ruby相關書籍的銷量在2005年增長15倍的基礎之上,今年又增長了7倍,已經超過Python和Perl。再看看是誰在關注Ruby,拋開一手把Ruby炒熱的“Pragmatic Programmer二人組”Dave Thomas和Andy Hunt不說,一大批編程老槍都在嘗試或者已經轉向Ruby,這其中的著名人物包括Robert C. Martin、Martin Fowler、Bruce Tate等。如果這些還不夠令人印象深刻的話,我們應該注意一下近期有關Ruby的一些事件。最近Sun雇用了開源項目JRuby的兩名主要開發者,讓他們可以全職開發JRuby,從而正式將Ruby語言搬上JVM。同時,微軟也在上個月的一次有關.NET語言的技術會議上邀請RubyCLR的主要開發者John Lam發表演講,外界傳言他將加入IronPython開發者Jim Hugunin所在的團隊,從而加速Ruby for .NET的開發進程。另一個致力于Rich Internet Application的軟件巨頭Adobe于幾天前剛剛發布了用以將Flex 2.0整合到Ruby on Rails中的SDK。對于那些整天盯著巨頭們臉色行事的人來說,這些消息就算不是金口玉言,至少也是明確的跡象了吧。 然而,比上面一切都更為重要的是,今天的世界已經變了,已經不是15年前C++統治一切的那個世界,也不是10年前Java中彩票的那個世界,甚至也不是5年前Visual Basic狂練葵花寶典的那個年代。互聯網改變了太多的東西,經濟形態和公司業務的形式和途徑都已經并且仍在發生迅速的、根本性的變化。開放、互聯、敏捷、整合、平等、自由、高速、專業,所有這些給我們帶來了新的經濟運行模式,也對軟件的開發提出了新的要求。Ruby,以及Ruby所代表的一類動態的、自由的程序設計語言和開發思想已經迎來了它們的時代,它們將和其他的科技一起,在下一個輪回中改變我們的工作,改變我們的生活,改變我們的觀念,直到下下個輪回將它們掃進歷史的功勞簿中為止。 所以,該放下的時候,就勇敢地放下吧。當然,如果想再跟發展大勢打一打,那就打一打,反正在技術進步的路上,保守的一方終究是要被解決的。

    posted @ 2006-09-26 08:25 Sheldon Sun 閱讀(126) | 評論 (0)編輯 收藏

    軟件構架師之路

    http://tech.csai.cn/sa/200608111524241005.htm 構架師(Architecture)是目前很多軟件企業最急需的人才,也是一個軟件企業中薪水最高的技術人才。換句話說,構架師是企業的人力資本,與人力資源相比其能夠通過構架、創新使企業獲得新的產品、新的市場和新的技術體系。那么什么是構架師、構架師的作用、如何定位一個構架師和如何成為一個構架師呢?這是許多企業、許多程序員朋友希望知道的或希望參與討論的話題內容。      我在此拋磚引玉,就上述幾個問題把我的體會和理解做簡單闡述。   所謂構架師通俗的說就是設計師、畫圖員、結構設計者,這些定義范疇主要用在建筑學上很容易理解。小時候到河中玩耍,經常干的事就是造橋,步驟如下:1、在沙灘上畫圖;2、選擇形狀好看、大小適合的石頭;3、搭建拱橋。其中我們挑出來畫圖的那位光PP小孩就是傳說中的 “構架師”了。   在軟件工程中,構架師的作用在于三方面:1、行業應用構架,行業構架師往往是行業專家,了解行業應用需求,其構架行為主要是將需求進行合理分析布局到應用模型中去,偏向于應用功能布局;2、應用系統技術體系構架,技術構架師往往是技術高手中的高手,掌握各類技術體系結構、掌握應用設計模式,其構架行為考慮軟件系統的高效性、復用性、安全性、可維護性、靈活性、跨平臺性等;3、規范構架師是通過多年磨礪或常年苦思頓悟后把某一類構架抽象成一套構架規范,當然也有專門研究規范而培養的規范構架師。他們的產物往往也分為應用規范和技術規范兩類。   與建筑學類似,如果軟件系統沒有一個好的構架是不可能成為成功的軟件系統的。沒有圖紙的建筑工地、沒有設計的造橋工程都是不可以想象的混亂世界。建筑工程如是,軟件工程中亦然!   由于國內合格、勝任的軟件構架師極為少見,直接導致了我國民族軟件產業水平的落后。在未來以信息產業為主導的社會,信息產業水平的低下將直接影響國家核心競爭力。究其原因,無企業非急功近利、個人缺乏引導。   企業的急功近利是有無法克服的原因的,那就是社會發展總體水平。“生存是第一位的,賺錢是第一位的”,多年來許多客戶抱怨國內的軟件公司無法信任、系統項目累做累敗、公司越換越差,但因國外不可能給中國做應用系統項目還不得不找國內軟件公司做。由于人月費用低、公司開發成本高,軟件企業對于應用只能草草了事,拿錢走人(很多公司拿不到后期尾款)。這樣的環境下,企業幾乎無法投入更多資源培養自己的構架師,加上眼花繚亂的跳槽風氣企業更是不愿投入……   那么要成為構架師的途徑似乎只有現在較為流行的軟件學院和個人自我培養了。關于軟件學院我接觸過不少,其宗旨絕大部分都是造就(or打造)企業需要的軟件構架師(or程序員or人才)。教師來源與企業、學員來源與企業、人才輸送到企業是他們辦學的手段。盡管各個如雨后春筍般出現的軟件口號差不多,但除了中科院、清華、北大等大院校可以相信一些之外,恐怕更多的就是為了圈錢賣學位了事……我有個朋友二十幾個人的小公司也想搞軟件學院:)   構架師不是通過理論學習可以搞出來的,不過不學習相關知識那肯定是不行的。參考軟件企業構架師需求、結合北京網暢公司構架師培養計劃以及目前構架師所需知識,我總結構架師自我培養過程大致如下僅供參考:   1、構架師胚胎(程序員)學習的知識是語言基礎、設計基礎、通信基礎等,應該在大學完成,內容包括 :java、c、c++、uml、RUP、XML、socket通信(通信協議)——學習搭建應用系統所必須的原材料。   2、構架師萌芽(高級程序員)學習分布式系統、組建等內容,可以在大學或第一年工作時間接觸,包括 :分布式系統原理、ejb、corba、com/com+、webservice(研究生可以研究網絡計算機、高性能并發處理等內容)   3、構架師幼苗(設計師)應該在掌握上述基礎之上,結合實際項目經驗,透徹領會應用設計模式,內容包括:設計模式(c++版本、java版本)、ejb設計模式、J2EE構架、UDDI、軟件設計模式等。在此期間,最好能夠了解軟件工程在實際項目中的應用以及小組開發、團隊管理。   4、軟件構架師的正是成型在于機遇、個人努力和天賦   軟件構架師其實是一種職位,但一個程序員在充分掌握軟構架師所需的基本技能后,如何得到這樣的機會、如何利用所掌握的技能進行應用的合理構架、如何不斷的抽象和歸納自己的構架模式、如何深入行業成為能夠勝任分析、構架為一體的精英人才這可不是每個人都能夠遇上的餡餅……   然而學海無涯,精力有限,個人如何能夠很快將這些所謂的構架師知識掌握?這是秘密,每個人都有自己的獨門家傳秘笈就不敢一一暴露了。不過有一點就是廣泛學習的基礎之上一定要根據個人興趣、從事領域確定一條自己的主線來努力

    posted @ 2006-09-26 08:12 Sheldon Sun 閱讀(323) | 評論 (0)編輯 收藏

    https://jdiameter.dev.java.net/examples.htm

    fasdfasfae

    posted @ 2006-09-25 13:23 Sheldon Sun 閱讀(453) | 評論 (0)編輯 收藏

    domain-specific languages == DSL

    Null

    posted @ 2006-09-25 09:05 Sheldon Sun 閱讀(106) | 評論 (0)編輯 收藏

    Martinn Flower's blog

    http://www.martinfowler.com/bliki/

    posted @ 2006-09-25 09:01 Sheldon Sun 閱讀(107) | 評論 (0)編輯 收藏

    Ruby On Rails與Jdon Framework架構比較

    http://java.ccidnet.com/art/297/20060508/547541_1.html 本文試圖比較同屬快速開發性質的Ruby on Rails(以下簡稱RoR)和Jdon Framework(以下簡稱JF)在架構上異同,供大家在實際架構選擇中比較。   RoR 是一個使用Ruby語言寫就的Web應用框架,Ruby語言是類似Python, Smalltalk, PHP和Perl的動態類型語言。從新特點層面看,Ruby on Rails并沒有提供比其他已經存在的Web應用框架新的東西,它的唯一特點就是快速開發。RoR大概誕生于2004年6月份。   JF是使用Java語言編寫的、基于Ioc/AOP微容器的快速開發工具。JF是基于JdonSD構件庫增刪改查框架基礎上發展起來的,1.0版本是在2004 年12月底完成。當時推出時很難定位,時至今日,它應該是Ruby on Rails、Spring和JBoss容器三個概念的一個中間體。屬于域驅動開發框架(DDDD:omain Driven Development framework )。   JF雖是筆者操作完成,其實它是國人網絡結晶的開源產物,很多需求和思想都來自Jdon社區熱情參與者,看到很多初學者總是為簡單和靈活做痛苦選擇,為了寫一個簡單系統,要么走入Jsp+JavaBeans誤區,要么被復雜技術配置纏身,忘記業務本職工作。JF 推出后,道友提出各種建議甚至猛烈批判,這些都形成了JF發展動力,促進JF完善。從用戶出發的簡易之道使JF的起點和立意一下和RoR這樣國外產品走到了一起,下面我們詳細進行一下兩者架構比較。 語言之爭   RoR代表的是動態類型語言派別;而Java是一種靜態類型語言,當初Java剛剛誕生時,這種兩種類型派別之爭曾經發生在Java和Smalltalk之間,后來現實選擇了Java這樣靜態類型語言,關鍵原因時動態類型語言在編程時難以找出其一些潛在的語言Bug。   但是,隨著軟件工程中單元測試的重視,動態類型語言+單元測試的結合克服了以上缺憾,從而使得RoR這樣得動態類型語言重新東山再起。   促成RoR受到敏捷工程派別的領域專家(如Martin Fowler)推崇另外一個原因是,它被認為是一種domain-specific languages(DSL)實現,DSL是一種專門供領域建模專家(也就是系統分析師)使用的語言,這些領域專家不同于程序高手,他們有一套自己認知世界和表達世界的思維和方式(如UML),因此,他們不感興趣于軟件設計細節,希望軟件能夠按照他們分析設計的結果去運行和執行就可以了。   其實,DSL并不是一個全新理念,它已經在我們軟件領域中反復出現,例如:我們很多人是關系數據庫領域專家,所以,盡管由O/R Mapping這樣工具出現,但是并沒有改變這些領域專家表達方式,他們還是使用SQL等嚴謹的數學思維來實現他們的表達方式。   DSL概念非常好,但是是否有必要重新搞一套DSL語言則涉及很多方面的問題,新的語言總會在實踐中有新的陷阱,Java經過十多年發展,成熟和發展是其特點。   當然,別以為RoR頂著DSL新名詞就是一個非常好的東西,對其本質微詞已經不絕于耳,有人認為它實質不過就是1994的Visual FoxPro(Ruby on Rails is a Bloody Square Turd ),提出該觀點的作者認為:為什么我們在一個沒有重構以及調試支持的編碼環境中工作?為什么還要重覆以前的痛苦呢?如果你確實喜歡RoR的ActiveRecord,為什么不用. NET呢?RoR 不是開發Web應用平臺, RoR is a cult(RoR是宗教崇拜,筆者注:大概因為是因為所謂大師級的人推薦原因).   無論如何,讓我們拋開爭執,通過比較看看RoR一些特點。 多層架構   現在多層架構已經深入人心,多層主要是指表現層MVC、業務層和持久層多層分離的體系,由于Java是一個技術自由選擇的世界,因此,每個層面都有不同的具體框架技術供選擇, 提供選擇是一種好事,但是又可能是一種壞事,需要應用者花費精力學習和研究,這非常類似我們購物。   在微軟世界,由于各層框架技術幾乎都是由一家提供的,所以,.NET就索性將這些框架直接集成到IDE開發工具,對于有的程序員感覺.NET用起來很快,將開發工具和框架混合成一體,但這是以綁定為代價的,甚至有程序員反感Java世界IDE+框架的開發方式,認為在開發工具之外還會多一個框架,并且認為違背KISS(keep it simple and stupid)原則,其實不然,關鍵是追求KISS原則的同時,不要使自己受制于某個廠商或平臺,使自己變得簡單以及愚蠢 (失去自己作為客戶的上帝位置,被廠商忽視,成為簡單而愚蠢的人),此為KMSS(keep me simple and stupid)。   在Java世界,多層結構實現路徑很多,從MVC到持久層框架有各種選擇,例如我們可以使用Struts以及Hibernate組合成一個J2EE多層 應用系統。   Rails也提供了model/view/controller多層實現,但是各層的實現框架也確定下來,省卻了程序員在多個框架之間選擇帶來的“麻煩”(這是相對的)。   而Jdon Framework則類似RoR這種提供缺省各層實現設計,表現層在struts基礎上進行了CRUD流程抽象;通過提供JdbcTemp實現持久層技術,當然,持久層具體實現也可以選擇hibernate等其他框架實現,秉承提供缺省的,但是也是可替換的宗旨。   下圖是兩者各層架構比較圖:   我們通過上圖可以看出,兩者流程基本一致,所不同的主要是兩點:RoR的Action Pack和Active Record,下面我們就這兩點解釋如下: Action Pack   Action Pack是RoR的MVC組件框架:   View templates,相當于Struts中的Jsp;   URL routing,相當于struts-config.xml流程配置,RoR不是使用XML配置,而是作為腳本代碼,這也是一些人吹噓的RoR無繁多 XML配置真相所在,其實,XML也是一種腳本,從某種意義上來說:XML比語言腳本更簡單易寫(至少語法不多)。   ActionController,初看相當于struts的DispatchAction,但是因為其包含業務邏輯,而我們在java中是不推薦在在控制層action中寫業務邏輯的。   ActionController功能在于:RoR可以將瀏覽器的請求直接映射到ActionController類的方法上,這有些類似Struts 中的DispatchAction,但是,在Java中,業務邏輯是不推薦寫在表現層的控制類中的,控制類只是負責前后臺流程協調,是一種 Mediator模式實現,不應該讓其加入更多職責;在JF中,業務邏輯是寫在Service類中,JF通過自己的命令服務調用模式,也可以直接將瀏覽器的請求直接映射到Service類的方法上,例如,調用http://localhost//MyWeb/abc.do?method=xxx,將直接激活Service類的xxx方法,程序員直接編寫xxx方法內容即可。   RoR的Filters過濾器也是Action Pack的一個部分,主要用來實現一些通用功能的動態插入,這在JF中是通過AOP攔截器和Decorator模式來實現的,見AOP vs Decorator 一文,在JiveJdon3.0中,我們通過攔截器實現了組件方法權限訪問、以及緩存等通用功能。   Action Pack中還有Helpers功能相當于Struts的標簽庫,它可以把Model/ActionForm和Action以及html連接在一起,下面是RoR的Helpers如:   Name: <%= text_field "person", "name", "size" => 20 %>   ....   當然,RoR的Helpers有很多種類,如Form Helpers/javascriptHelpers等等,相當于一個個API 庫。它的Ajax & JavaScript helpers倒是很時髦的。   RoR的Layouts相當于Struts的Tiles,這就不多說了。   Scaffolding提供一個數據表的CRUD功能實現,Scaffolding類似代碼生成器,生成CRUD代碼,缺點是,如果你更改了代碼, Scaffolding會在覆蓋,必須再更改Scaffolding設置,實際用起來比較麻煩。而JF的CRUD是一個MVC流程上的精簡,屬于開發框架性質,而不是代碼生成,只需要通過jdonframework.xml配置:                                                       Active Record   RoR有一個Active Record組件,其實就是ORM實現,相當于Hibernate,它是Martin Fowler的 Active Record pattern實現,它是指一個既包含數據又包含行為的對象,這些數據需要持久保存到對應的數據表中。Active Record一個很明顯的特征是:將數據訪問邏輯也包含在這個domain對象中,通過這種辦法讓人們可以知道如何從數據庫讀寫數據。如下圖:   Active Record其實類似JF中Domain Object + Dao,也就是將Dao中對數據庫的CRUD方法和Domain Object整合在一起,我們知道,Dao模式本質是橋模式,通過Dao可以將不同的數據庫訪問實現分離,并且在運行時組合,但是,Martin Fowler將Dao從Domain Object分離出去的對象稱為貧血對象。   他的這個觀點筆者認為不是從技術觀點,而是從領域建模角度出發的,其實從技術觀點講,將Dao從Domain Object中分離在設計上非常靈活,例如使用JF開發的JiveJdon3.0中,我們就可以在Dao層中使用Decorator模式(過濾器)加入一層緩存,這樣,雖然我們Dao層使用的SQL實現,我們也是可以實現持久層緩存,JiveJdon3.0整個Dao層設計相當于一個Hibernate的微型(或者說輕量化),好處是:JiveJdon3.0這樣實現的緩存可以被各層如表現層直接訪問,減少路徑,提升運行性能。 RoR秘籍   通過以上分析,我們也許已經明白RoR和JF定位,大家為什么突然擁戴RoR,這是因為大家比較厭惡XML配置,太復雜的XML配置只能增加開發的復雜性,而JF則在這方面從以下幾個方面進行了努力: 1. 表現層的struts-config.xml配置是模板化的,CRUD流程固化模板化,拷貝粘貼就可以完成配置。 2. JF自身的配置很簡單,只包括兩個部分Models和Services,配置語法主要集中再Models部分,語法數量不超過10個,Models負責CRUD流程配置,如果你不需要使用CRUD可以不用配置;Services是業務類配置,對于一個POJO類,只要寫:如下:        class="com.jdon.jivejdon.service.imp.ForumServiceImp"/>        class="com.jdon.jivejdon.service.imp.ForumMessageShell"/> 至于,這些POJO之間的調用關系,無需指定,這由JF內置IOC微容器自動配對解決。 3. 持久層試圖通過JdbcTemp或SQL語句簡化配置,當然Hibernate等java工具也在進步,不斷重構,相信會越來越簡單。   總結:相比RoR,作為DDD(Domain Driven Development framework )實現的JF在快速開發和軟件高質量上作了一個平衡,相當于在RoR(快速,但非主流語言)和Spring(高質量,但配置煩瑣)之間做了一個平衡。   JF一直也試圖爭取獲得國外軟件專家的認可,可能會因為其他因素未能如愿,但是,作為和RoR幾乎同時誕生的國產JF,作為由國人網民共同參與的結晶,已經用事實證明,國人有能力靠創新沖刺世界軟件領域的前列。   無論如何,在RoR精神的召引下,Java世界將引來第四代語言4GL時代,同時能夠滿足求簡單或求靈活等不同編程心理的需求,迎來新的發展

    posted @ 2006-09-25 08:54 Sheldon Sun 閱讀(192) | 評論 (0)編輯 收藏

    再駁Java消亡論和回應java消亡論的支持者

    9月14日,我在CSDN上看到了透明的一篇謬文 http://blog.csdn.net/gigix/archive/2006/09/11/1210180.aspx,論調十分之荒謬。所以,我在公司里冒著被老板發現的危險,即興寫了一篇短文http://blog.csdn.net/shendl/archive/2006/09/14/1222587.aspx ,予以駁斥。 CSDN的編輯把它和透明的那篇文章放在了一起。跟貼者甚眾,令我沒想到的是,我的文章居然被不少跟貼者駁斥,而且語言極盡諷刺、挖苦之能事。 我并不反對就技術問題爭論,也不是不允許別人就我的文章和觀點與我辯論。相反,我一向都非常歡迎同行指正我的錯誤,能夠使我有所提高。 但是,多年與人打交道的經驗讓我深深地相信這樣一個真理:“你永遠無法說服不想被你說服的人。” 這次眾多駁斥我的跟貼再一次驗證了這樣一個真理。 我的文章由于成文比較倉促,所以確實在文筆上有一些漏洞,遣詞造句也不是很妥當。但我認為,一個嚴肅的辯論者,是不會咬文嚼字的尋找對方文法上的弱點的。否則的話,除了數學公理之外,沒什么話可以說了! 對于這樣的人,在我眼里,并不是在污辱我的智商(盡管他是這樣以為的),而是在侮辱他自己的智商。這說明他完全不具備與人交流的能力。 如果一定要咬文嚼字,那么所有判斷句都不可以在文章里用了。Java會消亡嗎?廢話,一定會。宇宙都會消亡,什么能不消亡? 論點: 透明的意思是,3-5年內,Ruby將占據企業級應用市場的主流。也就是JavaEE和今天的Ruby換個位子。我認為,這是不可能的。Java平臺至少能夠繼續占據、企業級應用市場主流地位10年。 Java平臺優勢和對動態OO的支持 有人說我不懂Ruby,也不懂Java。這我就不敢茍同了。我是不懂Ruby,但并不代表我不懂Ruby,Python,Smalltalk語言為代表的動態面向對象語言的機制。對于Java,我也許不比某些人懂得多,但也絕不會比一般的Java程序員懂得少。 我對Ruby的認識,僅僅是今年5月Martin Fowler先生在上海交大作的一次演講中Martin Fowler的Ruby編程演示。我還略為研究過Smalltalk和Python的語法。但是它們的類庫,我沒有研究過。 因為,我還不打算靠它們吃飯,那厚厚的專用類庫對我而言是沒有價值的。 Spring的AOP實現需要使用“反射”這種動態技術。這也是促成我當年研究Smalltalk和Python這樣的動態面向對象語言的原因。我也十分折服于動態面向對象編程技術的強大能力。我一直認為動態OO技術在未來,將在編程中發揮越來越大的作用,也一直希望JVM能夠增加更多的動態技術。我還曾經寫過文章為動態OO技術搖旗吶喊過,此初衷依然不改! Java作為一個平臺也確實有這樣的能力,而且也正在向這個方面發展,JVM將會支持更多的動態OO技術。 .NET平臺當年推出之時,就以支持多種靜態面向對象編程語言為賣點。VB.NET,C#,Delphi,托管C++這4種主流的面向對象編程語言都可以在.NET平臺上運行。 同樣都是靜態面向對象編程語言,它們之間除了關鍵字不同之外,有什么本質上的區別嗎?沒有!VB.NET和C#是我所熟悉的兩種.NET語言。它們之間本質上確實沒什么區別。唯一的區別是,.NET平臺的技術更新時,C#會先得到支持,VB.NET要晚一些。比如,事件機制,.NET1.1時,VB.NET用的是類似于Java1.0時的機制,C#用的是Java更新版本的機制。我想,應該是因為微軟最重視C#的緣故吧。 .NET平臺同時支持多種類似的語言,雖然在市場上有吸引VB,C++,Delphi,Java等程序員的作用,但在技術上卻導致了開發資源的浪費。一種技術,要提供多個語言的實現。這比Java平臺只支持Java這一種靜態面向對象編程語言要低效的多。我在發現了微軟優先關照C#之后,就決定從VB.NET上轉到C#上,以免吃虧!自從Delphi投入.NET平臺之后,日漸式微,這也是一個平臺上不需要多種類似語言的明證!可以預見,.NET平臺上C#獨大的趨勢還會繼續下去。 .NET支持多種類似語言的另一個問題是,分裂了開發者社區。VB.NET,C#,Delphi,還有J#,托管C++,它們的語言原理和能力實際上都差不多,都是靜態面向對象語言,但是,由于語法不同,就分裂成了幾個開發者社區,彼此交流都不方便。 在我上一篇文章的評論者中,有人說我說錯了,Java平臺上除了Java之外還有Beanshell等語言。拜托!兄弟,你的理解力沒什么問題吧?我說的是Java平臺上只有一種官方支持的靜態面向對象編程語言。就是和.NET比較而言的。 Java平臺官方支持C++,C#,VB.NET,Delphi,J#嗎? Beanshell是一種動態面向對象語言,而且Sun官方可沒有支持它! 現在,Java平臺正在增強對動態編程能力的支持。目前,開源社區提供了Beanshell,JRuby,JPython,Groovy等面向對象編程語言。我相信,最后,在Java平臺上也會只剩下一種主流的動態面向對象編程語言。未來,Java平臺上會剩下兩種主流的編程語言:靜態面向對象編程語言類型是Java;動態面向對象編程語言是上面中的一種,也許是Groovy,也許是JRuby。 將來,我們Java程序員將有2件編程利器:Java和動態OO語言。對于編程問題,將能夠更加游刃有余!底層的API類庫,既可以是Java,也可以是其它動態OO語言所編寫。反正都一樣是.class文件,Java和動態OO語言都可以調用。 這就是未來!Ruby和Python這兩種平臺將會繼續慘淡的過日子,也許不會消亡,但成不了主流。不是因為它們的語法不好,機制不行,而是因為它們缺少Java平臺上那樣多的API,也缺少熟悉這些API的程序員。 它們的靈魂將會飛到Java平臺上,以JRuby,JPython的形式生存下來,在Java平臺上發展起來。 靜態OO語言和動態OO語言的優劣 接下來,再談一談靜態OO語言和動態OO語言的優劣的問題。 我欣賞動態OO語言,smalltalk雖然出現的很早,開發者甚少,但是在它的社區中卻誕生許多著名的程序員和設計模式等思想。MVC模式,XP極限編程等我所尊敬的技術都出自smalltalk。 但是,靜態OO語言一直占據著主流的地位,也不是沒有原因的。除了編譯型語言的執行速度比解釋型語言快之外,靜態OO語言還有其它的優勢。速度的快慢,在今天來看,并不是十分重要。Java比C++慢一些,但現在測試下來,C++最多比Java快一倍而已(不要跟我說某一個程序速度差很多,我這里指的是一般的程序,不作特別的優化和劣化處理)。只要速度不是相差一個數量級,就不是問題。 靜態OO語言意味著更嚴格的語法,更多的編輯和編譯時的檢查步驟。更強的糾錯能力,不正是編程語言發展的一個標準嗎?不是可以更好的提高效率嗎? 5月份那次看Martin Fowler先生演示編寫Ruby程序,IDE弱弱的報錯能力讓Martin先生也傷了不少腦筋! 不錯,Ruby不需要給變量聲明類型。想指向哪個類型,就指向哪個類型。但是,指錯了呢?只有在運行時才能發現類型指錯了。如果這是個復雜的程序,有很多執行路徑呢?如果測試人員沒能夠窮盡所有這些可能的路徑呢?這個錯誤豈不是會漏給用戶? 不錯,借助于測試驅動開發,是可以降低出錯幾率。但是,測試驅動開發也不是測試的銀彈,不能保證能夠找出所有的錯誤。而且,靜態編程語言也可以使用測試驅動開發技術。 市場預測 我預測,未來3-5年,Java平臺和.NET平臺都會增加對動態OO語言的支持力度,它們上面的動態OO語言將會達到實用化的程度。而Python和Ruby將會繼續維持現在這樣的市場規模。仍然處于邊緣。Python和Ruby的解釋器平臺不會得到多大范圍的應用。就像今天,Web2.0的那些小網站帶來了Web2.0的概念,但最后是門戶網站Yahoo,Sina等占據了Web2.0的市場。 DSL特定領域語言 接下來,說說DSL特定領域語言的問題。Matin Fowler最近轉調了。我記得原來他非常支持XML格式的作用。但是,最近他說Ruby是最合適的DSL語言。盡管我仍然十分敬佩Martin Fowler先生,但是對他的這個觀點,我不敢茍同。我認為,DSL語言還是應該使用xml格式,而不是使用Ruby這種類英語的編程語言來描述。 DSL可以說是一種“元數據”。用來描述程序。現在有2種元數據:標注和配置文件。 1.標注是.net首先引入的。Java在5.0之后也引入了。標注寫在源代碼中,和關鍵字一樣,只是標注是可以自定義的。 標注的優點是,簡單。缺點是表達能力不強。 2.配置文件,一般又分為3種:屬性文件,一般文本文件和xml文件。 屬性文件中的數據是以“名—值”對的形式表示的。缺乏數據之間的關系結構。表達能力不強。 文本文件,就是直接在文本中按照規定的語法寫上一段文本。類似自然語言,只是語法的限制很強。語法檢查,是一個大問題。如果沒有按照語法寫,就會發生運行時錯誤。 Xml文件,是層次結構的。它的前身是層次數據庫。它的格式嚴謹,語法容易驗證,規則容易定義。只是稍微復雜一點,需要寫上元素名。 但是,總的來說,XML文件格式的DSL還是功能最強大,語法驗證能力最強,目前也是首先的DSL語言的載體。 除了使用元數據之外,直接使用編程語言也是可以實現高等級的功能的。如,傳統的不使用xml配置文件的Java編程。Java作為一種編譯語言,需要編譯,不使用xml等配置,就不是很方便。 而Ruby作為解釋型語言,直接修改源代碼是非常方便的。我想這大概就是Martin Fowler先生關于使用Ruby作為DSL的原因吧。 但是,使用DSL語言的用戶,他懂Ruby嗎?懂編程嗎?愿意查看和修改源代碼嗎?我們中國的用戶懂英語嗎? 我認為,DSL使用XML文件還是首選! OO就是銀彈! 最后,談談關于OO的問題。有網友說我“言必OO?OO就是銀彈嗎?”。這里我回答他:OO就是銀彈! 我Blog上的副標題是:“以OO為中心,堅定不移的走Spring道路”。 面向對象編程,給我們帶來了多少API類庫。Int,String等基本的數據類型,以及順序、條件、循環3種控制流這樣簡單、細粒度的元素,通過類被封裝了起來,今天已經能夠通過層層疊疊的類支持對現實世界的種種對象的模擬和抽象。 借助于類庫,眾多的DSL特定領域語言已經被廣泛使用。今天的java程序員使用了更多的配置文件(這就是DSL)來編程。如Ant配置文件,Hibernate配置文件,Spring配置文件等等。 最近,我正在學習jBPM。jBPM也是一個Java類庫。通過Java類,它提供了一個DSL語言框架。我們能夠使用xml配置文件,編寫DSL語言:jpdl,bpel規范的。實現工作流、BPM等。 當然,除了OOP之外,還有AOP。但是,AOP只是OOP的補充。OOP能夠實現絕大部分的抽象模擬任務。 認為OO無用的程序員,可能工作在嵌入式開發等與硬件有關的工作領域。他們的編程領域中,業務邏輯比較簡單,不需要過多的抽象層次。 但是,這并不能成為否定OO作用的理由。你用不著OO,并不代表OO沒用,并不代表OO不是銀彈。 OO已經給我們帶來了多大的變化啊!Java的成功就是一例。 還是毛主席的那句話:“沒有調查,就沒有發言權”。對此我也是深有體會的,曾經也犯過很多錯。對于自己不懂的領域,硬是認為別人的說法荒謬。后來,自己真正了解了那個領域之后,才知道“今是而昨非”啊!

    posted @ 2006-09-25 08:53 Sheldon Sun 閱讀(556) | 評論 (2)編輯 收藏

    Nokia

    10.?諾基亞(Nokia)鎮的名字來自流經當地的一條河流。這條河名為“Nokianvirta”,在芬蘭古語種是黑貂的意思,這種動物現在已經絕跡。
      9.?諾基亞有時候被非諾基亞用戶和移動軟件開發人員稱做“aikon”(就是把“Nokia”反過來寫),因為“aikon”被用在許多SDK軟件包中,包括諾基亞自己的Symbian?S60?SDK。
      8.?和其他手機不同,諾基亞的通話計時器不會在通話連接的時候自動開啟,而是在通話開始的時候開啟(除了S60系列手機,比如諾基亞6600)。
      7.?諾基亞名列《財富》2006年最受推崇企業第20名(網絡通訊行業中的第1,非美國公司中的第4)。
      6.?在亞洲,數字4從來沒有出現在諾基亞手機的任何型號中,因為4在南亞和東亞的許多地區被認為是不吉利的。
      5.?諾基亞公司字體是AgfaMonotype?Nokia?Sans字體,最初由Eric?Spiekermann設計。此前在廣告和手機用戶手冊中,諾基亞最常用的是Agfa?Rotis?Sans字體。
      4.?諾基亞手機收到短信時的“特殊”鈴聲是摩斯密碼的“SMS”(短信服務),“漸強”短信鈴聲是摩斯密碼的“Connecting?People”(當時是翻譯成“科技以人為本”來著嗎?),“標準”短信鈴聲是摩斯密碼的“M”(代表“Message”,“信息”)。
      3.?諾基亞現在是世界上最大的數碼相機制造商,因為它的拍照手機銷售量超過了任何一個相機廠商。
      2.?實際上第一個商用GSM通話是1991年在赫爾辛基通過諾基亞支持的網絡打出的,打電話的人是芬蘭副總理Harri?Holkeri,用的是一個諾基亞手機。
      1.?諾基亞標志性的鈴聲"Nokia?tune"實際上是改編自19世紀的吉他作品《Gran?Vals》,作者是西班牙音樂家Francisco?Tárrega。這個鈴聲在諾基亞手機中最早名為“Grande?Valse”。在1998年,這支鈴聲已經廣為人知并被稱做“Nokia?Tune”,諾基亞將其改名并沿用至今

    posted @ 2006-09-23 19:34 Sheldon Sun 閱讀(133) | 評論 (0)編輯 收藏

    ??

    這兩天右眼總跳, 有點不祥的預感。。。

    posted @ 2006-09-08 11:12 Sheldon Sun 閱讀(92) | 評論 (0)編輯 收藏

    Jboss 設置根訪問方法

    在WAR包中添加JBOSS-WEB.XML, 設置他的/ 否則訪問將直接訪問到ROOT.war 研究了一個多小時, 不管效率高不高, 反正搞定了!!!

    posted @ 2006-09-05 16:30 Sheldon Sun 閱讀(163) | 評論 (0)編輯 收藏

    日志

    無聊的一天, 躺在床上聽一天收音機!

    西班牙贏了希臘奪冠, 無所謂, 只要美國不贏就好, 不是討厭美國隊, 讓他們認識一下自己的位置也好, 要不每次都象很“鳥”的樣子,把隊長的位置看的比比賽還重要, 整天吵啊吵, 這下老實了吧!!!!!

    posted @ 2006-09-03 20:31 Sheldon Sun 閱讀(108) | 評論 (0)編輯 收藏

    <2006年9月>
    272829303112
    3456789
    10111213141516
    17181920212223
    24252627282930
    1234567

    導航

    統計

    常用鏈接

    留言簿(3)

    隨筆檔案

    文章檔案

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 国产精品亚洲精品爽爽| 亚洲Av无码精品色午夜| 日本人的色道www免费一区| 日韩在线免费视频| 国产又大又粗又长免费视频 | 亚洲色婷婷一区二区三区| 亚洲精品天堂成人片?V在线播放| 国产一级高清免费观看| 又粗又硬免费毛片| gogo全球高清大胆亚洲| 亚洲一区精品伊人久久伊人| 亚洲人成人网站在线观看| 亚洲乱码无码永久不卡在线| 国产亚洲一区二区三区在线| 亚洲AV乱码久久精品蜜桃| 亚洲美免无码中文字幕在线| 亚洲人成7777影视在线观看| 亚洲看片无码在线视频| 亚洲av综合av一区二区三区| 国产成人精品亚洲一区| 一级做a毛片免费视频| 免费视频成人手机在线观看网址| 精品成人免费自拍视频| 蜜臀AV免费一区二区三区| 成人影片麻豆国产影片免费观看| 成人一a毛片免费视频| 无码国产亚洲日韩国精品视频一区二区三区| 日韩亚洲国产二区| 激情97综合亚洲色婷婷五| 亚洲成AV人片天堂网无码| 亚洲狠狠ady亚洲精品大秀| 33333在线亚洲| 国产亚洲精品美女久久久久| 一级做a爰全过程免费视频毛片| 久久香蕉国产线看免费| 7723日本高清完整版免费| 国产成人免费手机在线观看视频| 国产日韩成人亚洲丁香婷婷| 亚洲激情视频在线观看| 亚洲xxxx视频| 久久不见久久见免费影院www日本|