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

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

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

    2007年11月22日

    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 閱讀(301) | 評論 (0)編輯 收藏

    <2007年11月>
    28293031123
    45678910
    11121314151617
    18192021222324
    2526272829301
    2345678

    導航

    統計

    常用鏈接

    留言簿(3)

    隨筆檔案

    文章檔案

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 37pao成人国产永久免费视频 | 午夜老司机永久免费看片| 国产成A人亚洲精V品无码| 91精品免费国产高清在线| 视频一区在线免费观看| 亚洲一区二区三区高清| 国产精品成人无码免费| 免费国产成人α片| 亚洲av无码一区二区三区四区| 久久亚洲欧洲国产综合| 免免费国产AAAAA片| 日韩一区二区三区免费播放| 亚洲精品视频在线观看免费| 免费在线观看a级毛片| 91精品免费国产高清在线| 九九99热免费最新版| 在线综合亚洲欧洲综合网站| 在线A亚洲老鸭窝天堂| 免费看片A级毛片免费看| 人人玩人人添人人澡免费| 337p日本欧洲亚洲大胆人人| 亚洲欧洲综合在线| 国产亚洲一区区二区在线| 浮力影院第一页小视频国产在线观看免费 | 亚洲高清美女一区二区三区| 国产成人精品免费直播| 91香蕉国产线在线观看免费| fc2免费人成在线视频| 亚洲av无码成人影院一区| 亚洲国产韩国一区二区| 亚洲精品乱码久久久久久| 亚洲精品无码成人片在线观看 | 久久久国产精品亚洲一区| 亚洲中文字幕无码爆乳av中文| 色妞WWW精品免费视频| 一级毛片免费不卡在线| 中文字幕无码免费久久9一区9| 亚洲av成人无码网站…| 精品丝袜国产自在线拍亚洲| 亚洲伊人tv综合网色| 国产av天堂亚洲国产av天堂|