线程池+触发器实现动态创建定时器

用线程池 + 触发器实现动态去创建定时器的功能,仅做参考,有需要的可根据自身的业务需求做相关的调整

(有帮助的话希望支持下)

先贴个流程图:

思路说明:

1、ThreadPoolTaskScheduler:线程池任务调度类,能够开启线程池进行任务调度。
2、ThreadPoolTaskScheduler.schedule():创建一个定时计划ScheduledFuture,在这个方法需要添加两个参数,Runnable(线程接口类) 和CronTrigger(定时任务触发器)
3、在ScheduledFuture中有一个cancel可以停止定时任务。

案例说明:

本例用到6个类:
1、QuatzDynamicScheduled:业务逻辑入口
2、ScheduledRunnable:线程池
3、QuatzScheduled:业务需求,指定时间执行的定时器
4、ScheduledFutureMap:记录创建的定时器
5、MeetingScheduled:业务实体封装
6、MeetingUserScheduled:业务实体封装

注意:相关操作数据库的不贴出来。

所需Jar包: Quartz相关依赖包
源码:

/**
 * 

Description

*

动态创建定时器

* ====================== * ====================== * * @Author created by lgy * @Date 2019/12/19 */
@Component public class QuatzDynamicScheduled implements CommandLineRunner { private static final Logger log = LoggerFactory.getLogger(QuatzDynamicScheduled.class); @Autowired private ThreadPoolTaskScheduler poolTaskScheduler; @Autowired private ITDynamicTimerService dynamicTimerService; @Autowired private IMeetingService meetingService; @Autowired private IMeetingUserService meetingUserService; @Autowired private ITUserAttendeeService userAttendeeService; private ScheduledFuture<?> future; @Bean public ThreadPoolTaskScheduler threadPoolTaskScheduler() { return new ThreadPoolTaskScheduler(); } /** * 关闭触发器. * * @param name * @return */ public void closeDynamicScheduled(String name) { future = ScheduledFutureMap.getFutures().get(name); if (future != null) { future.cancel(true); ScheduledFutureMap.getFutures().remove(name); } } /** * 添加触发器. * * @param meetingScheduled * @param type * @param cron */ public void addScheduled(MeetingScheduled meetingScheduled, Integer type, String cron) { String name = meetingScheduled.getName(); /** * 判断如果触发器已经存在,先关闭再创建新的触发器 * 预防情况: * 1、修改与会人员触发. * 2、修改通知时间触发. */ if (ScheduledFutureMap.getFutures().get(name) != null) { closeDynamicScheduled(name); } ScheduledRunnable scheduledRunnable = new ScheduledRunnable(meetingScheduled, type, name); CronTrigger trigger = new CronTrigger(cron); future = this.poolTaskScheduler.schedule(scheduledRunnable, trigger); ScheduledFutureMap.getFutures().put(name, future); } /** * 添加动态定时器. * * @param meetingScheduled * @param type 0:发送短信 1:发送邮件 2:发送短信和邮件 * @param cron cron规则 * cron表达式中各时间元素使用空格进行分割,表达式有至少6个(也可能7个)分别表示如下含义: *

* 秒(0~59) * 分钟(0~59) * 小时(0~23) * 天(月)(0~31,但是你需要考虑你月的天数) * 月(0~11) * 天(星期)(1~7 1=SUN 或 SUN,MON,TUE,WED,THU,FRI,SAT) * 年份(1970-2099) * 其中每个元素可以是一个值(如6),一个连续区间(9-12),一个间隔时间(8-18/4)(/表示每隔4小时),一个列表(1,3,5),通配符。由于"月份中的日期"和"星期中的日期"这两个元素互斥的,必须要对其中一个设置?. *

* 0 0 10,14,16 * * ? 每天上午10点,下午2点,4点 * 0 0/30 9-17 * * ? 朝九晚五工作时间内每半小时 * 0 0 12 ? * WED 表示每个星期三中午12点 * "0 0 12 * * ?" 每天中午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期间的每1分钟触发 * "0 0/5 14 * * ?" 在每天下午2点到下午2:55期间的每5分钟触发 * "0 0/5 14,18 * * ?" 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发 * "0 0-5 14 * * ?" 在每天下午2点到下午2:05期间的每1分钟触发 * "0 10,44 14 ? 3 WED" 每年三月的星期三的下午2:10和2:44触发 * "0 15 10 ? * MON-FRI" 周一至周五的上午10:15触发 * "0 15 10 15 * ?" 每月15日上午10:15触发 * "0 15 10 L * ?" 每月最后一日的上午10:15触发 * "0 15 10 ? * 6L" 每月的最后一个星期五上午10:15触发 * "0 15 10 ? * 6L 2002-2005" 2002年至2005年的每月的最后一个星期五上午10:15触发 * "0 15 10 ? * 6#3" 每月的第三个星期五上午10:15触发 * @return */ public boolean addScheduledToSendMsg(MeetingScheduled meetingScheduled, Integer type, String cron) { log.info("动态添加定时器,参数列表:{'type':{},'cron':{},'meetingScheduled':{}}", new Object[]{type, cron, meetingScheduled}); if (logicNotNull(meetingScheduled)) { Date notiFyTime = meetingScheduled.getNotifyTime(); addOrUpdateRecordToDataBase(notiFyTime, meetingScheduled.getName()); /*判断 只有为当天的通知时间才创建触发器,否则只添加到数据库*/ if (isToday(notiFyTime.getTime())) { addScheduled(meetingScheduled, type, cron); } return true; } return false; } /** * 添加动态定时器. * * @param meetingScheduled * @param type * @param notifyTime * @return */ public boolean addScheduledToSendMsg(MeetingScheduled meetingScheduled, Integer type, Date notifyTime) { log.info("动态添加定时器,参数列表:{'type':{},'notifyTime':{},'meetingScheduled':{}}", new Object[]{type, notifyTime, meetingScheduled}); Calendar calendar = Calendar.getInstance(); calendar.setTime(notifyTime); int year = calendar.get(Calendar.YEAR), month = calendar.get(Calendar.MONTH), day = calendar.get(Calendar.DATE), hour = calendar.get(Calendar.HOUR_OF_DAY), min = calendar.get(Calendar.MINUTE), sec = calendar.get(Calendar.SECOND); String cron = sec + " " + min + " " + hour + " " + day + " " + month + " ? " + year; addScheduledToSendMsg(meetingScheduled, type, cron); return false; } /** * 添加动态定时器 * * @param meeting * @param userAttendees * @param type * @param cron * @return */ public boolean addScheduledToSendMsg(Meeting meeting, List<UserAttendee> userAttendees, Integer type, String cron) { if (userAttendees != null && userAttendees.size() > 0) { List<MeetingUserScheduled> users = new ArrayList<>(); for (UserAttendee userAttendee : userAttendees) { MeetingUserScheduled user = new MeetingUserScheduled(); user.setEmail(userAttendee.getEmail()); user.setName(userAttendee.getName()); user.setPhone(userAttendee.getPhone()); // 校验用户的非空参数,不满足 直接返回 if (!logicNotNull(user)) { return false; } users.add(user); } MeetingScheduled meetingScheduled = new MeetingScheduled(); meetingScheduled.setEndTime(meeting.getEndTime()); meetingScheduled.setMeetingContent(meeting.getDescription()); meetingScheduled.setMeetingTitle(meeting.getTitle()); meetingScheduled.setRoomName(meeting.getRoomIdName()); meetingScheduled.setStartTime(meeting.getStartTime()); meetingScheduled.setNotifyTime(meeting.getNotificationTime()); meetingScheduled.setName(meeting.getName()); meetingScheduled.setUsers(users); return addScheduledToSendMsg(meetingScheduled, type, cron); } return false; } /** * 添加动态定时器 * * @param meeting * @param userAttendees * @param type * @param notifyTime * @return */ public boolean addScheduledToSendMsg(Meeting meeting, List<UserAttendee> userAttendees, Integer type, Date notifyTime) { if (userAttendees != null && userAttendees.size() > 0) { List<MeetingUserScheduled> users = new ArrayList<>(); for (UserAttendee userAttendee : userAttendees) { MeetingUserScheduled user = new MeetingUserScheduled(); user.setEmail(userAttendee.getEmail()); user.setName(userAttendee.getName()); user.setPhone(userAttendee.getPhone()); // 校验用户的非空参数,不满足 直接返回 if (!logicNotNull(user)) { return false; } users.add(user); } MeetingScheduled meetingScheduled = new MeetingScheduled(); meetingScheduled.setEndTime(meeting.getEndTime()); meetingScheduled.setMeetingContent(meeting.getDescription()); meetingScheduled.setMeetingTitle(meeting.getTitle()); meetingScheduled.setRoomName(meeting.getRoomIdName()); meetingScheduled.setStartTime(meeting.getStartTime()); meetingScheduled.setNotifyTime(meeting.getNotificationTime()); meetingScheduled.setName(meeting.getName()); meetingScheduled.setUsers(users); Calendar calendar = Calendar.getInstance(); calendar.setTime(notifyTime); int year = calendar.get(Calendar.YEAR), month = calendar.get(Calendar.MONTH), day = calendar.get(Calendar.DATE), hour = calendar.get(Calendar.HOUR_OF_DAY), min = calendar.get(Calendar.MINUTE), sec = calendar.get(Calendar.SECOND); String cron = sec + " " + min + " " + hour + " " + day + " " + month + " ? " + year; return addScheduledToSendMsg(meetingScheduled, type, cron); } return false; } /** * 检验会议通知的内容相关字段非空 * * @param meetingScheduled * @return */ private boolean logicNotNull(MeetingScheduled meetingScheduled) { boolean b1 = meetingScheduled.getEndTime() != null, b3 = logicNotNull(meetingScheduled.getMeetingTitle()), b4 = logicNotNull(meetingScheduled.getRoomName()), b5 = meetingScheduled.getStartTime() != null, b6 = meetingScheduled.getUsers() != null && meetingScheduled.getUsers().size() > 0, b7 = meetingScheduled.getNotifyTime() != null, b8 = logicNotNull(meetingScheduled.getName()); if (b1 && b3 && b4 && b5 && b6 && b7 && b8) { return true; } return false; } /** * 校验会议通知用户成员相关字段不为空 * * @param meetingUserScheduled * @return */ private boolean logicNotNull(MeetingUserScheduled meetingUserScheduled) { boolean b1 = meetingUserScheduled.getEmail() != null && !meetingUserScheduled.equals(""), b2 = meetingUserScheduled.getName() != null && !meetingUserScheduled.equals(""), b3 = meetingUserScheduled.getPhone() != null && !meetingUserScheduled.equals(""); if (b1 && b2 && b3) { return true; } return false; } /** * 字符串判断非空 * * @param param * @return */ private boolean logicNotNull(String param) { if (param != null && !param.equals("")) { return true; } return false; } /** * 添加 or 更新 * 定时器记录到数据库 * * @param notifyTime */ private void addOrUpdateRecordToDataBase(Date notifyTime, String name) { try { TDynamicTimer dynamicTimer = new TDynamicTimer(); dynamicTimer.setCreateTime(new Date()); dynamicTimer.setDisable(1); dynamicTimer.setName(name); dynamicTimer.setNotifyTime(notifyTime); Map<String, Object> params = new HashMap<>(); params.put("name", name); List<TDynamicTimer> dynamicTimers = this.dynamicTimerService.selectByMap(params); if (dynamicTimers != null && dynamicTimers.size() > 0) { dynamicTimer.setId(dynamicTimers.get(0).getId()); this.dynamicTimerService.updateById(dynamicTimer); } else { this.dynamicTimerService.insert(dynamicTimer); } } catch (Exception e) { log.error(e.getMessage()); } } /** * 获取当天所有未执行的定时器 * * @return */ private List<TDynamicTimer> findDynamicTimers() { return this.dynamicTimerService.findAllTodayDynamicTimers(); } /** * 根据name获取会议信息. * * @param name * @return */ private Meeting getMeetingsByName(String name) { Meeting meeting = this.meetingService.getMeetingListByName(name); return meeting; } /** * 根据meetingId获取相关与会人员id * * @param meetingId * @return */ private List<Long> findMeetingUsersByMeetingId(Long meetingId) { Map<String, Object> params = new HashMap<>(); params.put("meeting_id", meetingId); List<MeetingUser> meetingUsers = this.meetingUserService.selectByMap(params); List<Long> userIds = new ArrayList<>(); if (meetingUsers != null && meetingUsers.size() > 0) { for (MeetingUser meetingUser : meetingUsers) { userIds.add(meetingUser.getUserId()); } } return userIds; } /** * 根据与会人员id获取用户详情信息. * * @param userIds * @return */ private List<UserAttendee> findMeetingUsersInfoByUserIds(List<Long> userIds) { List<UserAttendee> userAttendees = this.userAttendeeService.selectBatchIds(userIds); return userAttendees; } /** * 判断是否是今天 * * @param time * @return */ private boolean isToday(long time) { return isThisTime(time, "yyyy-MM-dd"); } private boolean isThisTime(long time, String pattern) { Date date = new Date(time); SimpleDateFormat sdf = new SimpleDateFormat(pattern); String param = sdf.format(date);//参数时间 String now = sdf.format(new Date());//当前时间 if (param.equals(now)) { return true; } return false; } /** * 检测未执行的定时器,并创建当天的定时器 */ public void checkUnExecutedTask() { List<TDynamicTimer> dynamicTimers = findDynamicTimers(); if (dynamicTimers != null && dynamicTimers.size() > 0) { for (TDynamicTimer dynamicTimer : dynamicTimers) { /*会议表 && 触发器记录表 关联的业务流水号*/ String name = dynamicTimer.getName(); /** * 1、根据流水号:name 获取相关的 meeting * 2、根据meetingId 获取相关的meetingUsers * 3、调用创建动态定时器方法 */ Meeting meeting = getMeetingsByName(name); if (meeting != null) { List<Long> userIds = findMeetingUsersByMeetingId(meeting.getMeetingId()); if (userIds != null && userIds.size() > 0) { List<UserAttendee> userAttendees = findMeetingUsersInfoByUserIds(userIds); addScheduledToSendMsg(meeting, userAttendees, meeting.getNotifyType(), meeting.getNotificationTime()); } } } } } /** * 应用启动成功后执行该方法 * * @param args * @throws Exception */ @Override public void run(String... args) throws Exception { log.info("应用启动成功,自动检测数据库记录,添加尚未处理的定时器"); checkUnExecutedTask(); } }


/**
 * 

Description

*

线程池

* ====================== * ====================== * * @Author created by lgy * @Date 2019/12/19 */
@Component public class ScheduledRunnable implements Runnable { private static final Logger log = LoggerFactory.getLogger(ScheduledRunnable.class); private MeetingScheduled meetingScheduled; private Integer type; private String name; @Autowired private ITDynamicTimerService dynamicTimerService; public ScheduledRunnable() { } public ScheduledRunnable(MeetingScheduled meetingScheduled, Integer type, String name) { this.meetingScheduled = meetingScheduled; this.type = type; this.name = name; } /*执行完关闭定时器*/ private void closeTimer(String name) { log.info("关闭执行完的定时器"); ScheduledFuture<?> future = ScheduledFutureMap.getFutures().get(name); future.cancel(true); /*修改数据库记录*/ dynamicTimerService.closeDynamicTimers(name); /*移除Map集合的值*/ ScheduledFutureMap.getFutures().remove(name); } @Override public void run() { switch (type.intValue()) { case 0: toSendMsg(this.meetingScheduled); closeTimer(name); break; case 1: toSendEmail(this.meetingScheduled); closeTimer(name); break; case 2: toSendEmailAndMsg(this.meetingScheduled); closeTimer(name); break; default: log.error("请注意type的值:\n0:发送短信 \n1:发送邮件 \n 2:同时发送短信和邮件"); break; } } /*发送短信*/ public void toSendMsg(MeetingScheduled meetingScheduled) { log.info("发送短信,参数列表:{'meetingScheduled':{}}", new Object[]{meetingScheduled}); } /*发送邮件*/ public void toSendEmail(MeetingScheduled meetingScheduled) { log.info("发送邮件,参数列表:{'meetingScheduled':{}}", new Object[]{meetingScheduled}); } /*同时发送短信和邮件*/ public void toSendEmailAndMsg(MeetingScheduled meetingScheduled) { /*发送短信*/ toSendMsg(meetingScheduled); /*发送邮件*/ toSendEmail(meetingScheduled); } public MeetingScheduled getMeetingScheduled() { return meetingScheduled; } public void setMeetingScheduled(MeetingScheduled meetingScheduled) { this.meetingScheduled = meetingScheduled; } public Integer getType() { return type; } public void setType(Integer type) { this.type = type; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
/**
 * 

Description

*

每天执行的定时器

* ====================== * ====================== * * @Author created by lgy * @Date 2019/12/23 */
@Component public class QuatzScheduled { @Autowired private QuatzDynamicScheduled quatzDynamicScheduled; /*每天凌晨0点01分执行*/ @Scheduled(cron = "0 01 00 ? * *") public void everyDay() { this.quatzDynamicScheduled.checkUnExecutedTask(); } }
/**
 * 

Description

*

定时器集合

* ====================== * ====================== * * @Author created by jy * @Date 2019/12/23 */
public class ScheduledFutureMap { private static final Map<String, ScheduledFuture<?>> FUTURES = new HashMap<>(); public static Map<String, ScheduledFuture<?>> getFutures() { return FUTURES; } }
/**
 * 

Description

*

* ====================== * ====================== * * @Author created by jy * @Date 2019/12/19 */
public class MeetingUserScheduled implements Serializable { private String name; private String phone; private String email; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } }
/**
 * 

Description

*

* ====================== * ====================== * * @Author created by jy * @Date 2019/12/19 */
public class MeetingScheduled { /*会议标题*/ private String meetingTitle; /*会议内容*/ private String meetingContent; /*会议开始时间*/ private Date startTime; /*会议结束时间*/ private Date endTime; /*开会会议室名称*/ private String roomName; /*通知开会时间*/ private Date notifyTime; // 业务流水号 private String name; /*通知的与会人员*/ private List<MeetingUserScheduled> users; public String getMeetingTitle() { return meetingTitle; } public void setMeetingTitle(String meetingTitle) { this.meetingTitle = meetingTitle; } public String getMeetingContent() { return meetingContent; } public void setMeetingContent(String meetingContent) { this.meetingContent = meetingContent; } public Date getStartTime() { return startTime; } public void setStartTime(Date startTime) { this.startTime = startTime; } public Date getEndTime() { return endTime; } public void setEndTime(Date endTime) { this.endTime = endTime; } public String getRoomName() { return roomName; } public void setRoomName(String roomName) { this.roomName = roomName; } public List<MeetingUserScheduled> getUsers() { return users; } public void setUsers(List<MeetingUserScheduled> users) { this.users = users; } public Date getNotifyTime() { return notifyTime; } public void setNotifyTime(Date notifyTime) { this.notifyTime = notifyTime; } public String getName() { return name; } public void setName(String name) { this.name = name; } }

你可能感兴趣的:(定时器)