2006年9月25日

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

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)编辑 收藏

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

Chain of responsibility

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

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

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

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

posted @ 2007-11-21 16:49 Sheldon Sun 阅读(332) | 评论 (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 阅读(573) | 评论 (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 阅读(295) | 评论 (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 阅读(553) | 评论 (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 阅读(251) | 评论 (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 阅读(434) | 评论 (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 阅读(332) | 评论 (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 阅读(274) | 评论 (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 阅读(109) | 评论 (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 阅读(110) | 评论 (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 阅读(237) | 评论 (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 阅读(227) | 评论 (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 阅读(121) | 评论 (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 阅读(165) | 评论 (0)编辑 收藏

session

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

posted @ 2007-05-15 13:34 Sheldon Sun 阅读(78) | 评论 (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 阅读(110) | 评论 (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 阅读(245) | 评论 (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 阅读(184) | 评论 (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 阅读(153) | 评论 (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 阅读(408) | 评论 (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 阅读(162) | 评论 (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 阅读(196) | 评论 (0)编辑 收藏

迭代化开发新问题

http://blog.csdn.net/fuchunyi/archive/2006/10/22/1345708.aspx 这周去拜访一个客户,他们正在实施RUP,问及效果如何,听到了一些关于迭代化开发的新问题。 这位客户是一家集成商,主要为甲方开发应用软件系统。实施迭代化开发的主要目的是控制项目风险,应用项目的最大风险一般都在于需求,采用迭代化可以通过迭代产生的原型系统来收集甲方客户的反馈,从而及早修正对于客户需求的误解。但是开发团队并没有象预想中那样收集到甲方的反馈,甲方还是习惯于用传统的瀑布模型来评价、验收系统,他们并没有对项目过程中交付的原型系统进行认真的确认,所以也没有太多的意见反馈给开发团队,很多需求的变更还是要到系统正式验收时才被提出来。因为在甲方的观念中,他们还不太认可项目结束之前所提交的中间结果。 另外,项目的合同是按照瀑布模型的阶段来签的,需求分析、概要设计、详细设计、编码完成、验收测试是项目回款的里程碑。采用迭代化开发之后,在原定的概要设计交付时间点上,可能需求分析和概要设计都只完成了部分的工作,比原定计划要晚一些;而详细设计和编码工作都已经开始了一部分,比原定计划要提前一些。这样就不能按照原定时间点来要求甲方就需求分析和概要设计那部分工作量付款,对于中国的集成商而言,项目回款是比合同签定都要重要的工作。 这些问题给我们的经验教训是应用项目开发采用迭代化开发流程,也需要让客户理解这一点,项目工作说明书中的工作单元内容也需要跟迭代化开发流程来符合。软件开发流程关系到所有的涉众(Stakeholder),仅仅是开发团队理解并实施这一流程是不够的。 还有一个反馈来自于很多项目团队,认为迭代化开发概念上听起来很有道理,但在项目中实施后往往感觉不到采用这处方法后对项目有什么太大的帮助。迭代化开发的主要目的在于控制项目风险,常见的项目风险如技术架构、客户需求等等。但是日常工作中的项目往往没有太多的风险,我们开发的往往是重复性的项目,电信事业部做的就是不同运营商的BOSS项目,社保事业部就是为不同省份开发社保系统,虽然有特殊需求,但系统架构和基本需求完全一样;更多的项目是对现有系统的维护性开发,实现客户提出的变更请求和改正软件缺陷,一般不会涉及到系统架构的改动。在这种类型的项目中,迭代化开发体现的不是对风险的控制,而是系统增量式开发而不断给涉众所带来的信心和鼓舞,开发人员可以在较断的时间周期内看到自己所开发的系统可以“跑”起来了,客户则可以看到整个项目在不断地往前推进。

posted @ 2006-10-23 08:58 Sheldon Sun 阅读(171) | 评论 (0)编辑 收藏

现在的公务员...

妈的, 想起来就有气, 现在的公务员一个比一个牛, 本来应该为人民服务, 态度却一个比一个差....

最近想办居住证续办, 想打个电话咨询一下, 试了N多个, 有的 还好借了告诉你个号码, 让你去打, 但一直战线, 更有的那起来就挂掉, 拿起来就挂,,,,,,

TNND!!!!

posted @ 2006-10-19 22:49 Sheldon Sun 阅读(216) | 评论 (1)编辑 收藏

一个技术牛人的悲惨遭遇

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

posted @ 2006-10-16 08:56 Sheldon Sun 阅读(147) | 评论 (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 阅读(115) | 评论 (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 阅读(135) | 评论 (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 阅读(125) | 评论 (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 阅读(235) | 评论 (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 阅读(121) | 评论 (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 阅读(321) | 评论 (0)编辑 收藏

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

fasdfasfae

posted @ 2006-09-25 13:23 Sheldon Sun 阅读(450) | 评论 (0)编辑 收藏

domain-specific languages == DSL

Null

posted @ 2006-09-25 09:05 Sheldon Sun 阅读(104) | 评论 (0)编辑 收藏

Martinn Flower's blog

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

posted @ 2006-09-25 09:01 Sheldon Sun 阅读(105) | 评论 (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 阅读(190) | 评论 (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 阅读(526) | 评论 (2)编辑 收藏

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

导航

统计

常用链接

留言簿(3)

随笔档案

文章档案

搜索

最新评论

阅读排行榜

评论排行榜