factory.setDataSource(dataSource);
factory.setJobFactory(jobFactory);
factory.setQuartzProperties(quartzProperties());
return factory;
}
//从quartz.properties文件中读取Quartz配置属性
@Bean
public Properties quartzProperties() throws IOException {
PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
propertiesFactoryBean.setLocation(new ClassPathResource(“/quartz.properties”));
propertiesFactoryBean.afterPropertiesSet();
return propertiesFactoryBean.getObject();
}
//配置JobFactory,为quartz作业添加自动连接支持
public final class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements
ApplicationContextAware {
private AutowireCapableBeanFactory beanFactory;
@Override
public void setApplicationContext(final ApplicationContext context) {
beanFactory = context.getAutowireCapableBeanFactory();
}
@Override
protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
final Object job = super.createJobInstance(bundle);
beanFactory.autowireBean(job);
return job;
}
}
}
四、Entity类
package com.ealen.entity;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.persistence.*;
import java.io.Serializable;
/**
- 这里个人示例,可自定义相关属性
*/
@Entity
@Table(name = “JOB_ENTITY”)
@Data
@Accessors(chain = true)
public class JobEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name; //job名称
private String jobGroup; //job组名
private String cron; //执行的cron
private String parameter; //job的参数
private String description; //job描述信息
private String vmParam; //vm参数
private String jarPath; //job的jar路径
private String status; //job的执行状态,这里我设置为OPEN/CLOSE且只有该值为OPEN才会执行该Job
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getJobGroup() {
return jobGroup;
}
public void setJobGroup(String jobGroup) {
this.jobGroup = jobGroup;
}
public String getCron() {
return cron;
}
public void setCron(String cron) {
this.cron = cron;
}
public String getParameter() {
return parameter;
}
public void setParameter(String parameter) {
this.parameter = parameter;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getVmParam() {
return vmParam;
}
public void setVmParam(String vmParam) {
this.vmParam = vmParam;
}
public String getJarPath() {
return jarPath;
}
public void setJarPath(String jarPath) {
this.jarPath = jarPath;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}
五、实现job接口
Job可以理解为就是一个工作任务,代码中就是一个实现了org.quartz.Job或org.quartz.StatefulJob接口的java类。当Scheduler决定运行Job时,execute()方法就会被执行。
具体可以干啥:
1、每天定时发送系统邮件
2、在指定的时刻发送一条短信给用户
3、执行完A任务后希望B任务在10秒后执行
总结就是任何java能做的任务都可以成为一个job。
package com.ealen.job;
import com.ealen.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
-
:@DisallowConcurrentExecution : 此标记用在实现Job的类上面,意思是不允许并发执行.
-
:注意org.quartz.threadPool.threadCount线程池中线程的数量至少要多个,否则@DisallowConcurrentExecution不生效
-
:假如Job的设置时间间隔为3秒,但Job执行时间是5秒,设置@DisallowConcurrentExecution以后程序会等任务执行完毕以后再去执行,否则会在3秒时再启用新的线程执行
*/
@DisallowConcurrentExecution
@Component
@Slf4j
public class DynamicJob implements Job {
private static final Logger log = LoggerFactory.getLogger(DynamicJob.class);
/**
-
核心方法,Quartz Job真正的执行逻辑.
-
@param executorContext executorContext JobExecutionContext中封装有Quartz运行所需要的所有信息
-
@throws JobExecutionException execute()方法只允许抛出JobExecutionException异常
*/
@Override
public void execute(JobExecutionContext executorContext) throws JobExecutionException {
//JobDetail中的JobDataMap是共用的,从getMergedJobDataMap获取的JobDataMap是全新的对象
JobDataMap map = executorContext.getMergedJobDataMap();
String jarPath = map.getString(“jarPath”);
String parameter = map.getString(“parameter”);
String vmParam = map.getString(“vmParam”);
log.info("Running Job name : {} ", map.getString(“name”));
log.info(“Running Job description : {}”, map.getString(“jobDescription”));
log.info("Running Job group: {} ", map.getString(“jobGroup”));
log.info(String.format(“Running Job cron : %s”, map.getString(“cronExpression”)));
log.info("Running Job jar path : {} ", jarPath);
log.info("Running Job parameter : {} ", parameter);
log.info("Running Job vmParam : {} ", vmParam);
long startTime = System.currentTimeMillis();
if (!StringUtils.isEmpty(jarPath)) {
File jar = new File(jarPath);
if (jar.exists()) {
ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.directory(jar.getParentFile());
List commands = new ArrayList<>();
commands.add(“java”);
if (!StringUtils.isEmpty(vmParam)) commands.add(vmParam);
commands.add(“-jar”);
commands.add(jarPath);
if (!StringUtils.isEmpty(parameter)) commands.add(parameter);
processBuilder.command(commands);
log.info("Running Job details as follows >>>>>>>>>>>>>>>>>>>>: ");
log.info("Running Job commands : {} ", StringUtil.getListString(commands));
try {
Process process = processBuilder.start();
logProcess(process.getInputStream(), process.getErrorStream());
} catch (IOException e) {
throw new JobExecutionException(e);
}
} else throw new JobExecutionException("Job Jar not found >> " + jarPath);
}
long endTime = System.currentTimeMillis();
log.info(">>>>>>>>>>>>> Running Job has been completed , cost time : {}ms\n ", (endTime - startTime));
}
//记录Job执行内容
private void logProcess(InputStream inputStream, InputStream errorStream) throws IOException {
String inputLine;
String errorLine;
BufferedReader inputReader = new BufferedReader(new InputStreamReader(inputStream));
BufferedReader errorReader = new BufferedReader(new InputStreamReader(errorStream));
while (Objects.nonNull(inputLine = inputReader.readLine())) log.info(inputLine);
while (Objects.nonNull(errorLine = errorReader.readLine())) log.error(errorLine);
}
}
六、定义dao接口
package com.ealen.dao;
import com.ealen.entity.JobEntity;
import org.springframework.data.jpa.repository.JpaRepository;
public interface JobEntityRepository extends JpaRepository<JobEntity, Long> {
JobEntity getById(Integer id);
}
七、service 服务层
package com.ealen.service;
import com.ealen.dao.JobEntityRepository;
import com.ealen.entity.JobEntity;
import com.ealen.job.DynamicJob;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class DynamicJobService {
@Autowired
private JobEntityRepository repository;
//通过Id获取Job
public JobEntity getJobEntityById(Integer id) {
return repository.getById(id);
}
//从数据库中加载获取到所有Job
public List loadJobs() {
return repository.findAll();
}
//获取JobDataMap.(Job参数对象)
public JobDataMap getJobDataMap(JobEntity job) {
JobDataMap map = new JobDataMap();
map.put(“name”, job.getName());
map.put(“jobGroup”, job.getJobGroup());
map.put(“cronExpression”, job.getCron());
map.put(“parameter”, job.getParameter());
map.put(“jobDescription”, job.getDescription());
map.put(“vmParam”, job.getVmParam());
map.put(“jarPath”, job.getJarPath());
map.put(“status”, job.getStatus());
return map;
}
//获取JobDetail,JobDetail是任务的定义,而Job是任务的执行逻辑,JobDetail里会引用一个Job Class来定义
public JobDetail getJobDetail(JobKey jobKey, String description, JobDataMap map) {
return JobBuilder.newJob(DynamicJob.class)
.withIdentity(jobKey)
.withDescription(description)
.setJobData(map)
.storeDurably()
.build();
}
//获取Trigger (Job的触发器,执行规则)
public Trigger getTrigger(JobEntity job) {
return TriggerBuilder.newTrigger()
.withIdentity(job.getName(), job.getJobGroup())
.withSchedule(CronScheduleBuilder.cronSchedule(job.getCron()))
.build();
}
//获取JobKey,包含Name和Group
public JobKey getJobKey(JobEntity job) {
return JobKey.jobKey(job.getName(), job.getJobGroup());
}
}
八、自定义工具类
package com.ealen.util;
import java.util.List;
import java.util.Map;
/**
- 自定义枚举单例对象 StringUtil
*/
public enum StringUtil {
getStringUtil;
//是否为空
public boolean isEmpty(String str) {
return (str == null) || (str.length() == 0) || (str.equals(“”));
}
//去空格
public String trim(String str) {
return str == null ? null : str.trim();
}
//获取Map参数值
public String getMapString(Map<String, String> map) {
String result = “”;
for (Map.Entry entry : map.entrySet()) {
result += entry.getValue() + " ";
}
return result;
}
//获取List参数值
public static String getListString(List list) {
StringBuilder result = new StringBuilder();
for (String s : list) {
result.append(s).append(" ");
}
return result.toString();
}
}
九、Dto
package com.ealen.web.dto;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
@Data
public class ModifyCronDTO {
@NotNull(message = “the job id cannot be null”)
private Integer id;
@NotEmpty(message = “the cron cannot be empty”)
private String cron;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getCron() {
return cron;
}
public void setCron(String cron) {
this.cron = cron;
}
}
十、Controller控制器
package com.ealen.web;
import com.ealen.dao.JobEntityRepository;
import com.ealen.entity.JobEntity;
import com.ealen.job.DynamicJob;
import com.ealen.service.DynamicJobService;
import com.ealen.web.dto.ModifyCronDTO;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.PostConstruct;
import javax.validation.constraints.NotNull;
import java.util.Objects;
import java.util.Set;
@RestController
@Slf4j
public class JobController {
private static final Logger log = LoggerFactory.getLogger(JobController.class);
@Autowired
private SchedulerFactoryBean schedulerFactoryBean;
@Autowired
private DynamicJobService jobService;
@Autowired
private JobEntityRepository repository;
//初始化启动所有的Job
@PostConstruct
public void initialize() {
try {
reStartAllJobs();
log.info(“init success”);
} catch (SchedulerException e) {
log.error("printStackTrace ", e);
}
}
//根据ID重启某个Job
@RequestMapping(“/refresh/{id}”)
public String refresh(@PathVariable @NotNull Integer id) throws SchedulerException {
String result;
JobEntity entity = jobService.getJobEntityById(id);
if (Objects.isNull(entity)) return "error: id is not exist ";
synchronized (log) {
JobKey jobKey = jobService.getJobKey(entity);
Scheduler scheduler = schedulerFactoryBean.getScheduler();
scheduler.pauseJob(jobKey);
scheduler.unscheduleJob(TriggerKey.triggerKey(jobKey.getName(), jobKey.getGroup()));
scheduler.deleteJob(jobKey);
JobDataMap map = jobService.getJobDataMap(entity);
JobDetail jobDetail = jobService.getJobDetail(jobKey, entity.getDescription(), map);
if (entity.getStatus().equals(“OPEN”)) {
scheduler.scheduleJob(jobDetail, jobService.getTrigger(entity));
result = "Refresh Job : " + entity.getName() + “\t jarPath: " + entity.getJarPath() + " success !”;
} else {
result = "Refresh Job : " + entity.getName() + "\t jarPath: " + entity.getJarPath() + " failed ! , " +
"Because the Job status is " + entity.getStatus();
}
}
return result;
}
//重启数据库中所有的Job
@RequestMapping(“/refresh/all”)
public String refreshAll() {
String result;
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
最后的话
无论是哪家公司,都很重视Spring框架技术,重视基础,所以千万别小看任何知识。面试是一个双向选择的过程,不要抱着畏惧的心态去面试,不利于自己的发挥。
同时看中的应该不止薪资,还要看你是不是真的喜欢这家公司,好了希望这篇文章对大家有帮助!
部分截图:
pping(“/refresh/all”)
public String refreshAll() {
String result;
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-wNF7ZBdd-1711787865461)]
[外链图片转存中…(img-k6jqS1TK-1711787865461)]
[外链图片转存中…(img-doAc0u97-1711787865462)]
[外链图片转存中…(img-evbrDKd5-1711787865462)]
[外链图片转存中…(img-m9Bs9zEo-1711787865462)]
[外链图片转存中…(img-d9m5hdYY-1711787865463)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
[外链图片转存中…(img-25Ts85i2-1711787865463)]
最后的话
无论是哪家公司,都很重视Spring框架技术,重视基础,所以千万别小看任何知识。面试是一个双向选择的过程,不要抱着畏惧的心态去面试,不利于自己的发挥。
同时看中的应该不止薪资,还要看你是不是真的喜欢这家公司,好了希望这篇文章对大家有帮助!
部分截图:
[外链图片转存中…(img-VkyVgXro-1711787865464)]