ActiveMQ之jdbc持久化订阅

JMS的基本概念和规范

消息传递域 (JMS domains)

也叫消息模式, 消息模型, 有2种:

  1. 点对点(p2p)
    在这里插入图片描述
概念
  • 消息队列(Queue)
  • 提供者(Sender)
  • 消费者(Receiver)
  • 每个消息都被发送到一个特定的队列,接收者从队列中获取消息。队列保留着消息,直到他们被消费或超时。
特点
  • 每个消息只有一个消费者(Consumer)(即一旦被消费,消息就不再在消息队列中)
  • 提供者和消费者之间在时间上没有依赖性,也就是说当提供者发送了消息之后,不管消费者有没有正在运行,它不会影响到消息被发送到队列
  • 每条消息仅会传送给一个消费者。可能会有多个消费者在一个队列中侦听,但是每个队列中的消息只能被队列中的一个消费者所消费。
  • 消息存在先后顺序。一个队列会按照消息服务器将消息放入队列中的顺序,把它们传送给消费者。当已被消费时,就会从队列头部将它们删除(除非使用了消息优先级)。
  • 消费者在成功接收消息之后需向队列应答成功

2. 发布订阅(pub/sub)

在这里插入图片描述
概念

  • 主题(Topic)
  • 发布者(Publisher)
  • 订阅者(Subscriber)

特点

  • 每个消息可以有多个消费者
  • 发布者和订阅者之间有时间上的依赖性。针对某个主题的订阅者,它必须创建一个订阅者之后,才能消费发布者的消息,而且为了消费消息,订阅者必须保持运行的状态。
  • 为了缓和这样严格的时间相关性,JMS允许订阅者创建一个可持久化的订阅。这样,即使订阅者没有运行,它也能接收到发布者的消息。
  • 每条消息都会传送给称为订阅者的多个消息消费者。
  • 发布者通常不会知道、也意识不到哪一个订阅者正在接收主题消息。
  • 消息被推送给消费者,这意味着消息会传送给消费者,而无须请求。

消息组成(数据格式)

1.消息头

包含消息的识别信息和路由信息

2.消息体
  • TextMessage --一个字符串对象

  • MapMessage --一套名称-值对

  • BytesMessage --一个字节的数据流

  • StreamMessage – Java原始值的数据流

  • ObjectMessage --一个序列化的 Java对象


配置详解:

从上可知:p2p模型和发布订阅(pub/sub)有个很大的区别就是时间上的依赖性的区别。p2p默认不依赖时间,而发布订阅需要创建一个可持久化的订阅。发布订阅模型默认自带了kahaDB 存储方式 (官方推荐。基于日志文件,5.4 之后的默认持久化)。无需配置。但是为了方便查看,这边改用jdbc来持久化订阅。下面提一下配置(linux上安装)。

第一步:引入3个jar包:

mysql(数据库驱动) 、HikariCP(连接池) 、slf4j(日志接口) , 放到 activemq安装目录下的lib文件夹下;

第二步:安装目录activemq/conf/activemq.xml 配置 dataSource
<!-- Hikari Datasource -->
    <bean id="activemq-mysql" class="com.zaxxer.hikari.HikariDataSource"  destroy-method="close">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
        <property name="jdbcUrl"   value="jdbc:mysql://192.168.5.4:3306/activemq?serverTimezone=GMT%2B8"/>
        <property name="username" value="root" />
        <property name="password" value="1234" />
    </bean>
配置持久化
<persistenceAdapter>
  <!--默认配置 <kahaDB directory="${activemq.data}/kahadb"/> -->
<jdbcPersistenceAdapter dataSource="#activemq-mysql" createTablesOnStartup="true"/></persistenceAdapter>
第三步:先建好数据库(库名同上jdbc配置),再重启activeMQ;
第四步:成功,自动建表如下:
ACTIVEMQ_ ACKS : 存储持久订阅的信息

ACTIVEMQ_ LOCK : 锁表(集群使用)

ACTIVEMQ_ MSGS : 消息表

三个表详解:

activemq_acks:

用于存储订阅关系,如果是持久化的Topic,订阅者和服务器订阅关系在这个表保:主要的数据库字段如下
container:消息的Destination
sub_dest:如果是使用的Static集群,这个字段会有集群和其他系统的信息
client_id:订阅者都必须有一个唯一的客户端id用于区分
sub_name:订阅者名称
selector:选择器,可以选择只消费满足条件的消息,条件可以用自定义属性实现,可以支持多属性and和or操作
last_acked_id:记录消费过的消息id

activemq_lock

在集群环境中才有用,只有一个broker可以获得消息,称为Master Broker,其他的只能作为备份等待

activemq_msg:

用于存储消息,Quene和Topic都存储在这个表:
id数据库的自增主键
container:消息的Destination
msgid_prod:消息的发送者客户端的主键
msg_seq:是发消息的顺序,msgid_prod+msg_seq可以组成JMS的MessageID
expiration:消息的过期时间,存储的是1970-01-01到现在的毫秒数
msg:消息本体的java序列对象的二进制数据
prioritry:优先级从0-9,数据越大优先级越高

最后附上测试代码:

jar包

	<dependency>
         <groupId>org.apache.activemq</groupId>
         <artifactId>activemq-all</artifactId>
         <version>5.15.11</version>
    </dependency>

连接配置


public class MyConfig {
    //定义ActiveMQ的连接地址
    public static final String ACTIVEMQ_URL = "tcp://192.168.5.4:61616";
    //topic 队列名称
    public static final String TOPIC_NAME = "topic_01";
}

发布者

public class PersistentSender {
    public static void main(String[] args) throws JMSException {
        //创建连接工厂
        ConnectionFactory activeMQConnectionFactory =
                new ActiveMQConnectionFactory(MyConfig.ACTIVEMQ_URL);
        //创建连接
        Connection connection = activeMQConnectionFactory.createConnection();
        //打开连接
        connection.start();
        //创建会话
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        //创建队列目标
        Destination destination = session.createTopic(MyConfig.TOPIC_NAME);
        //创建一个生产者
        MessageProducer producer = session.createProducer(destination);
        //发送消息时用使用持久模式(默认的,可写可不写)
        producer.setDeliveryMode(DeliveryMode.PERSISTENT);
        //创建消息
        TextMessage message = session.createTextMessage("我是永恒的帅哥擦擦擦");
        //发送消息
        producer.send(message);
        //在本地打印消息
        System.out.println("我现在发的消息是:" + message.getText());
        //关闭连接
        connection.close();
    }
}

接收者

public class PersistentRecv01 {
    public static void main(String[] args) throws JMSException {
        String myId = "PersistentRecv01";
        //创建连接工厂
        ConnectionFactory activeMQConnectionFactory =
                new ActiveMQConnectionFactory(MyConfig.ACTIVEMQ_URL);
        //创建连接
        Connection connection = activeMQConnectionFactory.createConnection();
        //持久订阅
        connection.setClientID(myId);
        //打开连接
        connection.start();
        //创建会话
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        //创建队列目标
        Topic topic = session.createTopic(MyConfig.TOPIC_NAME);
        //创建消费者
        MessageConsumer consumer = session.createDurableSubscriber(topic, myId);
        
        //接收消息(这里也可以用while循环)
        //textMessage = (TextMessage)consumer.receive(); 是一个阻塞队列
        //这里用监听器持续接收消息
        consumer.setMessageListener(new MessageListener() {
            @Override
            public void onMessage(Message message) {
                TextMessage receive = (TextMessage)message;
                try {
                    System.out.println("PersistentRecv 111 : " + receive.getText());
                } catch (JMSException e) {
                    e.printStackTrace();
                }
            }
        });
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值