JBoss ESB 4.x 介绍

Revision History
Revision 1.02008/09/27

Abstract

这篇文章主要是介绍了JBoss ESB的基础架构,以及通过一个简单的例子来认识JBoss ESB.

JBossESB是JBoss推出的ESB的实现,也是JBoss的SOA产品的基础.首先大家对于ESB的定义有很多的不同,我个人更喜欢把ESB看作是系统集成的一个平台. JBossESB是一个基于消息的中间件(Message Oriented). 在这篇文章中,我们只是看待ESB中的一个很基础部份,也就是怎么从Endpoint A发送信息给ESB的服务S1,然后再有S1发送信息到Endpoint B去调用服务. 至于其他的Router(路由)或者Data Transformation(数据转换),这里赞不介绍.

我们就假设一个简单的系统集成场景来开始阐述JBossESB的设计和概念.

 A系统(Endpoint A) –  Message ->  ESB -> –  Message --> B系统 (Endpoint B)

所以,如果简单的对于JBossESB定义的话,我们可以定义以下三个概念:

JBossESB 是一个面向服务(Service Oriented)的架构,所以在ESB内部的要么是一个Service, 要么是一个Message. 这里的Service就是指具有实现业务逻辑的服务,也可以是一个实现路由(Router),或者数据转化(Transformation)的服务. 就拿上面的这个例子,系统A发送一个Message给 ESB的一个服务,我们假设叫做S1, 那么S1收到Message后,做一些处理,转到S2的服务,S2再把处理后的结果发送给系统B. 这样就实现了A和B之间通过ESB的通信.

System A -> message -> S1 -> S2 ->....  -> message -> System B

那么在ESB内部是怎么去表达一个服务呢?这里引入了EndpointReference的概念,简称EPR. 有了服务之后,服务之间是通过什么样的传输层(比如JMS, FTP, HTTP)来通信呢? 所以ESB的内部也引入了Courier的API, 来统一抽象传输层. 刚我们也看到了,ESB的内部无非就是一系列的服务, 但是我们怎么来保存/注册这些服务的呢? JBossESB是使用jUDDI来注册和保存这些服务元数据的.

在要了解和运行JBossESB之前,我们最好了解下JBossESB中比较重要的几个概念

为了更好的来解释JBossESB, 最好的一个方法就是试下JBossESB自带的例子,这里我们先以helloworld_action的例子来讲解.

到这里,你已经成功的运行了helloworld_action的例子.

  1. JBossESB网站下载 jbossesb-server-4.4.GA.zip
  2. 解压jbossesb-server-4.4.GA.zip, 假设到/var/local/jbossesb-sever4.4. 下面以$jbossesb来替代.
  3. 在$jbossesb中,运行 bin/run.sh 来启动ESB server
  4. 另外打开一个窗口,到$jbossesb/samples/quickstarts/helloworld_actions, 运行: ant deploy
  5. 再运行: ant runtest
  6. 回到JBoss ESB server的控制台上,应该可以看到以下的输出:
    INFO  [STDOUT] [Hello World Action].
    INFO  [STDOUT] 
    &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
    INFO  [STDOUT] Body: Hello World Action
    INFO  [STDOUT] &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
    INFO  [STDOUT] ConsoleNotifier 2008/09/26 06:35:39.643<
    BEFORE**
    Hello World Action
    AFTER**
    >
    

下面我们来具体看下helloworld_action这个例子. 在JBoss ESB 4.4的例子中,我们默认以JBoss Messaging来作为JMS的实现.

在看jboss-esb.xml的配置时候,我们应该分成两个部份. providersservices.

首先是<providers>,它是有一系列的<provider>组成, 目前有jms-provider, fs-provider, ftp-provider等等. 然后我们在provider里面定义这个.esb文件里面service所定义的listener所需要的bus, Bus可以简单理解成消息传送所需要的传输层. 正如以下所显示的,我们定义了两个Bus,一个是给Gateway的Listener用,另外一个是给ESB-aware Message传输所需要的传输层.



    <providers>
          <jms-provider name="JBossMQ" connection-factory="ConnectionFactory">
                      
              <jms-bus busid="quickstartGwChannel">
                  <jms-message-filter
                      dest-type="QUEUE"
                      dest-name="queue/quickstart_helloworld_action_Request"
                  />
              </jms-bus>
              <jms-bus busid="quickstartEsbChannel">
                  <jms-message-filter
                      dest-type="QUEUE"
                      dest-name="queue/B"
                  />
              </jms-bus>

          </jms-provider>
      </providers>
               

第二部份就是定义services的部份, 在这里定义了当前这个esb包所提供的services. 每个service又是由 <listener><actions>组成的.



<services>
          
        <service category="HelloWorld_ActionESB" 
                 name="SimpleListener" 
                 description="Hello World" >
            <listeners>
                <jms-listener name="JMS-Gateway"
                    busidref="quickstartGwChannel"                         
                    is-gateway="true"
                />
                <jms-listener name="JMS-ESBListener"
                              busidref="quickstartEsbChannel"
                />                
            </listeners>
            <actions mep="OneWay">
            <action name="action2"
                    class="org.jboss.soa.esb.actions.SystemPrintln"
                    />
               <action name="displayAction" 
                    class="org.jboss.soa.esb.samples.quickstart.helloworldaction.MyJMSListenerAction" 
                    process="displayMessage">
                    <property name="exceptionMethod" value="exceptionHandler"/>
               </action>
               <action name="playAction" 
                    class="org.jboss.soa.esb.samples.quickstart.helloworldaction.MyJMSListenerAction" 
                    process="playWithMessage">        
                    <property name="exceptionMethod" value="exceptionHandler"/>
               </action>  
            </actions>
        </service>
      </services>
          

这里的action是对消息(Message)处理的地方.

目前在JBossESB中,一般有两种方式来调用service. 一种是通过Gateway listener, 另外一种是直接通过ServiceInvoker的API来调用.

回到我们的例子,我们通过JMS Gateway来访问ESB的服务.



public class SendJMSMessage {
              
  public void setupConnection() throws JMSException, NamingException
    {
        InitialContext iniCtx = new InitialContext();
        Object tmp = iniCtx.lookup("ConnectionFactory");
        QueueConnectionFactory qcf = (QueueConnectionFactory) tmp;
        conn = qcf.createQueueConnection();
        que = (Queue) iniCtx.lookup("queue/quickstart_helloworld_action_Request");
        session = conn.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE);
        conn.start();
        System.out.println("Connection Started");
    }
              
              
    public void sendAMessage(String msg) throws JMSException {  
        QueueSender send = session.createSender(que);        
        ObjectMessage tm = session.createObjectMessage(msg);
         tm.setStringProperty(StoreMessageToFile.PROPERTY_JBESB_FILENAME, "HelloWorldActionTest.log");
        send.send(tm);        
        send.close();
    }
       
    
    public static void main(String args[]) throws Exception
    {                   
        SendJMSMessage sm = new SendJMSMessage();
        sm.setupConnection();
        sm.sendAMessage(args[0]); 
        sm.stop();
    }
}
          

应该说,这是一个很普通发送JMS消息送到一个指定的Queue. 注意,我这里并没有全部拷贝这个SendJMSMessage类. 只是拷贝出重要的部分.(如果想要看完整的,请参考helloworld_action例子下面的代码)

在helloworld_action例子中,没有直接SendESBMessage的客户端来调用,但是我们可以看下helloworld的sample下面的,因为是一样的.



public class SendEsbMessage 
{
    public static void main(String args[]) throws Exception
    {
//      Setting the ConnectionFactory such that it will use scout
        System.setProperty("javax.xml.registry.ConnectionFactoryClass","org.apache.ws.scout.registry.ConnectionFactoryImpl");
        
        if (args.length < 3)
        {
            System.out.println("Usage SendEsbMessage <category> <name> <text to send>");
        }
        
        Message esbMessage = MessageFactory.getInstance().getMessage();
        esbMessage.getBody().add(args[2]);  
        new ServiceInvoker(args[0], args[1]).deliverAsync(esbMessage);
        
    }   
}

正如我们之前所说的,客户端用ServiceInvokerAPI大大简化了调用服务的过程. 我们在jboss-esb.xml中看到每个service都会有service-category和service-name的属性. 在ServiceInvoker中,用户只需要提供这两个属性,就能调用到ESB的服务,当然了,还需要juddi.properties文件. 这也是为什么我们的 sample下面一般会有这个文件.

通过前两个部分的介绍,应该说JBoss ESB简单的内部框架应该比较清楚了. 但是我们还没有涉及到其他部署和集成的一些模块. 正因为通过比如对Smooks, JBoss Rules, jBPM等的集成,使得JBoss ESB的功能更加强大,好用.