本文利用阻塞队列实现跑批任务。
队列配置类,可根据业务场景使用不同性质的队列,这里使用的是有界队列阻塞队列LinkedBlockingQueue。LinkedBlockingQueue队列也是按 FIFO(先进先出)排序元素。队列的头部元素是入队时间最长的元素, 队列的尾部元素是在入队时间最短的元素,队列执行获取操作会获得位于队列头部的元素,而新元素会被插入到队列的尾部。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
@Configuration
public class QueueConfig {
@Bean("taskQueue")
public BlockingQueue<TaskModel> taskQueue() {
return new LinkedBlockingQueue<>();
}
}
消费者
public interface QueueConsumer {
int threadSize = 2;
void start();
void stop();
}
消费者实现
import com.alibaba.nacos.common.utils.MapUtils;
import com.thinkive.cfy.cft.financial.scrm.queue.model.ContentSharingStatisticsModel;
import com.thinkive.cfy.cft.financial.scrm.zyzq.dao.StaffForwardStatMapper;
import com.thinkive.cfy.cft.financial.scrm.zyzq.dao.entity.StaffForwardStat;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.concurrent.BlockingQueue;
@Slf4j
@Component
public class TaskConsumer implements QueueConsumer {
@Autowired
@Qualifier("taskQueue")
private BlockingQueue<TaskModel> taskQueue;
int threadSize = 2;
private boolean run;
private TaskThread[] taskThreads;
private class TaskThread extends Thread {
@Override
public void run() {
while (run) {
try {
TaskModel model = taskQueue.take();
if (MapUtils.isEmpty(model.getMdcContextMap())) {
MDC.setContextMap(model.getMdcContextMap());
}
log.info("消费者消息:" + model);
//处理任务逻辑
} catch (Exception e) {
log.error("task消费异常:{}", e);
}
}
}
}
@Override
public void start() {
run = true;
taskThreads = new TaskThread[threadSize];
for (int i = 0; i < threadSize; i++) {
taskThreads [i] = new TaskThread();
taskThreads [i].start();
}
}
@Override
public void stop() {
run = false;
if (taskThreads != null) {
for (TaskThread thread : taskThreads ) {
thread.interrupt();
}
}
}
}
启动类
import com.alibaba.nacos.common.utils.MapUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import javax.annotation.PreDestroy;
import java.util.Map;
@Slf4j
@Component
public class QueueConsumerAware implements ApplicationContextAware {
private static Map<String, QueueConsumer> queueConsumerMap;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
queueConsumerMap = applicationContext.getBeansOfType(QueueConsumer.class);
for (Map.Entry<String, QueueConsumer> entry : queueConsumerMap.entrySet()) {
log.info("启动消费者:" + entry.getKey());
entry.getValue().start();
}
}
@PreDestroy
public void destroy() {
if (!MapUtils.isEmpty(queueConsumerMap)) {
for (Map.Entry<String, QueueConsumer> entry : queueConsumerMap.entrySet()) {
log.info("销毁消费者:" + entry.getKey());
entry.getValue().stop();
}
}
}
}
model抽象类
import java.util.Map;
public abstract class AbstractQueueModel {
private Map<String, String> mdcContextMap;
public Map<String, String> getMdcContextMap() {
return mdcContextMap;
}
public void setMdcContextMap(Map<String, String> mdcContextMap) {
this.mdcContextMap = mdcContextMap;
}
}
task实体
import java.io.Serializable;
import java.util.Date;
@Data
public class ContentSharingStatisticsModel extends AbstractQueueModel implements Serializable {
/**
* 任务主键
*/
private Long tid;
/**
* 业务时间
*/
private String serviceTime;
/**
* 业务内容
*/
private String msg;
}
使用方法:
@Autowired
@Qualifier("taskQueue")
private BlockingQueue<TaskModel> taskQueue;
//在需要的地方注入taskQueue队列,往队列里面添加model
TaskModel model = new TaskModel ();
//set需要的数据
taskQueue.put(model);