1. 程式人生 > >play框架 JOB

play框架 JOB

 

 

Job

由於Play是Web應用框架,所以大部分的應用邏輯是由響應HTTP請求的控制器來完成的。但是有時候我們需要在HTTP請求之外執行一些應用邏輯操作,比如初始化工作,維護任務或者在不阻塞HTTP請求執行池的情況下執行一些時間花費較長的任務。這時就可以利用Play提供的Job來滿足這些需求。

Job完全由框架管理,這意味著Play會管理所有的資料庫連線,JPA實體管理器的同步以及事務

補充:

Job就是需要在指定的時刻或者時間段內執行的任務,通常由作業排程程式來執行排程和管理。

 

1、實現

 

在Play中建立Job只需要繼承play.jobs.Job類:

package jobs;
 
import play.jobs.*;
 
public class MyJob extends Job {
    
    public void doJob() {
        // 執行一些業務邏輯
    }
}

如果希望建立具有返回值的Job,那麼需要覆蓋doJobWithResult()方法:

package jobs;
 
import play.jobs.*;
  
public class MyJob extends Job<String> {
    
    public String doJobWithResult() {
        // 執行一些業務邏輯
        return result;
    }
    
}

上例自定義的Job覆蓋了doJobWithResult()方法,並且方法的返回型別為String,事實上Job可以返回任何型別的值。



2、Bootstrap

 

2.1 應用啟動#

 

Bootstrap Job,顧名思義就是在應用開始時執行的任務,只需要新增@OnApplicationStart註解就可以把當前Job設定為Bootstrap Job:

import play.jobs.*;
 
@OnApplicationStart
public class Bootstrap extends Job {
    
    public void doJob() {
        if(Page.count() == 0) {
            new Page("root").save();
            Logger.info("A root page has been created.");
        }
    }
    
}

需要注意的是,Bootstrap Job不需要任何返回值。如果有多個帶有@OnApplicationStart註解的Bootstrap Job,那麼預設情況下這些Job會按照定義的先後順序執行。當所有的Bootstrap Job執行完成之後,Web應用就處於等待階段,等待處理那些即將到來的請求。

如果希望Web應用啟動後,能夠在執行Bootstrap Job的同時,又能很快地處理到來的請求,可以為@OnApplicationStart註解新增async=true屬性:@OnApplicationStart(async=true)。這樣應用程式開啟後,Bootstrap Job就會作為後臺程式非同步執行了。不僅如此,所有的非同步Job(async=true)也會在Web應用開啟之後同時執行。

 

注意:

Play具有兩種不同的工作模式:開發模式(DEV)和產品模式(PROD),因此Job的啟動時間也有略微差異。在DEV模式下,直到第一個HTTP請求到達時才會開啟應用,且不會預先編譯Java檔案。如果在該模式下更改Java原始檔可以立即生效,重新整理瀏覽器即可檢視修改後的結果。此外,應用還會在需要的時候自動重啟;而在PROD模式下,應用會在伺服器啟動時同步開啟,一旦應用開啟就會自動編譯所有的Java檔案,之後不再過載任何檔案(包括模板檔案和配置檔案),所以如果有檔案修改必須重啟應用才能生效。所以DEV模式下Job會延遲啟動。

2.2 應用停止#

Web應用停止或關閉的時候,常常也需要進行一些額外的操作,如進行資料的清理、日誌的列印等。如果開發者需要這類任務排程操作,可以使用Play提供的@OnApplicationStop註解。

import play.jobs.*;
 
@OnApplicationStop
public class Bootstrap extends Job {
 
    public void doJob() {
        Fixture.deleteAll();
    }
}

用法非常簡單,繼承Job類之後,重寫doJob()方法即可。

 

3、Scheduled Job

 

 

Scheduled Job是指可以被框架週期性執行的任務,可以使用@Every註解指定時間間隔控制Scheduled Job執行,例如:

import play.jobs.*;
 
@Every("1h")
public class Bootstrap extends Job {
    
    public void doJob() {
        List<User> newUsers = User.find("newAccount = true").fetch();
        for(User user : newUsers) {
            Notifier.sayWelcome(user);
        }
    }
    
}

在實際開發中,@Every註解並不能夠完全滿足開發需求,比如有時候需要指定Scheduled Job在具體的某個時間點執行。這時候可以使用@On註解指定時間點來執行Job,例如:

import play.jobs.*;
 
/** Fire at 12pm (noon) every day **/ 
@On("0 0 12 * * ?")
public class Bootstrap extends Job {
    
    public void doJob() {
        Logger.info("Maintenance job ...");
        ...
    }
    
}

與Bootstrap Job一樣,Scheduled Job也是不需要任何返回值的,即使返回了也會丟失。

 

補充:

@On標籤中使用的是Quartz庫的CRON表示式。CRON表示式是由7個子表示式組成的字串,每個子表示式都描述了單獨的日程細節。這些子表示式用空格分隔,分別表示:

  • Seconds 秒
  • Minutes 分鐘
  • Hours 小時
  • Day-of-Month 一個月中的某一天
  • Month 月
  • Day-of-Week 一週中的某一天
  • Year 年(可選)

 

具體CRON表示式的例子:"0 0 12 ? * WED",表示“每週三的中午12:00”。

 

 

4、Job的直接呼叫

 

 

Play的Job除了被框架自動呼叫外,也可以通過now()方法手動呼叫Job物件的例項,隨時觸發Job來執行指定任務。使用now()方法呼叫Job後,任務會立即執行:

public static void encodeVideo(Long videoId) {
    new VideoEncoder(videoId).now();
    renderText("Encoding started");
}

now()方法的返回值是Promise物件,通過該值可以在結束後獲得Job的執行結果。

 

Job的價值就體現在能夠無縫整合到Play應用當中,從而進一步提高了開發效率。Play針對不同的需求提供了各種形式的Job:Bootstrap Job在應用開始時執行;Scheduled Job會被框架週期性執行,本章最後還提到了如何直接在業務程式中呼叫Job。