XXL任务调度平台+java实现定时任务
一、JDK介绍 JDK是 Java 语言的软件开发工具包,主要用于移动设备、嵌入式设备上的java应用程序。JDK是整个java开发的核心,它包含了JAVA的运行环境(JVM+Java系统类库)和JAVA工具。二、准备工作(以下步骤自己有可以跳过) 1、需要准备一台服务器,大家可以在网上买,个人学习的话还是建议大家去安装一个虚拟机,去装一个Linux系统。关键字点击跳转:虚拟机安装教程
1.java实现定时任务的四种方案
1.1:Thread
/** * 定时任务----Thread * Created by lizhen on 2018/4/9 0009. */ public class TimeTask001 { public static int i = 0; public static void main(String[] args) { new Thread(new Runnable() { @Override public void run() { while(true){ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("我是定时任务:"+ ++i); } } }).start(); } }
1.2:TimerTask
import java.util.Timer; import java.util.TimerTask; /** * 定时任务====TimeTask * Created by lizhen on 2018/4/9 0009. */ public class TimeTask002 { public static int i= 0; public static void main(String[] args) { //执行任务代码 TimerTask timerTask = new TimerTask() { @Override public void run() { System.out.println("我是定时任务:"+ ++i); } }; Timer timer = new Timer(); //天数 long day = 0; //秒数 long mili = 1000; timer.schedule(timerTask,day,mili); } }
1.3:newSingleThreadScheduledExecuto(定时的单线程池)
/** * 定时任务====创建可定时的线程池 * Created by lizhen on 2018/4/9 0009. */ public class TimeTask003 { public static void main(String[] args) { Runnable runnable = new Runnable() { @Override public void run() { System.out.println("马上就要辞职,需要抓紧准备。。。。。"); } }; ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); // 第二个参数为首次执行的延时时间,第三个参数为定时执行的间隔时间 scheduledExecutorService.scheduleAtFixedRate(runnable, 1, 1, TimeUnit.SECONDS); } }
1.4:引入Quartz框架执行定时任务
1.4.1:引入maven依赖
<!-- quartz 定时任务调度框架 --> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.2.1</version> </dependency> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz-jobs</artifactId> <version>2.2.1</version> </dependency>
1.4.2:创建Quartz的启动类
/** * 定时任务====quartz启动类 * Created by lizhen on 2018/4/9 0009. */ public class StartJob { public static void main(String[] args) throws SchedulerException { //1.创建Scheduler的工厂 SchedulerFactory sf = new StdSchedulerFactory(); //2.从工厂中获取调度器实例 Scheduler scheduler = sf.getScheduler(); //3.创建JobDetail JobDetail jb = JobBuilder.newJob(MyJob.class) .withDescription("this is a ram job") //job的描述 .withIdentity("ramJob", "ramGroup") //job 的name和group .build(); //任务运行的时间,SimpleSchedle类型触发器有效 long time = System.currentTimeMillis() + 3 * 1000L; //3秒后启动任务 Date statTime = new Date(time); //4.创建Trigger //使用SimpleScheduleBuilder或者CronScheduleBuilder Trigger t = TriggerBuilder.newTrigger() .withDescription("") .withIdentity("ramTrigger", "ramTriggerGroup") //.withSchedule(SimpleScheduleBuilder.simpleSchedule()) .startAt(statTime) //默认当前时间启动,下面的用到了Quartz表达式:http://cron.qqe2.com/ .withSchedule(CronScheduleBuilder.cronSchedule("0/2 * * * * ?")) //两秒执行一次 .build(); //5.注册任务和定时器 scheduler.scheduleJob(jb, t); //6.启动 调度器 scheduler.start(); } }
1.4.3:创建执行任务的具体类
/** * 定时任务====quartz框架实现 * Created by lizhen on 2018/4/9 0009. */ public class MyJob implements Job { public void execute(JobExecutionContext context) throws JobExecutionException { System.out.println("quartz MyJob date:" + new Date().getTime()); } }
2.分布式Job
2.1在说分布式job之前,我们先考虑一下,传统的定时任务调度的缺点?
1.没有补偿机制,一旦出现异常,那么就不会执行,需要等到第二次的任务才能执行。
2.不支持集群,不支持路由策略(就是不能轮训)
3.没有管理平台,无法做统计
4.没有报警邮箱,状态监控(比如有了异常,假如我们重复执行,仍然失败怎么办?)
因为传统的定时任务这么多缺点,所以我们才会使用分布式任务调度平台
2.2那么集群情况下,分布式job怎么解决幂等性?
1.使用分布式锁,(ZK,redis)保证只有一台服务器在执行定时job
2.使用配置文件,配置文件上加上开关,flag=true的情况下才执行,false不执行。打包的时候,打不一样的配置文件的包。
3.使用数据库的唯一标识,谁插入进去,谁就执行,但是效率低,一般不会采用。
3.分布式任务调度平台之XXL—Job
XXL-RPC是一个分布式服务通讯框架,提供稳定高性能的RPC远程服务调用功能
官方文档地址:xxl的官方文档地址
3.1XXL设计思想
我们先将请求(任务JobHandler)注册到调度中心平台,而平台自身并不承担业务逻辑,“调度中心”负责发起调度请求。
将任务抽象成分散的JobHandler,交由“执行器”统一管理,“执行器”负责接收调度请求并执行对应的JobHandler中业务逻辑。因此,“调度”和“任务”两部分可以相互解耦,提高系统整体稳定性和扩展性;
3.2系统组成
任务:JobHandler,比如我要在handler里面记录日志,我要做的事情就是在handler里面。
执行器jetty:负责接收调度请求的服务器,接收之后调用JobHandler去执行任务逻辑。
调度中心:将执行器和任务注册至调度中心,由调度中心根据配置发出调度请求。先配置执行器,然后创建任务,因为任务是由执行器统一管理。
上面是我自己的理解,我们再看下一官方解释。
调度模块(调度中心): 负责管理调度信息,按照调度配置发出调度请求,自身不承担业务代码。调度系统与任务解耦,提高了系统可用性和稳定性,同时调度系统性能不再受限于任务模块; 支持可视化、简单且动态的管理调度信息,包括任务新建,更新,删除,GLUE开发和任务报警等,所有上述操作都会实时生效,同时支持监控调度结果以及执行日志,支持执行器Failover。
执行模块(执行器): 负责接收调度请求并执行任务逻辑。任务模块专注于任务的执行等操作,开发和维护更加简单和高效; 接收“调度中心”的执行请求、终止请求和日志请求等。
3.1配置部署调度中心
自己修改后的源码: https://github.com/lizhen376751/xxl-job-master.git
XXL-job的GitHub的源码: https://github.com/xuxueli/xxl-job
Quartz的cron的表达式地址 : http://cron.qqe2.com/
下载我的源码之后就是这种结构
/xxl-job/xxl-job-admin/src/main/resources/xxl-job-admin.properties 调度中心配置的配置,JDBC链接,报警邮箱,登录账号都在这个配置文件里面配置
需要注意jdbc的配置:xxl.job.db.url=jdbc:mysql://localhost:3306/xxl-job?useUnicode=true&characterEncoding=UTF-8
创建xxl-job的数据库,同时将xxl-job-master\xxl-job-master\doc\db\tables_xxl_job.sql 里面的sql语句黏贴复制,并执行所有的sql语句。其它的配置文件不需要修改,tomcat启动即可。
调度中心访问地址:http://localhost:8080/xxl-job-admin (该地址执行器将会使用到,作为回调地址,在执行器项目里面我们也会将这个注册地址进行配置,后面的项目名要么都加要么都去掉,我是没有加的),登录后运行界面如下图所示
3.2配置部署执行器
我是用springboot进行配置的,我的源码中已经配置好了,下面的教程是在另一个项目中去搭建的执行器
1.引入maven文件
<!--XXL-job--> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-server</artifactId> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-util</artifactId> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-http</artifactId> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-io</artifactId> </dependency> <dependency> <groupId>com.xuxueli</groupId> <artifactId>xxl-job-core</artifactId> <version>1.8.2</version> </dependency> <!--XXL-job-->
2.从调度中心我的源码中,在spring-boot的demo中将logback.xml和XxlJobConfig.java复制到新建的项目中。
3.在application.properties配置执行器的相关配置
#XXL相关配置 logging.config=classpath:logback.xml ### xxl-job admin address list:调度中心部署跟地址:如调度中心集群部署存在多个地址则用逗号分隔。执行器将会使用该地址进行"执行器心跳注册"和"任务结果回调"。 xxl.job.admin.addresses=http://127.0.0.1:8081 ### xxl-job executor address:执行器"AppName"和地址信息配置:AppName执行器心跳注册分组依据; #地址信息用于"调度中心请求并触发任务"和"执行器注册"。 #执行器默认端口为9999 xxl.job.executor.appname=myjobtest xxl.job.executor.ip=192.168.1.153 xxl.job.executor.port=9999 ### xxl-job log path 执行器运行日志文件存储的磁盘位置,需要对该路径拥有读写权限 xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler/
4.创建任务JobHandler
import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.handler.IJobHandler; import com.xxl.job.core.handler.annotation.JobHander; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; /** * xxl-job 自己写的定时任务 * Created by lizhen on 2018/4/9 0009. * <p> * 任务Handler的一个Demo(Bean模式) * <p> * 开发步骤: * 1、继承 “IJobHandler” ; * 2、装配到Spring,例如加 “@Service” 注解; * 3、加 “@JobHander” 注解,注解value值为新增任务生成的JobKey的值;多个JobKey用逗号分割; * 4、执行日志:需要通过 "XxlJobLogger.log" 打印执行日志; */ @Service @JobHander("myjobhandler") public class MyJobHandler extends IJobHandler { @Value("${xxl.job.executor.port}") private String port; @Override public ReturnT<String> execute(String... strings) throws Exception { System.out.println("定时任务调度成功===="+strings[0]+"===="+strings[1]+"=========="+strings[2]+"======+port:" + port); ReturnT.SUCCESS.setContent("success good good"); ReturnT.SUCCESS.setMsg("hello word!"); return ReturnT.SUCCESS; } }
5.启动项目即可,新项目的目录结构如图所示:
3.3将执行器和任务注册至调度中心
配置执行器
新建任务
cron表达式的配置 http://cron.qqe2.com/
查看调度日志
BEAN模式:任务逻辑以JobHandler的形式存在于“执行器”就是文章所演示的这种形式。
GLUE模式(Java):任务以源码方式维护在调度中心,支持通过Web IDE在线更新,实时编译和生效,因此不需要指定JobHandler。意思就是我们的代码不在项目里面进行维护,是将代码写在调度中心的平台上,实时的更新。剩下的模式大家可以看文档。
更多推荐
所有评论(0)