动态定时任务
使用的是springboot自带的定时任务:TaskScheduler,可动态控制定时任务。
定时任务已实现持久化,持久化方式为数据库,所以第一步需要建个存储任务的表,要求要有字段:enable_flag(是否开启任务)、cron_el(cron表达式)、identifier(任务标识符),SQL语句:
`enable_flag` tinyint unsigned DEFAULT '0',
`cron_el` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,
`identifier` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL
记得代码中引入mysql依赖和配置
- 建持久化的表
可参考建表语句:
表名不建议使用名称
wjjhook_task
,因为框架内实体是使用WjjhookTask
命名的。建议命名方式为
${projectName}_cron_task
CREATE TABLE `wjjhook_cron_task` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键',
`enable_flag` tinyint unsigned DEFAULT '0' COMMENT '是否开启任务',
`cron_el` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT 'cron表达式',
`identifier` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '任务标识符',
`memo` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '描述',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`create_by` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '创建人',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`update_by` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '更新人',
`del_flag` tinyint unsigned DEFAULT '0' COMMENT '逻辑删除',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_unique_identifier` (`identifier`,`del_flag`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
执行原理:
启动前手动在
@PostConstruct
方法中手动向任务池
中注册任务(以便扫描到的标识符能匹配到相应任务代码),进行执行。项目启动后会自 动调用*
IWjjhookTaskService.queryEnableList()
*的数据,进行启动执行。
使用:
-
建表,参考上述建表语句。(再次提醒,表名请勿使用
wjjhook_task
!以下以表名wjjhook_cron_task
为例) -
创建三个类(实现方法的拓展):
-
sql层:
WjjhookCronTaskMapper.xml
namespace需要根据自己包名设置
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.WangjjTaskMapper">
<select id="list" resultType="cn.skyisazure.wjjhook.module.WjjhookTaskModule">
SELECT
enable_flag,
cron_el,
identifier
FROM `wjjhook_cron_task`
WHERE del_flag = 0
</select>
<update id="updateTaskByIdentifier">
UPDATE `wjjhook_cron_task`
SET cron_el = #{cronEl}
WHERE identifier = #{identifier}
AND del_flag = 0
</update>
<update id="enableTaskByIdentifier">
UPDATE `wjjhook_cron_task`
SET enable_flag = 1
WHERE identifier = #{identifier}
AND del_flag = 0
</update>
<update id="disableTaskByIdentifier">
UPDATE `wjjhook_cron_task`
SET enable_flag = 0
WHERE identifier = #{identifier}
AND del_flag = 0
</update>
<update id="removeTask">
UPDATE `wjjhook_cron_task`
SET del_flag = 1
WHERE identifier = #{identifier}
AND del_flag = 0
</update>
</mapper> -
Dao层:
WjjhookCronTaskMapper
该类要被@MapperScan扫描到。
/**
* 定时任务
* @author wjian
*/
public interface WangjjTaskMapper {
/**
* 返回所有定时任务
* @return
*/
List<WjjhookTaskModule> list();
/**
* 修改定时任务表达式
* @param identifier
* @param cronEl
*/
void updateTaskByIdentifier(@Param("identifier") String identifier,@Param("cronEl") String cronEl);
/**
* 开启定时任务
* @param identifier
*/
void enableTaskByIdentifier(@Param("identifier") String identifier);
/**
* 禁用定时任务
* @param identifier
*/
void disableTaskByIdentifier(@Param("identifier") String identifier);
/**
* 删除定时任务
* @param identifier
*/
void removeTask(@Param("identifier") String identifier);
} -
实现类:
WjjhookTaskServiceImpl
/**
* 任务持久化实现类
* @author wangjj
*/
@Service
@RequiredArgsConstructor
public class WjjhookTaskServiceImpl implements IWjjhookTaskService {
private final WangjjTaskMapper wangjjTaskMapper;
/**
* 返回所有定时任务
* @return
*/
@Override
public List<WjjhookTaskModule> list() {
return wangjjTaskMapper.list();
}
/**
* 修改定时任务表达式
*
* @param identifier
* @param cronEl
* @return
*/
@Override
public void updateTaskByIdentifier(String identifier, String cronEl) {
wangjjTaskMapper.updateTaskByIdentifier(identifier, cronEl);
}
/**
* 开启定时任务
* @param identifier
* @return
*/
@Override
public void enableTaskByIdentifier(String identifier) {
wangjjTaskMapper.enableTaskByIdentifier(identifier);
}
/**
* 禁用定时任务
*
* @param identifier
* @return
*/
@Override
public void disableTaskByIdentifier(String identifier) {
wangjjTaskMapper.disableTaskByIdentifier(identifier);
}
/**
* 删除定时任务
*
* @param identifier
* @return
*/
@Override
public void removeTask(String identifier) {
wangjjTaskMapper.removeTask(identifier);
}
}
-
-
定义任务:
建一个存放定时任务的包:
com.example.core.task
,在该包下新建自己的任务类:/**
* 打印当前当前时间
* @author wangjj
*/
public class SimpleTask implements Runnable{
@Override
public void run() {
System.out.println("当前时间:"+LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
}
} -
注册任务(将第3步中定义的任务注册到任务中):
推荐第二种:自动注册。
-
第一种,手动注册: 在启动类中加入
@PostConstruct
注解的方法,注册任务示例:@SpringBootApplication
@MapperScan({"com.example.*.mapper"})
@EnableWjjhook(apiSelectorPackages = {
@ApiSelectorPackage(value = "com.example.demo.controller"),
})
public class ExampleDemoApplication {
public static void main(String[] args) {
SpringApplication.run(ExampleDemoApplication.class, args);
}
/**
* 注册任务
*/
@PostConstruct
public void registrarRunnable(){
TaskRegistrar taskRegistrar = SpringUtil.getBean(TaskRegistrar.class);
taskRegistrar.register("printTaskPool",new SimpleTask());
}
} -
第二种,自动注册:
借助于@Task注解,创建任务类,实现接口Runnable
优势:可使用@Autowired、@Resource注入bean,无需通过多余代码进行注入。
@Task(identifier = "simpleTask")
public class SimpleTask implements Runnable {
@Resource
private UserServer userServer;
@Override
public void run() {
System.out.println(getClass().getSimpleName()+",当前时间:"+ LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")));
}
}
-
最后在数据库中加入任务:
示例:
INSERT INTO `wjjhook_cron_task`
(`id`, `enable_flag`, `cron_el`, `identifier`, `memo`, `create_time`, `create_by`, `update_time`, `update_by`, `del_flag`)
VALUES
(5, 0, '*/1 * * * * ?', 'demo', '测试用', '2022-12-31 23:59:59', NULL, NULL, NULL, 0);
最后
注册任务那,手动注册,我建议按上述方式去写注册,其实也可以在SpringApplication.run(NiceDemoApplication.class, args);
后注册。