2011年3月29日

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 阅读(232) | 评论 (0)编辑 收藏

2011年3月23日

转:用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 阅读(265) | 评论 (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 阅读(232) | 评论 (0)编辑 收藏

2011年3月22日

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 阅读(1123) | 评论 (1)编辑 收藏

2008年6月11日

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 阅读(498) | 评论 (0)编辑 收藏

2007年11月22日

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 阅读(294) | 评论 (0)编辑 收藏

2007年11月21日

Chain of responsibility

刚才看了看职责链模式, 没什么概念, 脑袋还是比较混乱! 把思路写出来!

职责链主要是为了一个请求, 可能有很多个处理者, 这些处理者数目并不固定而设计的!

对每种处理, 都会有一个处理类来对应! 没个具体的处理类都会有一个后继: succor, 这个后继比处理类更广泛! 如果当前的处理类可以处理改请求, 则处理,否则使用后继的处理方法!

感觉最关键的一点就是对后继者的定义, 那为什么不用继承机制呢???

posted @ 2007-11-21 16:49 Sheldon Sun 阅读(331) | 评论 (1)编辑 收藏

2007年8月8日

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 阅读(572) | 评论 (0)编辑 收藏

2007年6月19日

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 阅读(294) | 评论 (0)编辑 收藏

2007年6月14日

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 阅读(552) | 评论 (0)编辑 收藏

仅列出标题  下一页
<2024年11月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

导航

统计

常用链接

留言簿(3)

随笔档案

文章档案

搜索

最新评论

阅读排行榜

评论排行榜