在物联网络,很多设备之间都在进行交互,其中云端在远程交流中起到了很重要的作用。比如,一台设备想进行调温,但是需要知道此时房间的温度,那就需要定时去查询传感器测出来的房间温度,如果温度过高,就降低温度, 否则就升高温度。在这个过程中云端就需要对传感器的状态进行监控,其中的定时任务就起到了作用。
什么是定时任务呢?
定时任务简答来说就是在指定时间内触发执行某个动作,比如早上设备了闹钟,提醒你起床。
在SpringBoot
应用中,有提供@EnableScheduling
、@Scheduled
来实现定时。其中:
@Scheduled
注解是SpringBoot
提供的⽤于定时任务控制的注解,主要⽤于控制任务在某个指定时间执⾏,或者每隔⼀段时间执⾏。
注意需要配合@EnableScheduling
使⽤,定时任务需要在配置类上添加@EnableScheduling
,表示对定时任务的支持;在对应执行任务的方法上添加@Scheduled
,声明需要执行定时任务的方法。
@Scheduled
主要有三种配置执⾏时间的⽅式:cron
、fixedRate
、fixedDelay
。例子分别是:
@Scheduled(cron = "0 0/5 * * * ?")
// 每5分钟执行一次@Scheduled(fixedDelay = 10000)
// fixedDelay 表示固定延迟时间,上个任务完成后,延迟多长时间执行@Scheduled(fixedRate = 1000 * 60)
// 按照一定频率执行任务,每隔1分钟执行一次 使用@Scheduled
注解的方式非常简单,首先我们创建一个类,并且加上@Component
注解,确保可以被扫描。 然后我们在方法上加上这里要用到的定时任务注解@Scheduled
() 其中,有个参数 cron=""
,是用来写入cron
表达式的。
@Component
public class CronJob{
// 定义每隔5分钟执行一次“Hello World”打印
`@Scheduled`(cron="0 0/5 * * * ?")
public void printHWScheduled(){
System.out.println("Hello World");
}
}
具体的cron
表达式练习:
具体的cron
表达式练习
除了配置@Scheduled
注解,还需要在启动类上添加注解@EnableScheduling
,以上两步就可以实现对方法实现定时。
@EnableScheduling
@SpringBootApplication
public class HelloWorldApplication {
public static void main(String[] args) {
SpringApplication.run(HelloWorldApplication.class, args);
}
}
综上所述,使用注解的方式在SpringBoot
的框架是非常方便实现定时任务的。但是也存在缺点:
cron
时, 以注解的方式就显得力不从心。对此接下来介绍一种,轻量化分布式任务调度平台。xxl-job
,地址为:
xxl-job项目地址
XXL-JOB
是一个分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。该项目在github
完全开源,有着丰富的文档、活跃的社区。由于其开箱即用,已经被很多互联网公司接入产品线。
相较于@Scheduled
注解,xxl-job
有着一下的优点:
等等,还有其他的优点。
接下就演示一下,在本地如何搭建一个xxl-job
服务。
clone
项目到本地xxl-job-admin
中的数据库路径maven
对项目进行打包,在终端使用命令:mvn install
。如下图所示,生成了一个war包如果出现了以上的界面,就说明任务调度中心Web界面就搭建完成。
接下来讲解下在SpringBoot
中如何使用xxl-job
。
pom.xml
中导入依赖<dependency>
<groupId>com.xuxueligroupId>
<artifactId>xxl-job-coreartifactId>
<version>2.3.1version>
dependency>
package com.xxl.job.executor.core.config;
import com.xxl.job.core.executor.XxlJobExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* xxl-job config
*
* @author xuxueli 2017-04-28
*/
@Configuration
@ComponentScan(basePackages = "com.xxl.job.executor.service.jobhandler")
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 XxlJobExecutor xxlJobExecutor() {
logger.info(">>>>>>>>>>> xxl-job config init.");
XxlJobExecutor xxlJobExecutor = new XxlJobExecutor();
xxlJobExecutor.setAdminAddresses(adminAddresses);
xxlJobExecutor.setAppName(appName);
xxlJobExecutor.setIp(ip);
xxlJobExecutor.setPort(port);
xxlJobExecutor.setAccessToken(accessToken);
xxlJobExecutor.setLogPath(logPath);
xxlJobExecutor.setLogRetentionDays(logRetentionDays);
return xxlJobExecutor;
}
}
每个配置的含义如下:
/**
### 调度中心部署根地址 [选填]:如调度中心集群部署存在多个地址则用逗号分隔。执行器将会使用该地址进行"执行器心跳注册"和"任务结果回调";为空则关闭自动注册;
xxl.job.admin.addresses=http://localhost:8080/xxl-job-admin
### 执行器通讯TOKEN [选填]:非空时启用;
xxl.job.accessToken=
### 执行器AppName [选填]:执行器心跳注册分组依据;为空则关闭自动注册
xxl.job.executor.appname=xxl-job-executor-sample
### 执行器注册 [选填]:优先使用该配置作为注册地址,为空时使用内嵌服务 ”IP:PORT“ 作为注册地址。从而更灵活的支持容器类型执行器动态IP和动态映射端口问题。
xxl.job.executor.address=
### 执行器IP [选填]:默认为空表示自动获取IP,多网卡时可手动设置指定IP,该IP不会绑定Host仅作为通讯实用;地址信息用于 "执行器注册" 和 "调度中心请求并触发任务";
xxl.job.executor.ip=
### 执行器端口号 [选填]:小于等于0则自动获取;默认端口为9999,单机部署多个执行器时,注意要配置不同执行器端口;
xxl.job.executor.port=9999
### 执行器运行日志文件存储磁盘路径 [选填] :需要对该路径拥有读写权限;为空则使用默认路径;
xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler
### 执行器日志文件保存天数 [选填] : 过期日志自动清理, 限制值大于等于3时生效; 否则, 如-1, 关闭自动清理功能;
xxl.job.executor.logretentiondays=30
* @return
*/
IJobHandler
接口,实现execute
方法,业务实现就在这里实现。package com.xxl.job.executor.service.jobhandler;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.IJobHandler;
import com.xxl.job.core.handler.annotation.JobHandler;
import com.xxl.job.core.log.XxlJobLogger;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
/**
* 任务Handler示例(Bean模式)
*
* 开发步骤:
* 1、继承"IJobHandler":“com.xxl.job.core.handler.IJobHandler”;
* 2、注册到Spring容器:添加“@Component”注解,被Spring容器扫描为Bean实例;
* 3、注册到执行器工厂:添加“@JobHandler(value="自定义jobhandler名称")”注解,注解value值对应的是调度中心新建任务的JobHandler属性的值。
* 4、执行日志:需要通过 "XxlJobLogger.log" 打印执行日志;
*
* @author xuxueli 2015-12-19 19:43:36
*/
@JobHandler(value="demoJobHandler")
@Component
public class DemoJobHandler extends IJobHandler {
@Override
public ReturnT<String> execute(String param) throws Exception {
XxlJobLogger.log("XXL-JOB, Hello World.");
for (int i = 0; i < 5; i++) {
XxlJobLogger.log("beat at:" + i);
TimeUnit.SECONDS.sleep(2);
}
return SUCCESS;
}
}
SpringBoot
项目,配置日志执行:如下显示demoJobHandler
已经注册成功,并且执行成功了两次
17:41:34.934 logback [Thread-7] INFO c.x.j.c.t.ExecutorRegistryThread - >>>>>>>>>>> xxl-job registry success, registryParam:RegistryParam{registGroup='EXECUTOR', registryKey='xxl-job-ex
ecutor-sample', registryValue='10.14.161.30:9999'}, registryResult:ReturnT [code=200, msg=null, content=null]
17:42:04.952 logback [Thread-7] INFO c.x.j.c.t.ExecutorRegistryThread - >>>>>>>>>>> xxl-job registry success, registryParam:RegistryParam{registGroup='EXECUTOR', registryKey='xxl-job-ex
ecutor-sample', registryValue='10.14.161.30:9999'}, registryResult:ReturnT [code=200, msg=null, content=null]
综上所述,一共讨论了两种定时的实现方式,所有的操作都是基于SpringBoot
框架实现的;每种方式都要自己的优势所在,可以根据自己业务的难易进行选择;以上的步骤亲测可以实现,欢迎留言讨论。