1. Redis实现定时消息通知

简单定时任务通知: 利用redis的keyspace notifications(即:键过期后事件通知机制)

开启方法

  • 修改server.conf文件,找到notify-keyspace-events , 修改为“Ex”
  • 使用cli命令: redis-cli config set notify-keyspace-events Ex
  • redis 配置参考

2. 例子

创建springboot项目

修改pom.xml 和 yml

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.9</version> <!-- 这个版本其实还是挺重要的,如果是2.7.3版本的话,大概会无法成功自动装载 RedisConnectionFactory -->
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>cn.lazyfennec</groupId>
    <artifactId>redisdemo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>redisdemo</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

application.yml

spring:
  redis:
    database: 0
    host: 192.168.1.7
    port: 6379
    jedis:
      pool:
        max-active: 8
        max-idle: 8
        min-idle: 0
        max-wait: 1

创建RedisConfig

package cn.lazyfennec.redisdemo.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
 * @Author: Neco
 * @Description:
 * @Date: create in 2022/9/20 23:19
 */
@Configuration
@EnableCaching
public class RedisConfig {
    @Bean
    public RedisTemplate&lt;String, Object&gt; redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        // 设置序列化
        Jackson2JsonRedisSerializer&lt;Object&gt; jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer&lt;Object&gt;(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        // 配置redisTemplate
        RedisTemplate&lt;String, Object&gt; redisTemplate = new RedisTemplate&lt;&gt;();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        RedisSerializer stringSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(stringSerializer); // key 序列化
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); // value 序列化
        redisTemplate.setHashKeySerializer(stringSerializer); // Hash key 序列化
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer); // Hash value 序列化
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }  
}

创建RedisListenerConfiguration

package cn.lazyfennec.redisdemo.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
/**
 * @Author: Neco
 * @Description:
 * @Date: create in 2022/9/21 11:02
 */
@Configuration
public class RedisListenerConfiguration {
    @Autowired
    private RedisConnectionFactory factory;
    @Bean
    public RedisMessageListenerContainer redisMessageListenerContainer() {
        RedisMessageListenerContainer redisMessageListenerContainer = new RedisMessageListenerContainer();
        redisMessageListenerContainer.setConnectionFactory(factory);
        return redisMessageListenerContainer;
    }
}

事件监听事件 RedisTask

package cn.lazyfennec.redisdemo.task;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.listener.KeyExpirationEventMessageListener;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.stereotype.Component;
import java.nio.charset.StandardCharsets;
/**
 * @Author: Neco
 * @Description:
 * @Date: create in 2022/9/21 11:05
 */
@Component
public class RedisTask extends KeyExpirationEventMessageListener {
    public RedisTask(RedisMessageListenerContainer listenerContainer) {
        super(listenerContainer);
    }
    @Override
    public void onMessage(Message message, byte[] pattern) {
        // 接收到事件后回调
        String channel = new String(message.getChannel(), StandardCharsets.UTF_8);
        String key = new String(message.getBody(), StandardCharsets.UTF_8);
        System.out.println("key:" + key + ", channel:" + channel);
    }
}

发布 RedisPublisher

package cn.lazyfennec.redisdemo.publisher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.Random;
import java.util.concurrent.TimeUnit;
/**
 * @Author: Neco
 * @Description:
 * @Date: create in 2022/9/21 16:34
 */
@Component
public class RedisPublisher {
    @Autowired
    RedisTemplate<String, Object> redisTemplate;
    // 发布
    public void publish(String key) {
        redisTemplate.opsForValue().set(key, new Random().nextInt(200), 10, TimeUnit.SECONDS);
    }
    // 循环指定时间触发
    @Scheduled(cron = "0/15 * * * * ?")
    public void scheduledPublish() {
        System.out.println("scheduledPublish");
        redisTemplate.opsForValue().set("str1", new Random().nextInt(200), 10, TimeUnit.SECONDS);
    }
}
  • 要实现Scheduled需要在启动类上加上注解
@SpringBootApplication
@EnableScheduling // 要加上这个,用以启动
public class RedisdemoApplication {

修改TestController

package cn.lazyfennec.redisdemo.controller;
import cn.lazyfennec.redisdemo.publisher.RedisPublisher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
/**
 * @Author: Neco
 * @Description:
 * @Date: create in 2022/9/21 16:32
 */
@RestController
public class TestController {
    @Autowired
    RedisPublisher redisPublisher;
    @GetMapping("/redis/{key}")
    public String publishEvent(@PathVariable String key) {
        // 发布事件
        redisPublisher.publish(key);
        return "OK";
    }
}