Spring-redis:实现发布/订阅(亲测有效,欢迎提问)

本文详细介绍如何在Spring框架中整合Redis实现发布订阅功能,包括导入maven依赖、配置Redis服务器信息、设置监听器等步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原理:Spring与redis整合后,配置的监听器会对项目进行监听,每当调用RedisTemplate这个类的convertAndSend(java.lang.String channel, java.lang.Object message)方法,像指定的频道(在配置文件之中)发送一条消息,该消息就会被监听器监听到,进而实现发布订阅功能。

一、导入maven依赖

spring集成redis需要导入的maven依赖有两个,如下:

        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
            <version>1.6.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.8.2</version>
        </dependency>

二、新建redis配置文件,配置redis服务器相关信息

文件名为:redis.properties

redis.host=localhost
redis.port=6379
redis.password=
redis.database=0
redis.timeout=1000
#session valid time
redis.maxInactiveIntervalInSeconds=1800

#redis pool config
redis.pool.maxTotal=300
redis.pool.maxIdle=5
redis.pool.minIdle=1
redis.pool.maxWaitMillis=6000
redis.pool.testWhileIdle=true
redis.testOnBorrow=true

三、新建redis配置文件redis-context.xml文件,注册redis相关配置信息

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context"
       xmlns:p="http://www.springframework.org/schema/p" xmlns:redis="http://www.springframework.org/schema/redis"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/redis http://www.springframework.org/schema/redis/spring-redis.xsd">

    <!-- TODO 定义 spring-redis 集成配置,包括常用操作和集成redis发布/订阅功能 -->
    <!-- TODO 通过在 spring-mvc.xml 中使用 import 标签导入此配置文件 -->

    <context:component-scan base-package="xin.shenwan.redis"/>

    <!-- 引入redis服务器配置 -->
    <context:property-placeholder location="classpath:/redis.properties" file-encoding="utf-8"
                                  ignore-unresolvable="true"/>

    <!-- 定义Spring RedisTemplate -->
    <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"
          p:connectionFactory-ref="redisConnectionFactory"/>

    <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <property name="maxIdle" value="${redis.pool.maxIdle}"/>
        <property name="maxTotal" value="${redis.pool.maxTotal}"/>
        <property name="testOnBorrow" value="${redis.pool.testWhileIdle}"/>
    </bean>

    <!-- 定义spring-redis连接工厂 -->
    <bean id="redisConnectionFactory"
          class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
        <property name="usePool" value="true"/>
        <property name="hostName" value="${redis.host}"/>
        <property name="port" value="${redis.port}"/>
        <property name="password" value="${redis.password}"/>
        <property name="timeout" value="${redis.timeout}"/>
        <property name="database" value="${redis.database}"/>
        <constructor-arg index="0" ref="jedisPoolConfig"/>
    </bean>
    <!-- 定义Spring RedisTemplate -->
    <bean id="stringRedisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">
        <property name="connectionFactory" ref="redisConnectionFactory"/>
        <property name="keySerializer" ref="stringRedisSerializer"/>
        <property name="valueSerializer" ref="stringRedisSerializer"/>
        <property name="hashKeySerializer" ref="stringRedisSerializer"/>
        <property name="hashValueSerializer" ref="stringRedisSerializer"/>
    </bean>

    <!-- 定义Spring Redis的序列化器 -->
    <!-- String序列化 -->
    <bean id="stringRedisSerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
    <!-- jdk序列化-->
    <bean id="jdkSerializer" class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>

    <!-- 将监听实现类注册到spring容器中 -->
    <bean id="dataSyncEventListener" class="xin.shenwan.redis.DataSyncEventListener"/>
    <!-- 注册监听器并引入监听实现类 -->
    <bean id="messageListener" class="org.springframework.data.redis.listener.adapter.MessageListenerAdapter">
        <property name="delegate" ref="dataSyncEventListener"/>
        <property name="serializer" ref="stringRedisSerializer"/>
        <!--<property name="serializer" ref="jdkSerializer" />-->
    </bean>

    <!-- 消息监听:其中可以通过method方法自定义—监听实现类中用来处理消息的方法 -->
    <redis:listener-container>
        <!--指定消息处理方法,序列化方式及主题名称-->
        <redis:listener ref="messageListener" method="onMessage" serializer="stringRedisSerializer" topic="channel1.0"/>
        <!--<redis:listener ref="messageListener" method="onMessage" serializer="jdkSerializer" topic="java"/>-->
    </redis:listener-container>

</beans>

四、spring-mvc.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:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-4.3.xsd
       http://www.springframework.org/schema/mvc
       http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd">

    <import resource="classpath:/redis-context.xml"/>
    <!--spring包扫描-->
    <context:component-scan base-package="xin.shenwan.*"/>
    <!--redis配置文件-->
    <context:property-placeholder location="classpath:/redis.properties" file-encoding="utf-8"
                                  ignore-unresolvable="true"/>
    <!--开启springmvc注解支持-->
    <mvc:annotation-driven/>

    <!-- 定义跳转的文件的前后缀 ,视图模式配置-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!-- 自动给后面action的方法return的字符串加上前缀和后缀,变成一个 可用的url地址 -->
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

    <!--对静态资源不做拦截,交给web容器-->
    <mvc:default-servlet-handler/>

</beans>

五、web.xml配置如下(仅供参考,看实际情况配置)

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
        http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
  <!-- Spring和mybatis的配置文件 -->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:spring-mybatis.xml</param-value>
  </context-param>

  <!-- 编码过滤器 -->
  <filter>
    <filter-name>encodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <async-supported>true</async-supported>
    <init-param>
      <param-name>encoding</param-name>
      <param-value>UTF-8</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>encodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

  <!-- Spring监听器 -->
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <!-- 防止Spring内存溢出监听器 -->
  <listener>
    <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
  </listener>

  <!--Spring MVC servlet-->
  <servlet>
    <servlet-name>SpringMVC</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:spring-mvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
    <async-supported>true</async-supported>
  </servlet>
  <servlet-mapping>
    <servlet-name>SpringMVC</servlet-name>
    <!-- 此处可以可以配置成*.do,对应struts的后缀习惯 -->
    <url-pattern>/</url-pattern>
  </servlet-mapping>

  <welcome-file-list>
    <welcome-file>/index.jsp</welcome-file>
  </welcome-file-list>

</web-app>

六、新建一个发布信息的类:发布的消息不可以为null,否则redis在set消息时会报NullPointerException

package xin.shenwan.redis;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

/**
 * @author 12450
 */
@Component
public class SendMessage {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 该方法调用redisTemplate发布信息,
     * @param channel 发布信息的频道名称
     * @param message 要发布的信息
     */
    public synchronized void sendMessage(String channel, String message) {
        redisTemplate.convertAndSend(channel, message);
    }


}

七、新建用于监听redis发布并获取到发布信息的监听类(该类实现了redis监听接口)

这里需要注意:实际情况中采用哪一种序列化方式合适就选择哪一种,选择时配置文件中的相关配置也需要进行更改

package xin.shenwan.redis;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import xin.shenwan.socket.RsSocket;

/**
 * @author 12450
 */
public class DataSyncEventListener implements MessageListener {
    @Autowired
    private RedisSerializer<String> stringRedisSerializer;
    @Autowired
    private JdkSerializationRedisSerializer jdkSerializationRedisSerializer;

    /**
     * 需要重写MessageListener的方法
     *
     * @param message
     * @param bytes
     */
    @Override
    public void onMessage(Message message, byte[] bytes) {
        String channel = stringRedisSerializer.deserialize(message.getChannel());
        Object object = stringRedisSerializer.deserialize(message.getBody());
        //采用jdk方式进行序列化
        /*Object channel = jdkSerializationRedisSerializer.deserialize(message.getChannel());
        Object object = jdkSerializationRedisSerializer.deserialize(message.getBody());*/
        System.out.println("channel is :" + channel);
        //向客户端发送的信息
        String messageToUser = object.toString();
        System.out.println("message is :" + messageToUser);
    }
}

八、测试类

package xin.shenwan.controller;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import xin.shenwan.redis.SendMessage;

@Controller
@RequestMapping(value = "/test")
public class RedisTest {
    @Autowired
    SendMessage sendMessage;

    @RequestMapping(value = "/sendMsg")
    public void redis() {
        for (int i = 0; i < 10; i++) {
            sendMessage.sendMessage("channel1.0", "第" + i + "次发送信息");
        }
    }
}

启动项目访问链接,注意看控制台输出:

只是很基础的入门总结,欢迎各位大神提出改进意见。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值