Bootstrap

RabbitMQ基础封装

RabbitMQ池化方案

private void sendKernel(Message message){
        //使用线程池进行异步提交
        AsyncBaseQueue.submit(new Runnable() {
            @Override
            public void run() {
                String topic=message.getTopic();
                String routingKey=message.getRoutingKey();
                CorrelationData correlationData=new CorrelationData(
                        String.format("%s#%s", message.getMessageId(), System.currentTimeMillis())
                );
                rabbitTemplate.convertAndSend(topic,routingKey,message,null,correlationData);
                log.info("#RabbitBrokerImpl.sendKernel# send to rabbitmq, messageid: {}",
                        message.getMessageId());
            }
        });
    }

 虽然实现了线程池,完成了多线程,但是RabbitTemplate是由Spring帮我们注入的,默认是单例的。所以,我们还需要把RabbitTemplate池化

@Slf4j
@Component
public class RabbitTemplateContainer implements RabbitTemplate.ConfirmCallback {
    private Map<String /* TOPIC */, RabbitTemplate> rabbitMap = Maps.newConcurrentMap();

    private Splitter splitter=Splitter.on("#");

    /* 连接工厂 */
    @Autowired
    private ConnectionFactory connectionFactory;

    public RabbitTemplate getTemplate(Message message) throws MessageRuntimeException {
        Preconditions.checkNotNull(message);
        String topic = message.getTopic();
        RabbitTemplate rabbitTemplate = rabbitMap.get(topic);
        if (rabbitTemplate != null) {
            return rabbitTemplate;
        }
        log.info("#RabbitTemplateContainer.getTemplate# topic: {} is not exist, create one",topic);
        RabbitTemplate newRabbitTemplate=new RabbitTemplate(connectionFactory);
        newRabbitTemplate.setRetryTemplate(new RetryTemplate());
        newRabbitTemplate.setRoutingKey(message.getRoutingKey());
        newRabbitTemplate.setExchange(topic);
        // TODO: 2020-02-27 对message的序列化方式
//        newRabbitTemplate.setMessageConverter();

        String messageType=message.getMessageType();
        if(!MessageType.RAPID.equals(messageType)){
            //需要设置callback
            newRabbitTemplate.setConfirmCallback(this);
        }

        rabbitMap.put(topic,newRabbitTemplate);
        return rabbitMap.get(topic);

    }

    @Override
    public void confirm(CorrelationData correlationData, boolean b, String s) {
        // TODO: 2020-02-27 具体的应答
        List<String> strings=splitter.splitToList(correlationData.getId());
        String messageId=strings.get(0);
        long sendTime=Long.parseLong(strings.get(1));
        if (b){
            log.info("send message is OK, confirm messageId: {}, send time: {}",messageId,sendTime);
        }else{
            log.error("send message is Failed, confirm messageId: {}, send time: {}",messageId,sendTime);
        }
    }
}

实现消息异步提交的线程池 

@Slf4j
public class AsyncBaseQueue {
    public static final int THREAD_SIZE = Runtime.getRuntime().availableProcessors();
    public static final int QUEUE_SIZE = 10000;

    public static ExecutorService executorService =
            new ThreadPoolExecutor(THREAD_SIZE, THREAD_SIZE, 60L, TimeUnit.SECONDS,
                    new ArrayBlockingQueue<>(QUEUE_SIZE), new ThreadFactory() {
                @Override
                public Thread newThread(Runnable r) {
                    Thread t = new Thread();
                    t.setName("rabbitmq_client_async_sender");
                    return t;
                }
            }, new RejectedExecutionHandler() {
                @Override
                public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                    log.error("async sender is error rejected, runnable:{}, executor:{}",
                            r, executor);
                }
            });

    public static void submit(Runnable r){
        executorService.submit(r);
    }
}

ThreadLocal实现RabbitMQ消息的批量发送

首先实现一个ThreadLocal类:

public class MessageHolder {
    private List<Message> messages=  new ArrayList<>();

    @SuppressWarnings({"rawtypes","unchecked"})
    public static final ThreadLocal<MessageHolder> holder=new ThreadLocal(){
        @Override
        protected Object initialValue() {
            return new MessageHolder();
        }
    };

    public static void add(Message message){
        holder.get().messages.add(message);
    }

    public static List<Message> clear(){
        List<Message> tmp=new ArrayList<>(holder.get().messages);
        holder.remove();
        return tmp;

    }

}
# ProducerClient.class
	@Override
    public void send(List<Message> messages) throws MessageRuntimeException {
        messages.forEach(message -> {
            message.setMessageType(MessageType.RAPID);
            MessageHolder.add(message);
        });
        rabbitBroker.sendMessages();
    }
# RabbitBrokerImpl.class
	@Override
    public void sendMessages() {
        List<Message> messages=MessageHolder.clear();
        messages.forEach(message -> {
            sendKernel(message);
        });
    }

之前的版本

把批量消息直接放到参数变量里

# ProducerClient.class
	@Override
    public void send(List<Message> messages) throws MessageRuntimeException {
        messages.forEach(message -> {
            message.setMessageType(MessageType.RAPID);
        });
        rabbitBroker.sendMessages(messages);
    }
# RabbitBrokerImpl.class
    @Override
    public void sendMessages(List<Message> messages) {
        messages.forEach(message -> {
            sendKernel(message);
        });
    }

 

;