基于Springboot的定时任务quartz用法有感

抽象思维、差异化接口提取以及反射的应用

虽然刚入门java的时候。我们就会学到类似于面向对象、面向接口。
方法重载重写的理论知识。
但是在实际的处理业务的过程中。为了开发进度的需要或者种种原因。
我们能体现这种面向接口。提取公共方法以及差异化接口的地方的确少之又少。
最主要的是思维认知的缺乏和时间的不允许。最起码在于我是这么认为的。
这次的项目我要记录一下。
因为我在顾问的帮助下运用到抽象提取接口。然后差异化代码加上反射的方式。
实现了定时任务的操作。
并且实现了其中的业务job与管理job的分离。
其中业务job又拆分出共通代码来增强代码的简洁程度。

detail

具体业务是这样的:主要是实现数据实时定时抽取。然后写入csv并上传服务器的操作。其中定时配置,包括要抽取的表名、sql、间隔时间、开始时间都在数据库里动态配置。
所以。业务都是共通的一套业务。业务上的唯一不同就是要抽取的表名不同 了。
主要的难点是如何设计动态的根据数据库里的配置来增加job这一层。以及代码的简洁程度和可扩展性。

具体最后的实现方法逻辑是这样的。

一共有两层定时任务。一层管理用任务。一层工作用任务。
管理层任务job负责首次把数据库里的配置job动态加载到Scheduler中、以及定时刷新既有job的配置。因为每一个抽取业务的定时信息配置都会在画面当中实时变化。
工作用任务负责调用具体的业务类型job。比如说分类表抽取、商品表抽取等等。
这样。既满足了实时刷新配置属性的功能。又能满足实时定时抽取数据的业务需要。

其中管理层job比较简单。就是项目启动。在Scheduler中加入管理job就好。
重点在于工作用job。不可能 每一个表都得建立一套job机制来满足。因为本身业务是有共同性的。就是写文件上传。
怎么能使代码更简洁、更有层次、更有扩展性的来做好工作用job是一个值得考虑的地方。

首先我们可以这样做。每个业务数据抽取指定相同的job类。意思是不管数据库里有几张表。要抽几个表的数据。我们都把他归于工作用job里。然后我们在工作用 job中根据不同表名来调用不同的类名实现业务调用。

再然后。我们现在到了工作用job中。因为每个具体业务都有写入csv然后上传至ftp的操作。唯一不同的是每个表对应的sql文查出来的bean可能会有所不同 。上传ftp都是相同的。这样。我们又可以抽象出来一个业务操作类。
重点的是。在业务操作类中。根据表名取到全类名。利用反射机制拿到不同的业务job类对象。执行对象的写入csv操作。然后再业务操作类中执行相同的上传操作。
这样首先是很繁琐。有几个表名就得有几个对象。这样我们就考虑一下。面向接口来编程。我们所有的业务job都实现相同 的接口。这下我们根据反射获取的业务job全类名就只有一个了。根据不同的全类名调用 的业务job又是我们想要的job。这样代码变的既简洁明了。又使业务操作类更有了可维护性和可扩展性。不失为一种好方法。这就是具体的面向接口。并且去提取公共方法和差异化代码的实现。

可能语言总结的还有欠缺。但是贴上代码就会好很多了。
下来就是贴几段主要的方式代码。

启动类

package cn.com.winpeace.kiban.web;

import cn.com.winpeace.kiban.winperpsrv.allofpackages.CheckHead;
import cn.com.winpeace.kiban.winperpsrv.persistence.dao.AllPackagesMapper;
import cn.com.winpeace.kiban.winperpsrv.persistence.model.RealCrtMaterResultDO;
import cn.com.winpeace.kiban.winperpsrv.schedulerManager.SchedulerManager;
import cn.com.winpeace.kiban.winperpsrv.test.QuartzTriggerZero;
import cn.com.winpeace.kiban.winperpsrv.vo.JobInfoDto;
import org.quartz.Scheduler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import tk.mybatis.spring.annotation.MapperScan;

import java.util.ArrayList;
import java.util.List;

/**
 * @author nehcoab
 * @date 2018/7/13
 */
@SpringBootApplication
@ComponentScan({"cn.com.winpeace.kiban"})
@MapperScan({"cn.com.winpeace.kiban.*.persistence.dao"})
public class Application {



    public static void main(String[] args) throws Exception {
        SpringApplication.run(Application.class, args);

        //执行校验操作
        CheckHead checkHead = new CheckHead();
        //checkHead.checkSystemConfig();


        //增加管理数据job
        RealCrtMaterResultDO realCrtMaterResultDO =
                new RealCrtMaterResultDO("RefreshJobManager", "RefreshJobManager","2019-10-13",
                        "09:16:10", 15, "1", "1",
                        "cn.com.winpeace.kiban.winperpsrv.allofpackages.ConfigurationJob");

        // 任务管理启动
        Scheduler scheduler = SchedulerManager.getScheduler();
        SchedulerManager.addManagerJob(scheduler, realCrtMaterResultDO);
        SchedulerManager.run(scheduler, 0);


    }
}

管理用job代码:

package cn.com.winpeace.kiban.winperpsrv.allofpackages;
/**
 * @ClassName ConfigurationJob
 * @Description TODO
 * @Author YPF
 * @Date 2019/9/2814:04
 * @Version 1.0
 */

import cn.com.winpeace.kiban.winperpsrv.logger.MySchedulerTestLogger;
import cn.com.winpeace.kiban.winperpsrv.persistence.dao.AllPackagesMapper;
import cn.com.winpeace.kiban.winperpsrv.persistence.model.RealCrtMaterResultDO;
import cn.com.winpeace.kiban.winperpsrv.schedulerManager.SchedulerManager;
import cn.com.winpeace.kiban.winperpsrv.test.QuartzTriggerZero;
import cn.com.winpeace.kiban.winperpsrv.vo.JobInfoDto;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.*;

/**
 * @ClassName ConfigurationJob
 * @Description peizhiJOB 实时数据配置任务。实时配置调度刷新表实时任务
 * @Author YPF
 * @Date 2019/9/2814:04
 * @Version 1.0
 **/
@Component
public class ConfigurationJob implements Job{

	@Autowired
	AllPackagesMapper allPackagesMapper;

	public static ConfigurationJob configurationJob;

	@PostConstruct
	public void init() {
		configurationJob = this;
	}

	@Override
	public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
		MySchedulerTestLogger.log("实时配置数据刷新 is begin-----------------");
		refresh(jobExecutionContext);
		MySchedulerTestLogger.log("实时配置数据刷新 is end-----------------");
	}
	private void refresh(JobExecutionContext jobExecutionContext) {
		try {
			//最新任务管理数据读入
			List<RealCrtMaterResultDO> realCrtMaterResultDOS = configurationJob.allPackagesMapper.selectConfigurationMessage();

			//获取调度器
			Scheduler scheduler = jobExecutionContext.getScheduler();
			for(RealCrtMaterResultDO newJobInfo : realCrtMaterResultDOS){
				//获取job任务明细
				JobDetail job = SchedulerManager.getJobDetail(scheduler, newJobInfo);
				if(job==null){
					if(newJobInfo.getCron_status().toString().equals("1") && newJobInfo.getValid_status().toString().equals("1")){
						//新规job 或 job再次开始
						MySchedulerTestLogger.log("实时配置数据 is new JOB!" + newJobInfo.getCustomer_id() + "."
								+ newJobInfo.getIf_id());
						SchedulerManager.addJob(scheduler,newJobInfo);
					}
				}else{
					RealCrtMaterResultDO oldJobInfo = SchedulerManager.getJobInfo(job);
					if((oldJobInfo.getCron_status().toString().equals("0") && newJobInfo.getCron_status() .toString().equals("1"))
						|| (oldJobInfo.getValid_status().toString().equals("0") && newJobInfo.getValid_status() .toString().equals("1"))){
						//job状态从关闭改为激活。 job开始执行
						MySchedulerTestLogger.log("ReschedulerJob is OFF -> ON!" + job.getKey());
					}else if ((oldJobInfo.getCron_status() .toString().equals("0") && newJobInfo.getCron_status() .toString().equals("0"))
						|| (oldJobInfo.getValid_status() .toString().equals("0") && newJobInfo.getValid_status() .toString().equals("0"))){
						//job关闭改为关闭。 job无动作
						MySchedulerTestLogger.log("ReschedulerJob is OFF -> OFF!" + job.getKey());
					}else if ((oldJobInfo.getCron_status() .toString().equals("1") && newJobInfo.getCron_status() .toString().equals("0"))
						|| (oldJobInfo.getValid_status() .toString().equals("1") && newJobInfo.getValid_status() .toString().equals("0"))){
						//job状态从激活改为关闭。 job停止
						SchedulerManager.unscheduleJob(scheduler,newJobInfo);
					}else if((oldJobInfo.getCron_status() .toString().equals("1") && newJobInfo.getCron_status()  .toString().equals("1"))
						|| (oldJobInfo.getValid_status() .toString().equals("1") && newJobInfo.getValid_status()  .toString().equals("1"))){
						//job状态从激活改为激活。  有可能job间隔时间变更
						if(oldJobInfo.getCron_intervals() != newJobInfo.getCron_intervals()){
							//job时间变更
							MySchedulerTestLogger.log("ReschedulerJob is change IntervalInSeconds!" + job.getKey());
							SchedulerManager.rescheduleJob(scheduler,newJobInfo);
						}
					}
				}
			}
		}catch(Exception e){
			e.printStackTrace();
		}
	}
}

工作用job代码:

package cn.com.winpeace.kiban.winperpsrv.allofpackages;
/**
 * @ClassName IfWorkJob
 * @Description TODO
 * @Author YPF
 * @Date 2019/10/119:45
 * @Version 1.0
 */

import cn.com.winpeace.kiban.winperpsrv.logger.MySchedulerTestLogger;
import cn.com.winpeace.kiban.winperpsrv.persistence.dao.AllPackagesMapper;
import cn.com.winpeace.kiban.winperpsrv.persistence.model.RealCrtMaterResultDO;
import cn.com.winpeace.kiban.winperpsrv.schedulerManager.SchedulerManager;
import cn.com.winpeace.kiban.winperpsrv.util.ApplicationContextProvider;
import cn.com.winpeace.kiban.winperpsrv.util.TableNameLinkWorkClassUtil;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.List;

/**
 * @ClassName IfWorkJob
 * @Description TODO
 * @Author YPF
 * @Date 2019/10/119:45
 * @Version 1.0
 **/
@Component
public class IfWorkJob implements Job {

	private static final String CURRENT_JOB_INFO_KEY = "CURRENT_JOB_INFO_KEY";

	@Autowired
	AllPackagesMapper allPackagesMapper;

	public static IfWorkJob ifWorkJob;

	@PostConstruct
	public void init() {
		ifWorkJob = this;
	}

	public void run(){
		MySchedulerTestLogger.log("IfBuyerExecute is begin-----------------");
	}
	@Override
	public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
		try{
			JobDetail jobDetail = jobExecutionContext.getJobDetail();
			RealCrtMaterResultDO jobInfo = (RealCrtMaterResultDO) jobDetail.getJobDataMap().get(CURRENT_JOB_INFO_KEY);

			CsvFTP csvFTP = (CsvFTP)ApplicationContextProvider.getBean("CsvFTP", CsvFTP.class);
			csvFTP.run(jobInfo.getIf_id());

		}catch (Exception e){
			e.printStackTrace();
		}
	}
}

业务类代码:

package cn.com.winpeace.kiban.winperpsrv.allofpackages;
/**
 * @ClassName CsvFTP
 * @Description TODO
 * @Author YPF
 * @Date 2019/10/1311:16
 * @Version 1.0
 */

import cn.com.winpeace.kiban.winperpsrv.util.ApplicationContextProvider;
import cn.com.winpeace.kiban.winperpsrv.util.TableNameLinkWorkClassUtil;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

/**
 * @ClassName CsvFTP
 * @Description TODO
 * @Author YPF
 * @Date 2019/10/1311:16
 * @Version 1.0
 **/
@Component("CsvFTP")
@Scope("prototype")
public class CsvFTP {

		public void run(String jobInfo) throws  Exception {
			//根据表名取得csv编辑class名
			String className = TableNameLinkWorkClassUtil.getWorkClass(jobInfo);
			//实例化csv编辑class
			IfInterfaceWorkClass csvEditClass = (IfInterfaceWorkClass) ApplicationContextProvider.getBean(jobInfo, Class.forName(className));
			//取得sql文
			//执行csv编辑
			csvEditClass.run(jobInfo);
			//ftp上传  共通方法
		}
}

其中不同表业务以及接口代码如下

@Service("if_buyer")
@Scope("prototype")
public class IfBuyerExecute implements  IfInterfaceWorkClass  {

	private final static String timeFormat = "HH:mm:ss";
	public final static String shortDateFormat = "yyyy-MM-dd";
	public final static String longDateFormat = "yyyy-MM-dd HH:mm:ss";
	public final static String simpleDateFormat = "yyyyMMdd";
	public final static String completeDateFormat = "yyyyMMddHHmmssSSS";
	public final static String IFID ="if_buyer";

	private static Logger logger = StdOutErrRedirect.logger;

	public static IfBuyerExecute ifBuyerExecute;

	@PostConstruct
	public void init() {
		ifBuyerExecute = this;
	}


	@Value("${config.cronUser}")
	private String cronUser;

	@Override
	//表的csv编辑操作 根据sql文--》dao-》保存csv
	public void run(String jobInfo){

		MySchedulerTestLogger.log("IfBuyerExecute is begin-----------------"+jobInfo);
		PumpEnv pumpEnv = ifBuyerExecute.pumpEnvMapper.getPumpEnv();
		MySchedulerTestLogger.log(pumpEnv.toString());
	}

package cn.com.winpeace.kiban.winperpsrv.allofpackages;
/**
 * @ClassName IfCategoryExecute
 * @Description TODO
 * @Author YPF
 * @Date 2019/9/2820:16
 * @Version 1.0
 */

import cn.com.winpeace.kiban.winperpsrv.logger.MySchedulerTestLogger;
import cn.com.winpeace.kiban.winperpsrv.persistence.model.RealCrtMaterResultDO;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

/**
 * @ClassName IfCategoryExecute
 * @Description TODO
 * @Author YPF
 * @Date 2019/9/2820:16
 * @Version 1.0
 **/
@Component("if_category")
@Scope("prototype")
public class IfCategoryExecute  implements  IfInterfaceWorkClass {


	@Override
	public void run(String jobInfo){
		MySchedulerTestLogger.log("IfCategoryExecute is begin-----------------"+jobInfo);



	}


}

package cn.com.winpeace.kiban.winperpsrv.allofpackages;

import cn.com.winpeace.kiban.winperpsrv.persistence.model.RealCrtMaterResultDO;

/**
 * @ClassName ifInterfaceWorkClass
 * @Description TODO
 * @Author YPF
 * @Date 2019/10/1311:04
 * @Version 1.0
 */
public interface IfInterfaceWorkClass {

	public void run(String jobInfo);
}

job工具类代码:

package cn.com.winpeace.kiban.winperpsrv.schedulerManager;



import cn.com.winpeace.kiban.winperpsrv.allofpackages.IfWorkJob;
import cn.com.winpeace.kiban.winperpsrv.persistence.model.RealCrtMaterResultDO;
import cn.com.winpeace.kiban.winperpsrv.vo.JobInfoDto;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

public class SchedulerManager {

	private static final String CURRENT_JOB_INFO_KEY = "CURRENT_JOB_INFO_KEY";

	/**
	 * SchedulerFactory  用于Scheduler的创建和管理
	 * getSchedule():创建调度者
	 * @return
	 * @throws Exception
	 */
	public static Scheduler getScheduler() throws Exception {
		SchedulerFactory schedulerFactory = new StdSchedulerFactory();
		return schedulerFactory.getScheduler();
	}

	/**
	 * 初始化scheduler 获取Scheduler 增加job任务
	 * @param scheduler
	 * @param jobInfos
	 * @throws Exception
	 */
	public static void init(Scheduler scheduler,  List<RealCrtMaterResultDO> jobInfos) throws Exception {
		for (RealCrtMaterResultDO jobInfo : jobInfos) {
			if (jobInfo.getCron_status().toString().equals("1") && jobInfo.getValid_status().equals("1")) {
				addJob(scheduler, jobInfo);
			}
		}
	}

	/**
	 * 指定时间间隔启动调度
	 * @param scheduler
	 * @param delayedSeconds
	 * @throws Exception
	 */
	public static void run(Scheduler scheduler, int delayedSeconds) throws Exception {

		scheduler.startDelayed(delayedSeconds);
	}

	/**
	 * 代码用法解析:
	 * JobDetail
	 *  增加job执行任务。JobBuilder --建造者模式。链式建造。
	 *  newJob():定义job任务。每个JobInfoDto是真正执行逻辑所在。
	 *  withIdentity(): 定义name/group
	 *  jobDetail.getJobDataMap().put():实现了java.util.Map 接口。可以向 JobDataMap 中存入键/值对,那些数据对可在的 Job 类中传递和进行访问。这是一个向 Job 传送配置的信息便捷方法。
	 * Trigger:触发条件
	 *  一个Job可以对应多个Trigger。当多个Trigger同一时间点出发,那么根据优先级判断。数字越大,优先级越高。默认优先级为5。同一个任务有多个trigger时,触发先后顺序:时间->优先级->字母排序
	 *  newTrigger()定义触发器。TriggerBuilder --建造者模式。链式建造。
	 *  withIdentity():定义name/group
	 *  startAt():根据job任务间隔时间来触发执行job任务。  【startNow():一旦加入scheduler,立即生效】
	 *  withSchedule():增加Schedule 使用SimpleSchedule简单调度器,指定时间间隔触发。
	 *  scheduleJob():注册Trigger和job并进行调度
	 * @param scheduler
	 * @param jobInfo
	 * @throws Exception
	 */
	public static void addJob(Scheduler scheduler, RealCrtMaterResultDO jobInfo) throws Exception {
		Class<Job> cls = (Class<Job>) Class.forName("cn.com.winpeace.kiban.winperpsrv.allofpackages.IfWorkJob");
		JobDetail jobDetail = JobBuilder.newJob(cls)
				.withIdentity(jobInfo.getIf_id(), jobInfo.getCustomer_id())
				.build();
		jobDetail.getJobDataMap().put(CURRENT_JOB_INFO_KEY, jobInfo);

		Trigger trigger = TriggerBuilder.newTrigger()
				.withIdentity(jobInfo.getIf_id(), jobInfo.getCustomer_id())
				.startAt(getStartTime(jobInfo.getCron_intervals()))
				.withSchedule(SimpleScheduleBuilder.simpleSchedule()
						.withIntervalInSeconds(jobInfo.getCron_intervals()).repeatForever())
				.build();
		scheduler.scheduleJob(jobDetail, trigger);
	}
	public static void addManagerJob(Scheduler scheduler, RealCrtMaterResultDO jobInfo) throws Exception {
		Class<Job> cls = (Class<Job>) Class.forName(jobInfo.getJobClass());
		JobDetail jobDetail = JobBuilder.newJob(cls)
				.withIdentity(jobInfo.getIf_id(), jobInfo.getCustomer_id())
				.build();
		jobDetail.getJobDataMap().put(CURRENT_JOB_INFO_KEY, jobInfo);

		Trigger trigger = TriggerBuilder.newTrigger()
				.withIdentity(jobInfo.getIf_id(), jobInfo.getCustomer_id())
				.startAt(getStartTime(jobInfo.getCron_intervals()))
				.withSchedule(SimpleScheduleBuilder.simpleSchedule()
						.withIntervalInSeconds(jobInfo.getCron_intervals()).repeatForever())
				.build();
		scheduler.scheduleJob(jobDetail, trigger);
	}


	/**
	 * 刷新job属性
	 *  JobKey:JobKey是表明Job身份的一个对象
	 *  getJobDetail();根据jobkey获取job详情
	 *  getJobDataMap():根据创建时放入的map的key查询job配置信息
	 * 重新创建触发器
	 *   使用更新后的job间隔时间
	 * @param scheduler
	 * @param jobInfo
	 * @throws Exception
	 */
	public static void rescheduleJob(Scheduler scheduler, RealCrtMaterResultDO jobInfo) throws Exception {
		JobKey jobKey = JobKey.jobKey(jobInfo.getIf_id(), jobInfo.getCustomer_id());
		JobDetail jobDetail = scheduler.getJobDetail(jobKey);
		RealCrtMaterResultDO oldJobInfo = (RealCrtMaterResultDO) jobDetail.getJobDataMap().get(CURRENT_JOB_INFO_KEY);
		oldJobInfo.setCron_intervals(jobInfo.getCron_intervals());
		oldJobInfo.setCron_date(jobInfo.getCron_date());
		oldJobInfo.setCron_time(jobInfo.getCron_time());
		
		TriggerKey triggerKey = TriggerKey.triggerKey(jobInfo.getIf_id(), jobInfo.getCustomer_id());
		Trigger trigger = TriggerBuilder.newTrigger()
				.withIdentity(jobInfo.getIf_id(), jobInfo.getCustomer_id())
				.startAt(getStartTime(jobInfo.getCron_intervals(), jobInfo.getCron_date()+" "+jobInfo.getCron_time()))
				.withSchedule(SimpleScheduleBuilder.simpleSchedule()
						.withIntervalInSeconds(jobInfo.getCron_intervals()).repeatForever())
				.build();
		scheduler.rescheduleJob(triggerKey, trigger);
	}

	/**
	 * 停止job任务  unscheduleJob针对TriggerKey【deleteJob针对jobKey】
	 * @param scheduler
	 * @param jobInfo
	 * @throws Exception
	 */
	public static void unscheduleJob(Scheduler scheduler, RealCrtMaterResultDO jobInfo) throws Exception {
		TriggerKey triggerKey = TriggerKey.triggerKey(jobInfo.getIf_id(), jobInfo.getCustomer_id());
		scheduler.unscheduleJob(triggerKey);  
	}

	private static Date getStartTime(int delayedSeconds) {
		Date date = new Date(System.currentTimeMillis() + 1000 * delayedSeconds);
		return date;
	}
	
	private static Date getStartTime(int intervalInSeconds, String delayedSeconds) {
		//date转化为毫秒数
		Date date = null;
		try {
			System.out.println(delayedSeconds);
			SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			long time = simpleDateFormat.parse(delayedSeconds).getTime();
			long diff=0;
			if(time>System.currentTimeMillis()){
				//若设定时间比之当前时间大再计算推迟时间
				 diff = System.currentTimeMillis()-time;
			}
			date =  new Date(System.currentTimeMillis() + 1000 * (intervalInSeconds + diff));
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return date;
	}
	
	public static JobDetail getJobDetail(Scheduler scheduler, RealCrtMaterResultDO jobInfo) throws Exception {
		JobKey jobKey = JobKey.jobKey(jobInfo.getIf_id(), jobInfo.getCustomer_id());
		return scheduler.getJobDetail(jobKey);
	}
	
	public static RealCrtMaterResultDO getJobInfo(JobDetail jobDetail) throws Exception {
		return (RealCrtMaterResultDO) jobDetail.getJobDataMap().get(CURRENT_JOB_INFO_KEY);
	}
	public static long getSecond(String time){
		long s = 0;
		if(time.length()==8){ //时分秒格式00:00:00
			int index1=time.indexOf(":");
			int index2=time.indexOf(":",index1+1);
			s = Integer.parseInt(time.substring(0,index1))*3600;//小时
			s+=Integer.parseInt(time.substring(index1+1,index2))*60;//分钟
			s+=Integer.parseInt(time.substring(index2+1));//秒
		}
		if(time.length()==5){//分秒格式00:00
			s = Integer.parseInt(time.substring(time.length()-2)); //秒  后两位肯定是秒
			s+=Integer.parseInt(time.substring(0,2))*60;    //分钟
		}
		return s;
	}
}

最重要的是。面向接口编程。以及抽取共通业务和实现代码差异化。
怎样以更简洁的方式实现业务的可扩展性、可维护性 。以及降低调查问题的难度是比较重要的。还是需要思维的更抽象化来实现。以后也要尽量往这方面更高的层次去想。去提高自己提取抽象业务的能力。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 好的,下面是关于使用Spring BootQuartz实现定时任务的简介: Quartz是一个流行的Java定时任务框架,可以在应用程序中执行各种定时任务,如定期备份、数据抽取和数据分析等。而Spring Boot是一个快速开发框架,提供了方便的集成Quartz的方式。 要使用Spring BootQuartz实现定时任务,首先需要在pom.xml文件中添加QuartzSpring Boot Quartz的依赖项。然后,定义一个定时任务,可以使用注解@Scheduled来指定任务的执行时间。例如: ```java @Component public class MyScheduler { @Scheduled(cron = "0 0/10 * * * ?") public void myTask() { //执行定时任务的代码 } } ``` 上述代码表示每隔10分钟执行一次myTask()方法。然后,在Spring Boot的主类中,使用@EnableScheduling注解来开启定时任务的支持。例如: ```java @SpringBootApplication @EnableScheduling public class MyApp { public static void main(String[] args) { SpringApplication.run(MyApp.class, args); } } ``` 最后,启动应用程序,定时任务将按照预定时间自动执行。如果需要更高级的定时任务控制,还可以使用Quartz的其他功能,如JobDetail和Trigger等。 ### 回答2: SpringBoot是一个开源的Java开发框架,它提供了很多有用的工具和插件,其中之一便是定时任务quartzquartz是一款功能强大的开源调度框架,它提供了简单易用的任务调度机制,支持多线程和分布式部署,可以满足大部分的调度需求。 在SpringBoot中,我们可以很方便地使用quartz来实现定时任务。以下是使用SpringBootquartz实现定时任务的基本步骤: 1. 在pom.xml文件中添加quartz的依赖项: ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency> ``` 2. 创建一个任务类,实现Job接口,并实现execute方法来定义任务逻辑: ``` @Component public class MyTask implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { // 定时任务的执行逻辑 } } ``` 3. 在配置文件中定义任务调度器,并为任务分配cron表达式: ``` spring: quartz: job-store-type: jdbc properties: org.quartz.scheduler.instanceName: MyScheduler org.quartz.threadPool.threadCount: 5 job-details: myJob: durability: true requestsRecovery: true trigger-details: myTrigger: cron: 0 0/1 * * * ? job-name: myJob job-data-map: name: world ``` 4. 在任务执行类中,使用@Scheduled注解来指定任务的执行时间: ``` @Component public class MyTask { @Scheduled(cron = "0 0/1 * * * ?") public void doTask(){ // 定时任务的执行逻辑 } } ``` 以上4种方法都是使用SpringBootquartz实现定时任务的简单示例,根据实际需求可以进行相应调整和扩展。总的来说,使用springbootquartz实现定时任务非常方便,能够让我们更加轻松地管理、调度和执行任务,提高开发效率和质量。 ### 回答3: Spring Boot是一款快速构建基于Spring应用的工具,可帮助简化开发和部署。在Spring Boot中,与Quartz相比,Scheduled定时任务通常是首选的。但是,Quartz比Scheduled更灵活、功能更强大、配置更灵活,因此在一些特殊情况下,使用Quartz进行定时任务调度是比较必要的。 Quartz是用Java语言编写的一个开源的调度框架,其主要用于在一个预定义的时间间隔内重复执行某个任务,或者在特定时间点执行某个任务。Quartz提供了众多功能,比如支持分布式定时任务管理、支持动态创建/删除任务、支持时间表达式、状态存储、监控和事件触发等等。 Spring Boot集成了Quartz非常容易,只需要在Spring Boot项目中添加Quartz相关依赖,在Spring Boot配置文件中增加Quartz配置即可。以下是一个完整的Spring Boot集成Quartz的示例代码: 1.在pom.xml中添加QuartzSpring Boot Starter Web依赖: ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>${quartz.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> </dependency> ``` 2.在配置文件中增加Quartz相关配置: ``` spring.quartz.job-store-type=memory spring.quartz.properties.org.quartz.threadPool.threadCount=10 spring.quartz.properties.org.quartz.jobStore.class=org.quartz.simpl.RAMJobStore ``` 3.编写定时任务处理类: ``` @Component public class JobScheduler { @Autowired private Scheduler scheduler; @Scheduled(cron = "0 0/1 * * * ?") public void doSomething() { JobDetail jobDetail = buildJobDetail(); Trigger trigger = buildJobTrigger(jobDetail); try { scheduler.scheduleJob(jobDetail, trigger); } catch (SchedulerException e) { e.printStackTrace(); } } private JobDetail buildJobDetail() { JobDataMap jobDataMap = new JobDataMap(); jobDataMap.put("key", "value"); return JobBuilder.newJob(Job.class) .withIdentity(UUID.randomUUID().toString(), "job-group") .withDescription("sample job") .usingJobData(jobDataMap) .storeDurably(true) .build(); } private Trigger buildJobTrigger(JobDetail jobDetail) { return TriggerBuilder.newTrigger() .forJob(jobDetail) .withIdentity(UUID.randomUUID().toString(), "trigger-group") .withDescription("sample trigger") .withSchedule(CronScheduleBuilder.cronSchedule("0 0/1 * * * ?")) .build(); } } ``` 虽然Quartz需要对定时任务进行配置,但是它提供了更为灵活的条件和任务调度,非常适合在实际生产环境中使用。总之,使用Spring Boot集成Quartz可以非常方便地实现定时任务的调度,既简单又强大,可以大大提高应用的效率和可靠性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值