java crumb_Java学习教程之定时任务全家桶

定时任务应用非常广泛,Java提供的现有解决方案有很多。

本次主要讲schedule、quartz、xxl-job、shedlock等相关的代码实践。

一、SpringBoot使用Schedule

核心代码:

@Component

public class ScheduleTask {

private Logger logger = LoggerFactory.getLogger(ScheduleTask.class);

@Scheduled(cron = "0/1 * * * * ? ")

public void one() {

logger.info("one:" + new Date());

}

@Scheduled(cron = "0/1 * * * * ? ")

public void two() {

logger.info("two:" + new Date());

}

@Scheduled(cron = "0/1 * * * * ? ")

public void three() {

logger.info("three:" + new Date());

}

}

运行效果如下:

37d4d1934ae975559ad9fb82a7e49110.png

除此之外还可以这样实现,核心代码:

@PropertySource(value = {

"classpath:task.properties",

}, encoding = "utf-8")

@Component("scheduleTask")

public class ScheduleTask implements SchedulingConfigurer {

@Value("${TEST_JOB_TASK_CRON}")

private String cron;

@Override

public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {

scheduledTaskRegistrar.addTriggerTask(new Runnable() {

@Override

public void run() {

System.out.println("执行任务:" + DateUtil.date());

}

}, new Trigger() {

@Override

public Date nextExecutionTime(TriggerContext triggerContext) {

return new CronTrigger(cron).nextExecutionTime(triggerContext);

}

});

}

public void setCron(String cron) {

this.cron = cron;

}

}

有朋友或许很疑惑,为什么要写这么一大堆,这个与前面的代码又有何区别呢?

区别是多线程并行。其实多线程并行也可以不用这么写,只需写一段核心配置类代码即可。

定时任务多线程配置类:

@Configuration

public class ScheduleConfig implements SchedulingConfigurer {

public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {

scheduledTaskRegistrar.setScheduler(Executors.newScheduledThreadPool(5));

}

}

再次启动,查看效果,如下:

168b5524f04b34c7ee2a935df56659e8.png

由此看出走不同的线程执行,不同的线程执行的好处是,如果某一个线程挂掉后,并不会阻塞导致其它定时任务无法执行。

另外如果要想并发执行,前面的配置可以不要,直接用SpringBoot提供的现成注解即可,核心代码如下:

@Component

@EnableAsync

public class ScheduleAsyncTask {

private Logger logger = LoggerFactory.getLogger(ScheduleAsyncTask.class);

@Scheduled(cron = "0/1 * * * * ? ")

@Async

public void one() {

logger.info("one Async:" + new Date());

}

@Scheduled(cron = "0/1 * * * * ? ")

@Async

public void two() {

logger.info("two Async:" + new Date());

}

@Scheduled(cron = "0/1 * * * * ? ")

@Async

public void three() {

logger.info("three Async:" + new Date());

}

}

除此外,还有基于schedule动态定时任务(所谓动态只不过是指cron表达式放在对应的数据表里),简单示例代码:

@Configuration

public class DynamicScheduleTask implements SchedulingConfigurer {

@Autowired

@SuppressWarnings("all")

CronMapper cronMapper;

@Mapper

public interface CronMapper {

@Select("select cron from cron limit 1")

public String getCron();

}

/**

* 执行定时任务.

*/

public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {

taskRegistrar.addTriggerTask(

//1.添加任务内容(Runnable)

() -> System.out.println("执行动态定时任务: " + LocalDateTime.now().toLocalTime()),

//2.设置执行周期(Trigger)

triggerContext -> {

//2.1 从数据库获取执行周期

String cron = cronMapper.getCron();

//2.2 合法性校验.

if (StringUtils.isEmpty(cron)) {

// Omitted Code ..

}

//2.3 返回执行周期(Date)

return new CronTrigger(cron).nextExecutionTime(triggerContext);

}

);

}

}

核心配置文件(application.yml):

spring:

datasource:

url: jdbc:mysql://127.0.0.1:3306/test

username: root

password: 1234

SQL脚本:

DROP DATABASE IF EXISTS `test`;

CREATE DATABASE `test`;

USE `test`;

DROP TABLE IF EXISTS `cron`;

CREATE TABLE `cron` (

`cron_id` varchar(30) NOT NULL PRIMARY KEY,

`cron` varchar(30) NOT NULL

);

INSERT INTO `cron` VALUES ('1', '0/5 * * * * ?');

运行效果如下:

c99cfbac74139ec5477f94586456597f.png

二、SpringBoot使用Quartz

1.Maven依赖

org.springframework.boot

spring-boot-starter-quartz

2.配置文件

spring:

quartz:

#相关属性配置

properties:

org:

quartz:

scheduler:

instanceName: clusteredScheduler

instanceId: AUTO

jobStore:

class: org.quartz.impl.jdbcjobstore.JobStoreTX

driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate

tablePrefix: QRTZ_

isClustered: true

clusterCheckinInterval: 10000

useProperties: false

threadPool:

class: org.quartz.simpl.SimpleThreadPool

threadCount: 10

threadPriority: 5

threadsInheritContextClassLoaderOfInitializingThread: true

#数据库方式

job-store-type: jdbc

#初始化表结构

jdbc:

initialize-schema: always

datasource:

url: jdbc:mysql://127.0.0.1:3306/test

username: root

password: 1234

3.启动类

@SpringBootApplication

@EnableScheduling

public class BlogQuartzApplication {

public static void main(String[] args) {

SpringApplication.run(BlogQuartzApplication.class, args);

}

}

4.配置类

@Configuration

public class QuartzConfiguration {

// 使用jobDetail包装job

@Bean

public JobDetail myCronJobDetail() {

return JobBuilder.newJob(CouponTimeOutJob.class).withIdentity("couponTimeOutJob").storeDurably().build();

}

// 把jobDetail注册到Cron表达式的trigger上去

@Bean

public Trigger CronJobTrigger() {

CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule("0/1 * * * * ?");

return TriggerBuilder.newTrigger()

.forJob(myCronJobDetail())

.withIdentity("CouponTimeOutJobTrigger")

.withSchedule(cronScheduleBuilder)

.build();

}

}

5.定时任务类

public class CouponTimeOutJob extends QuartzJobBean {

@Override

protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {

System.out.println("定时任务执行");

}

}

6.启动成功不报错

(1)对应的数据库会生成定时任务相关的数据表

9565d7e0a8ff403de767471631096ac7.png

(2)控制台不断输出定时任务执行日志

03939d47bc1b3adce577101ba940c6ba.png

三、SpringBoot使用xxl-job

之前写过一样的例子,如今简化了下。

关于xxl-job使用详情,可以参考我的这篇文章:

1.Maven依赖

com.xuxueli

xxl-job-core

2.2.0

2.配置类

@Configuration

public class XxlJobConfig {

private Logger logger = LoggerFactory.getLogger(XxlJobConfig.class);

@Value("${xxl.job.admin.addresses}")

private String adminAddresses;

@Value("${xxl.job.executor.appname}")

private String appName;

@Value("${xxl.job.executor.ip}")

private String ip;

@Value("${xxl.job.executor.port}")

private int port;

@Value("${xxl.job.accessToken}")

private String accessToken;

@Value("${xxl.job.executor.logpath}")

private String logPath;

@Value("${xxl.job.executor.logretentiondays}")

private int logRetentionDays;

@Bean(initMethod = "start", destroyMethod = "destroy")

public XxlJobSpringExecutor xxlJobExecutor() {

logger.info(">>>>>>>>>>> xxl-job config init.");

XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();

xxlJobSpringExecutor.setAdminAddresses(adminAddresses);

xxlJobSpringExecutor.setAppname(appName);

xxlJobSpringExecutor.setIp(ip);

xxlJobSpringExecutor.setPort(port);

xxlJobSpringExecutor.setAccessToken(accessToken);

xxlJobSpringExecutor.setLogPath(logPath);

xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);

return xxlJobSpringExecutor;

}

}

3.配置文件内容

# web port

server.port=8081

# no web

#spring.main.web-environment=false

### xxl-job admin address list, such as "http://address" or "http://address01,http://address02"

xxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin

### xxl-job, access token

xxl.job.accessToken=

### xxl-job executor appname

xxl.job.executor.appname=blog-job-xxl-job

### xxl-job executor registry-address: default use address to registry , otherwise use ip:port if address is null

xxl.job.executor.address=

### xxl-job executor server-info

xxl.job.executor.ip=

xxl.job.executor.port=8888

### xxl-job executor log-path

xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler

### xxl-job executor log-retention-days

xxl.job.executor.logretentiondays=30

4.定时任务类

@Component

public class XxlJobTaskExample {

@XxlJob("blogJobHandler")

public ReturnT blogJobHandler(String param) throws Exception {

System.out.println("执行");

XxlJobLogger.log("XXL-JOB, Hello World.");

for (int i = 0; i < 5; i++) {

XxlJobLogger.log("beat at:" + i);

TimeUnit.SECONDS.sleep(2);

}

return ReturnT.SUCCESS;

}

}

5.执行效果

分别如下所示:

9ed20acf3e4a062ff977dcde90e2d96d.png

7e11fd766022de3d6fd28b5d72fb4d3d.png

四、SpringBoot使用ShedLock

1.导入Maven依赖

net.javacrumbs.shedlock

shedlock-spring

4.0.4

net.javacrumbs.shedlock

shedlock-provider-redis-spring

2.5.0

org.springframework.boot

spring-boot-starter-data-redis

2.编写配置类

@Configuration

@EnableSchedulerLock(defaultLockAtMostFor = "PT30M")

public class ShedLockConfig {

@Bean

public LockProvider lockProvider(RedisTemplate redisTemplate) {

return new RedisLockProvider(redisTemplate.getConnectionFactory());

}

}

3.编写具体的定时任务

@Component

public class TaskSchedule {

/**

* 每分钟执行一次

* [秒] [分] [小时] [日] [月] [周] [年]

*/

@Scheduled(cron = "1 * * * * ?")

@SchedulerLock(name = "synchronousSchedule")

public void SynchronousSchedule() {

System.out.println("Start run schedule to synchronous data:" + new Date());

}

}

4.编写启动类

@SpringBootApplication

@EnableScheduling

public class ShedLockRedisApplication {

public static void main(String[] args) {

SpringApplication.run(ShedLockRedisApplication.class);

}

}

5.配置文件

server:

tomcat:

uri-encoding: UTF-8

max-threads: 1000

min-spare-threads: 30

port: 8083

spring:

redis:

database: 0

host: localhost

port: 6379

password: # 密码(默认为空)

timeout: 6000ms # 连接超时时长(毫秒)

jedis:

pool:

max-active: 1000 # 连接池最大连接数(使用负值表示没有限制)

max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)

max-idle: 10 # 连接池中的最大空闲连接

min-idle: 5 # 连接池中的最小空闲连接

6.测试

我之所以用shedlock是因为确保在集群环境下各微服务的定时任务只执行一个,而不是全部都运行相同的定时任务。

本次测试效果如下:

351e0507da08eff66c1cf08b1fd6c86d.png

到此这篇关于Java学习教程之定时任务全家桶的文章就介绍到这了,更多相关Java定时任务全家桶内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值