2.1 修改登录名认证和Connection的使用
2.1.1 修改登录名认证
在 conf/activemq.xml 文件中,可以修改登录认证,即ConnectionFactory中填写的用户名,密码。
<plugins>
<simpleAuthenticationPlugin>
<users>
<authenticationUser username="lys" password="lys" groups="users,admins"></authenticationUser>
</users>
</simpleAuthenticationPlugin>
</plugins>
2.1.2 Connection使用
在成功创建ConnentionFactory后,下一步是创建Connection,它是JMS定义的一个接口,ConnectionFactory负责返回可以与底层消息传递系统进行通信的实现。通常用户只使用单一连接。根据JMS文档,Connection的目的是“利用JMS提供者封装开放的接连”,以及表示“客户端与提供者服务之间的开放tcp/ip stocket”。
当一个Connection被创建时,它的传输默认是关闭的,必须使用start方法开启。一个Connection可以创建多个Session。
当一个程序执行完成后,必须关闭之前创建的Connection,否则ActiveMQ不能释放资源,关闭一个Connection同样也关闭了 Session,MessageProducer 和 MessageConsumer。
Connection createConnection();
Connection createConnection(String userName, String password);
2.2 Session使用
Session是一个发送或接收消息的线程,可以使用Session创建 MessageProducer,MessageConsumer 和 Message。
Session可以被事务化,也可以不被事务化,通常可以通过向Connection上的适当创建方法传递一个boolean参数对此进行设置。
Session createSession(boolean transacted, int acknowlwdgeMode);
transacted为使用事务标识,acknowledgeMode为签收模式。
- 当一个事务被提交,消息被处理,如果事务中有一步执行失败,事务就会回滚。这个事务中已经执行的动作将被撤销。在发送消息最后也必须要使用session.commit()方法表示提交事务。
- 签收模式有三种形式:
- Session.AUTO_ACKNOWLEDGE:当客户端从receive或onMessage成功返回时,Session自动签收客户端的这条消息的收条。(常用)
- Session.CLIENT_ACKNOWLEDGE:客户端通过调用消息的acknowledge方法签收消息。在这种情况下,签收发生在Session层面:签收一个已消费的消息会自动地签收这个Session所有已消费的收条。
- Session.DUPS_OK_ACKNOWLEDGE:此选项指示Session不必确保对传送消息的签收,他可能引起消息的重复,但是降低了Session的开销,所有只有客户端能容忍重复消息的时候,才使用。
2.2.1 事务代码示例
// 第一步:建立ConnectionFactory工厂对象,需要填入用户名,密码,以及连接的地址。默认tcp://127.0.0.1:61616
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(Contstants.USERNAME, Contstants.PASSWORD, Contstants.URL);
// 第二部:通过ConnectionFactory工厂对象我们创建一个Connection连接
// 并且调用Connection的start启动连接, Connection默认是关闭的。
Connection connection = connectionFactory.createConnection();
connection.start();
// 第三部:使用事务提交
Session session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);
// 第四部: 通过Session创建Destination,指的是一个客户端用来指定生产消息目标和消息来源的对象
// 在ptp模式中,Destination被称做为Queue(队列),在Pub/Sub模式下,Destination被称作Topic(主题)
Destination destination = session.createQueue("helloworld-queue");
// 第五步:我们需要通过Session对象创建消息的发送和接受对象,(生产者和消费者)MessageProducer/MessageConsumer
MessageProducer producer = session.createProducer(destination);
// 第六步:我们可以使用MessageProducer的setDeliveryMode方法为其设置持久化特性和非持久化特性(DeliveryMode)
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
// 第七部:最后我们使用jms规范的TextMessage形式创建数据(通过Session对象),
// 并用MessageProducer的send方法发送数据,同理客户端使用receive方法进行接受数据。
for (int i = 0; i < 5; i++) {
TextMessage message = session.createTextMessage("producer hello word!" + i);
producer.send(message);
}
session.commit();
// 最后不要忘了关闭资源。
if (connection != null) {
connection.close();
}
如果在for循环中 throw exception 或者没有执行 session.commit(),则在ActiveMQ查不到消息。
2.2.2 手动签收示例
发送端和接收端设置为 Session.CLIENT_ACKNOWLEDGE。
Session session = connection.createSession(Boolean.FALSE, Session.CLIENT_ACKNOWLEDGE);
接受端在接收完数据后要执行,否则在ActiveMQ的管理后台中,仍然显示数据没有消费。
message.acknowledge();
2.3 MessageProducer使用
MessageProducer由Session创建,用来向Destination发送消息。
void send(Destination destination, Message message);
void send(Destination destination, Message message, int deliveryMode, int priority, long timeToLive);
void send(Message message);
void send(Message message, int deliveryMode, int priority, long timeToLive);
deliveryMode为传送模式,priority为消息优先级,timeToLive为消息过期时间。
ActiveMQ支持两种消息传递模式,PRESISTENT和NON_PRESISTENT两种。如果不指定传送模式,默认为持久性消息。如果能容忍消息丢失,那么使用非持久性消息可以改善性格和减少存储的开销。
消息优先级从0-9十个级别,0-4是普通消息,5-9是加急消息,如果不指定优先级,则默认为4,JMS不要求严格按照这十个优先级发送消息,但必须保证加急消息要先于普通消息到达。
默认情况下,消息不回过期。如果消息在特定的周期内失去意义,那么可以设置过去时间,时间单位为毫秒。
2.4 MessageComsumer使用
MessageConsumer由Session创建,用来从Destination接受消息。
MessageConsumer createConsumer(Destination destination);
MessageConsumer createConsumer(Destination destination, String messageSelector);
MessageConsumer createConsumer(Destination destination, String messageSelector, boolean noLocal);
TopicSubscriber createDurableSubscriber(Topic topic, String name);
TopicSubscriber createDurableSubscriber(Topic topic, String name, String messageSelector, boolean noLocal);
messageSelector为消息选择器,noLocal默认设置为false,当设置为true时限制消费者只能接受和自己想通的连接(Connection)所发布的消息,此标记只适用于主题,不适用于队列,name标识订阅主题所对应的订阅名称,持久订阅时需要设置此参数。
2.4.1 messageSelector 示例
发送端代码:
必须使用带Property的方法,否则不能过滤
for (int i = 0; i < 10; i++) {
MapMessage message = session.createMapMessage();
// 必须使用带Property的方法,否则不能过滤
message.setIntProperty("id", i);
message.setString("content", "message");
producer.send(message, DeliveryMode.PERSISTENT, i, 1000 * 60 * 5);
}
接收端代码
// 定义过滤条件
public static final String SELECTOR_0 = "id > 5";
// 省略....
// 接受数据代码
MessageConsumer consumer = session.createConsumer(destination, SELECTOR_0);
// 第六步:接受message
while (true) {
MapMessage message = (MapMessage) consumer.receive();
String msg = message.getString("content") + message.getIntProperty("id");
System.out.println(msg);
}
运行结果: