Elastic-Job的使用

参考的博客

Elastic-Job是一个分布式调度解决方案,由两个相互独立的子项目Elastic-Job-Lite和Elastic-Job-Cloud组成。
Elastic-Job-Lite定位为轻量级无中心化解决方案,使用jar包的形式提供分布式任务的协调服务; --摘自官网

具体的详细介绍,大家可以去官网查阅

这篇文章主要是整合springboot 的简单例子。通过一步一步实现,来逐步的熟悉elastic-job 这个组件,首要条件就是需要你有个运行的zookeeper

搭建springboot项目

这里不在赘述如果搭建,这里我只贴出我的pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <parent>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-parent</artifactId>
       <version>2.0.1.RELEASE</version>
       <relativePath/> <!-- lookup parent from repository -->
   </parent>
   <groupId>com.kevin</groupId>
   <artifactId>es-job</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <name>es-job</name>
   <description>Demo project for Spring Boot</description>

   <properties>
       <java.version>1.8</java.version>
       <elastic-job.version>2.1.4</elastic-job.version>
   </properties>

   <dependencies>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter</artifactId>
       </dependency>

       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-test</artifactId>
           <scope>test</scope>
       </dependency>

       <!--  elastic-job dependency -->
       <dependency>
           <groupId>com.dangdang</groupId>
           <artifactId>elastic-job-lite-core</artifactId>
           <version>${elastic-job.version}</version>
       </dependency>
       <dependency>
           <groupId>com.dangdang</groupId>
           <artifactId>elastic-job-lite-spring</artifactId>
           <version>${elastic-job.version}</version>
       </dependency>

       <!-- spring boot dependency -->

       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-web</artifactId>
       </dependency>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-actuator</artifactId>
       </dependency>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-configuration-processor</artifactId>
           <optional>true</optional>
       </dependency>

       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-jdbc</artifactId>
       </dependency>
       <!-- mysql驱动 -->
       <dependency>
           <groupId>mysql</groupId>
           <artifactId>mysql-connector-java</artifactId>
       </dependency>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-data-jpa</artifactId>
       </dependency>
   </dependencies>

   <build>
       <plugins>
           <plugin>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-maven-plugin</artifactId>
           </plugin>
       </plugins>
   </build>

</project>

主要的就是加载这2个依赖

    <!--  elastic-job dependency -->
       <dependency>
           <groupId>com.dangdang</groupId>
           <artifactId>elastic-job-lite-core</artifactId>
           <version>${elastic-job.version}</version>
       </dependency>
       <dependency>
           <groupId>com.dangdang</groupId>
           <artifactId>elastic-job-lite-spring</artifactId>
           <version>${elastic-job.version}</version>
       </dependency>

整合elasticjob

  1. 编写配置application.yml
zookeeper:
 address: 192.168.247.7:2181
 namespace: elastic-job
 connectionTimeout: 10000
 sessionTimeout: 10000
 maxRetries: 3

# simplejob配置
simpleJob:
   cron: 0/5 * * * * ?
   shardingTotalCount: 5
   shardingItemParameters: 0=java,1=php,2=erlang,3=angular,4=vue
   jobParameter: source1=public,source2=private
   failover: true
   monitorExecution: true
   monitorPort: 8889
   maxTimeDiffSeconds: -1
   jobShardingStrategyClass: com.dangdang.ddframe.job.lite.api.strategy.impl.AverageAllocationJobShardingStrategy

dataflowJob:
   cron: 0/10 * * * * ?
   shardingTotalCount: 2
   shardingItemParameters: 0=jinan,1=qingdao




############################################################
#
# 配置数据源信息
#
############################################################
spring:
 datasource: # 数据源的相关配置
     type: com.zaxxer.hikari.HikariDataSource          # 数据源类型:HikariCP
     driver-class-name: com.mysql.jdbc.Driver          # mysql驱动
     url: jdbc:mysql://localhost:3306/elasticjob?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false
     username: root
     password: root
     hikari:
       connection-timeout: 30000       # 等待连接池分配连接的最大时长(毫秒),超过这个时长还没可用的连接则发生SQLException, 默认:30秒
       minimum-idle: 5                 # 最小连接数
       maximum-pool-size: 20           # 最大连接数
       auto-commit: true               # 自动提交
       idle-timeout: 600000            # 连接超时的最大时长(毫秒),超时则被释放(retired),默认:10分钟
       pool-name: DateSourceHikariCP     # 连接池名字
       max-lifetime: 1800000           # 连接的生命时长(毫秒),超时而且没被使用则被释放(retired),默认:30分钟 1800000ms
       connection-test-query: SELECT 1
  1. 注册中心加载到spring 容器中
/**
* @author: kevin
* @Date: 2020/1/22
*/
@Configuration
@ConditionalOnExpression("'${zookeeper.address}'.length() > 0")
public class RegistryCenterConfig {

   /**
    * 	把注册中心加载到spring 容器中
    * @return
    */
   @Bean(initMethod = "init")
   public ZookeeperRegistryCenter registryCenter(@Value("${zookeeper.address}") final String serverLists,
                                                 @Value("${zookeeper.namespace}") final String namespace,
                                                 @Value("${zookeeper.connectionTimeout}") final int connectionTimeout,
                                                 @Value("${zookeeper.sessionTimeout}") final int sessionTimeout,
                                                 @Value("${zookeeper.maxRetries}") final int maxRetries) {
       ZookeeperConfiguration zookeeperConfiguration = new ZookeeperConfiguration(serverLists, namespace);
       zookeeperConfiguration.setConnectionTimeoutMilliseconds(connectionTimeout);
       zookeeperConfiguration.setSessionTimeoutMilliseconds(sessionTimeout);
       zookeeperConfiguration.setMaxRetries(maxRetries);

       return new ZookeeperRegistryCenter(zookeeperConfiguration);

   }
}
  1. 配置JobEventConfig事件追踪
/**
* @author: kevin
* @Date: 2020/1/22
*/
@Configuration
public class JobEventConfig {

   @Autowired
   private DataSource dataSource;

   @Bean
   public JobEventConfiguration jobEventConfiguration() {
       return new JobEventRdbConfiguration(dataSource);
   }

}
  1. 编写自己的job并完成配置

    4.1 定义自己的job

/**
* @author: kevin
* @Date: 2020/1/22
*/

@Component
public class MySimpleJob implements SimpleJob {
   @Override
   public void execute(ShardingContext shardingContext) {
       System.out.println(shardingContext.getShardingParameter());
   }
}

​ 4.2 编写作业配置

@Configuration
public class MySimpleJobConfig {
   @Autowired
   private ZookeeperRegistryCenter registryCenter;

   @Autowired
   private JobEventConfiguration jobEventConfiguration;

   /**
    * 	具体真正的定时任务执行逻辑
    * @return
    */
   @Bean
   public SimpleJob simpleJob() {
       return new MySimpleJob();
   }

   /**
    * @param simpleJob
    * @return
    */
   @Bean(initMethod = "init")
   public JobScheduler simpleJobScheduler(final SimpleJob simpleJob,
                                          @Value("${simpleJob.cron}") final String cron,
                                          @Value("${simpleJob.shardingTotalCount}") final int shardingTotalCount,
                                          @Value("${simpleJob.shardingItemParameters}") final String shardingItemParameters,
                                          @Value("${simpleJob.jobParameter}") final String jobParameter,
                                          @Value("${simpleJob.failover}") final boolean failover,
                                          @Value("${simpleJob.monitorExecution}") final boolean monitorExecution,
                                          @Value("${simpleJob.monitorPort}") final int monitorPort,
                                          @Value("${simpleJob.maxTimeDiffSeconds}") final int maxTimeDiffSeconds,
                                          @Value("${simpleJob.jobShardingStrategyClass}") final String jobShardingStrategyClass) {

       return new SpringJobScheduler(simpleJob,
               registryCenter,
               getLiteJobConfiguration(simpleJob.getClass(),
                       cron,
                       shardingTotalCount,
                       shardingItemParameters,
                       jobParameter,
                       failover,
                       monitorExecution,
                       monitorPort,
                       maxTimeDiffSeconds,
                       jobShardingStrategyClass),
               jobEventConfiguration,
               new SimpleJobListener());

   }


   private LiteJobConfiguration getLiteJobConfiguration(Class<? extends SimpleJob> jobClass, String cron,
                                                        int shardingTotalCount, String shardingItemParameters, String jobParameter, boolean failover,
                                                        boolean monitorExecution, int monitorPort, int maxTimeDiffSeconds, String jobShardingStrategyClass) {

       //定义作业核心配置
       JobCoreConfiguration jobCoreConfiguration = JobCoreConfiguration
               .newBuilder(jobClass.getName(), cron, shardingTotalCount)
               .misfire(true)
               .failover(failover)
               .jobParameter(jobParameter)
               .shardingItemParameters(shardingItemParameters)
               .build();

       //定义SIMPLE类型配置
       SimpleJobConfiguration simpleJobConfiguration = new SimpleJobConfiguration(jobCoreConfiguration, jobClass.getCanonicalName());

       //定义Lite作业根配置
       LiteJobConfiguration liteJobConfiguration = LiteJobConfiguration.newBuilder(simpleJobConfiguration)
               .jobShardingStrategyClass(jobShardingStrategyClass)
               .monitorExecution(monitorExecution)
               .monitorPort(monitorPort)
               .maxTimeDiffSeconds(maxTimeDiffSeconds)
               .overwrite(true)
               .build();

       return liteJobConfiguration;
   }

5.使用自定义注解完成job的注册(适合多job,无需配置多个config类,第四步与第五步均可实现,选择一个即可

​ 5.1 编写注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface ElasticSimpleJob {
    String jobName() default "";

    String cron() default "";

    String shardingTotalCount() default "";

    String shardingItemParameters() default "";

    boolean overwrite() default false;

    Class<? extends JobShardingStrategy> jobStrategy() default AverageAllocationJobShardingStrategy.class;

    boolean jobEvent() default false;

    Class<? extends ElasticJobListener>[] jobListener() default {};
}

​ 5.2 编写job,并添加刚刚编写的注解

@ElasticSimpleJob(
        jobName = "demoJob.jobName",
        cron = "demoJob.cron",
        overwrite = true,
        shardingTotalCount = "demoJob.shardingTotalCount",
        jobListener = {DemoJob.DemoJobListener.class}
)
@Slf4j
public class DemoJob implements SimpleJob {
    
    @Override
    public void execute(final ShardingContext shardingContext) {
        System.out.println("sssssssssssss");
    }

    protected static class DemoJobListener implements ElasticJobListener {

        @Override
        public void beforeJobExecuted(final ShardingContexts shardingContexts) {
            log.info("demoJob开始了");
        }

        @Override
        public void afterJobExecuted(final ShardingContexts shardingContexts) {
            log.info("demoJob结束了");
        }
    }
    
}

​ 5.3 编写Job的实体类

@Data
public class SimpleJobEntity {
    String jobName;
    String cron;
    int shardingTotalCount;
    String shardingItemParameters;
    boolean overwrite;
    Class<?> jobStrategy;
    boolean isJobEvent;
    Class<? extends ElasticJobListener>[] listeners;
    ElasticJobListener[] listenerInstances;
}

​ 5.4编写自动配置类(根据注解拿到job的信息完成注册)

@Component
@Slf4j
public class SimpleJobAutoConfig {

    @Autowired
    private CoordinatorRegistryCenter zkCenter;

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private Environment environment;


    @Value("${regCenter.namespace}")
    private String namespace;


    @PostConstruct
    public void initSimpleJob() {
        log.info("初始化JOB任务中...");
        Map<String, Object> beans = applicationContext.getBeansWithAnnotation(ElasticSimpleJob.class);
        log.info("发现JOB任务:{}", beans.size());
        for (Map.Entry<String, Object> entry : beans.entrySet()) {
            Object instance = entry.getValue();
            Class<?>[] interfaces = instance.getClass().getInterfaces();
            for (Class<?> superInterface : interfaces) {
                if (superInterface == SimpleJob.class) {
                    ElasticSimpleJob annotation = instance.getClass().getAnnotation(ElasticSimpleJob.class);
                    SimpleJobEntity simpleJobEntity = getSimpleJobEntity(annotation);
                    if (simpleJobEntity == null) {
                        log.error("#SimpleJobAutoConfig.initSimpleJob 未发现job配置信息:{}", instance.getClass().getName());
                        continue;
                    }
                    log.info("正在注册JOB任务:{}", simpleJobEntity.getJobName());
                    //  job核心配置
                    final JobCoreConfiguration jcc;
                    final JobCoreConfiguration.Builder builder = JobCoreConfiguration.newBuilder(namespace + "." + simpleJobEntity.getJobName(), simpleJobEntity.getCron(), simpleJobEntity.getShardingTotalCount());
                    if (StringUtils.isNotBlank(simpleJobEntity.getShardingItemParameters())) {
                        builder.shardingItemParameters(simpleJobEntity.getShardingItemParameters());
                    }
                    jcc = builder.build();

                    //  job类型配置
                    SimpleJobConfiguration simpleJobConfiguration = new SimpleJobConfiguration(jcc,
                            instance.getClass().getCanonicalName());

                    //  job根的配置
                    LiteJobConfiguration ljc;
                    LiteJobConfiguration.Builder liteBuilder = LiteJobConfiguration.newBuilder(simpleJobConfiguration);
                    if (simpleJobEntity.getJobStrategy() != null) {
                        liteBuilder.jobShardingStrategyClass(simpleJobEntity.getJobStrategy().getCanonicalName());
                    }
                    ljc = liteBuilder.build();

                    if (simpleJobEntity.isJobEvent()) {

                    } else {
                        new SpringJobScheduler((ElasticJob) instance, zkCenter, ljc, simpleJobEntity.getListenerInstances()).init();
                        log.info("注册JOB任务成功:{}", simpleJobEntity.getJobName());
                    }
                }
            }
        }
        log.info("初始化JOB任务成功");
    }

    private SimpleJobEntity getSimpleJobEntity(ElasticSimpleJob annotation) {
        try {
            if (StringUtils.isBlank(annotation.jobName())) {
                return null;
            }
            if (StringUtils.isBlank(annotation.cron())) {
                return null;
            }
            SimpleJobEntity simpleJobEntity = new SimpleJobEntity();
            simpleJobEntity.setJobName(environment.getProperty(annotation.jobName()));
            simpleJobEntity.setCron(environment.getProperty(annotation.cron()));
            simpleJobEntity.setOverwrite(annotation.overwrite());
            simpleJobEntity.setJobStrategy(annotation.jobStrategy());
            simpleJobEntity.setJobEvent(annotation.jobEvent());
            if (annotation.shardingTotalCount() != null) {
                simpleJobEntity.setShardingTotalCount(Integer.valueOf(environment.getProperty(annotation.shardingTotalCount())));
            } else {
                simpleJobEntity.setShardingTotalCount(1);
            }
            if (StringUtils.isNotBlank(annotation.shardingItemParameters())) {
                simpleJobEntity.setShardingItemParameters(environment.getProperty(annotation.shardingItemParameters()));
            }
            simpleJobEntity.setListenerInstances(getElasticJobListener(annotation));
            return simpleJobEntity;
        } catch (Exception e) {
            log.error("",e);
        }
        return null;
    }
    
    private ElasticJobListener[] getElasticJobListener(ElasticSimpleJob annotation) {
        Class<? extends ElasticJobListener>[] listeners = annotation.jobListener();
        //监听器
        ElasticJobListener[] listenerInstances = null;
        if (listeners.length > 0) {
            listenerInstances = new ElasticJobListener[listeners.length];
            List<ElasticJobListener> listenerInstanceList = new ArrayList<>();
            Arrays.asList(listeners).forEach(item -> {
                ElasticJobListener listenerInstance = null;
                try {
                    listenerInstance = item.getDeclaredConstructor().newInstance();
                    listenerInstanceList.add(listenerInstance);
                } catch (InstantiationException | NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
                    log.error("", e);
                }
            });
            listenerInstanceList.toArray(listenerInstances);
        } else {
            listenerInstances = new ElasticJobListener[0];
        }
        return listenerInstances;
    }
}

完成后,如有新job加入通过@ElasticSimpleJob添加job的信息(如5.2)即可完成job的注册

运行

这里直接启动后,可以看到控制台打印

java
php
erlang
angular
vue

搭建运维的平台

elastic-job-lite-console-2.1.5.tar.gz解压,修改conf文件中的zookeeper地址

文件地址:elastic-job-lite-console-2.1.5.tar.gz

linux启动start.sh

window启动start.bat

posted @ 2020-12-26 09:49  shouyaya  阅读(842)  评论(0编辑  收藏  举报