java实现redis消息订阅与发布(一)

redis消息订阅与发布

redis除了做缓存外,还提供了消息订阅发布的功能。
redis是绝大多数系统都会引入的中间件,如果项目中仅仅是一小块部分需要消息订阅与发布功能,特地为此引入消息中间件有点太重了,因此,使用redis做消息订阅与发布性价比更高。

Java实现redis的订阅与发布

@Configuration
@EnableCaching
public class RedisConfiguration extends CachingConfigurerSupport {

    /**
     * 驱动事件监听容器线程
     * <p>
     * 这里为了线程安全,用一个线程来监听。而且这里不需要很大的并发~
     *
     * @return SimpleAsyncTaskExecutor
     */
    @Bean
    public ThreadPoolExecutor simpleEventAsyncTaskExecutor() {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 10, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10));
        return executor;
    }

    /**
     * redis消息监听器容器
     * 可以添加多个去监听不同话题的redis监听器,只需要把消息监听器和相应的消息订阅处理器绑定,
     * 该消息监听器通过反射技术调用消息订阅处理器的相关方法进行一些业务处理
     *
     * @param connectionFactory            RedisConnectionFactory
     * @param catAdapter                   MessageListenerAdapter
     * @param fishAdapter                  MessageListenerAdapter
     * @param executor                     ThreadPoolExecutor
     * @return RedisMessageListenerContainer
     */
    @Bean
    RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory,
                                            MessageListenerAdapter catAdapter,
                                            MessageListenerAdapter fishAdapter,
                                            ThreadPoolExecutor executor) {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);
        // 设置线程池
        container.setTaskExecutor(executor);
        // 这个container 可以添加多个 messageListener 订阅了一个叫cat 的通道
        container.addMessageListener(catAdapter, new PatternTopic(Channel.Cat_Channel.getChannel()));
        container.addMessageListener(fishAdapter, new PatternTopic(Channel.fish_Channel.getChannel()));
        return container;
    }

    /**
     * 消息监听器适配器,绑定消息处理器
     *
     * @param redisTemplate RedisTemplate
     * @return MessageListenerAdapter
     */
    @Bean
    MessageListenerAdapter catAdapter(RedisTemplate redisTemplate) {
        return new MessageListenerAdapter(new CatListener(redisTemplate));
    }

    /**
     * 消息监听器适配器,绑定消息处理器
     *
     * @param redisTemplate RedisTemplate
     * @return MessageListenerAdapter
     */
    @Bean
    MessageListenerAdapter fishAdapter(RedisTemplate redisTemplate) {
        return new MessageListenerAdapter(new FishListener(redisTemplate));
    }

    @Bean
    StringRedisTemplate stringRedisTemplate(RedisConnectionFactory connectionFactory) {
        return new StringRedisTemplate(connectionFactory);
    }

    @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        // 使用Jackson2JsonRedisSerialize 替换默认序列化
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
        // 设置value的序列化规则和 key的序列化规则
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

}
@Component
@Slf4j
public class CatListener implements MessageListener {

    private final RedisTemplate redisTemplate;

    public CatListener(RedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    @Override
    public void onMessage(Message message, byte[] bytes) {
        log.debug("CatListener message: {}", message.toString());
    }
}

@Component
@Slf4j
public class FishListener implements MessageListener {

    private final RedisTemplate redisTemplate;

    public FishListener(RedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    @Override
    public void onMessage(Message message, byte[] bytes) {
        log.debug("FishListener message: {}", message.toString());
    }
}
@EnableScheduling
@Component
public class MessageSender {

    private final StringRedisTemplate stringRedisTemplate;

    public MessageSender(StringRedisTemplate stringRedisTemplate) {
        this.stringRedisTemplate = stringRedisTemplate;
    }

    /**
     * 间隔2s 通过StringRedisTemplate对象向redis消息队列cat频道发布消息
     */
    @Scheduled(fixedRate = 5000)
    public void sendCatMessage() {
        stringRedisTemplate.convertAndSend(Channel.Cat_Channel.getChannel(), "i am cat");
    }

    /**
     * 间隔1s 通过StringRedisTemplate对象向redis消息队列fish频道发布消息
     */
    @Scheduled(fixedRate = 10000)
    public void sendFishMessage() {
        stringRedisTemplate.convertAndSend(Channel.fish_Channel.getChannel(), "i am fish");
    }

}
public enum Channel {

    Cat_Channel("cat"),
    fish_Channel("fish");

    private String channel;

    Channel(String channel) {
        this.channel = channel;
    }

    public String getChannel() {
        return this.channel;
    }
}

配置文件

spring:
  redis:
    host: ${SPRING_REDIS_HOST:localhost}
    port: ${SPRING_REDIS_PORT:6379}
    database: ${SPRING_REDIS_DATABASE:1}
    password: ${SPRING_REDIS_PASSWORD:}
    jedis:
      pool:
        # 资源池中最大连接数
        # 默认8-1表示无限制;可根据服务并发redis情况及服务端的支持上限调整
        max-active: ${SPRING_REDIS_POOL_MAX_ACTIVE:50}
        # 资源池运行最大空闲的连接数
        # 默认8-1表示无限制;可根据服务并发redis情况及服务端的支持上限调整,一般建议和max-active保持一致,避免资源伸缩带来的开销
        max-idle: ${SPRING_REDIS_POOL_MAX_IDLE:50}
        # 当资源池连接用尽后,调用者的最大等待时间(单位为毫秒)
        # 默认 -1 表示永不超时,设置5秒
        max-wait: ${SPRING_REDIS_POOL_MAX_WAIT:5000}
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值