feat:动态获取任务的cron和开关

This commit is contained in:
Xiang
2026-01-06 15:30:26 +08:00
parent 95a590f088
commit 64ca6f4478
14 changed files with 275 additions and 12 deletions

48
readme.md Normal file
View File

@@ -0,0 +1,48 @@
# Xxz-job任务调度系统
### (一)
### (二)版本控制
#### 1v1.0版本-master分支上
1. 设计Xxz-job注解以及EnableXxzJob注解编写xxz-job注解扫描器以及注解执行器本机单机执行任务。
```java
// 第一版Xxz-job注解内容
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface XxzJob {
/**
* bean的名称
*
* @return
*/
String name();
/**
* cron调度方法
* @return
*/
String cron();
boolean enabled() default true;
/**
* 是否支持多机分布式运行
* 若为false每台机器都会执行一次
* 若为true仅一台机器会执行
*
* @return
*/
boolean distributed() default true;
}
```
第一版XxzJob注解仅支持单机并且cron固定的方式进行设计能够将任务根据cron正常启动。
#### 2v1.1版本-feat/schedule_v1_0106
1. 动态获取定时任务的cron和开关
1.

View File

@@ -0,0 +1,29 @@
package com.xiang.app.quartz.admin.server;
import com.xiang.app.quartz.admin.domain.entity.JobConfigDO;
import com.xiang.app.quartz.admin.service.ITaskConfigService;
import com.xiang.xservice.basic.common.resp.Result;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* @Author: xiang
* @Date: 2026-01-06 15:05
*/
@RestController
@RequiredArgsConstructor
@RequestMapping("/open/quartz/fetch")
public class XxzJobFetchController {
private final ITaskConfigService taskConfigService;
@GetMapping("/list")
public Result<JobConfigDO> list(@RequestParam("appName") String appName) {
List<JobConfigDO> jobsByAppName = taskConfigService.getJobsByAppName(appName);
return Result.success(jobsByAppName);
}
}

View File

@@ -1,5 +1,6 @@
package com.xiang.app.quartz.admin.service; package com.xiang.app.quartz.admin.service;
import com.xiang.app.quartz.admin.domain.entity.JobConfigDO;
import com.xiang.app.quartz.admin.domain.req.TaskRegisterRequest; import com.xiang.app.quartz.admin.domain.req.TaskRegisterRequest;
import java.util.List; import java.util.List;
@@ -23,4 +24,6 @@ public interface ITaskConfigService {
* @return * @return
*/ */
boolean registerTasks(List<TaskRegisterRequest> request); boolean registerTasks(List<TaskRegisterRequest> request);
List<JobConfigDO> getJobsByAppName(String appName);
} }

View File

@@ -67,6 +67,11 @@ public class TaskConfigServiceImpl implements ITaskConfigService {
return true; return true;
} }
@Override
public List<JobConfigDO> getJobsByAppName(String appName) {
return quartzConfigManage.selectByAppName(appName);
}
private static void putDataIntoDo(TaskRegisterRequest item, JobConfigDO jobConfigDO, String applicationName) { private static void putDataIntoDo(TaskRegisterRequest item, JobConfigDO jobConfigDO, String applicationName) {
jobConfigDO.setApplicationName(applicationName); jobConfigDO.setApplicationName(applicationName);
jobConfigDO.setApplicationAddress(item.getApplicationAddress()); jobConfigDO.setApplicationAddress(item.getApplicationAddress());

View File

@@ -25,6 +25,11 @@
<artifactId>xmc-common</artifactId> <artifactId>xmc-common</artifactId>
<version>1.0</version> <version>1.0</version>
</dependency> </dependency>
<dependency>
<groupId>com.xiang.starter</groupId>
<artifactId>xmc-http-starter</artifactId>
<version>1.0</version>
</dependency>
<dependency> <dependency>
<groupId>com.xiang.starter</groupId> <groupId>com.xiang.starter</groupId>
<artifactId>xmc-cache-starter</artifactId> <artifactId>xmc-cache-starter</artifactId>

View File

@@ -22,11 +22,11 @@ public @interface XxzJob {
*/ */
String name(); String name();
/** // /**
* cron调度方法 // * cron调度方法
* @return // * @return
*/ // */
String cron(); // String cron();
boolean enabled() default true; boolean enabled() default true;
/** /**

View File

@@ -0,0 +1,14 @@
package com.xiang.core.quartz.api;
import com.xiang.core.quartz.model.JobConfigDO;
import java.util.List;
/**
* @Author: xiang
* @Date: 2026-01-06 15:10
*/
public interface AdminJobClient {
List<JobConfigDO> fetchJobByAppName(String appName);
}

View File

@@ -0,0 +1,45 @@
package com.xiang.core.quartz.api;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.xiang.core.quartz.model.JobConfigDO;
import com.xiang.core.quartz.model.XxzJobProperties;
import com.xiang.xmc.service.http.helper.HttpHelper;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* @Author: xiang
* @Date: 2026-01-06 15:11
*/
@Component
@RequiredArgsConstructor
public class HttpAdminJobClientImpl implements AdminJobClient{
private final XxzJobProperties xxzJobProperties;
@Override
public List<JobConfigDO> fetchJobByAppName(String appName) {
String address = xxzJobProperties.getAdminAddress();
address = address + "/open/quartz/fetch/list";
Map<String, String> params = Maps.newHashMap();
params.put("appName", appName);
String resp = HttpHelper.doGet(address, null, params);
if (StringUtils.isNotBlank(resp)) {
JSONObject jsonObject = JSON.parseObject(resp);
if (Objects.nonNull(jsonObject)) {
String data = JSON.toJSONString(jsonObject.get("data"));
if (StringUtils.isNotBlank(data)) {
return JSON.parseArray(data, JobConfigDO.class);
}
}
}
return Lists.newArrayList();
}
}

View File

@@ -1,14 +1,22 @@
package com.xiang.core.quartz.boostrap; package com.xiang.core.quartz.boostrap;
import com.xiang.core.quartz.api.AdminJobClient;
import com.xiang.core.quartz.holder.JobDefinitionHolder; import com.xiang.core.quartz.holder.JobDefinitionHolder;
import com.xiang.core.quartz.model.JobDefinition; import com.xiang.core.quartz.model.JobConfigDO;
import com.xiang.core.quartz.model.XxzJobProperties;
import com.xiang.core.quartz.schedule.JobScheduler; import com.xiang.core.quartz.schedule.JobScheduler;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner; import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
/** /**
* @Author: xiang * @Author: xiang
* @Date: 2026-01-06 09:50 * @Date: 2026-01-06 09:50
@@ -19,13 +27,29 @@ public class JobBootstrap implements ApplicationRunner {
@Autowired @Autowired
private JobScheduler scheduler; private JobScheduler scheduler;
@Autowired
private AdminJobClient adminJobClient;
@Autowired
private XxzJobProperties xxzJobProperties;
@Override @Override
public void run(ApplicationArguments args) { public void run(ApplicationArguments args) {
List<JobConfigDO> jobConfigDOS = adminJobClient.fetchJobByAppName(xxzJobProperties.getAppName());
if (CollectionUtils.isEmpty(jobConfigDOS)) {
return;
}
Map<String, JobConfigDO> map = jobConfigDOS.stream().collect(Collectors.toMap(JobConfigDO::getBeanName, Function.identity(), (a, b) -> a));
JobDefinitionHolder.getAll() JobDefinitionHolder.getAll()
.stream() .forEach(item -> {
.filter(JobDefinition::isEnabled) if (map.containsKey(item.getName())) {
.forEach(scheduler::schedule); JobConfigDO jobConfigDO = map.get(item.getName());
if (jobConfigDO.getJobSwitch() == 1) {
item.setCron(jobConfigDO.getCron());
item.setEnabled(jobConfigDO.getJobSwitch() == 1);
scheduler.schedule(item);
}
}
});
} }
} }

View File

@@ -0,0 +1,84 @@
package com.xiang.core.quartz.model;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* @Author: xiang
* @Date: 2025-12-30 09:42
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("xmc_quartz_config")
public class JobConfigDO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* id
*/
private Long id;
/**
* 应用名称
*/
private String applicationName;
/**
* 应用地址
*/
private String applicationAddress;
/**
* 定时任务名称
*/
private String beanName;
/**
* 任务执行调度时间
*/
private String cron;
/**
* 类名
*/
private String clazz;
/**
* 方法
*/
private String method;
/**
* 任务开关
* 0:关闭 1:开启
*/
private Integer jobSwitch;
/**
* 删除标识0:未删除 1:已删除)
*/
private Integer delFlag;
/**
* 创建时间
*/
private LocalDateTime createTime;
/**
* 修改时间
*/
private LocalDateTime updateTime;
/**
* 上次执行时间
*/
private LocalDateTime lastRunningTime;
}

View File

@@ -20,4 +20,9 @@ public class XxzJobProperties {
* DB刷新任务间隔毫秒 * DB刷新任务间隔毫秒
*/ */
private int refreshInterval = 5000; private int refreshInterval = 5000;
/**
* 调度中心地址
*/
private String adminAddress;
} }

View File

@@ -50,8 +50,8 @@ public class JobScanner implements SmartInitializingSingleton {
job.setDistributed(xxzJob.distributed()); job.setDistributed(xxzJob.distributed());
job.setBean(bean); job.setBean(bean);
job.setMethod(method); job.setMethod(method);
job.setEnabled(xxzJob.enabled()); // job.setEnabled();
job.setCron(xxzJob.cron()); // job.setCron(xxzJob.cron());
JobDefinitionHolder.register(job); JobDefinitionHolder.register(job);
} }
} }

View File

@@ -12,7 +12,7 @@ import org.springframework.stereotype.Component;
@Component @Component
public class TestXxzJob1 { public class TestXxzJob1 {
@XxzJob(name = "TestXxzJob", cron = "0/1 * * * * ? ", enabled = true) @XxzJob(name = "TestXxzJob")
public void test() { public void test() {
log.info("任务调度开始"); log.info("任务调度开始");
} }

View File

@@ -1,5 +1,6 @@
xxz-job: xxz-job:
app-name: springboot-quartz-test app-name: springboot-quartz-test
admin-address: http://127.0.0.1:30030
spring: spring:
main: main: