最近在郵件提醒的業務里,需要根據後臺每個項目的配置定時的向項目聯繫人推送郵件提醒,這時我明白需要定時任務了,作為java小白,我向同事做了咨詢,推薦我使用Quartz,以下便是我在項目里的學習心得。 首先配置文件: 依賴的jar包 <dependency> <groupId>org.quartz-s ...
最近在郵件提醒的業務里,需要根據後臺每個項目的配置定時的向項目聯繫人推送郵件提醒,這時我明白需要定時任務了,作為java小白,我向同事做了咨詢,推薦我使用Quartz,以下便是我在項目里的學習心得。
首先配置文件:
依賴的jar包
<dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>1.8.0</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>3.2.17.RELEASE</version> </dependency>
配置文件:
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor"> <property name="corePoolSize" value="1"/> <property name="maxPoolSize" value="20"/> <property name="queueCapacity" value="100"/> <property name="keepAliveSeconds" value="2000"/> <property name="rejectedExecutionHandler"> <bean class="java.util.concurrent.ThreadPoolExecutor$AbortPolicy"/> </property> </bean> <bean id="quartzManager" class="com.imaster.admin.web.schemajob.QuartzManager"> <property name="scheduler" ref="schedulerManager"/> </bean> <bean id="quartzManagerJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <property name="targetObject" ref="quartzManager"/>
<!--自定義定時管理類的的執行方法, -->
<property name="targetMethod" value="reScheduleJob"/>
<property name="concurrent" value="false"/> </bean> <bean id="cronTriggerBean" class="org.springframework.scheduling.quartz.SimpleTriggerBean"> <property name="jobDetail" ref="quartzManagerJobDetail"/> <!-- 延時0秒 執行任務 --> <property name="startDelay" value="0"/> <!-- 任務執行周期 1min 是自定義定時任務管理類的執行間隔,以毫秒為單位--> <property name="repeatInterval" value="60000"/> </bean> <!-- 總管理類 如果將lazy-init='false'那麼容器啟動就會執行調度程式 --> <bean id="schedulerManager" lazy-init="false" autowire="no" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="triggers"> <list> <ref bean="cronTriggerBean"/> </list> </property> <property name="jobFactory" ref="jobFactory"></property> <property name="taskExecutor" ref="taskExecutor"/> </bean> <!--註意標記有背景色的這兩行很重要是為了在執行方法中能夠註入到需要的service--> <bean id="jobFactory" class="com.imaster.admin.web.schemajob.JobAdapter"></bean>
quartzManager定義自己的的定時器管理類
1.讀取資料庫的定時任務的設置數據
2.添加新的定時任務
3.刪除已取消的定時任務
4.更新已有的定時任務
package com.imaster.admin.web.schemajob; import com.imaster.admin.model.vo.TaskVo; import com.imaster.admin.shared.service.version2.ExhibitorReserveExhibitionService; import com.imaster.constant.ApplicationConfig; import com.imaster.shared.enums.TaskTypeEnum; import com.imaster.shared.model.ExhibitorReserveExhibition; import org.quartz.JobDataMap; import org.quartz.JobDetail; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.slf4j.Logger; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.quartz.CronTriggerBean; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @Author wanghh * 2020/5/9 11:45 */ public class QuartzManager implements BeanFactoryAware { private static final Logger logger = org.slf4j.LoggerFactory.getLogger(ApplicationConfig.SERVER_NAME); private Scheduler scheduler; private static BeanFactory beanFactory; @Autowired ExhibitorReserveExhibitionService reserveExhibitionService; /** * 定時要執行的方法類。 */ public void reScheduleJob() { // 1.讀取資料庫中的任務列表。 //獲取簡訊定時任務 List<ExhibitorReserveExhibition> list = reserveExhibitionService.selectList(null); for (ExhibitorReserveExhibition item : list ) { TaskVo taskVo = new TaskVo(); taskVo.setTaskId(item.getId()); taskVo.setTaskType(TaskTypeEnum.EXHIBITOR_RESERVE.getCode()); taskVo.setCronExpression(String.format("0 %s %s * * ? ",item.getAcceptEmailMinute(),item.getAcceptEmailHour())); if (item.getDeleted() == 1 || item.getEnabled() == 0||item.getAcceptEmailRuleTime()==0) { //去掉過時的任務 removeExpireTasks(taskVo); } else { configSchedul(taskVo); } } } /** * 移除過期任務 * * @param bo */ private void removeExpireTasks(TaskVo bo) { try { CronTriggerBean trigger = (CronTriggerBean) scheduler.getTrigger(bo.getTaskId() + "name" + bo.getTaskType(), Scheduler.DEFAULT_GROUP); if (trigger != null) { logger.info("==移除任務==" + bo.getTaskId() + "name" + bo.getTaskType()); scheduler.pauseTrigger(trigger.getName(), trigger.getGroup());// 停止觸發器 scheduler.unscheduleJob(trigger.getName(), trigger.getGroup());// 移除觸發器 scheduler.deleteJob(trigger.getJobName(), trigger.getJobGroup());// 刪除任務 } } catch (SchedulerException e) { logger.error("移除任務失敗..."); e.printStackTrace(); } } /** * 配置任務列表 * * @param bo */ private void configSchedul(TaskVo bo) { try { CronTriggerBean trigger = (CronTriggerBean) scheduler.getTrigger(bo.getTaskId() + "name" + bo.getTaskType(), Scheduler.DEFAULT_GROUP); if (trigger == null) {//說明schedule中不存在該定時任務 createTriggerTask(bo); } else { updateTriggerTask(bo, trigger); } } catch (SchedulerException e) { logger.error("獲取觸發器trigger失敗..."); e.printStackTrace(); } } /** * 更新任務列表 * * @param bo */ private void updateTriggerTask(TaskVo bo, CronTriggerBean trigger) { try { // 判斷從DB中取得的任務時間和現在的quartz線程中的任務時間是否相等 // 如果相等,則表示用戶並沒有重新設定資料庫中的任務時間,這種情況不需要重新rescheduleJob if (trigger.getCronExpression() != null && !trigger.getCronExpression().equalsIgnoreCase(bo.getCronExpression())) { logger.info("=真正更新方法:=" + bo.getTaskId() + "name" + bo.getTaskType()); trigger.setCronExpression(bo.getCronExpression()); scheduler.rescheduleJob(bo.getTaskId() + "name" + bo.getTaskType(), Scheduler.DEFAULT_GROUP, trigger); logger.info("更新任務時間失敗..."); } } catch (Exception e) { logger.error("更新任務時間失敗..."); e.printStackTrace(); } } /** * 創建任務列表 * * @param bo */ private void createTriggerTask(TaskVo bo) { logger.info("=創建:=" + bo.getTaskId() + "name" + bo.getTaskType()); try { Class clazz = QuartzJobFactory.class;//執行計劃任務的類 JobDetail jobDetail = new JobDetail(bo.getTaskId() + "", clazz); Map map = new HashMap(); map.put("task", bo); jobDetail.setJobDataMap(new JobDataMap(map)); jobDetail.setName(bo.getTaskId() + "name" + bo.getTaskType()); scheduler.addJob(jobDetail, true); // 將Job添加到管理類 // 新一個基於Spring的時間類 CronTriggerBean c = new CronTriggerBean(); c.setCronExpression(bo.getCronExpression());// 設置時間表達式 c.setName(bo.getTaskId() + "name" + bo.getTaskType());// 設置名稱 c.setJobDetail(jobDetail);// 註入Job c.setJobName(bo.getTaskId() + "name" + bo.getTaskType());// 設置Job名稱 scheduler.scheduleJob(c);// 註入到管理類 scheduler.rescheduleJob(bo.getTaskId() + "name" + bo.getTaskType(), Scheduler.DEFAULT_GROUP, c);// 刷新管理類 } catch (Exception e) { logger.error("創建" + bo.getTaskId() + "name" + bo.getTaskType() + "任務失敗..."); e.printStackTrace(); } } @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { QuartzManager.beanFactory = beanFactory; } public Scheduler getScheduler() { return scheduler; } public QuartzManager setScheduler(Scheduler scheduler) { this.scheduler = scheduler; return this; } public static BeanFactory getBeanFactory() { return beanFactory; } }QuartzManager
QuartzJobFactory 定義了具體定時任務的執行管理
所有的定時任務都會在時間點執行這個類的execute(),然後我們根據定時任務的TaskType來確定具體的任務,另外註意我這邊是直接將我的參數作為taskId了,所有我傳入的參數是taskId,如果可以根據自己的業務需要在TaskVO中補充自己的參數
package com.imaster.admin.web.schemajob; import com.alibaba.fastjson.JSON; import com.imaster.admin.model.vo.TaskVo; import com.imaster.admin.web.biz.ExhibitorReserveBiz; import com.imaster.constant.ApplicationConfig; import com.imaster.shared.enums.TaskTypeEnum; import org.quartz.Job; import org.quartz.JobDataMap; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.slf4j.Logger; import org.springframework.beans.factory.annotation.Autowired; /** * @Author wanghh * 2020/5/9 12:07 */ public class QuartzJobFactory implements Job { private static final Logger logger = org.slf4j.LoggerFactory.getLogger(ApplicationConfig.SERVER_NAME); @Autowired private ExhibitorReserveBiz exhibitorReserveBiz; @Override public void execute(JobExecutionContext context) throws JobExecutionException { JobDataMap jobDataMap = context.getJobDetail().getJobDataMap(); TaskVo taskVo = (TaskVo) jobDataMap.get("task"); logger.info("定時任務開始執行。。。。。。。。。。。" + JSON.toJSONString(taskVo)); if (TaskTypeEnum.EXHIBITOR_RESERVE.getCode().equals(taskVo.getTaskType())) { logger.info("zhangshangbaoming job=======" + taskVo.getTaskId()); exhibitorReserveBiz.sendAcceptTimeEmail(taskVo.getTaskId()); //msgSendSchemaService.sendSchemaMsg(taskVo.getTaskId()); } } }QuartzJobFactory
JobAdapter 這個類其實我沒有明白,只能邯鄲學步,請見諒,看別人的註釋吧。
package com.imaster.admin.web.schemajob; import org.quartz.spi.TriggerFiredBundle; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.scheduling.quartz.AdaptableJobFactory; /** * @Author wanghh * 2020/5/11 10:17 */ public class JobAdapter extends AdaptableJobFactory { @Autowired private AutowireCapableBeanFactory capableBeanFactory; @Override protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception { //調用父類的方法 Object jobInstance = super.createJobInstance(bundle); //進行註入 capableBeanFactory.autowireBean(jobInstance); return jobInstance; } }
TaskVo 實體類
package com.imaster.admin.model.vo; import lombok.Data; /** * @Author wanghh * 2020/5/9 11:50 */ @Data public class TaskVo { public String taskId; public String taskType; public String cronExpression; public String state; }TaskVo
以上就是我本次需求的處理,說實話,我只是在照葫蘆畫瓢,以後的項目之餘我會逐步的去補充。
另外我和原創都是單台的伺服器,所以沒有考慮到集群的情況下。
原創地址:https://www.cnblogs.com/likun10579/p/10896831.html
謝謝挖坑大王的分享。@挖坑大王