首先引入redis的pom引用
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
编写redis配置类
@Configuration @EnableCaching public class RedisConfig extends CachingConfigurerSupport { @Bean @SuppressWarnings(value = { "unchecked", "rawtypes" }) public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) { RedisTemplate<Object, Object> template = new RedisTemplate<>(); template.setConnectionFactory(connectionFactory); FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class); ObjectMapper mapper = new ObjectMapper(); mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY); serializer.setObjectMapper(mapper); // 使用StringRedisSerializer来序列化和反序列化redis的key值 template.setKeySerializer(new StringRedisSerializer()); template.setValueSerializer(serializer); // Hash的key也采用StringRedisSerializer的序列化方式 template.setHashKeySerializer(new StringRedisSerializer()); template.setHashValueSerializer(serializer); template.afterPropertiesSet(); return template; } @Bean public DefaultRedisScript<Long> limitScript() { DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(); redisScript.setScriptText(limitScriptText()); redisScript.setResultType(Long.class); return redisScript; } /** * 限流脚本 */ private String limitScriptText() { return "local key = KEYS[1]\n" + "local count = tonumber(ARGV[1])\n" + "local time = tonumber(ARGV[2])\n" + "local current = redis.call('get', key);\n" + "if current and tonumber(current) > count then\n" + " return tonumber(current);\n" + "end\n" + "current = redis.call('incr', key)\n" + "if tonumber(current) == 1 then\n" + " redis.call('expire', key, time)\n" + "end\n" + "return tonumber(current);"; } /** * redis消息监听器容器 * 可以添加多个监听不同话题的redis监听器,只需要把消息监听器和相应的消息订阅处理器绑定,该 消息监听器 * 通过反射技术调用消息订阅处理器的相关方法进行一些业务处理 * @param connectionFactory * @return */ @Bean RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) { RedisMessageListenerContainer container = new RedisMessageListenerContainer(); container.setConnectionFactory(connectionFactory); return container; } @Bean(initMethod = "init", destroyMethod = "destroy") public RedisMqConsumerContainer redisMqConsumerContainer(RedisTemplate<Object, Object> redisTemplate) { RedisMqConsumerContainer config = new RedisMqConsumerContainer(redisTemplate); config.addConsumer(QueueConfiguration.builder() .queue(QueueName.ENTERPRISE_REGISTER.getKey()) .consumer(new EnterpriseRegisterListener()) .build()); config.addConsumer(QueueConfiguration.builder() .queue(QueueName.BUSINESS_FIRM_LOGO.getKey()) .consumer(new businessfirmListener()) .build()); return config; } }
定义消息生产者
@Component public class QueueSender { private RedisTemplate<Object, Object> redisTemplate; public QueueSender(RedisTemplate<Object, Object> redisTemplate) { this.redisTemplate = redisTemplate; } public void sendMsg(String queue, Object msg) { redisTemplate.opsForList().leftPush(queue, msg); } }
消费队列名
public enum QueueName { /**企业审核通过*/ ENTERPRISE_REGISTER("enterprise_register"), /**企业审核通过*/ BUSINESS_FIRM_LOGO("business_firm_logo"), ; private String key; QueueName(String key){ this.key = key; } }
消息队列配置类
public class QueueConfiguration { /** * 队列名称 */ private String queue; /** * 消费者 */ private MsgConsumer consumer; private QueueConfiguration() { } public static Builder builder() { return new Builder(); } String getQueue() { return queue; } MsgConsumer getConsumer() { return consumer; } public static class Builder { private QueueConfiguration configuration = new QueueConfiguration(); public QueueConfiguration defaultConfiguration(MsgConsumer consumer) { configuration.consumer = consumer; configuration.queue = consumer.getClass().getSimpleName(); return configuration; } public Builder queue(String queue) { configuration.queue = queue; return this; } public Builder consumer(MsgConsumer consumer) { configuration.consumer = consumer; return this; } public QueueConfiguration build() { if (configuration.queue == null || configuration.queue.length() == 0) { if (configuration.consumer != null) { configuration.queue = configuration.getClass().getSimpleName(); } } return configuration; } }
消息接收监听器
public class QueueListener implements Runnable{ public static final Logger log = LoggerFactory.getLogger(QueueListener.class); private RedisTemplate<Object, Object> redisTemplate; private String queue; private MsgConsumer consumer; public QueueListener(RedisTemplate<Object, Object> redisTemplate, String queue, MsgConsumer consumer) { this.redisTemplate = redisTemplate; this.queue = queue; this.consumer = consumer; } @Override public void run() { log.info("QueueListener start...queue:{}", queue); while (RedisMqConsumerContainer.run) { try { Object msg = redisTemplate.opsForList().rightPop(queue, 8, TimeUnit.SECONDS); if (msg != null) { try { consumer.onMessage(msg); } catch (Exception e) { consumer.onError(msg, e); } } } catch (QueryTimeoutException ignored) { log.error("Queue:{}", queue, ignored); } catch (Exception e) { if (RedisMqConsumerContainer.run) { log.error("Queue:{}", queue, e); } else { log.info("QueueListener exits...queue:{}", queue); } } } } }
定义消费接口
public interface MsgConsumer { void onMessage(Object message); void onError(Object msg, Exception e); }
消费者容器
public class RedisMqConsumerContainer { private static final Logger log = LoggerFactory.getLogger(RedisMqConsumerContainer.class); private Map<String, QueueConfiguration> consumerMap = new HashMap<>(); private RedisTemplate<Object, Object> redisTemplate; static boolean run; private ExecutorService exec; public RedisMqConsumerContainer(RedisTemplate<Object, Object> redisTemplate) { this.redisTemplate = redisTemplate; } public void addConsumer(QueueConfiguration configuration) { if (consumerMap.containsKey(configuration.getQueue())) { log.warn("Key:{} this key already exists, and it will be replaced", configuration.getQueue()); } if (configuration.getConsumer() == null) { log.warn("Key:{} consumer cannot be null, this configuration will be skipped", configuration.getQueue()); } consumerMap.put(configuration.getQueue(), configuration); } public void destroy() { run = false; this.exec.shutdown(); log.info("QueueListener exiting."); while (!this.exec.isTerminated()) { } log.info("QueueListener exited."); } public void init() { run = true; this.exec = Executors.newCachedThreadPool(r -> { final AtomicInteger threadNumber = new AtomicInteger(1); return new Thread(r, "RedisMQListener-" + threadNumber.getAndIncrement()); }); consumerMap = Collections.unmodifiableMap(consumerMap); consumerMap.forEach((k, v) -> exec.submit(new QueueListener(redisTemplate, v.getQueue(), v.getConsumer()))); } }
配置消费者
public class businessfirmListener implements MsgConsumer { private static Logger log = LoggerFactory.getLogger(businessfirmListener.class); @Override public void onMessage(Object message) { log.info("企业logo同步状态监听器收到消息:" + message); String id = (String) message; BusinessFirmDo businessFirmDo = new BusinessFirmDo(); businessFirmDo.setId(id); businessFirmDo.setPushStatus(1); IBusinessFirmService bean = SpringUtils.getBean(IBusinessFirmService.class); try { bean.updateBusinessFirm(businessFirmDo); } catch (Exception e) { e.printStackTrace(); } log.info("收到消息:" + message); } @Override public void onError(Object msg, Exception e) { log.error("发生错误,消息:{}", msg, e); } }
生产消息
@Autowired private QueueSender queueSender;
//发送mq,异步修改推送状态为 已推送 queueSender.sendMsg(QueueName.ENTERPRISE_REGISTER.getKey(),"123456");