Quartz の Job と JobDetail の詳細な分析

怪我咯
リリース: 2017-07-02 10:43:20
オリジナル
2396 人が閲覧しました

以下のエディターは、Quartz の Job と JobDetail の詳細な分析を提供します。編集者はこれがとても良いものだと思ったので、皆さんの参考として今から共有します。編集者をフォローして、

Quartzが何に使えるのか見てみましょう?

Quartz はタスク スケジューリング フレームワークです。例えばこんな問題に遭遇したら

毎月25日にクレジットカードの自動返済をしたい

毎年4月1日に憧れの女神に匿名のグリーティングカードを送りたい

1 時間ごとに支払いたいです。ラブ アクション映画の学習ノートをクラウド ディスクにバックアップします。

これらの質問の要約は、次のとおりです。特定の決まった時間に何かをする。また、時間トリガー条件は非常に複雑になる場合があります (毎月の最終営業日の 17:50 など)。これを行うには特別なフレームワークが必要になるほど複雑です。 Quartz はこのようなことを行うためにあります。トリガー条件の定義を与えると、その時点で対応するジョブが動作するようにトリガーされます。

これ以上ナンセンスはありません。コードは素晴らしいです。 。 。

public static void main(String[] args) {
   try { //创建scheduler
  Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();

  //定义一个Trigger
  Trigger trigger =TriggerBuilder.newTrigger().withIdentity("trigger1", "group1") //定义name/group
    .startNow()//一旦加入scheduler,立即生效
    .withSchedule(SimpleScheduleBuilder.simpleSchedule() //使用SimpleTrigger
      .withIntervalInSeconds(1) //每隔一秒执行一次
      .repeatForever()) //一直执行
    .build();
  //定义一个JobDetail
  JobDetail job =JobBuilder.newJob(HelloQuartz.class) //定义Job类为HelloQuartz类,这是真正的执行逻辑所在
    .withIdentity("job1", "group1") //定义name/group
    .usingJobData("name", "quartz") //定义属性
    .build();
  //加入这个调度
  scheduler.scheduleJob(job, trigger);
  //启动之
  scheduler.start();
  //运行一段时间后关闭
   Thread.sleep(10000);
   scheduler.shutdown(true);
  } catch (Exception e) {
  e.printStackTrace();
}

}
ログイン後にコピー

HelloQuartz クラス

public class HelloQuartz implements Job {
  public void execute(JobExecutionContext context) throws JobExecutionException {
    JobDetail detail = context.getJobDetail();
    String name = detail.getJobDataMap().getString("name");
    System.out.println("say hello to " + name + " at " + new Date());
  }
}
ログイン後にコピー


jar パッケージ:

この例は、Quartz の 3 つの最も重要な基本要素をよくカバーしています:

Scheduler: スケジューラー。すべてのスケジュールはそれによって制御されます。

トリガー: トリガー条件を定義します。この例では、そのタイプは SimpleTrigger で、1 秒ごとに実行されます (SimpleTrigger については後で詳しく説明します)。

JobDetail と Job: JobDetail はタスク データを定義し、実際の実行ロジックはジョブ内にあります。この例では、HelloQuartz です。 Job を直接使用するのではなく、JobDetail + Job として設計されているのはなぜですか?これは、スケジューラがジョブを直接使用する場合、タスクが同時に実行される可能性があるため、同じジョブ インスタンスへの同時アクセスの問題が発生する可能性があります。 JobDetail & Jobメソッドでは、スケジューラが実行されるたびにJobDetailを元に新しいJobインスタンスが作成されるため、同時アクセスの問題を回避できます。

スケジューラ

スケジューラはQuartzの頭脳であり、すべてのタスクはそれによって実装されます。

Schduelr には、JobStore と ThreadPool という 2 つの重要なコンポーネントが含まれています。

JobStore には、トリガー、スケジューラー、JobDetail、ビジネス ロックなどの実行時情報が保存されます。 RAMJob (メモリ実装)、JobStoreTX (JDBC、トランザクションは Quartz によって管理)、JobStoreCMT (JDBC、コンテナ トランザクションを使用)、ClusteredJobStore (クラスタ実装)、TerracottaJobStore (Terracotta とは) といった複数の実装があります。

ThreadPool はスレッド プールであり、Quartz には独自のスレッド プール実装があります。すべてのタスクはスレッド プールによって実行されます。

SchedulerFactory

SchdulerFactory は、名前が示すように、Schduler を作成するために使用されます。DirectSchedulerFactory と StdSchdulerFactory の 2 つの実装があります。前者は、コード内で独自の Schduler パラメーターをカスタマイズするために使用できます。後者は、クラスパスの下のquartz.properties設定を直接読み取り(存在しない場合はデフォルト値を使用します)、Schdulerをインスタンス化します。一般的に言えば、StdSchdulerFactory を使用するだけで十分です。

SchdulerFactory 自体は、リモート スケジューラーの管理に使用できる RMI スタブの作成をサポートしています。機能はローカルのスケジューラーと同じであり、ジョブをリモートで送信できます。ご覧のとおり、JobDetail を作成するときに必要なため、JobDetail インスタンスをスケジューラに渡します。実行されたジョブのクラス名は JobDetail に渡されるため、スケジューラは実行するジョブのタイプを認識します。スケジューラがジョブを実行するたびに、そのクラスの新しいインスタンスが作成されてから、execute(...) メソッドが呼び出されます。 ; 実行後、インスタンスへの参照は破棄され、インスタンスはガベージ コレクションされます。この実行戦略の結果の 1 つは、ジョブにパラメーターのない

コンストラクター

が必要になることです (デフォルトの JobFactory を使用する場合)。データ属性はジョブ クラスで定義しないでください。これらの属性の値はジョブの複数の実行にわたって保持されないためです。

では、ジョブ インスタンスに属性や設定を追加するにはどうすればよいでしょうか?ジョブの複数の実行中にジョブのステータスを追跡するにはどうすればよいですか?答えは、JobDataMap、JobDetailオブジェクトの一部です。

JobDataMap

JobDataMap には無制限の (シリアル化された) データ オブジェクトを含めることができ、そのデータはジョブ インスタンスの実行時に使用できます。JobDataMap は Java Map インターフェイスの実装であり、簡単に保存できるようにいくつかのメソッドが追加されています。基本的な型のデータを取得します。

将job加入到scheduler之前,在构建JobDetail时,可以将数据放入JobDataMap,如下示例:

JobDetail job=JobBuilder.newJob(RemindJob.class)
      .withIdentity("job1", "group1")
      .usingJobData("hello", "we are family")
      .build();
ログイン後にコピー

在job的执行过程中,可以从JobDataMap中取出数据,如下示例:

@Override
  public void execute(JobExecutionContext context) throws JobExecutionException {
    service.printPlan("你好!");
    JobKey key=context.getJobDetail().getKey();
    
    JobDataMap map = context.getJobDetail().getJobDataMap();
    String string = map.getString("hello");
    System.out.println(key+"==========="+string);
    
    Date date=new Date();
    String time = date.toString();
    System.out.println(time+"job is starting");
  }
ログイン後にコピー

如果你使用的是持久化的存储机制(本教程的JobStore部分会讲到),在决定JobDataMap中存放什么数据的时候需要小心,因为JobDataMap中存储的对象都会被序列化,因此很可能会导致类的版本不一致的问题;Java的标准类型都很安全,如果你已经有了一个类的序列化后的实例,某个时候,别人修改了该类的定义,此时你需要确保对类的修改没有破坏兼容性;更多细节,参考现实中的序列化问题。另外,你也可以配置JDBC-JobStore和JobDataMap,使得map中仅允许存储基本类型和String类型的数据,这样可以避免后续的序列化问题。

如果你在job类中,为JobDataMap中存储的数据的key增加set方法(如在上面示例中,增加setJobSays(String val)方法),那么Quartz的默认JobFactory实现在job被实例化的时候会自动调用这些set方法,这样你就不需要在execute()方法中显式地从map中取数据了。

在Job执行时,JobExecutionContext中的JobDataMap为我们提供了很多的便利。它是JobDetail中的JobDataMap和Trigger中的JobDataMap的并集,但是如果存在相同的数据,则后者会覆盖前者的值。

下面的示例,在job执行时,从JobExecutionContext中获取合并后的JobDataMap:

@Override
  public void execute(JobExecutionContext context) throws JobExecutionException {
    service.printPlan("你好!");
    JobKey key=context.getJobDetail().getKey();
    
  /*  JobDataMap map = context.getJobDetail().getJobDataMap();
    String string = map.getString("hello");
    System.out.println(key+"==========="+string);*/


     JobDataMap map = context.getMergedJobDataMap();
     String string = map.getString("hello");
     System.out.println(key+"---------------------  "+string);
ログイン後にコピー

以上がQuartz の Job と JobDetail の詳細な分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート