Redis的消息

部分参考链接

原文

CountDownLatch

概述

目的

这节讲的是用Redis来实现消息的发布和订阅,这里会使用Spring Data Redis来完成。

这里会用到两个东西,StringRedisTemplateMessageListenerAdapter。分别用来发布String类型的消息和订阅接收这些消息。

你需要的准备的

  • 大概15min(实际用下来应该不够)
  • 喜欢的ide或者文本编辑器(我使用intellij)
  • Jdk1.8+
  • Gradle4+ 或者 Maven3.2+(这里用Maven)

如何通过Maven来完成

新建maven项目

创建pom.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright (c) 2019.
~ lou
--> <project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <groupId>org.springframework</groupId>
<artifactId>gs-messaging-redis</artifactId>
<version>1.0-SNAPSHOT</version> <parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.RELEASE</version>
</parent> <properties>
<java.version>1.8</java.version>
</properties> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.1.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>1.5.2.RELEASE</version>
</dependency>
</dependencies> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build> </project>

Spring Boot Maven Plugin 有以下几个作用

  • 把项目打包成一个可执行的jar文件。
  • 搜索并标记public static void main()为可执行类。
  • 使用内置的依赖管理

需要一个Redis Server

这里还需要一个Redis Server,搭设过程就不演示了,假设已经搭好,server: localhost:6379, password:xxxxxx。

创建一个Redis 消息接收类

src/main/java/hello/Receiver.java

/*
* Copyright (c) 2019.
* lou
*/ package hello; import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import java.util.concurrent.CountDownLatch; public class Receiver { private static final Logger logger = LoggerFactory.getLogger(Receiver.class); private CountDownLatch latch; @Autowired
public Receiver(CountDownLatch latch) {
this.latch = latch;
} public void receiveMessage(String message){
logger.info("接收到消息"+message);
latch.countDown();
} }

CountDownLatch用来阻塞当前进程,调用countDown方法一次减少1,到0释放。。CountDownLatch 无法重置,如有需要,使用CyclicBarrier

创建一个Redis配置类

Redis的配置应该是放在配置文件中的,所以需要创建一个redis配置类,来读取resource/application.properties中的配置并赋值给相应的connectionFactory。

先添加一下application.properties

spring.redis.password=xxxxx
spring.redis.port=6379
spring.redis.host=localhost

然后创建一个hello/RedisStandaloneConfigurationPropertySource.java

/*
* Copyright (c) 2019.
* lou
*/ package hello; import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; //配置RedisConnectionFactory
@Configuration
@PropertySource(value = "application.properties",encoding = "utf-8")
public class RedisStandaloneConfigurationPropertySource {
private Logger logger = LoggerFactory.getLogger(RedisStandaloneConfigurationPropertySource.class);
@Value("${spring.redis.host}")
private String hostName;
@Value("${spring.redis.port}")
private int port;
@Value("${spring.redis.password}")
private String password; @Override
public String toString() {
return "RedisStandaloneConfigurationPropertySource{" +
"hostName='" + hostName + '\'' +
", port=" + port +
", password='" + password + '\'' +
'}';
} @Bean
RedisConnectionFactory getRedisConnectionFactory() {
//日志记录一下
logger.info("redis的配置为:"+this.toString());
JedisConnectionFactory factory = new JedisConnectionFactory();
RedisStandaloneConfiguration configuration = factory.getStandaloneConfiguration();
configuration.setHostName(hostName);
configuration.setPort(port);
configuration.setPassword(password);
return factory;
}
}

这个类的功能就是读取配置文件,并且定义一个RedisConnectionFactory的Bean,后面会用到。

注册这个消息接收类并发送消息

Spring Data Redis提供了发送和接收消息的所有组件。重点需要配置以下几个东西

  • 一个Connection Factory(连接管理工厂)
  • 一个 Message Listener Container(消息接收容器)
  • 一个Redis Template

使用Redis Template来发送消息,然后把Receiver注册到Message Listener Container中。Connection Factory驱动Template和Container,让他们可以连接到redis server。

例子中使用Spring boot的RedisConnectionFactory,它是基于JedisJedisConnectionFactory的实例。Connection Factory会同时注入到container和template中。

src/main/java/hello/Application.java

/*
* Copyright (c) 2019.
* lou
*/ package hello; import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter; import java.util.concurrent.CountDownLatch; @SpringBootApplication
public class Application {
private static final Logger logger = LoggerFactory.getLogger(Application.class); //Container 由RedisConnectionFactory 和MessageListenerAdapter实例化
@Bean
RedisMessageListenerContainer container(@Qualifier("getRedisConnectionFactory") RedisConnectionFactory connectionFactory, MessageListenerAdapter listenerAdapter) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.addMessageListener(listenerAdapter, new PatternTopic("chat")); return container;
} @Bean
MessageListenerAdapter listenerAdapter(Receiver receiver) {
//通过Receiver实例化Adapter,设置默认listen方法,receiveMessage
return new MessageListenerAdapter(receiver, "receiveMessage");
} @Bean
Receiver receiver(CountDownLatch latch) {
return new Receiver(latch);
} @Bean
CountDownLatch latch() {
return new CountDownLatch(100);//设置上限100
} //StringRedisTemplate由RedisConnectionFactory实例化
@Bean
StringRedisTemplate template(@Qualifier("getRedisConnectionFactory") RedisConnectionFactory connectionFactory) {
return new StringRedisTemplate(connectionFactory);
} public static void main(String[] args) throws InterruptedException {
ApplicationContext ctx = SpringApplication.run(Application.class, args); CountDownLatch latch = ctx.getBean(CountDownLatch.class);
latch.await();
System.exit(0);
}
}

这样Application就完成了。

  • RedisMessageListenerContainer由container方法返回。
  • MessageListenerAdapter 由listenAdapter方法返回,构造函数里面第二个参数表示调用的方法receiveMessage,这个在receiver类中已经定义。
  • StringRedisTemplate 由template方法返回,这个类关注于操作key和value都是String类型的数据。

创建一个webapi来测试这个功能

src/main/java/hello/controller/TestController.java

/*
* Copyright (c) 2019.
* lou
*/ package hello.controller; import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import java.util.Random; @RestController
public class TestController {
Random random = new Random();
StringRedisTemplate template; public TestController(StringRedisTemplate template) {
this.template = template;
} @GetMapping("test")
public int TestMethod(@RequestParam(name = "t", defaultValue = "hello") String t) {
ValueOperations operations = template.opsForValue();
//测试读写redis
operations.set("t", t);
//发送消息
template.convertAndSend("chat", "消息" + t); return random.nextInt(100);
}
}

test方法里面调用convertAndSend方法,发送消息,启动后访问http://localhost:8080/test?t=2432,可以看到日志上有返回内容。

构建可执行jar

打包 mvn package

运行 java -jar ./target/xxx.jar。看到可以运行起来。

小结

这个demo教了我们如何通过配置文件配置redis连接,然后实现发布和订阅。

[SpingBoot guides系列翻译]Redis的消息订阅发布的更多相关文章

  1. 基于Redis的消息订阅/发布

    在工业生产设计中,我们往往需要实现一个基于消息订阅的模式,用来对非定时的的消息进行监听订阅. 这种设计模式在 总线设计模式中得到体现.微软以前的WCF中实现了服务总线 ServiceBus的设计模式. ...

  2. SpringBoot+Redis 实现消息订阅发布

    什么是 Redis Redis 是一个开源的使用 ANSI C语言编写的内存数据库,它以 key-value 键值对的形式存储数据,高性能,读取速度快,也提供了持久化存储机制. Redis 通常在项目 ...

  3. [SpingBoot guides系列翻译]文件上传

    文件上传 这节的任务是做一个文件上传服务. 概况 参考链接 原文 thymeleaf spring-mvc-flash-attributes @ControllerAdvice 你构建的内容 分两部分 ...

  4. Redis的消息订阅/发布 Utils工具类

    package cn.cicoding.utils; import org.json.JSONException; import org.json.JSONObject; import redis.c ...

  5. Redis之Redis消息订阅发布简介

    概念: Redis消息订阅发布是进程间的一种消息通信模式,发送者pub发送消息,订阅者sub接收消息. 使用须知: 需要先订阅后发布,才能接收到消息.在订阅时,相当于创建了可供发布的频道. 案例: ( ...

  6. Redis实现消息的发布/订阅

    利用spring-boot结合redis进行消息的发布与订阅: 发布: class Publish { private static String topicName = “Topic:chat”; ...

  7. 基于redis的消息订阅与发布

    Redis 的 SUBSCRIBE 命令可以让客户端订阅任意数量的频道, 每当有新信息发送到被订阅的频道时, 信息就会被发送给所有订阅指定频道的客户端. 作为例子, 下图展示了频道 channel1  ...

  8. Redis的消息订阅及发布及事务机制

    Redis的消息订阅及发布及事务机制 订阅发布 SUBSCRIBE PUBLISH 订阅消息队列及发布消息. # 首先要打开redis-cli shell窗口 一个用于消息发布 一个用于消息订阅 # ...

  9. spring boot: 用redis的消息订阅功能更新应用内的caffeine本地缓存(spring boot 2.3.2)

    一,为什么要更新caffeine缓存? 1,caffeine缓存的优点和缺点 生产环境中,caffeine缓存是我们在应用中使用的本地缓存, 它的优势在于存在于应用内,访问速度最快,通常都不到1ms就 ...

随机推荐

  1. js ajax设置和获取自定义header信息的方法总结

    目录 1.js ajax 设置自定义header 1.1 方法一: 1.2 方法二: 2.js ajax 获取请求返回的response的header信息 3.js ajax 跨域请求的情况下获取自定 ...

  2. 【总结】《氨基酸新晋管理者领导力培训》第一次课_Day2_学习心得

    7月26日第二天学习心得: 今天主要学习了执行贯彻和绩效反馈两大块内容,我的心得有: 一.执行层面有两大原则:--理解员工需求: 回顾了一下自己以往的经历,一般这块我用的最多的一般是在接到一个新项目的 ...

  3. Java设计模式:Abstract Factory(抽象工厂)模式

    概念定义 抽象工厂(Abstract Factory)模式提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类. 抽象工厂模式中,系统的产品有多于一个的产品族(一个产品族里定义多个产品) ...

  4. 基于bert的命名实体识别,pytorch实现,支持中文/英文【源学计划】

    声明:为了帮助初学者快速入门和上手,开始源学计划,即通过源代码进行学习.该计划收取少量费用,提供有质量保证的源码,以及详细的使用说明. 第一个项目是基于bert的命名实体识别(name entity ...

  5. HashMap框架源码深入解读,面试不用愁

    在Java Collections Framework的体系中中,主要有两个重要的接口,一个是List.Set和Queue所属的Collection,还有一个就是Map接口了.在上一篇文章中介绍了Li ...

  6. Vue-nodeJS环境搭建

    Node.jsNode.js是一个基于Chrome V8引擎的[JavaScript运行环境]. Node.js使用了一个事件驱动.非阻塞式I/O 的模型.Node.js是一个让JavaScript运 ...

  7. Java8 日期和时间API

    LocalDate.LocalTime.Instant.Duration.Period 1.1使用LocalDate和LocalTime 1.1.1LocalDate的创建方式和相关方法使用示例 @T ...

  8. 通过JS屏蔽鼠标右键

    我也是第一次接触这个功能,只需一行代码即可搞定,直译过来就是“屏蔽上下文菜单”,特此记录一下吧. document.oncontextmenu = () => false;

  9. webpack打包配置禁止html标签全部转为小写

    用webpack打包页面,发现html中特别写的用来给后端识别的大写标签全部被转为了小写标签,这时候需要将加一个配置 ,caseSensitive:true ,禁止大小写转换. webpack配置: ...

  10. IOS中的深拷贝和浅拷贝

    标签: 什么是深拷贝?什么是浅拷贝? 为什么经常看到字符串属性要这样定义,那个copy是神马意思? @property(nonatomic,copy)NSString* name; 为什么下面的写法是 ...