Springboot は Quartz プロジェクトの使用を統合します (完全なコードを含む)

序文: クォーツはタイミング スケジューリング フレームワークです。現在の市場に関する限り、実際にはクォーツよりも優れたタイミング スケジューリング フレームワークがいくつかあります。それらはクォーツよりも優れたパフォーマンスを備えているだけでなく、学習コストが低く、また、タイミングタスクの視覚的な操作。たとえば、xxl-Job と elastic-Job は、現在仕事で最も一般的に使用されているタイミング スケジューリング フレームワークであり、分散プロジェクトに適しており、優れたパフォーマンスを備えています。これは多くの人が混乱する質問ですが、この場合、なぜクォーツを理解して学ぶ必要があるのでしょうか? 私個人としては、Quartz の学習には 2 つの側面があると考えています。1 つは、フレームワーク xxl-Job と elastic-Job は Quartz に基づいて開発されており、Quartz を学習することは、タイミング スケジューリングの理解に役立ちます。2 番目の側面は作業要件です。伝統的なインターネット企業の中には、スケジュールされたタスクの開発を完了するために Quartz を使用するプロジェクトがまだ多くあります。Quartz を理解していなければ、たとえ書くように頼んでも上司は対応できません。スケジュールされたタスク。

1. クォーツの基本概念ここに画像の説明を挿入します

上の図からわかるように、ジョブは複数の jobDetails に対してカプセル化でき、jobDetail はトリガーのルールを設定できますが、トリガーに装備できる jobDetail は 1 つだけです。

スケジューラ: スケジュールされたタスクの作業コンテナまたはワークプレイスとして理解でき、すべてのスケジュールされたタスクがその中に配置され、開始および停止できます。

トリガー: スケジュールされたタスクの作業ルール構成として理解でき、たとえば、数分ごとに呼び出すことも、毎日指定した時刻に実行することもできます。

jobDetail : スケジュールされたタスクの情報 (スケジュールされたタスク、グループなどの名前の構成など)。

job : スケジュールされたタスクの実際のビジネス処理ロジック。

2. クォーツのシンプルな使い方

これはquartzのAPIの使い方で、公式サイトに直接使用例が掲載されていますが、この方法は業務では使用しません。

アドレス: https://www.quartz-scheduler.org/documentation/quartz-2.3.0/quick-start.html

public class QuartzTest {
    
    

    public static void main(String[] args) throws Exception{
    
    
        try {
    
    

            Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();


            scheduler.start();
            JobDetail job = newJob(HelloJob.class)
                    .withIdentity("job1", "group1")
                    .build();

            Trigger trigger = newTrigger()
                    .withIdentity("trigger1", "group1")
                    .startNow()
                    .withSchedule(simpleSchedule()
                            .withIntervalInSeconds(2)
                            .repeatForever())
                    .build();

            scheduler.scheduleJob(job, trigger);

            TimeUnit.SECONDS.sleep(20);
            scheduler.shutdown();

        } catch (SchedulerException se) {
    
    
            se.printStackTrace();
        }
    }
}
3. クォーツとスプリングブーツの統合と使用

公式サイトでも紹介されていますが、quartzの依存関係を参照しておけば、springbootが自動的にスケジューラを適応させてくれます。もちろん、新しい Bean を作成して、SchedulerFactoryBean のいくつかのデフォルト属性値を変更することもできます。

javaBean メソッドを使用して、実際のビジネス ニーズに応じて SchedulerFactoryBean を初期化します (オプション。デフォルトの SchedulerFactoryBean を使用します)

@Configuration
public class QuartzConfiguration {
    
    

    // Quartz配置文件路径
    private static final String QUARTZ_CONFIG = "config/quartz.properties";

    @Value("${task.enabled:true}")
    private boolean enabled;

    @Autowired
    private DataSource dataSource;

    @Bean
    public SchedulerFactoryBean schedulerFactoryBean() {
    
    
        SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
        schedulerFactoryBean.setDataSource(dataSource);
        // 设置加载的配置文件
        schedulerFactoryBean.setConfigLocation(new ClassPathResource(QUARTZ_CONFIG));

        // 用于quartz集群,QuartzScheduler 启动时更新己存在的Job
        schedulerFactoryBean.setOverwriteExistingJobs(true);

        schedulerFactoryBean.setStartupDelay(5);// 系统启动后,延迟5s后启动定时任务,默认为0

        // 启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了
        schedulerFactoryBean.setOverwriteExistingJobs(true);

        // SchedulerFactoryBean在初始化后是否马上启动Scheduler,默认为true。如果设置为false,需要手工启动Scheduler
        schedulerFactoryBean.setAutoStartup(enabled);
        return schedulerFactoryBean;
    }
}

Quartz を使用してスケジュールされたタスクを実装するには、まず新しいジョブを作成する必要があります。Springboot では、新しいジョブ クラスはQuartzJobBean を継承する必要があります。

public class HelloJob extends QuartzJobBean {
    
    
    @Override
    protected void executeInternal(JobExecutionContext context)  {
    
    
        StringJoiner joiner = new StringJoiner(" | ")
                .add("---HelloJob---")
                .add(context.getTrigger().getKey().getName())
                .add(DateUtil.formatDate(new Date()));
        System.out.println(joiner);

    }
}

jobDetail と Trigger を作成してスケジュールされたタスクを開始します。これを実現するには 2 つの方法があります。基本的には、jobDetail と Trigger を作成します。

方法 1: 対応するジョブの JobDetail と Trigger を作成します。この方法で注意する点は 2 つあります。JobDetail はpersist.storeDurively() に設定する必要があります。トリガーの作成には .forJob("helloJob") を使用する必要があります。 JobDetail と一致しており、定義は同じです。

@Component
public class HelloJobDetailConfig {
    
    

    @Bean
    public JobDetail helloJobDetail(){
    
    
        JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
                .withIdentity("helloJob")
                .storeDurably()
                .usingJobData("data", "保密信息")
                .build();
        return jobDetail;
    }

    @Bean
    public Trigger helloJobTrigger(){
    
    
        Trigger trigger = TriggerBuilder.newTrigger()
                .forJob("helloJob")
                .withSchedule(simpleSchedule()
                        .withIntervalInSeconds(3)
                        .repeatForever())
                .build();

        return trigger;
    }
}

方法 2: Bean を注入する前に JobDetail と Trigger を初期化して作成し、スケジューラを使用してそれらを呼び出します。これはネイティブ API 呼び出しと同様です。

@Component
public class HelloJobDetailConfig2 {
    
    

    @Autowired
    private Scheduler scheduler;

    @PostConstruct
    protected void InitHelloJob() throws Exception {
    
    
        JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
                .withIdentity("helloJob")
//                .storeDurably()
                .usingJobData("data", "保密信息")
                .build();
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("helloTrigger")
                .withSchedule(simpleSchedule()
                        .withIntervalInSeconds(3)
                        .repeatForever())
                .build();
        scheduler.scheduleJob(jobDetail,trigger);

    }
}
4. クォーツの持続性

ここに画像の説明を挿入します

Quartz の永続化には 2 種類のストレージがあり、通常は Quartz 関連のテーブルとビジネス テーブルが同じデータベースに配置されます。ただし、パフォーマンスの問題を考慮する場合は、ビジネス テーブルを別のデータベースに、Quartz 関連のテーブルを 1 つのデータベースに配置して、複数のデータ ソースを構成する必要があります。

https://docs.spring.io/spring-boot/docs/2.3.12.RELEASE/reference/html/spring-boot-features.html#boot-features-quartz

Spring の公式 Web サイトには、デフォルトでインメモリ JobStore が使用されると記載されています。ただし、アプリケーションに DataSourcebean があり、spring.quartz が使用可能な場合は、JDBC ベースのストレージを構成できます。ジョブ ストレージ タイプのプロパティはそれに応じて構成されます。2 番目の構成は、テーブル データを削除し、テーブルを起動するたびに再作成することです (実際の運用環境では、DML を使用して手動でテーブルを作成することを好み、この値は Never に設定されます)。Quartz jar パッケージでは、このパスの下にさまざまなデータベースの dml があります: org.quartz.impl.jdbcjobstore

spring.quartz.job-store-type =jdbc

spring.quartz.jdbc.initialize-schema =never

別の方法:

Quartz にアプリケーションのメイン DataSource の代わりに DataSource を使用させるには、DataSource Bean を宣言し、その @bean メソッドに @QuartzDataSource アノテーションを付けます。これを行うと、SchedulerFactoryBean とスキーマ初期化の両方で Quartz 固有の DataSource が使用されるようになります。

@Configuration
public class QuartzDataSourceConfig {
    
    

    @Bean
    @QuartzDataSource
    public DataSource quartzDataSource() {
    
    
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setUsername("root");
        dataSource.setPassword("123456");
        dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/quartz?useUnicode=true&characterEncoding=utf-8&useSSL=false");
        return dataSource;
    }
}

もう一つ注意点があります。Springコンテナにジョブビーンを注入すると、次回からジョブビーンを注入する必要がないので、@Componentをコメントアウトします。

5. クォーツの不発戦略

**誤射:** タスクのトリガー時間に達しましたが、タスクはトリガーされません。

理由: - @DisallowConcurrentExecution アノテーションを使用し、タスク実行時間 > タスク間隔を使用します。

- スレッド プールがいっぱいで、タスクを実行するためのリソースがありません。

- マシンがダウンしているか、停止していると考えられますが、できるだけ早く動作を再開します。

@DisallowConcurrentExecution : これは一般的に使用されるアノテーションで、前のタスクが実行された後に次のタスクが実行され、タスクの並列実行が許可されていないことを証明します。

@PersistJobDataAfterExecution : タスクの実行後、データは次の実行まで保持されます。

異なる ScheduleBuilder、SimpleScheduleBuilder、および非 SimpleScheduleBuilder に対して、異なる火災戦略を設定できます。

SimpleScheduleBuilder は 6 種類、SimpleScheduleBuilder は 3 種類ありますが、実際の作業では CronScheduleBuilder を使用します。

.withMisfireHandlingstructIgnoreMisfires()
MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY = -1
トリガーされていない実行はすべてただちに実行され、トリガーはスケジュールどおりに実行されます。

.withMisfireHandlingstructFireAndProceed()
MISFIRE_INSTRUCTION_FIRE_ONCE_NOW = 1
最初の誤った実行をただちに実行し、他の実行を破棄します (つまり、すべての誤った実行はマージされます)。つまり、トリガーの実行が何回失敗しても、それらは 1 回だけ実行され、その後トリガーが実行されます。その後、スケジュールどおりに実行されます。(デフォルトの不点火戦略)

.withMisfireHandlingstructionDoNothing()
MISFIRE_INSTRUCTION_DO_NOTHING = 2
トリガーされていない実行はすべて、トリガーの次のスケジューリング サイクルが計画どおりに実行される前に破棄されます。

6. まとめ

クォーツに関するもう 1 つの非常に重要なポイントは、コーンの表現です。個人的には、丸暗記する必要はないと思いますが、書き方が本当に分からない場合は、コーンの表現をオンラインで見つけて、オンラインで変換するだけで済みます。

単純なデモのコード アドレス: https://gitee.com/gorylee/quartz-demo
本番プロジェクトでの Quartz の構成使用コード アドレス: https://gitee.com/gorylee/learnDemo/tree/master/quartzDemo

おすすめ

転載: blog.csdn.net/qq798867485/article/details/128072743