Weblogic 服务器提供了非常强大的JMS消息中间件平台,其性能优越,远超同类JMS产品比IBM 的MQ也快很多。并且,Weblogic JMS提供了非常强大的消息传递功能使得基于该平台的Java 消息解决方案非常的完整。本文,旨在阐述WebLogic JMS 服务器的一些比较重要的特性,以及如何配合在一起使用。

  1. 本文所要介绍的WebLogic JMS特性有:

DQ (Distributed Queue):分布式Queue。通过配置DQ可以提供消息队列的集群式部署,提高一个队列的Capacity以及提供HA支持。对于客户端透明。

SAF 存储转发:可以在两个WebLogic服务器(相同版本)之间,从一段发送JMS消息到另一端,并保证发送能到达终端的Destination。如果,两台服务器之间的网络连接暂不可用,则会将消息保存至发送方的本地存储中。用户可以设定多种转发策略和Qos设定。

UOW(Unit-Of-Work):WLS可以将多条消息标签为一个工作单元(UOW),只有当该UOW中所有的消息都被发送到队列中后,Consumer端才能获取该工作单元的所有消息。并且,所有属于该UOW的消息,保证只有一个Consumer能进行处理。

  1. 客户用例

在某家工厂构建的一个门店和总部数据中心系统之间的一个异步信息同步的解决方案中,采用了UOW+SAF+DQ的方式来传送大文件的切片,并在终端还原文件。由于文件被切片传送,因此,根据JMS 队列传输的原理,默认配置的JMS DQ会将文件切片分散接收在集群的各个节点的QUEUE上,并且每个节点上配置的消息驱动EJB(MDB)也不能保证只有一个实例能获取文件的全部切片,这样的默认行为令还原大文件切片变为一个需要在多个MDB之间协调完成的事务,处理过程复杂,效率也不高。并且通过SAF来克服在VPN网络环境中可能的各类异常,保证消息传递的质量。

针对该用户的这种需求,提出的解决方案是使用UOW来将一个文件的切片打包为一个工作单元的方式来传送。

方案示意图如下:

上图中的UOW1、UOW2、UOW3表示的是代表一个大文件切片的一组/一个工作单元消息(多条)。大文件会先经过JAVA程序进行切片,然后通过JMS API和UOW的API来发送到一个本地的WebLogic服务器的队列上。本地队列被配置为通过SAF转发到远程的一个DQ中。远程的DQ接收到消息后,会根据UOW的ID来将一组消息(统一UOW ID的消息)作为一个整体,分配到集群中的某一个实例。在该集群中部署一个MDB EJB。该EJB的实例会收到属于一个文件的所有切片,然后进行还原处理。由于使用了UOW,可以保证每个文件的所有切片,有且只有一个MDB实例可以进行处理。

  1. 配置过程简述
  1. 首先安装远端WebLogic服务器并配置好集群。
  2. 分别创建三个JMS Server在三个集群节点上。
  3. 创建一个JMS Module,并在JMS Module中定义一个子部署target到cluster上。
  4. 创建一个Distributed Queue, target到定义好的子部署上,记得在高级配置区域中选择工作单元 (UOW) 消息处理策略为单个消息传递。 该配置启动UOW支持。
  5. 安装本地WebLogic服务器
  6. 创建SAF存储转发代理。
  7. 创建SAF导入目的地,并在SAF远程上下文定义中,配置远程集群的URL,例如:t3://172.16.100.1:7003,172.16.100.1:7004,172.16.100.1:7005。
  8. 配置子部署并将SAF导入目的地target到子部署上。

详细部署请参考WLS相关文档。

  1. 示例代码

UOW 发送:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
import java.util.UUID;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Hashtable;
import javax.jms.*;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import weblogic.jms.extensions.WLMessageProducer;
  
/** This example shows how to establish a connection
 * and send messages to the JMS queue. The classes in this
 * package operate on the same JMS queue. Run the classes together to
 * witness messages being sent and received, and to browse the queue
 * for messages. The class is used to send messages to the queue.
 */
public class QueueSendUOW
{
  // Defines the JNDI context factory.
  public final static String JNDI_FACTORY="weblogic.jndi.WLInitialContextFactory";
  
  // Defines the JMS context factory.
  public final static String JMS_FACTORY="dizzyworldConnectionFactory";
  
  // Defines the queue.
  public final static String QUEUE="dizzyworldDistributedQueue";
  
  private QueueConnectionFactory qconFactory;
  private QueueConnection qcon;
  private QueueSession qsession;
  private QueueSender qsender;
  private Queue queue;
  private TextMessage msg;
  
  /**
   * Creates all the necessary objects for sending
   * messages to a JMS queue.
   *
   * @param ctx JNDI initial context
   * @param queueName name of queue
   * @exception NamingException if operation cannot be performed
   * @exception JMSException if JMS fails to initialize due to internal error
   */
  public void init(Context ctx, String queueName)
    throws NamingException, JMSException
  {
    qconFactory = (QueueConnectionFactory) ctx.lookup(JMS_FACTORY);
    qcon = qconFactory.createQueueConnection();
    qsession = qcon.createQueueSession(true, Session.AUTO_ACKNOWLEDGE);
    queue = (Queue) ctx.lookup(queueName);
    qsender = qsession.createSender(queue);
  
    msg = qsession.createTextMessage();
    qcon.start();
  }
  
  /**
   * Sends a message to a JMS queue.
   *
   * @param message  message to be sent
   * @exception JMSException if JMS fails to send message due to internal error
   */
  public void send(String message, String strUOW, int SeqNo, boolean isLast) throws JMSException {
    msg.setText(message);
    msg.setStringProperty("JMS_BEA_UnitOfWork", strUOW);
    msg.setIntProperty("JMS_BEA_UnitOfWorkSequenceNumber", SeqNo);
    msg.setBooleanProperty("JMS_BEA_IsUnitOfWorkEnd", isLast);
    qsender.send(msg, DeliveryMode.NON_PERSISTENT, 7, 0);
  }
  
  
  /**
   * Closes JMS objects.
   * @exception JMSException if JMS fails to close objects due to internal error
   */
  public void close() throws JMSException {
    qsession.commit();
    qsender.close();
    qsession.close();
    qcon.close();
  }
  
  
 /** main() method.
  *
  * @param args WebLogic Server URL
  * @exception Exception if operation fails
  */
  public static void main(String[] args) throws Exception {
    if (args.length != 1) {
      System.out.println("Usage: java QueueSendUOW WebLogicURL");
      return;
    }
    InitialContext ic = getInitialContext(args[0]);
    QueueSendUOW qs = new QueueSendUOW();
    qs.init(ic, QUEUE);
    readAndSend(qs);  
    qs.close();
  }
  
  
  private static void readAndSend(QueueSendUOW qs)
    throws IOException, JMSException
  {
    BufferedReader msgStream = new BufferedReader(new InputStreamReader(System.in));
    String line=null;
    UUID UOW = null;
    boolean quitNow = false;
      
    int seqNumber = 1;
  
    UOW = UUID.randomUUID();
    while (! quitNow) {
      System.out.print("Enter message (\"quit\" to quit): \n");
      line = msgStream.readLine();
      if (line != null && line.trim().length() != 0) {
        quitNow = line.equalsIgnoreCase("quit");
        if ( ! quitNow ) {
          qs.send( line, String.valueOf(UOW), seqNumber, false );
        } else {
          qs.send( line, String.valueOf(UOW), seqNumber, true );
        }
        System.out.println("JMS Message Sent: " + line + "\n");
        seqNumber += 1;
      }
    }
  }
  
  
  private static InitialContext getInitialContext(String url)
    throws NamingException
  {
    Hashtable<String,String> env = new Hashtable<String,String>();
    env.put(Context.INITIAL_CONTEXT_FACTORY, JNDI_FACTORY);
    env.put(Context.PROVIDER_URL, url);
    return new InitialContext(env);
  }
  
}

MDB 接收:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package mdb;
  
   
  
import java.util.ArrayList;
  
   
  
import javax.ejb.MessageDriven;
  
   
  
import javax.ejb.MessageDrivenContext;
  
   
  
import javax.jms.JMSException;
  
import javax.jms.Message;
  
import javax.jms.MessageListener;
  
import javax.jms.ObjectMessage;
  
import javax.jms.TextMessage;
  
   
  
@MessageDriven(mappedName = "dizzyworldDistributedQueue")
  
public class MessageDrivenEJBBean implements MessageListener {
  
    private static final boolean VERBOSE = true;
  
    private int count =0;
  
    private MessageDrivenContext m_context;
  
    private int m_tradeLimit;
  
    public void onMessage(Message msg) {
  
         
  
        try {
  
            System.out.println(count++);
  
            System.out.println(msg.getClass());
  
            if (msg instanceof ObjectMessage) {
  
                ArrayList msgList =
  
                    (ArrayList)(((ObjectMessage)msg).getObject());
  
                int numMsgs = msgList.size();
  
                log("Received [" + numMsgs + "] Messages");
  
                log("UOW id: " +
  
                                   (((TextMessage)msgList.get(0)).getStringProperty("JMS_BEA_UnitOfWork")));
  
                for (int i = 0; i < numMsgs; i++) {
  
                    log("Message[" + i + "] " +
  
                                       ((TextMessage)msgList.get(i)).getText());
  
                }
  
                System.out.println();
  
            }
  
        } catch (JMSException jmse) {
  
            // TODO: Add catch code
  
            jmse.printStackTrace();
  
        }
  
    }
  
   
  
   
  
    private void log(String s) {
  
        if (VERBOSE)
  
            System.out.println(s);
  
    }
  
}

5. 测试

设定相关类路径并启动发送客户端,示例:java – cp %CLASSPATH% QueueSendUOW t3://172.16.100.102:7001

启动后输入一条或多条消息,输入’quit’完成一个UOW。

将MDB部署到集群中,在WLS的输出信息中,检查消息接收。

WebLogic JMS的强大功能组合:UOW+SAF+分布式Queue相关推荐

  1. Spring JMS 整合Weblogic JMS(weblogicMQ)

    1. Weblogic JMS配置 1.1.  JMS Server配置 1)      启动weblogic11g 管理控制台; 2)      在左窗格中选择"Services" ...

  2. 精美UI强大娱乐功能组合微信小程序源码

    介绍: 这是一个多娱乐功能的小程序 具体由以下功能组合: 网易云在线音乐(***音乐和网易云功能界面一样) 外卖CPS(外卖平台优惠劵) 打车CPS(打车平台优惠劵) 头像功能(多分类头像,另外还支持 ...

  3. 【小程序源码】精美UI强大娱乐功能组合微信小程序源码下载,安装简单

    这是一个多娱乐功能的小程序 具体由以下功能组合: 在线音乐 短视频去印 外卖CPS(外卖平台优惠劵) 打车CPS(打车平台优惠劵) 头像功能(多分类头像,另外还支持姓氏头像制作) 图片加水印 表情包功 ...

  4. 精美UI强大娱乐功能组合微信小程序源码下载,安装简单

    这是一个多娱乐功能的小程序 具体由以下功能组合: 网易云在线音乐(在线播放音乐和网易云功能界面一样) 网易云升级 短视频去水印 外卖CPS(外卖平台优惠劵) 打车CPS(打车平台优惠劵) 头像功能(多 ...

  5. 微信小程序:强大工具箱组合源码

    这是一个比较强大的一款工具箱 内有去水印功能(支持几十家平台去水印) 朋友圈功能|(发圈套图等) 头像,朋友圈封面,壁纸等 另外还有快递查询,手持弹幕等 另外还有一个强大的去水印历史记录 历史记录可以 ...

  6. The Power of Blending Options(混合选项的强大功能)

    在我公布了最近文章" 制作图标的过程 "之后,我收到了一些想要深入了解混合选项的回复,还有混合选项的更直接.实际的用法. 目前,混合选项是PHOTOSHOP初学者的首个绊脚石,初学 ...

  7. Python标准库的强大功能的相关介绍

    http://pyfun.com/rumen/201009/1223.html Python标准库是十分庞大的,其中也有一些质量比较高的库,例如,wXPython.Python以及其他的图形库,等等, ...

  8. matlab里面板有什么作用,MATLAB轻松享受GPU的强大功能

    MATLAB轻松享受GPU的强大功能 MATLAB的GPU支持为活跃于许多学科的大量研究人员(不一定是CUDA编程专家)提供了一种加速科学计算的新方法.考虑到MATLAB主要是用于科学计算和工程计算, ...

  9. 在线计算机多功能,一种多功能组合计算机制造技术

    本实用新型专利技术涉及计算机硬件设备领域,具体涉及一种多功能组合计算机,包括主机箱,电源开关,所述主机箱内表面设置防辐射层,主机箱的侧板上设置通气孔,通气孔上设置过滤罩,过滤罩底部四边一体固定设置法兰 ...

最新文章

  1. Foundation框架: 11.NSDate的基本认识和使用
  2. Adapter (适配器模式)
  3. oracle 好书( 09 对象管理 )
  4. gcc编译C++程序
  5. rowspan不显示 wpf_wpf的datagrid绑定datatable列不自动更新解决方案
  6. 关店9000家,市值蒸发90%,女装巨头大崩溃的根源找到了
  7. jsf如何与数据库连接_JSF数据库示例– MySQL JDBC
  8. Android ViewPager + PagerAdapter 实现轮播图
  9. 手机背景图片在安卓手机上不显示
  10. 我了解的一些线阵相机知识
  11. css文字不换行显示、超出显示点点点等实用性小记
  12. 钟道隆逆向英语学习法—学习SpeciaI English的三个阶段
  13. 【大厂面试】面试官看了赞不绝口的Redis笔记(三)分布式篇
  14. 从0开始学代码第五周!!!
  15. C#一年级100以内的加减训练
  16. 网校平台对在线教育的好处
  17. 教程 | 虚拟机VMware Workstation Pro安装教程
  18. Microelectronic学习章节总结(1)-- 计算机架构复习
  19. Android定时任务及闹钟的实现
  20. ie模版字符串_字符串(String)模板引擎被视为是有害的

热门文章

  1. 2019莆田学院c语言试卷,莆田学院《C++面向对象程序设计》模拟试卷及答案
  2. 单片机c语言的按键程序,新按键程序
  3. IDEA常用快捷设置
  4. 用Python写一个pubmed的爬虫代码
  5. matlab 离散阶跃函数,MATLAB编程实现简单阶跃函数波形
  6. 考研政治考题分布、单选多选技巧Keywords、大题点默析
  7. DM8: 查询统计当前数据库登录用户的每张表的数据量
  8. Cocos Creator 资源加载流程剖析【二】——Download部分
  9. 天津SEO基础(三)关键字广告,竞价排名
  10. MFC获取临时文件夹的路径