1.概述
Elastic-Job是一个分布式调度解决方案,由两个相互独立的子项目Elastic-Job-Lite和Elastic-Job-Cloud组成。
Elastic-Job-Lite定位为轻量级无中心化解决方案,使用jar包的形式提供最轻量级的分布式任务的协调服务,外部依赖仅Zookeeper。
官网文档地址:http://elasticjob.io/
2.项目实战
第一步:引入maven依赖jar
<dependency>
<groupId>com.dangdang</groupId>
<artifactId>elastic-job-lite-core</artifactId>
<version>2.1.5</version>
</dependency>
<dependency>
<groupId>com.dangdang</groupId>
<artifactId>elastic-job-lite-spring</artifactId>
<version>2.1.5</version>
</dependency>
<dependency>
<groupId>com.dangdang</groupId>
<artifactId>elastic-job-common-core</artifactId>
<version>2.1.5</version>
</dependency>
第二步:配置elasticjob.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:reg="http://www.dangdang.com/schema/ddframe/reg"
xmlns:job="http://www.dangdang.com/schema/ddframe/job"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.dangdang.com/schema/ddframe/reg
http://www.dangdang.com/schema/ddframe/reg/reg.xsd
http://www.dangdang.com/schema/ddframe/job
http://www.dangdang.com/schema/ddframe/job/job.xsd
">
<!--配置注册中心 -->
<reg:zookeeper id="regCenter"
server-lists="127.0.0.1:2181"
namespace="dd-job"
base-sleep-time-milliseconds="1000"
max-sleep-time-milliseconds="3000"
max-retries="3" />
<!-- 配置任务-->
<job:simple id="myElasticJob"
class="com.task.MyElasticJob"
registry-center-ref="regCenter"
cron="*/10 * * * * ?"
sharding-total-count="1"
overwrite="true" >
<!--监听器,定时任务执行前,执行后的处理-->
<job:listener class="com.task.MyElasticJobListener"/>
<!--分布式监听器,定时任务执行前,执行后的处理 只会在一台机器上面执行-->
<job:distributed-listener class="com.task.MyAbstractDistributeOnceElasticJobListener"
started-timeout-milliseconds="30000"
completed-timeout-milliseconds="30000"/>
</job:simple>
<!-- 配置带作业数据库事件追踪的简单作业-->
<job:simple id="eventTraceElasticJob"
class="com.task.MySimpleListenerElasticJob"
registry-center-ref="regCenter"
cron="*/10 * * * * ?"
sharding-total-count="1"
sharding-item-parameters="0=A,1=B,2=C"
event-trace-rdb-data-source="dataSource">
</job:simple>
</beans>
第三步:编写任务作业类,任务监听类
任务作业类 MyElasticJo.class
编写需要处理的业务逻辑
package com.task;
import com.dangdang.ddframe.job.api.ShardingContext;
import com.dangdang.ddframe.job.api.simple.SimpleJob;
import lombok.extern.slf4j.Slf4j;
import java.net.InetAddress;
import java.net.UnknownHostException;
@Slf4j
public class MyElasticJob implements SimpleJob {
@Override
public void execute(ShardingContext shardingContext) {
log.info("该执行定时任务了=========================");
try {
log.info("本机ip地址========================="+ InetAddress.getLocalHost().getHostAddress());
log.info(String.format("------Thread ID: %s, 任务总片数: %s, 当前分片项: %s",
Thread.currentThread().getId(), shardingContext.getShardingTotalCount(), shardingContext.getShardingItem()));
/**
* 实际开发中,有了任务总片数和当前分片项,就可以对任务进行分片执行了
* 比如 SELECT * FROM user WHERE status = 0 AND MOD(id, shardingTotalCount) = shardingItem
*/
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
}
任务监听类 MyElasticJobListener.class
任务作业前,作业后所需要处理的业务逻辑
package com.task;
import com.dangdang.ddframe.job.executor.ShardingContexts;
import com.dangdang.ddframe.job.lite.api.listener.ElasticJobListener;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class MyElasticJobListener implements ElasticJobListener {
@Override
public void beforeJobExecuted(ShardingContexts shardingContexts) {
// do something ...
log.info("该执行定时任务了======beforeJobExecuted");
}
@Override
public void afterJobExecuted(ShardingContexts shardingContexts) {
// do something ...
log.info("该执行定时任务了======afterJobExecuted");
}
}
任务监听类 MyAbstractDistributeOnceElasticJobListener.class
任务作业前,作业后所需要处理的业务逻辑-分布式应用中只会在一台服务器上面执行
package com.task;
import com.dangdang.ddframe.job.executor.ShardingContexts;
import com.dangdang.ddframe.job.lite.api.listener.AbstractDistributeOnceElasticJobListener;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class MyAbstractDistributeOnceElasticJobListener extends AbstractDistributeOnceElasticJobListener {
public MyAbstractDistributeOnceElasticJobListener(long startedTimeoutMilliseconds, long completedTimeoutMilliseconds) {
super(startedTimeoutMilliseconds, completedTimeoutMilliseconds);
}
@Override
public void doBeforeJobExecutedAtLastStarted(ShardingContexts shardingContexts) {
// do something ...
log.info("该执行定时任务了======doBeforeJobExecutedAtLastStarted");
}
@Override
public void doAfterJobExecutedAtLastCompleted(ShardingContexts shardingContexts) {
// do something ...
log.info("该执行定时任务了======doAfterJobExecutedAtLastCompleted");
}
}
任务作业类 MySimpleListenerElasticJob.class
编写需要处理的业务逻辑-带作业数据库事件追踪的简单作业(跟普通任务作业一样只是在配置中新增了event-trace-rdb-data-source="dataSource" 用于监控作业的状态)
package com.task;
import com.dangdang.ddframe.job.api.ShardingContext;
import com.dangdang.ddframe.job.api.simple.SimpleJob;
import lombok.extern.slf4j.Slf4j;
import java.net.InetAddress;
import java.net.UnknownHostException;
@Slf4j
public class MySimpleListenerElasticJob implements SimpleJob {
@Override
public void execute(ShardingContext shardingContext) {
log.info("Listener该执行定时任务了=========================");
try {
log.info("Listener本机ip地址========================="+ InetAddress.getLocalHost().getHostAddress());
log.info(String.format("Listener------Thread ID: %s, 任务总片数: %s, 当前分片项: %s",
Thread.currentThread().getId(), shardingContext.getShardingTotalCount(), shardingContext.getShardingItem()));
/**
* 实际开发中,有了任务总片数和当前分片项,就可以对任务进行分片执行了
* 比如 SELECT * FROM user WHERE status = 0 AND MOD(id, shardingTotalCount) = shardingItem
*/
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
}
如上所述所有基础配置都已经配置完成,启动项目查看日志即可。具体详细配置根据自己业务配置,更多的配置参数请查看官网文档。
第二种方式:纯java代码方式
第一步:新增配置文件.yml文件也行 application.properties
reg-center.server-list: 127.0.0.1:2181
reg-center.namespace: elastic-job-lite-spring-boot
monitor.cron: 0/5 * * * * ?
monitor.sharding-total-count: 2
monitor.sharding-item-parameters: 0=CIB,1=ICBC
monitor.job-description: 监控
monitor.job-parameter: hello elastic job
第二步:新增作业,监听,配置java类
package com.config;
import com.dangdang.ddframe.job.lite.api.JobScheduler;
import com.dangdang.ddframe.job.lite.config.LiteJobConfiguration;
import com.dangdang.ddframe.job.lite.spring.api.SpringJobScheduler;
import com.dangdang.ddframe.job.reg.zookeeper.ZookeeperRegistryCenter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 作业配置
*/
@Configuration
public class MonitorJobConfig {
@Autowired
private ZookeeperRegistryCenter regCenter;
@Autowired
private ServiceMonitor serviceMonitor;
@Autowired
private LiteJobConfiguration liteJobConfiguration;
@Autowired
private ServiceListener serviceListener;
@Bean(initMethod = "init")
public JobScheduler simpleJobScheduler() {
return new SpringJobScheduler(serviceMonitor
, regCenter
, liteJobConfiguration,serviceListener);
}
}
package com.config;
import com.dangdang.ddframe.job.config.JobCoreConfiguration;
import com.dangdang.ddframe.job.config.simple.SimpleJobConfiguration;
import com.dangdang.ddframe.job.lite.config.LiteJobConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 作业属性
*/
@Configuration
public class MonitorJobProperties {
@Value("${monitor.cron:#{null}}")
private String cron;
@Value("${monitor.sharding-total-count:#{null}}")
private int shardingTotalCount;
@Value("${monitor.sharding-item-parameters:#{null}}")
private String shardingItemParameters;
@Value("${monitor.job-description:#{null}}")
private String jobDescription;
@Value("${monitor.job-parameter:#{null}}")
private String jobParameter;
@Autowired
private ServiceMonitor serviceMonitor;
@Bean
public LiteJobConfiguration liteJobConfiguration() {
JobCoreConfiguration.Builder builder = JobCoreConfiguration.newBuilder(serviceMonitor.getClass().getName()
, cron, shardingTotalCount);
JobCoreConfiguration jobCoreConfiguration = builder
.shardingItemParameters(shardingItemParameters)
.description(jobDescription)
.jobParameter(jobParameter)
.build();
SimpleJobConfiguration simpleJobConfiguration = new SimpleJobConfiguration(jobCoreConfiguration, serviceMonitor.getClass().getCanonicalName());
return LiteJobConfiguration
.newBuilder(simpleJobConfiguration)
.overwrite(true)
.build();
}
}
package com.config;
import com.dangdang.ddframe.job.reg.zookeeper.ZookeeperConfiguration;
import com.dangdang.ddframe.job.reg.zookeeper.ZookeeperRegistryCenter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 注册中心配置
*/
@Configuration
public class RegistryCenterConfig {
@Value("${reg-center.server-list:#{null}}")
private String serverList;
@Value("${reg-center.namespace:#{null}}")
private String namespace;
@Bean(initMethod = "init")
public ZookeeperRegistryCenter regCenter() {
return new ZookeeperRegistryCenter(new ZookeeperConfiguration(serverList, namespace));
}
}
package com.config;
import com.dangdang.ddframe.job.executor.ShardingContexts;
import com.dangdang.ddframe.job.lite.api.listener.ElasticJobListener;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class ServiceListener implements ElasticJobListener {
@Override
public void beforeJobExecuted(ShardingContexts shardingContexts) {
// do something ...
log.info("该执行定时任务了======beforeJobExecuted");
}
@Override
public void afterJobExecuted(ShardingContexts shardingContexts) {
// do something ...
log.info("该执行定时任务了======afterJobExecuted");
}
}
package com.config;
import com.dangdang.ddframe.job.api.ShardingContext;
import com.dangdang.ddframe.job.api.simple.SimpleJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* 作业
*/
@Component
@Slf4j
public class ServiceMonitor implements SimpleJob {
@Override
public void execute(ShardingContext shardingContext) {
log.info("sharding context is {}", shardingContext);
}
}
所有基础配置已经完成,启动项目查看日志即可。
特别注意几点:
1、sharding-total-count:1 此配置值必须大于0,如果配置为0的话启动应用会报错,当你改为1或者大于1之后启动项目还是会报错,因为配置值注册到zookeeper中了,重启zookeeper也无效。必须找到zookeeper中的数据存储目录全部删除才行。(或者把 任务作业类配置的bean id 名称改掉也是可以的。)
2、项目中的zookeeper 版本需要与服务器上面的版本一致 。zookeeper版本也需要跟 curator-recipe 版本对应兼容,不然启动应用也会报错。