1 任務調度
定時JOB,在什麼時間進行執行代碼任務。
1.1 使用線程方式
public static void main(String[] args) {
Runnable runnable = new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
count++;
System.out.println(count);
} catch (Exception e) {
// TODO: handle exception
}
}
}
};
Thread thread = new Thread(runnable);
thread.start();
}
1.2 timerTask
public static void main(String[] args) {
TimerTask timerTask = new TimerTask() {
@Override
public void run() {
count++;
System.out.println(count);
}
};
Timer timer = new Timer();
// 天數
long delay = 0;
// 秒數
long period = 1000;
timer.scheduleAtFixedRate(timerTask, delay, period);
}
1.3 線程池
public static void main(String[] args) {
Runnable runnable = new Runnable() {
public void run() {
// task to run goes here
System.out.println("Hello !!");
}
};
ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
// 第二個參數爲首次執行的延時時間,第三個參數爲定時執行的間隔時間
service.scheduleAtFixedRate(runnable, 1, 1, TimeUnit.SECONDS);
}
1.4 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>
任務:
public class JobTask implements Job {
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("quartz job date: "+new Date().getTime());
}
}
啓動類:
public static void main(String[] args) throws SchedulerException {
//1、創建scheduler的工廠
StdSchedulerFactory stdSchedulerFactory = new StdSchedulerFactory();
//2、從工廠中獲取調度器實例
Scheduler scheduler = stdSchedulerFactory.getScheduler();
//3、創建JobDetail
JobDetail jobDetail = JobBuilder.newJob(JobTask.class)
.withDescription("this is a quartz job")
.withIdentity("quartzJob", "quartzGroup")
.build();
//任務運行的時間、simpleSchedule類型觸發器有效
long time=System.currentTimeMillis()+5*1000;//5秒後
Date startTime=new Date(time);
//創建trigger
//使用SimpleScheduleBuilder或者CronScheduleBuilder
Trigger trigger = TriggerBuilder.newTrigger()
.withDescription("quartz trigger")
.withIdentity("quartzTrigger", "quartzTriggerGroup")
.startAt(startTime)
.withSchedule(CronScheduleBuilder.cronSchedule("0/2 * * * * ?"))
.build();
//5、註冊任務和定時器
scheduler.scheduleJob(jobDetail,trigger);
//啓動
scheduler.start();
}
2 分佈式任務調度
雖然以上是可以實現任務調度,但是一般情況下這個應用是要部署在多個tomcat服務器上的,那麼又怎麼保證冪等性(對於一個job,不可能每臺服務器都讓他執行一次嘛,這不就重複執行了嗎)呢。
1、使用分佈式鎖,保證只有一臺服務器在執行
2、添加配置文件標識,兩臺服務器的配置文件不同,根據配置文件不同進行任務的調度,缺點是,那這就不支持集羣 了。
3、數據庫唯一標識,比如根據某一字段爲TRUE標識可以執行,執行時改爲FALSE,執行完後再改爲TRUE,缺點是經常操作數據庫,效率低
4、使用分佈式任務調度平臺XXLJOB
總的來說傳統的任務調度有很多缺點:
1、沒有補償機制(比如某個任務調度失敗後,只能等待下次調度或者人工調度)
2、不支持集羣
3、不支持路由策略
4、統計(每個服務或者項目都有自己的任務調度,肯定是要統計一些成功啊失敗什麼的,傳統調度的話只能自己管理自己的,可是這種任務調度的話最好是採用集中管理比較好)
5、管理平臺(沒有提供一個集中管理所有任務調度的平臺)
6、報警郵箱(比如說重試N次以後,都不成功那就發瘋郵件吧)、狀態監控(運行、結束、等待)
而以上這些在分佈式調度平臺XXLJOB都有支持。
2.1 XXL-JOB執行原理
首先對於任何一個客戶端的任務,需要註冊到xxl-job的admin平臺,然後admin將任務分發到各個執行器去執行,這裏選擇每個執行器的原理類似負載均衡策略。
實戰演練一下:
1、首先下載XXL-JOB
2、使用開發工具eclipse或者idea導入該項目
3、找到master/doc下的數據庫文件導入數據庫比如xx-job
4、修改配置文件xxl-job-admin.properties中數據庫的鏈接地址和密碼,這裏如果有自己搭建郵箱服務器也可填寫郵箱服務器等信息
5、將該項目部署到tomcat服務器進行啓動,訪問http://127.0.0.1:8081/,輸入密碼用戶名(默認admin,123456)
6、在web頁面中新建執行器以及任務
7、根據他提供的一些例子比如spring boot的,導入他的依賴以及配置文件這些信息到自己的項目中
8、填寫好admin部署的項目地址,這點很重要,指定執行器名稱、ip、端口、以及日誌文件路徑
9、記住XxlJobConfig這個配置文件一定要導入
10、新建一個Handler類似這樣
/**
* 任務Handler的一個Demo(Bean模式)
*
* 開發步驟: 1、繼承 “IJobHandler” ; 2、裝配到Spring,例如加 “@Service” 註解; 3、加 “@JobHander”
* 註解,註解value值爲新增任務生成的JobKey的值;多個JobKey用逗號分割; 4、執行日誌:需要通過 "XxlJobLogger.log"
* 打印執行日誌;
*
* @author xuxueli 2015-12-19 19:43:36
*/
@JobHander(value = "demoJobHandler")//這個對應admin中的對應執行器中的任務的名稱
@Service
public class DemoJobHandler extends IJobHandler {
@Value("${xxl.job.executor.port}")
private String port;
@Override
public ReturnT<String> execute(String... params) throws Exception {//任務執行的代碼
XxlJobLogger.log("XXL-JOB, Hello World." + port);
System.out.println("XXL-JOB, Hello World." + port);
for (int i = 0; i < 5; i++) {
XxlJobLogger.log("beat at:" + i);
// TimeUnit.SECONDS.sleep(2);
}
return ReturnT.SUCCESS;
}
}
啓動項目後即可。這個是一個分佈式job調度平臺,可以試着啓動多個項目然後添加到同一個執行器中執行,按照他的規則填好集羣中的ip即可。