diff --git a/sys-api/src/main/java/com/qihang/sys/api/controller/HomeController.java b/sys-api/src/main/java/com/qihang/sys/api/controller/HomeController.java index a04de7b4..ed927d30 100644 --- a/sys-api/src/main/java/com/qihang/sys/api/controller/HomeController.java +++ b/sys-api/src/main/java/com/qihang/sys/api/controller/HomeController.java @@ -1,6 +1,6 @@ package com.qihang.sys.api.controller; -import com.qihang.sys.api.service.EchoService; +import com.qihang.sys.api.feign.EchoService; import jakarta.annotation.Resource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; diff --git a/sys-api/src/main/java/com/qihang/sys/api/domain/SysTask.java b/sys-api/src/main/java/com/qihang/sys/api/domain/SysTask.java new file mode 100644 index 00000000..25f0faf3 --- /dev/null +++ b/sys-api/src/main/java/com/qihang/sys/api/domain/SysTask.java @@ -0,0 +1,176 @@ +package com.qihang.sys.api.domain; + +import java.io.Serializable; +import java.util.Date; + +/** + * + * @TableName sys_task + */ +public class SysTask implements Serializable { + /** + * + */ + private Integer id; + + /** + * + */ + private String taskName; + + /** + * + */ + private String cron; + + /** + * + */ + private String method; + + /** + * + */ + private String remark; + + /** + * + */ + private Date createTime; + + private static final long serialVersionUID = 1L; + + /** + * + */ + public Integer getId() { + return id; + } + + /** + * + */ + public void setId(Integer id) { + this.id = id; + } + + /** + * + */ + public String getTaskName() { + return taskName; + } + + /** + * + */ + public void setTaskName(String taskName) { + this.taskName = taskName; + } + + /** + * + */ + public String getCron() { + return cron; + } + + /** + * + */ + public void setCron(String cron) { + this.cron = cron; + } + + /** + * + */ + public String getMethod() { + return method; + } + + /** + * + */ + public void setMethod(String method) { + this.method = method; + } + + /** + * + */ + public String getRemark() { + return remark; + } + + /** + * + */ + public void setRemark(String remark) { + this.remark = remark; + } + + /** + * + */ + public Date getCreateTime() { + return createTime; + } + + /** + * + */ + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } + + @Override + public boolean equals(Object that) { + if (this == that) { + return true; + } + if (that == null) { + return false; + } + if (getClass() != that.getClass()) { + return false; + } + SysTask other = (SysTask) that; + return (this.getId() == null ? other.getId() == null : this.getId().equals(other.getId())) + && (this.getTaskName() == null ? other.getTaskName() == null : this.getTaskName().equals(other.getTaskName())) + && (this.getCron() == null ? other.getCron() == null : this.getCron().equals(other.getCron())) + && (this.getMethod() == null ? other.getMethod() == null : this.getMethod().equals(other.getMethod())) + && (this.getRemark() == null ? other.getRemark() == null : this.getRemark().equals(other.getRemark())) + && (this.getCreateTime() == null ? other.getCreateTime() == null : this.getCreateTime().equals(other.getCreateTime())); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((getId() == null) ? 0 : getId().hashCode()); + result = prime * result + ((getTaskName() == null) ? 0 : getTaskName().hashCode()); + result = prime * result + ((getCron() == null) ? 0 : getCron().hashCode()); + result = prime * result + ((getMethod() == null) ? 0 : getMethod().hashCode()); + result = prime * result + ((getRemark() == null) ? 0 : getRemark().hashCode()); + result = prime * result + ((getCreateTime() == null) ? 0 : getCreateTime().hashCode()); + return result; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(getClass().getSimpleName()); + sb.append(" ["); + sb.append("Hash = ").append(hashCode()); + sb.append(", id=").append(id); + sb.append(", taskName=").append(taskName); + sb.append(", cron=").append(cron); + sb.append(", method=").append(method); + sb.append(", remark=").append(remark); + sb.append(", createTime=").append(createTime); + sb.append(", serialVersionUID=").append(serialVersionUID); + sb.append("]"); + return sb.toString(); + } +} \ No newline at end of file diff --git a/sys-api/src/main/java/com/qihang/sys/api/service/EchoService.java b/sys-api/src/main/java/com/qihang/sys/api/feign/EchoService.java similarity index 75% rename from sys-api/src/main/java/com/qihang/sys/api/service/EchoService.java rename to sys-api/src/main/java/com/qihang/sys/api/feign/EchoService.java index 54f38aeb..31d0e43d 100644 --- a/sys-api/src/main/java/com/qihang/sys/api/service/EchoService.java +++ b/sys-api/src/main/java/com/qihang/sys/api/feign/EchoService.java @@ -1,10 +1,10 @@ -package com.qihang.sys.api.service; +package com.qihang.sys.api.feign; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; -@FeignClient(name = "tao-oms") +@FeignClient(name = "tao-api") public interface EchoService { @GetMapping(value = "/test/na") String echo(); diff --git a/sys-api/src/main/java/com/qihang/sys/api/mapper/SysTaskMapper.java b/sys-api/src/main/java/com/qihang/sys/api/mapper/SysTaskMapper.java new file mode 100644 index 00000000..1de8c665 --- /dev/null +++ b/sys-api/src/main/java/com/qihang/sys/api/mapper/SysTaskMapper.java @@ -0,0 +1,18 @@ +package com.qihang.sys.api.mapper; + +import com.qihang.sys.api.domain.SysTask; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** +* @author TW +* @description 针对表【sys_task】的数据库操作Mapper +* @createDate 2024-03-07 09:27:01 +* @Entity com.qihang.sys.api.domain.SysTask +*/ +public interface SysTaskMapper extends BaseMapper { + +} + + + + diff --git a/sys-api/src/main/java/com/qihang/sys/api/service/SysTaskService.java b/sys-api/src/main/java/com/qihang/sys/api/service/SysTaskService.java new file mode 100644 index 00000000..ead08149 --- /dev/null +++ b/sys-api/src/main/java/com/qihang/sys/api/service/SysTaskService.java @@ -0,0 +1,13 @@ +package com.qihang.sys.api.service; + +import com.qihang.sys.api.domain.SysTask; +import com.baomidou.mybatisplus.extension.service.IService; + +/** +* @author TW +* @description 针对表【sys_task】的数据库操作Service +* @createDate 2024-03-07 09:27:01 +*/ +public interface SysTaskService extends IService { + +} diff --git a/sys-api/src/main/java/com/qihang/sys/api/service/impl/SysTaskServiceImpl.java b/sys-api/src/main/java/com/qihang/sys/api/service/impl/SysTaskServiceImpl.java new file mode 100644 index 00000000..f26cb3ae --- /dev/null +++ b/sys-api/src/main/java/com/qihang/sys/api/service/impl/SysTaskServiceImpl.java @@ -0,0 +1,22 @@ +package com.qihang.sys.api.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.qihang.sys.api.domain.SysTask; +import com.qihang.sys.api.service.SysTaskService; +import com.qihang.sys.api.mapper.SysTaskMapper; +import org.springframework.stereotype.Service; + +/** +* @author TW +* @description 针对表【sys_task】的数据库操作Service实现 +* @createDate 2024-03-07 09:27:01 +*/ +@Service +public class SysTaskServiceImpl extends ServiceImpl + implements SysTaskService{ + +} + + + + diff --git a/sys-api/src/main/java/com/qihang/sys/api/task/OrderTaskJD.java b/sys-api/src/main/java/com/qihang/sys/api/task/OrderTaskJD.java new file mode 100644 index 00000000..c7773d99 --- /dev/null +++ b/sys-api/src/main/java/com/qihang/sys/api/task/OrderTaskJD.java @@ -0,0 +1,30 @@ +package com.qihang.sys.api.task; + +import com.qihang.sys.api.domain.SysTask; +import com.qihang.sys.api.feign.EchoService; +import com.qihang.sys.api.service.SysTaskService; +import com.qihang.sys.api.task.service.IPollableService; +import jakarta.annotation.Resource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + + +@Service +public class OrderTaskJD implements IPollableService { + @Autowired + private SysTaskService taskService; + @Resource + private EchoService echoService; + @Override + public void poll() { + String echo = echoService.echo(); + System.out.printf("更新京东订单%s",echo); + } + + @Override + public String getCronExpression() { + SysTask task = taskService.getById(2); +// return "0/1 * * * * ?"; + return task.getCron(); + } +} \ No newline at end of file diff --git a/sys-api/src/main/java/com/qihang/sys/api/task/core/CronTaskLoader.java b/sys-api/src/main/java/com/qihang/sys/api/task/core/CronTaskLoader.java new file mode 100644 index 00000000..381dd52a --- /dev/null +++ b/sys-api/src/main/java/com/qihang/sys/api/task/core/CronTaskLoader.java @@ -0,0 +1,45 @@ +package com.qihang.sys.api.task.core; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.util.concurrent.atomic.AtomicBoolean; + +@Component +public class CronTaskLoader implements ApplicationRunner { +// private static final Logger log = LoggerFactory.getLogger(CronTaskLoader.class); + private final SchedulingConfiguration schedulingConfiguration; + private final AtomicBoolean appStarted = new AtomicBoolean(false); + private final AtomicBoolean initializing = new AtomicBoolean(false); + + public CronTaskLoader(SchedulingConfiguration schedulingConfiguration) { + this.schedulingConfiguration = schedulingConfiguration; + } + + /** + * 定时任务配置刷新(1分钟刷新一次) + */ + @Scheduled(fixedDelay = 600000) + public void cronTaskConfigRefresh() { + if (appStarted.get() && initializing.compareAndSet(false, true)) { +// log.info("定时调度任务动态加载开始>>>>>>"); + try { + schedulingConfiguration.refresh(); + } finally { + initializing.set(false); + } +// log.info("定时调度任务动态加载结束<<<<<<"); + } + } + + @Override + public void run(ApplicationArguments args) { + if (appStarted.compareAndSet(false, true)) { + cronTaskConfigRefresh(); + } + } +} \ No newline at end of file diff --git a/sys-api/src/main/java/com/qihang/sys/api/task/core/SchedulingConfiguration.java b/sys-api/src/main/java/com/qihang/sys/api/task/core/SchedulingConfiguration.java new file mode 100644 index 00000000..2818cb23 --- /dev/null +++ b/sys-api/src/main/java/com/qihang/sys/api/task/core/SchedulingConfiguration.java @@ -0,0 +1,84 @@ +package com.qihang.sys.api.task.core; + +import com.qihang.sys.api.task.service.IPollableService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.SchedulingConfigurer; +import org.springframework.scheduling.config.CronTask; +import org.springframework.scheduling.config.ScheduledTask; +import org.springframework.scheduling.config.ScheduledTaskRegistrar; + +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +@Configuration +@EnableAsync +@EnableScheduling +public class SchedulingConfiguration implements SchedulingConfigurer, ApplicationContextAware { + private static final Logger log = LoggerFactory.getLogger(SchedulingConfiguration.class); + private static ApplicationContext appCtx; + private final ConcurrentMap scheduledTaskHolder = new ConcurrentHashMap<>(16); + private final ConcurrentMap cronExpressionHolder = new ConcurrentHashMap<>(16); + private ScheduledTaskRegistrar taskRegistrar; + + public static synchronized void setAppCtx(ApplicationContext appCtx) { + SchedulingConfiguration.appCtx = appCtx; + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + setAppCtx(applicationContext); + } + + @Override + public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { + this.taskRegistrar = taskRegistrar; + } + + /** + * 刷新定时任务表达式 + */ + public void refresh() { + Map beanMap = appCtx.getBeansOfType(IPollableService.class); + if (beanMap.isEmpty() || taskRegistrar == null) { + return; + } + beanMap.forEach((beanName, task) -> { + String expression = task.getCronExpression(); + String taskName = task.getTaskName(); + if (null == expression) { + log.warn("定时任务[{}]的任务表达式未配置或配置错误,请检查配置", taskName); + return; + } + // 如果策略执行时间发生了变化,则取消当前策略的任务,并重新注册任务 + boolean unmodified = scheduledTaskHolder.containsKey(beanName) && cronExpressionHolder.get(beanName).equals(expression); + if (unmodified) { + log.info("定时任务[{}]的任务表达式未发生变化,无需刷新", taskName); + return; + } + Optional.ofNullable(scheduledTaskHolder.remove(beanName)).ifPresent(existTask -> { + existTask.cancel(); + cronExpressionHolder.remove(beanName); + }); + if (ScheduledTaskRegistrar.CRON_DISABLED.equals(expression)) { + log.warn("定时任务[{}]的任务表达式配置为禁用,将被不会被调度执行", taskName); + return; + } + CronTask cronTask = new CronTask(task::poll, expression); + ScheduledTask scheduledTask = taskRegistrar.scheduleCronTask(cronTask); + if (scheduledTask != null) { + log.info("定时任务[{}]已加载,当前任务表达式为[{}]", taskName, expression); + scheduledTaskHolder.put(beanName, scheduledTask); + cronExpressionHolder.put(beanName, expression); + } + }); + } +} diff --git a/sys-api/src/main/java/com/qihang/sys/api/task/service/IPollableService.java b/sys-api/src/main/java/com/qihang/sys/api/task/service/IPollableService.java new file mode 100644 index 00000000..b23cb867 --- /dev/null +++ b/sys-api/src/main/java/com/qihang/sys/api/task/service/IPollableService.java @@ -0,0 +1,26 @@ +package com.qihang.sys.api.task.service; + +public interface IPollableService { + /** + * 执行方法 + */ + void poll(); + + /** + * 获取周期表达式 + * + * @return CronExpression + */ + default String getCronExpression() { + return null; + } + + /** + * 获取任务名称 + * + * @return 任务名称 + */ + default String getTaskName() { + return this.getClass().getSimpleName(); + } +} diff --git a/sys-api/src/main/resources/mapper/SysTaskMapper.xml b/sys-api/src/main/resources/mapper/SysTaskMapper.xml new file mode 100644 index 00000000..7c9460df --- /dev/null +++ b/sys-api/src/main/resources/mapper/SysTaskMapper.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + id,task_name,cron, + method,remark,create_time + + diff --git a/tao-api/src/main/java/com/qihang/tao/controller/HomeController.java b/tao-api/src/main/java/com/qihang/tao/controller/HomeController.java index cdc5cbd4..fcd916d4 100644 --- a/tao-api/src/main/java/com/qihang/tao/controller/HomeController.java +++ b/tao-api/src/main/java/com/qihang/tao/controller/HomeController.java @@ -28,7 +28,7 @@ HomeController { //https://open.taobao.com/v2/doc?spm=a219a.15212433.0.0.6aca669aUe3Kme#/abilityToOpen?treeId=780&docType=1&docId=102635 TaoGoods taoGoods = goodsMapper.selectById(1L); - return serverName; + return "serverName"; } }