Springboot 定時任務集羣(Quartz方式,利用zookeeper實現分佈式鎖方式)

■1.Quartz方式(Quartz版本:2.2.3)

Quartz的定時任務能力比較強大,它自己就可以實現集羣功能。Quartz在實現集羣功能時,利用了數據庫對任務進行調度,而其使用到的數據庫表數據都是自動裝填的不用認爲管理表數據。我們只需要按照Quartz要求建表即可。所需要建表,Quartz已經幫我們寫好了SQL,只需要對照你的數據庫找到相應的SQL執行一下即可。

Quartz官網:http://www.quartz-scheduler.org/

從官網上直接下載 Quartz 2.2.3 .tar.gz,解壓後【quartz-2.2.3/docs/dbTables】下存放各數據庫建表的sql文件。

本實例使用的是postgeresql數據庫。所以,使用tables_postgres.sql創建所需要的表。

下面是項目代碼

A.文件目錄結構

B.各文件內容:pom.xml

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com</groupId>
	<artifactId>lpwmsbatch</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>

	<name>lpwmsbatch</name>
	<description>Demo project for Spring Boot</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.4.RELEASE</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>1.3.2</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.postgresql</groupId>
			<artifactId>postgresql</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid</artifactId>
			<version>1.1.8</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.apache.curator/curator-framework -->
		<dependency>
			<groupId>org.apache.curator</groupId>
			<artifactId>curator-framework</artifactId>
			<version>2.12.0</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-quartz</artifactId>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz -->
		<dependency>
			<groupId>org.quartz-scheduler</groupId>
			<artifactId>quartz</artifactId>
			<version>2.2.3</version>
		</dependency>
		<dependency>
			<groupId>org.quartz-scheduler</groupId>
			<artifactId>quartz-jobs</artifactId>
			<version>2.2.3</version>
		</dependency>
	</dependencies>

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

各文件內容:application.properties

# 服務端口
server.port=8080

# Mybatis
spring.profiles.active=dev
mybatis.type-aliases-package=com.infosky.batch.model
mybatis.mapper-locations=classpath*:com/infosky/batch/mapper/*.xml

# 數據源
spring.datasource.url=jdbc:postgresql://xxx.xxx.xxx.xxx:5432/lpaa
spring.datasource.username=test
spring.datasource.password=test
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true

# ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓Quartz↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
# ============================================================================
# Configure Main Scheduler Properties  
# ============================================================================
# 調度標識名 集羣中每一個實例都必須使用相同的名稱 
org.quartz.scheduler.instanceName= TestScheduler

# ID設置爲自動獲取 每一個必須不同
# 1. 當你想生成intanceId的時候可以設置爲AUTO
# 2. 當你想從系統屬性org.quartz.scheduler.instanceId取值時可以設置爲SYS_PROP
org.quartz.scheduler.instanceId= instance_one

# 生成Schudule實體Id的類,只有在屬性org.quartz.scheduler.instanceId設置爲AUTO時使用,默認的實現org.quartz.scheduler.SimpleInstanceGenerator是基於主機名稱和時間戳生成。其他的實現查看具體的文檔
# org.quartz.scheduler.instanceIdGenerator.class

# Scheduler線程的名稱
# org.quartz.scheduler.threadName

# 指定Scheduler是否以守護線程(服務)運行
# org.quartz.scheduler.makeSchedulerThreadDaemon

# 當調度程序空閒時,在重新查詢可用觸發器之前,調度程序將等待毫秒的時間數。不建議少於5000ms,而少於1000是不合法的參數
# org.quartz.scheduler.idleWaitTime

# 使用JobStore(比如連接數據庫)時Schueduler檢測到失去數據庫連接後重新嘗試連接的毫秒數
# org.quartz.scheduler.doFailureRetryInterval

# 給Scheduler Context、Job、Trigger的JobDataMaps設置屬性值的方式
# org.quartz.scheduler.jobFactory.class

# 鍵值對,保存在Scheduler Context中,比如有這樣的配置org.quartz.shceduler.key.MyKey=MyValue,則在Scheduler Context中賦值方式爲scheduler.getContext().put(“MyKey”, “MyValue”
# org.quartz.contenxt.key.SOME_KEY

# 事務管理JNDI URL地址。只有當Quartz使用JobStoreCMT和org.quartz.scheduler.wrapJobExecutionInUserTransaction 設置爲true時使用
# org.quartz.scheduler.userTransactionURL

# 只有當你在執行一個Job時想使用UserTransaction時設置爲true,參考@ExecuteInJTATransaction 註解
# org.quartz.scheduler.wrapJobExecutionInUserTransaction

# 在同一時間運行Scheduler獲取trigger的數量。如果設置的數量>1,並且使用JDBC JobStore,則屬性org.quartz.jobStore.acquireTriggersWithinLock應設置爲true,可以避破壞數據。
# org.quartz.scheduler.batchTriggerAcquisitionMaxCount

# 運行Scheduler在獲取和觸發tigger的提前的時間。
# org.quartz.scheduler.batchTriggerAcquisitionFireAheadTimeWindow

# 是否跳過版本檢測。可以設置系統參數org.terracotta.quartz.skipUpdateCheck=true或者在JAVA命令行使用-D選項。在正式庫運行時應設置爲true。
org.quartz.scheduler.skipUpdateCheck= true

# ============================================================================
# Configure ThreadPool  
# 線程池配置
# ============================================================================
# 線程池的實現類(一般使用SimpleThreadPool即可滿足幾乎所有用戶的需求)
# Scheduler使用的線程池名稱,實現了ThreadPool接口,參考org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.class= org.quartz.simpl.SimpleThreadPool

# 指定線程數,至少爲1(無默認值)(一般設置爲1-100直接的整數合適) 
org.quartz.threadPool.threadCount= 5

# 設置線程的優先級(最大爲java.lang.Thread.MAX_PRIORITY 10,最小爲Thread.MIN_PRIORITY 1,默認爲5)
org.quartz.threadPool.threadPriority= 5

# ============================================================================
# Configure JobStore  
# JDBCJobStore和JobStoreTX
# JDBCJobStore和JobStoreTX都使用關係數據庫來存儲Schedule相關的信息。
# JobStoreTX在每次執行任務後都使用commint或者rollback來提交更改。
# 如果在一個標準的獨立應用或者在一個沒有使用JTA事務管理的應用中使用Quartz,JDBCJobStore是一個不錯的選擇。
# ============================================================================
# 信息保存時間 默認值60秒 
# 觸發器失敗後下次觸發的時間間隔
org.quartz.jobStore.misfireThreshold= 60000

# 數據保存方式爲數據庫持久化  
org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX

# 使用的數據庫驅動,具體的驅動列表詳情如下。一般org.quartz.impl.jdbcjobstore.StdJDBCDelegate可以滿足大部分數據庫 
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.PostgreSQLDelegate

# 使用自己的配置文件
# 配置參數可以被設置爲true(默認爲false),這樣可以指導JDBCJobStore,JobDataMaps中的值都是字符串,因此這樣可以以名字-值對存儲,而不是存儲更加複雜的對象(序列化形式BLOB)。從長遠來看,這是很安全的,因爲避免了將非字符串類序列化爲BLOB的類版本問題。
org.quartz.jobStore.useProperties=false

# 數據庫別名 隨便取
org.quartz.jobStore.dataSource=myDS

# 表的前綴,默認QRTZ_ 
org.quartz.jobStore.tablePrefix=QRTZ_

# 是否加入集羣
org.quartz.jobStore.isClustered=true

# 檢查集羣下的其他調度器實體的事件間隔
# org.quartz.jobStore.clusterCheckinInterval

# 如果值爲true,就是告訴Quartz(當使用JobStoreTX或CMT)調用JDBC連接的setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE)方法。這可以防止在高負載、持久事務時鎖定超時。
# org.quartz.jobStore.txIsolationLevelSerializable

#============================================================================
# Other Example Delegates
#============================================================================
#org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.DB2v6Delegate
#org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.DB2v7Delegate
#org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.DriverDelegate
#org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.HSQLDBDelegate
#org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.MSSQLDelegate
#org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.PointbaseDelegate
#org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.PostgreSQLDelegate
#org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.WebLogicDelegate
#org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.oracle.OracleDelegate
#org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.oracle.WebLogicOracleDelegate

#============================================================================
# Configure Datasources  
#============================================================================
# 數據庫引擎 
# 必須是數據庫的JDBC驅動的類名
org.quartz.dataSource.myDS.driver= org.postgresql.Driver

# 數據庫連接
org.quartz.dataSource.myDS.URL= jdbc:postgresql://xxx.xxx.xxx.xxx:5432/lpaa
org.quartz.dataSource.myDS.user= test
org.quartz.dataSource.myDS.password= test

# 允許最大連接
org.quartz.dataSource.myDS.maxConnections= 5

# SQL查詢字符串,數據源用於檢測和替換失敗或者故障連接
org.quartz.dataSource.myDS.validationQuery= select 0

# 空閒連接測試的時間(單位秒),只有設置了validationQuery屬性,才使能。默認值爲50秒
# org.quartz.dataSource.NAME.idleConnectionValidationSeconds

# 是否每一次從數據池衝獲取連接時,都要去執行數據庫SQL查詢,以確保連接有效。如果爲false,那麼在check-in時驗證。默認值爲false
# org.quartz.dataSource.NAME.validateOnCheckout

# 丟棄連接的超時時間。若值爲0,則禁止這個特性。默認值爲0
# org.quartz.dataSource.NAME.discardIdleConnectionsSeconds

# 應用服務器管理的數據源的JNDI的URL
# org.quartz.dataSource.NAME.jndiURL

#============================================================================
# Configure Plugins 
#============================================================================

#org.quartz.plugin.shutdownHook.class: org.quartz.plugins.management.ShutdownHookPlugin
#org.quartz.plugin.shutdownHook.cleanShutdown: true
#org.quartz.plugin.triggHistory.class: org.quartz.plugins.history.LoggingJobHistoryPlugin
#↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑Quartz↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑

各文件內容:SpringBootStartApplication.java

package com.infosky.batch;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan("com.infosky.batch.dao")
public class SpringBootStartApplication {

	public static void main(String[] args) {
		SpringApplication.run(SpringBootStartApplication.class, args);
	}
}

各文件內容:AutowiringSpringBeanJobFactory.java

package com.infosky.batch.quartz;

import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.scheduling.quartz.SpringBeanJobFactory;

public final class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware {

	private transient AutowireCapableBeanFactory beanFactory;

	@Override
	public void setApplicationContext(final ApplicationContext context) {
		beanFactory = context.getAutowireCapableBeanFactory();
	}

	@Override
	protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
		final Object job = super.createJobInstance(bundle);
		beanFactory.autowireBean(job);
		return job;
	}
}

各文件內容:CheckStatusTask.java

package com.infosky.batch.quartz;

import org.quartz.*;
import org.springframework.stereotype.Component;

@PersistJobDataAfterExecution
@DisallowConcurrentExecution
@Component
public class CheckStatusTask implements Job {
	public void execute(JobExecutionContext context) throws JobExecutionException {
		// 定時任務邏輯
		System.out.println("^^^^^^^^^^^^^");
	}

}

各文件內容:QuartzConfig.java

package com.infosky.batch.quartz;

import org.quartz.spi.JobFactory;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import java.util.Properties;

/**
 * 配置定時任務
 *
 */
@Configuration
public class QuartzConfig {
	public static final String QUARTZ_PROPERTIES_PATH = "/application.properties";

	@Bean
	public JobFactory jobFactory(ApplicationContext applicationContext) {
		AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();
		jobFactory.setApplicationContext(applicationContext);
		return jobFactory;
	}

	@Bean
	public SchedulerFactoryBean schedulerFactoryBean(JobFactory jobFactory) {
		SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
		schedulerFactoryBean.setJobFactory(jobFactory);
		schedulerFactoryBean.setStartupDelay(20);
		// 用於quartz集羣,加載quartz數據源配置
		schedulerFactoryBean.setQuartzProperties(quartzProperties());
		return schedulerFactoryBean;
	}

	public Properties quartzProperties() {
		PropertiesFactoryBean factoryBean = new PropertiesFactoryBean();
		factoryBean.setLocation(new ClassPathResource(QUARTZ_PROPERTIES_PATH));
		try {
			factoryBean.afterPropertiesSet();
			return factoryBean.getObject();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
}

各文件內容:QuartzScheduler.java

package com.infosky.batch.quartz;

import static org.quartz.CronScheduleBuilder.cronSchedule;
import javax.annotation.PostConstruct;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Component;

/**
 * 定時任務調度器
 */
@Component
public class QuartzScheduler {
	@SuppressWarnings("SpringJavaAutowiringInspection")
	@Autowired
	private SchedulerFactoryBean schedulerFactoryBean;

	@PostConstruct
	public void init() throws SchedulerException {
		scheduleJobs();
	}

	public void scheduleJobs() throws SchedulerException {
		System.out.println("=======任務初始化========");
		Scheduler scheduler = schedulerFactoryBean.getScheduler();
		// 需要傳遞數據,就是使用JobDataMa
//		 JobDataMap jobDataMap = new JobDataMap();
//		 jobDataMap.put("jobArg", "world");
		// CheckStatusTask.class 是需要執行定時任務的類名
		JobDetail jobDetail = JobBuilder.newJob(CheckStatusTask.class)//.setJobData(jobDataMap)
				// .setJobData(jobDataMap)
				.withDescription("CheckStatusTask").withIdentity("job-CheckStatus", "demo-group").build();
		// InsertEvaluateTask.class 是需要執行定時任務的類名
		// JobDetail jobDetail2 = JobBuilder.newJob(InsertEvaluateTask.class)
		// // .setJobData(jobDataMap)
		// .withDescription("InsertEvaluateTask")
		// .withIdentity("job-InsertEvaluate", "demo-group")
		// .build();

		Trigger trigger = TriggerBuilder.newTrigger().forJob(jobDetail).withSchedule(cronSchedule("*/1 * * * * ? "))
				.build();

		// Trigger trigger2 = TriggerBuilder.newTrigger()
		// .forJob(jobDetail2)
		// .withSchedule(cronSchedule("0 0/1 * * * ? "))
		// .build();

		try {
			if (!scheduler.checkExists(JobKey.jobKey("job-CheckStatus", "demo-group"))) {
				scheduler.scheduleJob(jobDetail, trigger);
			}
			// if(!scheduler.checkExists(JobKey.jobKey("job-InsertEvaluate","demo-group"))){
			// scheduler.scheduleJob(jobDetail2,trigger2);
			// }
			scheduler.start();
			System.out.println("=======任務初始化完成========");
		} catch (SchedulerException e) {
			e.printStackTrace();
		}
	}
}

●注意:利用數據庫這種方式當程序意外終止或者需要修改定時任務時(比如刪除一些定時任務),重新啓動時有可能因爲DB表數據與定時任務不整合可能出現啓動異常異常,這時只需要刪除Quartz對應的數據庫表重新啓動即可。

數據庫對應表

qrtz_fired_triggers
qrtz_paused_trigger_grps
qrtz_scheduler_state
qrtz_locks
qrtz_simple_triggers
qrtz_cron_triggers
qrtz_simprop_triggers
qrtz_blob_triggers
qrtz_triggers
qrtz_job_details
qrtz_calendars

■zookeeper實現分佈式鎖方式

A.文件目錄結構

B.各文件內容:pom.xml

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.infosky.batch</groupId>
	<artifactId>lpwmsbatch</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>

	<name>lpwmsbatch</name>
	<description>Demo project for Spring Boot</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.4.RELEASE</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>1.3.2</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.postgresql</groupId>
			<artifactId>postgresql</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid</artifactId>
			<version>1.1.8</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.apache.curator/curator-framework -->
		<dependency>
			<groupId>org.apache.curator</groupId>
			<artifactId>curator-framework</artifactId>
			<version>2.12.0</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-quartz</artifactId>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz -->
		<dependency>
			<groupId>org.quartz-scheduler</groupId>
			<artifactId>quartz</artifactId>
			<version>2.2.3</version>
		</dependency>
		<dependency>
			<groupId>org.quartz-scheduler</groupId>
			<artifactId>quartz-jobs</artifactId>
			<version>2.2.3</version>
		</dependency>
	</dependencies>

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

各文件內容:TaskService.java

package task;

import java.text.SimpleDateFormat;
import java.util.Date;

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class TaskService {

	// 每分鐘啓動
	@Scheduled(cron = "0 0/1 * * * ?")
	public void oneMinuteJob(){
		System.out.println("now time:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
	}
}

各文件內容:SpringBootStartApplication.java

package com.infosky.batch;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@MapperScan("com.infosky.batch.dao")
@EnableScheduling
public class SpringBootStartApplication {

	public static void main(String[] args) {
		SpringApplication.run(SpringBootStartApplication.class, args);
	}
}

各文件內容:ZookeeperUtils.java

package com.infosky.batch.utils;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;

public class ZookeeperUtils {

	/**
	 * 創建節點。創建成功即獲得執行權。
	 * @param strNote
	 * @throws Exception
	 */
	public static void createNote(String strNote) throws Exception {
		// 獲取連接
		CuratorFramework curatorFramework = CuratorFrameworkFactory.builder().connectString("172.22.70.45:2181")
				.sessionTimeoutMs(4000).retryPolicy(new ExponentialBackoffRetry(1000, 3)).namespace("curator").build();

		curatorFramework.start();
		try{
			// 獲取節點值
			byte[] valNote = curatorFramework.getData().forPath("/taskLock");
			// 節點存在時
			if(valNote != null && valNote.length > 0){
				// 獲取節點值
				String strVal = new String(valNote);
				// 節點保存時間
				long logVal = Long.parseLong(strVal);
				// 當前時間
				long logCurrent = DateUtils.getDateTime();
				
				// 節點超過存活時間,刪除節點
				if(logCurrent - logVal > 1000*60*60){
					curatorFramework.delete().forPath("/taskLock");
				}
			}
		}catch(Exception e){}
		
		// 創建節點
		curatorFramework.create().withMode(CreateMode.PERSISTENT).forPath("/taskLock", String.valueOf(DateUtils.getDateTime()).getBytes());
	}
}

各文件內容:測試代碼:TTT.java

package com.infosky.batch.utils;

import java.util.Date;

public class TTT {

	public static void main(String[] args) {
		try {
			ZookeeperUtils.createNote("");
			System.out.println("$$$$$$$$$$$$$$$$$$$$$$$$$$$$搶到鎖");
			System.out.println(new Date());
		} catch (Exception e) {
			System.out.println("############################未搶到鎖");
		}

	}

}

各文件內容:DateUtils.java

package com.infosky.batch.utils;

public class DateUtils {

	public static final String JAVA_DATETIME_FORMATTER_24 = "yyyy-MM-dd HH:mm:ss";
	
	/**
	 * 獲取當前時間
	 * @return
	 */
	public static long getDateTime(){
		return System.currentTimeMillis();
	}
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章