我们使用Disruptor做消息队列的学习,我们做一个简单的记录。
1.添加依赖
<!--Disruptor-->
<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
<version>3.3.4</version>
</dependency>
2.消息体Model
import lombok.Data;
/**
* @author qx
* @date 2023-05-04
* @Descripion: 消息体Model
*/
@Data
public class MessageModel {
private String message;
}
3.构造EventFactory
import com.lmax.disruptor.EventFactory;
/**
* @author qx
* @date 2023-05-04
* @Descripion: 构造EventFactory
*/
public class HelloEventFactory implements EventFactory<MessageModel> {
@Override
public MessageModel newInstance() {
return new MessageModel();
}
}
4.构造EventHandler-消费者
import com.lmax.disruptor.EventHandler;
import lombok.extern.slf4j.Slf4j;
/**
* @author qx
* @date 2023-05-04
* @Descripion: 构造EventHandler-消费者
*/
@Slf4j
public class HelloEventHandler implements EventHandler<MessageModel> {
@Override
public void onEvent(MessageModel messageModel, long l, boolean b) throws Exception {
Thread.sleep(1000);
log.info("消费者处理消息开始");
if (messageModel != null){
log.info("消费者消费的消息是:{}",messageModel);
}
log.info("消费者处理消息结束");
}
}
5.构造BeanManager
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
* @author qx
* @date 2023-05-04
* @Descripion: 构造BeanManager
*/
@Component
public class BeanManager implements ApplicationContextAware {
private static ApplicationContext applicationContext = null;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
BeanManager.applicationContext = applicationContext;
}
public static ApplicationContext getApplicationContext(){
return applicationContext;
}
public static Object getBean(String name){
return applicationContext.getBean(name);
}
public static <T> T getBean(Class<T> tClass){
return applicationContext.getBean(tClass);
}
}
6.构造MQManager
import com.lmax.disruptor.BlockingWaitStrategy;
import com.lmax.disruptor.RingBuffer;
import com.lmax.disruptor.dsl.Disruptor;
import com.lmax.disruptor.dsl.ProducerType;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @author qx
* @date 2023-05-04
* @Descripion: 构造MQManager
*/
@Configuration
public class MQManager {
@Bean("messageModel")
public RingBuffer<MessageModel> messageModelRingBuffer() {
//定义用于事件处理的线程池, Disruptor通过java.util.concurrent.ExecutorSerivce提供的线程来触发consumer的事件处理
ExecutorService executor = Executors.newFixedThreadPool(2);
//指定事件工厂
HelloEventFactory factory = new HelloEventFactory();
//指定ringbuffer字节大小,必须为2的N次方(能将求模运算转为位运算提高效率),否则将影响效率
int bufferSize = 1024 * 256;
//单线程模式,获取额外的性能
Disruptor<MessageModel> disruptor = new Disruptor<>(factory, bufferSize, executor,
ProducerType.SINGLE, new BlockingWaitStrategy());
//设置事件业务处理器---消费者
disruptor.handleEventsWith(new HelloEventHandler());
// 启动disruptor线程
disruptor.start();
//获取ringbuffer环,用于接取生产者生产的事件
RingBuffer<MessageModel> ringBuffer = disruptor.getRingBuffer();
return ringBuffer;
}
}
7.构造Mqservice和实现类-生产者
/**
* @author qx
* @date 2023-05-04
* @Descripion: 构造Mqservice
*/
public interface DisruptorMqService {
/**
* 消息
* @param message 消息内容
*/
void sayHelloMq(String message);
}
import com.lmax.disruptor.RingBuffer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @author 秦迅
* @date 2023-05-04
* @Descripion: 构造Mqservice实现类
*/
@Service
@Slf4j
public class DisruptorMqServiceImpl implements DisruptorMqService{
@Autowired
private RingBuffer<MessageModel> messageModelRingBuffer;
@Override
public void sayHelloMq(String message) {
log.info("record the message: {}",message);
//获取下一个Event槽的下标
long sequence = messageModelRingBuffer.next();
try {
//给Event填充数据
MessageModel event = messageModelRingBuffer.get(sequence);
event.setMessage(message);
log.info("往消息队列中添加消息:{}", event);
} catch (Exception e) {
log.error("failed to add event to messageModelRingBuffer for : e = {},{}",e,e.getMessage());
} finally {
//发布Event,激活观察者去消费,将sequence传递给改消费者
//注意最后的publish方法必须放在finally中以确保必须得到调用;如果某个请求的sequence未被提交将会堵塞后续的发布操作或者其他的producer
messageModelRingBuffer.publish(sequence);
}
}
}
8.构造测试类及方法
import com.example.disruptordemo.disruptor.DisruptorMqService;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@Slf4j
@SpringBootTest
class DisruptorDemoApplicationTests {
@Autowired
private DisruptorMqService disruptorMqService;
@Test
void contextLoads() throws InterruptedException {
disruptorMqService.sayHelloMq("发送测试消息");
log.info("消息队列已经发送完毕");
//这里停止2000ms是为了确定是处理消息是异步的
Thread.sleep(2000);
}
}
结果
2023-05-04 12:10:34.689 INFO 7856 --- [ main] c.e.d.disruptor.DisruptorMqServiceImpl : record the message: 发送测试消息
2023-05-04 12:10:34.691 INFO 7856 --- [ main] c.e.d.disruptor.DisruptorMqServiceImpl : 往消息队列中添加消息:MessageModel(message=发送测试消息)
2023-05-04 12:10:34.691 INFO 7856 --- [ main] c.e.d.DisruptorDemoApplicationTests : 消息队列已经发送完毕
2023-05-04 12:10:35.691 INFO 7856 --- [pool-1-thread-1] c.e.d.disruptor.HelloEventHandler : 消费者处理消息开始
2023-05-04 12:10:35.691 INFO 7856 --- [pool-1-thread-1] c.e.d.disruptor.HelloEventHandler : 消费者消费的消息是:MessageModel(message=发送测试消息)
2023-05-04 12:10:35.692 INFO 7856 --- [pool-1-thread-1] c.e.d.disruptor.HelloEventHandler : 消费者处理消息结束