之前做的一个同步接口最近需要改成异步接口,开始还以为是消息改成消息队列推送,后来发现其实就是将请求的数据封装放到队列中。然后采用定时器定时的去执行数据。
涉及知识:
spring的定时器任务:
fixedDelay // 在上一个任务完成之后,多久后再次执行:
fixedRate = 2000//定义一个按一定频率执行的定时任务,每隔多少毫秒执行一次
initialDelay = 5000//启动项目后多久开始执行该计划
cron = "0 0 5 * * *" //格式: [秒] [分] [小时] [日] [月] [周] [年]
"0 0 12 * * ?" 每天中午十二点触发
"0 15 10 ? * *" 每天早上10:15触发
"0 15 10 * * ?" 每天早上10:15触发
"0 15 10 * * ? *" 每天早上10:15触发
"0 15 10 * * ? 2005" 2005年的每天早上10:15触发
"0 * 14 * * ?" 每天从下午2点开始到2点59分每分钟一次触发
"0 0/5 14 * * ?" 每天从下午2点开始到2:55分结束每5分钟一次触发
"0 0/5 14,18 * * ?" 每天的下午2点至2:55和6点至6点55分两个时间段内每5分钟一次触发
"0 0-5 14 * * ?" 每天14:00至14:05每分钟一次触发
"0 10,44 14 ? 3 WED" 三月的每周三的14:10和14:44触发
"0 15 10 ? * MON-FRI" 每个周一、周二、周三、周四、周五的10:15触发
BlockingQueue:线程阻塞队列。是一个 高效并且线程安全的队列类
add(E o); //将指定的元素添加到此队列中(如果立即可行),在成功时返回 true,其他情况则抛出 IllegalStateException。
drainTo(Collection<? super E> c); //移除此队列中所有可用的元素,并将它们添加到给定 collection 中。
drainTo(Collection<? super E> c,int maxElements);//最多从此队列中移除给定数量的可用元素,并将这些元素添加到给定 collection 中
offer(E o); //如果可能的话,将指定元素插入此队列中。
offer(E o, long timeout, TimeUnit unit); //将指定的元素插入此队列中,如果没有可用空间,将等待指定的等待时间(如果有必要)。
poll(long timeout, TimeUnit unit); //检索并移除此队列的头部,如果此队列中没有任何元素,则等待指定等待的时间(如果有必要)。
put(E o); //将指定元素添加到此队列中,如果没有可用空间,将一直等待(如果有必要)。
remainingCapacity(); //返回在无阻塞的理想情况下(不存在内存或资源约束)此队列能接受的元素数量;如果没有内部限制,则返回 Integer.MAX_VALUE。
take(); //检索并移除此队列的头部,如果此队列不存在任何元素,则一直等待。
实现过程:
1. 首先写一个普通的类,并加标签@Component,让spring可以扫描到
2. 定义一个public static BlockingQueue<Object> queue = new LinkedBlockingQueue<Object>(1000);的队列。并初始化大小,我这里设为1000
3. 写一个普通的方法。加上spring定时器的注解@Scheduled,设置具体的执行计划。方法中写具体的处理方法
4.在提供出去的接口处添加具体的代码。每次别人访问的时候将请求数据封装成对象添加到队列中。注意:这里要判断队列是否满了。
具体demo:
1. TestTaskService
@Component
public class TestTaskService {
private static Logger log = Logger.getLogger(TestTaskService.class);
public static BlockingQueue<User> queue = new LinkedBlockingQueue<User>(1000);
@Autowired
public TestTaskMapper testTaskMapper;
@Scheduled(fixedRate = 2000, initialDelay = 5000)
public void dealCoupon() {
try {
List<User> list = new ArrayList<User>();
queue.drainTo(list, 50);
if(list.size()>0){
log.info("测试定时器开始。。。。:" + list.size());
for(User o:list){
int age = o.getAge();
String name = o.getName();
try {
testTaskMapper.addUser(name, age);
} catch (Exception e) {
log.info("添加失败"+e);
}
}
}
} catch (Exception e) {
log.error("添加失败" + e, e);
}
}
}
2. TestTaskController
@RequestMapping("/")
@Controller
public class TestTaskController {
@RequestMapping("/task")
@ResponseBody
public String testTask(String name,String password){
try {
appendCoupons(name, Integer.valueOf(password));
} catch (Exception e) {
return "添加失败";
}
return "测试定时任务";
}
private void appendCoupons(String name, int age) throws Exception {
User u=new User();
u.setName(name);
u.setAge(age);
if(TestTaskService.queue.size()>999) {
throw new java.lang.Exception("添加失败");
}else{
TestTaskService.queue.add(u);
}
}
}
3. TestTaskMapper
public interface TestTaskMapper {
public void addUser(@Param("name")String name, @Param("age")int age);
}
4.TestTaskMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.cjx.firstSpringboot.mapper.TestTaskMapper">
<insert id="addUser">
insert into user value (null,#{name},#{age})
</insert>
</mapper>