JMS(Java Message Service)作为JavaEE平台的消息服务标准规范,在现代分布式系统中扮演着重要角色。它通过标准化的API为不同系统间的异步通信提供了可靠保障。我在实际企业级应用开发中发现,合理运用JMS能有效解耦系统组件,提升整体架构的弹性。
与直接API调用相比,JMS带来的核心优势体现在三个方面:
在消息服务器选型时,我们面临ActiveMQ Classic与Artemis的抉择。经过性能测试对比,Artemis展现出显著优势:
提示:生产环境推荐使用2.x稳定版,目前最新为2.27.0版本
安装过程需要注意以下关键步骤:
bash复制# 解压安装包
tar -xvf apache-artemis-2.27.0-bin.tar.gz
mv apache-artemis-2.27.0 /opt/artemis
# 设置环境变量
export ARTEMIS_HOME=/opt/artemis
export PATH=$PATH:$ARTEMIS_HOME/bin
# 创建实例目录
artemis create /var/artemis-instance \
--user admin \
--password password \
--require-login
配置要点说明:
启动服务时推荐使用systemd管理:
ini复制# /etc/systemd/system/artemis.service
[Unit]
Description=ActiveMQ Artemis
After=network.target
[Service]
ExecStart=/var/artemis-instance/bin/artemis run
User=artemis
Restart=always
[Install]
WantedBy=multi-user.target
常见问题处理:
etc/broker.xml中max-disk-usage参数ARTEMIS_OPTS环境变量配置JVM参数acceptor配置中的connectionsAllowedJMS定义了两类消息通道,其特性对比如下:
| 特性 | Queue | Topic |
|---|---|---|
| 消息模式 | 点对点 | 发布/订阅 |
| 消费者数量 | 单消费者 | 多消费者 |
| 消息持久化 | 默认持久 | 需显式声明 |
| 离线消息处理 | 自动保留 | 需持久订阅 |
| 负载均衡 | 多个消费者分担 | 所有消费者接收全量 |
在实际项目中,我们需要根据业务需求选择适当的消息可靠性级别:
持久化消息(PERSISTENT)
事务会话(Transacted Session)
java复制Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
try {
// 业务操作
session.commit();
} catch (Exception e) {
session.rollback();
}
确认机制:
Maven依赖配置要点:
xml复制<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-artemis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>artemis-jakarta-client</artifactId>
<version>2.27.0</version>
</dependency>
连接工厂配置示例:
java复制@Bean
public ConnectionFactory jmsConnectionFactory() {
ActiveMQJMSConnectionFactory factory = new ActiveMQJMSConnectionFactory();
factory.setBrokerURL("tcp://localhost:61616");
factory.setUser("admin");
factory.setPassword("password");
return new CachingConnectionFactory(factory);
}
Spring提供了三种消息发送方式:
java复制jmsTemplate.convertAndSend("queue.name", payloadObject);
java复制jmsTemplate.send("queue.name", session -> {
TextMessage message = session.createTextMessage();
message.setStringProperty("priority", "HIGH");
return message;
});
java复制jmsReactiveOperations.send("queue.name", Mono.just(message))
.subscribe();
消费端配置关键参数:
java复制@JmsListener(
destination = "order.queue",
concurrency = "5-10",
subscription = "durable-sub",
selector = "priority = 'HIGH'"
)
public void processOrder(Order order) {
// 处理逻辑
}
监听容器配置要点:
java复制@Bean
public DefaultJmsListenerContainerFactory jmsListenerContainerFactory() {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
factory.setConcurrency("3-5");
factory.setSessionTransacted(true);
factory.setErrorHandler(t -> log.error("处理异常", t));
return factory;
}
java复制@Bean
public ConnectionFactory pooledConnectionFactory() {
PooledConnectionFactory pool = new PooledConnectionFactory();
pool.setConnectionFactory(rawConnectionFactory());
pool.setMaxConnections(50);
pool.setBlockIfSessionPoolIsFull(true);
return pool;
}
java复制jmsTemplate.setMessageConverter(new MarshallingMessageConverter() {
@Override
protected void marshal(Object object, Message message) {
// 压缩逻辑实现
}
});
properties复制spring.jms.listener.max-messages-per-task=50
spring.jms.listener.receive-timeout=5000
java复制@Bean
public HealthIndicator artemisHealth() {
JmsHealthIndicator indicator = new JmsHealthIndicator();
indicator.setConnectionFactory(connectionFactory);
return indicator;
}
properties复制management.endpoints.web.exposure.include=health,metrics,jms
management.metrics.enable.jms=true
java复制@Bean
public ServletRegistrationBean artemisConsole() {
return new ServletRegistrationBean(
new JolokiaServlet(),
"/console/jolokia/*"
);
}
连接超时:
java复制factory.setConnectTimeout(30000);
认证失败:
处理策略:
java复制jmsTemplate.setExplicitQosEnabled(true);
jmsTemplate.setTimeToLive(60000); // 1分钟
分布式事务配置示例:
java复制@Bean
public JtaTransactionManager transactionManager() {
return new JtaTransactionManager();
}
@Bean
public JmsListenerContainerFactory<?> transactionalFactory(
ConnectionFactory cf,
PlatformTransactionManager tm) {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(cf);
factory.setTransactionManager(tm);
factory.setSessionTransacted(true);
return factory;
}
在大型电商系统中,我们通过JMS实现了订单处理与库存更新的最终一致性。具体方案是:订单服务完成支付后发送JMS消息,库存服务通过事务性监听器处理消息并更新库存。当遇到网络分区时,Artemis的持久化队列保证了消息不丢失,系统恢复后自动继续处理