消息中间件(消息队列),是在分布式中的重要组件。
主要应用场景:
(一)流量削锋
例如商城的抢购,用户过多服务器无法同时处理,采用中间件按照队列处理。
(二)异步消息
传统消息分为串行和并行,串行所占用的时间长,并行存在着服务器如果是单线程的不能处理。
使用中间件,如注册案例,当用户到注册时就结束注册页面,其余发送邮件的过程交给了中间件。
(三)应用解耦
中间件可以将消费者和服务者之间的关系进行解耦。如果消费者宕机了,不影响服务者的操作。在点对点模式下,消息不会丢失,当消费者上线就可以得到服务者提供的消息。
(四)消息通讯
有两种模式:一种点对点的模式(消息不会丢失),一种发布/订阅的模式(消息会丢失以为着需要同时在线,并且服务者消费者需要在同一个主题下,才可以收到消息)。
常用的消息中间件:ActiveMQ RabbitMQ 阿里巴巴开源 ZeroMQ Kafka 大数据(日志处理kafka+storm)
JMS(Java Messaging Service)是 Java 平台上有关面向消息中间件的技术规范 消息中间件是一种机制,而JMS是java实现消息中间件的手段(规范)
案例:
1 引入pom
<dependencies>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-client</artifactId>
<version>5.13.4</version>
</dependency>
</dependencies>
2 服务者
/*创建session的参数说明
createSession(paramA,paramB);
paramA 取值有 : true or false 表示是否支持事务
paramB 取值有:Session.AUTO_ACKNOWLEDGE,Session.CLIENT_ACKNOWLEDGE,DUPS_OK_ACKNOWLEDGE,SESSION_TRANSACTED
createSession(paramA,paramB);
paramA是设置事务的,paramB设置acknowledgment mode
paramA设置为false时:paramB的值可为Session.AUTO_ACKNOWLEDGE,Session.CLIENT_ACKNOWLEDGE,DUPS_OK_ACKNOWLEDGE其中一个。
paramA设置为true时:paramB的值忽略, acknowledgment mode被jms服务器设置为SESSION_TRANSACTED 。
Session.AUTO_ACKNOWLEDGE为自动确认,客户端发送和接收消息不需要做额外的工作。
Session.CLIENT_ACKNOWLEDGE为客户端确认。客户端接收到消息后,必须调用javax.jms.Message的acknowledge方法。jms服务器才会删除消息。
DUPS_OK_ACKNOWLEDGE允许副本的确认模式。一旦接收方应用程序的方法调用从处理消息处返回,会话对象就会确认消息的接收;而且允许重复确认。在需要考虑资源使用时,这种模式非常有效。*/
public class producer {
public static void main(String[] args) throws JMSException {
//1 创建连接工厂 连接url是安装的activemq端口(实现jms接口)
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://192.168.50.128:61616");
//2 创建连接
Connection connection = connectionFactory.createConnection();
//3 打开连接
connection.start();
//4创建session 参数代表支不支持事务
Session session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
//5创建模式 参数是名字
Queue queue = session.createQueue("NAME");
//6创建生产者
MessageProducer producer = session.createProducer(queue);
//7创建消息 选择文本消息(还有map消息)
TextMessage textMessage = session.createTextMessage("你好,世界");
//8发送消息
producer.send(textMessage);
session.close();
connection.close();
}
}
3 消费者
public class consumer {
public static void main(String[] args) throws JMSException {
//创建连接工厂
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://192.168.50.128:61616");
//创建连接
Connection connection = connectionFactory.createConnection();
//打开连接
connection.start();
//创建session
Session session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
//创建模式,指定名字
Queue queue = session.createQueue("NAME");
//创建消费者
MessageConsumer consumer = session.createConsumer(queue);
//配置监听器
consumer.setMessageListener(new MessageListener() {
public void onMessage(Message message) {
TextMessage textMessage= (TextMessage) message;
try {
System.out.println(textMessage.getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
});
}
4 测试,运行消费者服务者 观察结果
web 项目 spring整合开发
1 导入pom
<properties>
<spring.version>5.0.2.RELEASE</spring.version>
</properties>
<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-all</artifactId>
<version>5.11.2</version>
</dependency>
<dependency>
<groupId>javax.jms</groupId>
<artifactId>javax.jms-api</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
2 创建服务者
配置spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:amq="http://activemq.apache.org/schema/core"
xmlns:jms="http://www.springframework.org/schema/jms"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/jms
http://www.springframework.org/schema/jms/spring-jms.xsd
http://activemq.apache.org/schema/core
http://activemq.apache.org/schema/core/activemq-core.xsd">
<!--
目的:spring和activeMq整合:通过整合JmsTemplate对象进行消息发送
-->
<!--1.连接工厂-->
<bean id="activeMQConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://localhost:61616"></property>
</bean>
<!--2.spring管理连接工厂-->
<bean id="connectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory" ref="activeMQConnectionFactory"></property>
</bean>
<!--3.通过连接工厂创建jmstemplate-->
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="connectionFactory"></property>
</bean>
<!--4.1 指定目的地址:queue-->
<bean id="queue" class="org.apache.activemq.command.ActiveMQQueue">
<!--名称-->
<constructor-arg value="xxx01"></constructor-arg>
</bean>
<!--4.2 指定目的地址:topic-->
<bean id="topic" class="org.apache.activemq.command.ActiveMQTopic">
<!--名称-->
<constructor-arg value="xxx02"></constructor-arg>
</bean>
<!--扫描工具类 创建一个发送消息的工具类-->
<context:component-scan base-package="cn.utils"></context:component-scan>
</beans>
创建发送消息的工具类,并交给spring管理
@Component
public class JmsTemplateUtils {
@Autowired
private JmsTemplate jmsTemplate;
@Autowired
private Destination queue;
@Autowired
private Destination topic;
// 发消息的方法
public void send(final String value){
//模板发送 需要的参数是模式,一个MessageCreator的实现类
jmsTemplate.send(topic, new MessageCreator() {
public Message createMessage(Session session) throws JMSException {
TextMessage textMessage = session.createTextMessage(value);
return textMessage;
}
});
}
}
服务者测试
public class SpringProducer {
public static void main(String[] args) {
// 加载配置文件
ClassPathXmlApplicationContext context=new
ClassPathXmlApplicationContext("classpath:applicationContext-jms.xml");
// 发送
JmsTemplateUtils jmsTemplateUtils =(JmsTemplateUtils)context.getBean("jmsTemplateUtils");
jmsTemplateUtils.send("你好,世界");
}
}
3 创建消费者项目 引入相同的pom
配置消费者的spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:amq="http://activemq.apache.org/schema/core"
xmlns:jms="http://www.springframework.org/schema/jms"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/jms
http://www.springframework.org/schema/jms/spring-jms.xsd
http://activemq.apache.org/schema/core
http://activemq.apache.org/schema/core/activemq-core.xsd">
<!--1.连接工厂-->
<bean id="activeMQConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://localhost:61616"></property>
</bean>
<!--2.spring管理连接工厂-->
<bean id="connectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory" ref="activeMQConnectionFactory"></property>
</bean>
<!--3.1 配置监听器管理器
配置是基于queue类型的消息监听用来监听点对点的消息
destination-type:指定类型
connection-factory:指定管理连接工厂
-->
<bean id="queueListener" class="cn.listener.QueueListener"></bean>
<jms:listener-container destination-type="queue" connection-factory="connectionFactory">
<jms:listener destination="xxx01" ref="queueListener"></jms:listener>
</jms:listener-container>
<!--3.1 配置监听器管理器
配置是基于topic类型的消息监听用来监听发布/订阅的消息
-->
<bean id="topicListener" class="cn.listener.TopicListener"></bean>
<jms:listener-container destination-type="topic" connection-factory="connectionFactory">
<jms:listener destination="xxx02" ref="topicListener"></jms:listener>
</jms:listener-container>
</beans>
创建消费者的监听 实现MessageListener
// 点对点
public class QueueListener implements MessageListener{
@Override
public void onMessage(Message message) {
TextMessage textMessage=(TextMessage)message;
try {
System.out.println(textMessage.getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
}
// 发布和订阅
public class TopicListener implements MessageListener{
@Override
public void onMessage(Message message) {
TextMessage textMessage=(TextMessage)message;
try {
System.out.println(textMessage.getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
}