转载

Weblogic Jms简单应用

Weblogic Jms 简单使用

目录

1      基本用法

1.1      Jms 服务端

1.1.1     配置 Jms 服务器

1.1.2     配置 Jms 模块

1.2      Jms 客户端

1.2.1     Jar 包导入

1.2.2     程序开发

2      整合 Spring

3      参考文档

1        基本用法

对于 Weblogic Jms 的使用可以分为两部分,一部分是 Weblogic 作为服务端发布对应的 Jms 服务为客户端程序提供服务,一部分是我们的应用程序作为客户端发布消息到 Jms 服务端或从 Jms 服务端获取消息进行消费。

1.1      Jms 服务端

Weblogic 作为 Jms 服务端提供 Jms 服务需要在 Weblogic 的控制台进行一些配置,主要是 Jms 服务器和 Jms 模块。 Jms 服务器作为 Jms 服务的核心提供 Jms 服务,也可以说是作为 Jms 模块的一个管理容器; Jms 模块下可以进行 ConnectionFactory Topic Queue 等资源的定义, Weblogic 允许我们通过 JNDI 对它们进行访问。

1.1.1配置Jms服务器

首先我们需要配置一个 Jms 服务器。在控制台左边的域结构下面找到对应的域,进入到服务 -> 消息传送 ->Jms 服务器,如下图所示。

Weblogic Jms简单应用

然后在右边出现的列表点击“新建”按钮进入新建 Jms 服务器的导航页面,之后根据提示一步一步操作即可。

1.1.2配置Jms模块

配置好 Jms 服务器后我们需要配置对应的 Jms 模块, Jms 模块用来分模块管理一组资源,一个 Jms 模块下可包括 ConnectionFactory Topic Queue 等资源。在控制台左边的域结构下面,进入到服务 -> 消息传送 ->Jms 模块,如下图所示。

Weblogic Jms简单应用

然后在右边出现的列表中点击“新建”按钮进入新建 Jms 模块的导航界面,之后就根据提示进行操作即可。新建好 Jms 模块后,我们可以在 Jms 模块列表点击对应 Jms 模块的链接到对应 Jms 模块下的资源列表页面,在对应的资源列表页面,我们点击“新建”按钮新建对应的资源。

1.2      Jms 客户端

1.2.1Jar包导入

在进行客户端开发的时候我们首先需要导入对应的 jar 包。按照 Weblogic 官网文档的说明,我们在开发 Weblogic Jms 客户端的时候只需要把 wlclient.jar wljmsclient.jar 加入 classpath 即可。这两个 jar 包在 Weblogic 安装目录( WL_HOME )下的 server/lib 目录下,如: /home/weblogic/Oracle/Middleware/Oracle_Home/wlserver/server/lib 。但是我在开发的时候只导入这两个 jar 包,客户端程序跑不起来,错误信息是“ Root exception is org.omg.CORBA.COMM_FAILURE:   vmcid: SUN  minor code: 203  completed: No ”。而加上 wlfullclient.jar 则访问正常。 wlfullclient.jar 默认不在 WL_HOME/server/lib 目录下,需要我们在 WL_HOME/server/lib 目录下通过运行“ java –jar wljarbuilder.jar ”来生成,生成后的 wljarbuilder.jar 非常大,有 60 M ,可以将里面一些与工程现有 jar 包有冲突的类删除。

1.2.2程序开发

客户端程序的开发的时候获取如 ConnectionFactory Topic Queue 等这些在服务端配置的资源时都需要通过 JNDI 从服务端获取。所以我们首先得构造一个获取 JNDI 对象的 Context 。在构造 Context 时我们需要提供两个参数, Context.PROVIDER_URL Context.INITIAL_CONTEXT_FACTORY ,这两个参数都由 Weblogic 提供,第一个参数表示提供 JNDI 对象的服务地址,这里对应的值是“ t3://host:port ”, host Weblogic 服务主机的 IP 地址, port 是对应的端口;第二个参数是用于获取 InitialContext InitialContextFactory 接口的实现类名称,对于 Weblogic 而言,它应当是“ weblogic.jndi.WLInitialContextFactory ”。这里我针对它提供了一个工具类,这个工具类的主要作用是把 Context 封装起来了,然后提供了对应的根据 JNDI 名称获取对应对象的方法,还封装了一个 ConnectionFactory ,提供了获取 Connection 的方法。

import java.io.IOException;

import java.util.Hashtable;

import java.util.Properties;

import javax.jms.Connection;

import javax.jms.ConnectionFactory;

import javax.jms.JMSException;

import javax.naming.Context;

import javax.naming.InitialContext;

import javax.naming.NamingException;

import org.apache.log4j.Logger;

public  class JmsUtil {

private  static Context context ;

private  static  final Properties props = new Properties();

private  static  final ConnectionFactory connectionFactory ;

private  static  final String CONNECTION_FACTORY_JNDI = "weblogic.jms.XAConnectionFactory" ;

private  static  final Logger logger = Logger. getLogger (JmsUtil. class );

static {

try {

props .load(JmsUtil. class .getResourceAsStream( "jms.properties" ));

} catch (IOException e1) {

logger .error( " 读取 jms.properties 配置文件出错 " , e1);

}

Hashtable<String, String> environment = new Hashtable<>();

// 指定对应 JNDI 提供者的地址

environment.put(Context. PROVIDER_URL , props .getProperty(Context. PROVIDER_URL ));

// 指定获取 InitialContext InitialContextFactory

environment.put(Context. INITIAL_CONTEXT_FACTORY , props .getProperty(Context. INITIAL_CONTEXT_FACTORY ));

try {

// 构造一个获取 JNDI 对象的 Context

context = new InitialContext(environment);

} catch (NamingException e) {

logger .error( " 初始化 InitialContext 失败 " , e);

}

connectionFactory = JmsUtil. lookup ( CONNECTION_FACTORY_JNDI );

}

/**

* 获取 Jms 连接

* @return

*/

public  static Connection getConnection() {

try {

return connectionFactory .createConnection();

} catch (JMSException e) {

logger .error( " 创建 Connection 失败 " , e);

return null ;

}

}

/**

* 获取指定名称的 JNDI 对象

* @param name

* @return

*/

public  static <T> T lookup(String name) {

try {

return (T) context .lookup(name) ;

} catch (NamingException e) {

logger .error( " 对应的资源不存在 " , e);

return null ;

}

}

}

上述所使用到的 jms.properties 文件的内容如下。

java.naming.provider.url= t3://10.10.10.3:7001

java.naming.factory.initial= weblogic.jndi.WLInitialContextFactory

具体程序开发的步骤如下。

1 、获取 ConnectionFactory

获取 ConnectionFactory 的时候可以获取我们自己定义好的 ConnectionFactory ,也可以直接获取 Weblogic 预先为我们定义好的两个 ConnectionFactory ,它们对应的 JNDI 名称如下。

·          weblogic.jms.ConnectionFactory

·          weblogic.jms.XAConnectionFactory

这两个内置的 ConnectionFactory 的区别是第二个支持 JTA 事务,而第一个不支持,只支持本地事务。

// 根据 JNDI 名称获取对应的 ConnectionFactory

ConnectionFactory connectionFactory = JmsUtil. lookup ( "weblogic.jms.XAConnectionFactory" );

这里获取的 ConnectionFactory 是一个 Weblogic 提供的 JMSConnectionFactory 对象或 JMSXAConnectionFactory 对象,你可以根据需要将它们强转为一个 QueueConnectionFactory 对象或 TopicConnectionFactory 对象, QueueConnectionFactory TopicConnectionFactory Weblogic 提供的专门针对为 Queue 服务和为 Topic 服务的两个接口。在下文的步骤中都不会将它们进行类型强转,而是基于标准的 Jms 接口进行开发。有兴趣的朋友可以查看 Weblogic Jms 文档或对应的 API 文档了解更多内容。

2 、获取 Connection

Connection 是通过 ConnectionFactory 进行获取的。

// 通过 ConnectionFactory 获取一个 Connection

Connection conn = connectionFactory.createConnection();

3 、创建一个 Session

// 第一个参数表示是否需要事务支持,第二个参数表示消息的应答方式

Session session = conn .createSession( false , Session. AUTO_ACKNOWLEDGE );

4 、获取目的地

无论我们的程序是作为生产者还是作为消费者,它都需要一个目的地,这个目的地可以是一个 Topic ,也可以是一个 Queue

// 获取一个目的地,这里暂时不区分是 Topic 还是 Queue

Destination dest = JmsUtil. lookup ( "dest_queue" );

5 、生成者模式

1 )如果我们的客户端是作为生产者进行消息的生产,那么我们就需要创建一个对应的生产者。生产者是通过 Session 进行创建的。

// 创建指定目的地的生产者

MessageProducer producer = session.createProducer(dest);

2 )有了生产者之后我们还需要创建对应的需要进行发送的 Message Message 是通过 Session 进行发送的, Message 有很多种类型,以下只是简单的文本类型的 Message

// 创建一个消息

Message message = session .createTextMessage( "Hello" );

3 )有了 Message 后我们就可以把它交给生产者进行发送了。

// 发送消息

producer.send(message);

6 、消费者模式

1 )如果我们的客户端程序是作为消费者进行消费的,那么我们首先应该创建一个消费指定目的地 Message 的消费者。

// 创建消费者

MessageConsumer consumer = session.createConsumer(dest);

2 )创建了消费者后就是对消息的消费了, MessageConsumer 中定义了好几个接收消息的方法,不过它们都是一次消费,也就是说调用一次最多只会消费一条 Message ,也有不消费的,方法名是以 receive 打头的,这里就不说了有兴趣的朋友可以去看一下 API 文档。这里准备介绍的是通过 MessageListener 进行消费的情形,即给 MessageConsumer 指定一个 MessageListener ,这样一旦有对应的可以进行消费的消息过来后就会自动的回调 MessageListener onMessage 方法。

// 指定消息监听器

consumer.setMessageListener( new MessageListener() {

@Override

public void onMessage(Message msg) {

logger .info( " 收到一条消息: " + msg);

}

});

7 、启动 Connection

当我们的客户端程序是作为消费者时最后需要调用 Connection start 方法,这样我们的 Consumer 才能接收到对应的信息,如果什么时候希望暂停接收信息,则可以调用对应 Connection stop 方法,等到想再次接收 Message 的时候可以再次调用 Connection start 方法。当我们的程序是作为生产者时可以不用调用 Connection start 方法。

到此我们的 Weblogic Jms 客户端程序开发已经基本完成了, Jms 开发的大体思路也都是这样的。上述内容只是比较简单的描述了下服务端的配置和客户端的开发过程。如果希望进行更深入的了解可以参考 Weblogic 的官方文档和 Jms 相关的 API 文档。

2        整合 Spring

Spring 整合 Jms 的文章之前写过,是基于 ActiceMQ 写的,这里关于 Spring 整合 Jms 的内容就不详细说了,只是简单的说一下基于 Weblogic Jms 整合 Spring 时一些不一样的地方。 Weblogic Jms 资源都是通过 JNDI 获取的,所以在整合 Spring 时这些资源也还是需要通过 JNDI 进行获取。 Spring 为我们提供了一个 JndiTemplate 类,其中封装了获取 InitialContext 的方法,通过它我们可以获取到指定 InitialContext 下指定 JNDI 名称的对象。 Spring 还为我们提供了一个 JndiObjectFactoryBean 类,它实现了 FactoryBean 接口,通过给它指定一个 jndiTemplate 和一个 jndiName 可以让它返回指定 jndiName JndiTemplate 中对应的对象。所以在整合 Spring 的时候我们可以通过它们来获取 Weblogic 提供的那些 Jms 对象,其它的就喝 Spring 整合标准的 Jms 是一样的用法了,具体可以参考我之前写的关于 Spring 整合 JMS 的文章。以下是 Weblogic Jms 整合 Spring 的一段示例配置。

< bean id = "jndiTemplate" class = "org.springframework.jndi.JndiTemplate" >

< property name = "environment" >

< props >

< prop key = "java.naming.factory.initial" > ${java.naming.factory.initial} </ prop >

< prop key = "java.naming.provider.url" > ${java.naming.provider.url} </ prop >

</ props >

</ property >

</ bean >

<!-- 提供 Jms 服务的 ConnectionFactory -->

< bean id = "jmsConnectionFactory" class = "org.springframework.jndi.JndiObjectFactoryBean"

p:jndiTemplate-ref = "jndiTemplate" p:jndiName = "${jms.jndi.example.connection.factory}" />

<!-- Spring 封装的 Jms ConnectionFactory ,需要注入一个真正提供 Jms 服务的 ConnectionFactory -->

< bean id = "springJmsConnectionFactory"

class = "org.springframework.jms.connection.SingleConnectionFactory"

p:targetConnectionFactory-ref = "jmsConnectionFactory" />

< bean id = "statusQueue" class = "org.springframework.jndi.JndiObjectFactoryBean"

p:jndiTemplate-ref = "jndiTemplate" p:jndiName = "${jms.jndi.example.status.queue}" />

< bean id = "jmsTemplate" class = "org.springframework.jms.core.JmsTemplate"

p:connectionFactory-ref = "springJmsConnectionFactory" />

<!-- Spring 提供的消息监听容器,用以绑定 ConnectionFactory Destination MessageListener ,为指定 ConnectionFactory Destination 指定 MessageListener -->

< bean id = "statusQueueListenerContainer"

class = "org.springframework.jms.listener.DefaultMessageListenerContainer"

p:connectionFactory-ref = "springJmsConnectionFactory"

p:destination-ref = "statusQueue" p:messageListener-ref = "statusMessageListener" />

<!-- 消息监听器 -->

< bean id = "statusMessageListener" class = "com.xxx.StatusMessageListener" />      

3        参考文档

http://docs.oracle.com/cd/E23943_01/web.1111/e13738/toc.htm (配置和管理 Jms

http://docs.oracle.com/cd/E23943_01/nav/wls.htm Weblogic 官方文档导航)

http://docs.oracle.com/cd/E23943_01/web.1111/e13727/toc.htm (客户端开发)

https://docs.oracle.com/javaee/7/api/ JavaEE1.7 API 文档)

Spring 整合 JMS( )—— 基于 ActiveMQ 实现

(注:本文是基于 Weblogic12.1.3.0.0 Spring3.0.6 所写)

正文到此结束
Loading...