自定义注解监听redis队列


import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
import org.springframework.stereotype.Component;

import java.io.Serializable;
import java.lang.annotation.*;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;

@Slf4j
@Configuration
@Component
@SuppressWarnings("unused")
public class RedisQueueScanEvent implements ApplicationListener<ContextRefreshedEvent> {

    static final ConcurrentHashMap<String, AdapterConsumer> REDIS_QUEUE_LISTENER = new ConcurrentHashMap<>();

    @Autowired
    RedisConnectionFactory redisConnectionFactory;

    @Bean
    RedisMessageListenerContainer redisMessageListenerContainer() {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(redisConnectionFactory);
        return container;
    }

    @Autowired
    RedisMessageListenerContainer redisMessageListenerContainer;

    public static class Message implements Serializable {
        private static final long version = 1L;
        private final byte[] body;

        public Message(byte[] body) {
            this.body = body;
        }

        public byte[] getBody() {
            return body;
        }
    }

    @Target({ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface RedisQueue {
        String[] queues();
    }

    static class AdapterConsumer implements Serializable {
        private static final long version = 1L;
        private final CountDownLatch latch;
        private final String queueName;
        private final Object bean;
        private final Method method;

        public AdapterConsumer(CountDownLatch latch, String queueName, Object bean, Method method) {
            this.latch = latch;
            this.queueName = queueName;
            this.bean = bean;
            this.method = method;
        }

        /**
         * 队列消息接收方法
         */
        public void consumeMessage(String json) {
            log.info(String.format("redis队列名:%s,消息内容:%s", queueName, json));
            try {
                method.invoke(bean, new Message(json.getBytes(StandardCharsets.UTF_8)));
            } catch (Exception e) {
                log.error(String.format("消费redis消息队列数据失败,失败信息:%s", e));
                //推送失败的话可以保存到数据库,然后定时推送
            } finally {
                latch.countDown();
            }
        }
    }

    void addRedisMessageListenerContainer() {
        REDIS_QUEUE_LISTENER.forEach((queueName, consumer) -> {
            MessageListenerAdapter messageListenerAdapter = new MessageListenerAdapter(consumer, "consumeMessage");
            messageListenerAdapter.afterPropertiesSet();
            redisMessageListenerContainer.addMessageListener(messageListenerAdapter, new PatternTopic(queueName));
        });
        redisMessageListenerContainer.afterPropertiesSet();
    }

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        // 根容器为Spring容器
        if (Objects.nonNull(event.getApplicationContext().getParent())) {
            return;
        }
        Map<String, Object> beans = event.getApplicationContext().getBeansWithAnnotation(Component.class);
        for (Object bean : beans.values()) {
            Method[] methods = bean.getClass().getMethods();
            for (Method declaredMethod : methods) {
                Class<?>[] parameterTypes = declaredMethod.getParameterTypes();
                if (parameterTypes.length == 1 && parameterTypes[0].isAssignableFrom(Message.class)) {
                    RedisQueue ma = AnnotationUtils.findAnnotation(declaredMethod, RedisQueue.class);
                    if (Objects.nonNull(ma)) {
                        for (String queueName : ma.queues()) {
                            REDIS_QUEUE_LISTENER.put(queueName, new AdapterConsumer(new CountDownLatch(1), queueName, bean, declaredMethod));
                        }
                    }
                }
            }
        }
        addRedisMessageListenerContainer();
    }

}
命令行向队列写入消息
redis-cli
publish fincmp.adapter.queue '{"name":"zs","age":18}'

写入队列


import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.JedisPoolConfig;

import java.nio.charset.StandardCharsets;

public class RedisUtil {

    /**
     * 1.配置连接池参数
     */
    public static JedisPoolConfig getPoolConfig() {
        JedisPoolConfig jedisPoolConfig = new redis.clients.jedis.JedisPoolConfig();
        jedisPoolConfig.setMaxTotal(1024);
        jedisPoolConfig.setMaxIdle(100);
        jedisPoolConfig.setMinEvictableIdleTimeMillis(50000);
        jedisPoolConfig.setTimeBetweenEvictionRunsMillis(20000);
        jedisPoolConfig.setNumTestsPerEvictionRun(-1);
        jedisPoolConfig.setSoftMinEvictableIdleTimeMillis(10000);
        jedisPoolConfig.setMaxWaitMillis(1000);
        jedisPoolConfig.setTestOnBorrow(true);
        jedisPoolConfig.setTestWhileIdle(true);
        jedisPoolConfig.setTestOnReturn(false);
        jedisPoolConfig.setJmxEnabled(true);
        jedisPoolConfig.setJmxNamePrefix("pool");
        jedisPoolConfig.setBlockWhenExhausted(false);
        return jedisPoolConfig;
    }

    /**
     * 2.获取连接工厂
     */
    public static JedisConnectionFactory getConnectionFactory(JedisPoolConfig poolConfig) {
        JedisConnectionFactory jedisConnectFactory = new JedisConnectionFactory();
        //必须执行这个函数,初始化RedisTemplate
        jedisConnectFactory.afterPropertiesSet();
        return jedisConnectFactory;
    }

    /**
     * 3.获取RedisTemplate实例
     */
    public static RedisTemplate<String, String> getRedisTemplate(JedisConnectionFactory connectionFactory) {
        RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(connectionFactory);
        StringRedisSerializer serializer = new StringRedisSerializer();
        redisTemplate.setDefaultSerializer(serializer);
        redisTemplate.setKeySerializer(serializer);
        redisTemplate.setValueSerializer(serializer);

        //必须执行这个函数,初始化RedisTemplate
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

    public static void main(String[] args) {
        String queueName = "a";
        String data = "{\"name\":\"张三\",\"age\":18}";
        //1.配置连接池参数
        JedisPoolConfig poolConfig = getPoolConfig();
        //2.获取连接工厂
        JedisConnectionFactory connectionFactory = getConnectionFactory(poolConfig);
        connectionFactory.getConnection().publish(queueName.getBytes(StandardCharsets.UTF_8), data.getBytes(StandardCharsets.UTF_8));
    }
}

Java执行shell命令


import java.io.*;
import java.nio.charset.StandardCharsets;

@SuppressWarnings("unused")
public class Message {

    public Message() {
        throw new IllegalStateException("Utility class");
    }

    public static void main(String[] args) {
        String s = runCmdByRuntime("D:\\apps\\Redis\\redis-cli", "publish a '{\"name\":\"张三\",\"age\":18}'");
        System.out.println(s);
    }

    private static String getReaderLineString(InputStream in) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8));
        if (!br.ready()) {
            return "";
        }
        StringBuilder sb = new StringBuilder();
        String curStr;
        while ((curStr = br.readLine()) != null) {
            sb.append(curStr).append("\n");
        }
        return sb.toString();
    }

    public static String runCmdByRuntime(String... cmds) {
        StringBuilder stdOutput = new StringBuilder();
        Process proc = null;
        OutputStream out = null;
        InputStream err = null;
        InputStream in = null;
        try {
            Runtime runtime = Runtime.getRuntime();
            proc = runtime.exec(cmds[0]);
            out = proc.getOutputStream();
            err = proc.getErrorStream();
            in = proc.getInputStream();
            for (int i = 1; i < cmds.length; i++) {
                out.write(cmds[i].getBytes(StandardCharsets.UTF_8));
                out.flush();
            }
            out.close();
            stdOutput.append(getReaderLineString(err));
            stdOutput.append(getReaderLineString(in));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (proc != null) {
                    proc.destroyForcibly();
                }
                if (in != null) {
                    in.close();
                }
                if (err != null) {
                    err.close();
                }
                if (out != null) {
                    out.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return stdOutput.toString();
    }
}

你可能感兴趣的:(java,redis,java)