Maison  >  Article  >  Java  >  A quoi peut servir le Quartz ?

A quoi peut servir le Quartz ?

零下一度
零下一度original
2018-05-22 09:28:404551parcourir

A quoi peut servir le Quartz ?

Quartz est un framework de planification de tâches. Par exemple, si vous rencontrez ce problème

  • Vous souhaitez rembourser automatiquement votre carte bancaire le 25 de chaque mois

  • Vous souhaitez payer vous-même le 1er avril de chaque année. La déesse du béguin envoie une carte de vœux anonyme

  • Je souhaite sauvegarder mes notes d'étude de films d'action d'amour sur le disque cloud toutes les heures

Ceux-ci Le problème peut se résumer ainsi : faire quelque chose à une heure régulière. Et les conditions de déclenchement temporel peuvent être très complexes (par exemple, 17h50 le dernier jour ouvrable de chaque mois), si complexes qu'un cadre spécial est nécessaire pour ce faire. Quartz est là pour faire ce genre de chose. Vous lui donnez une définition des conditions de déclenchement, et il est responsable du déclenchement du Job correspondant pour qu'il commence à fonctionner à ce moment précis.

Fin de bêtises, le code est génial. . .

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());
    }
}

paquet pot :

Cet exemple couvre très bien les trois éléments de base les plus importants de Quartz :

  • Scheduler : Scheduler. Toute la planification est contrôlée par celui-ci.

  • Déclencheur : Définir les conditions de déclenchement. Dans l'exemple, son type est SimpleTrigger, qui est exécuté toutes les 1 seconde (ce qu'est SimpleTrigger sera décrit en détail ci-dessous).

  • JobDetail & Job : JobDetail définit les données de la tâche, et la véritable logique d'exécution est dans le Job, dans l'exemple c'est HelloQuartz. Pourquoi est-il conçu comme JobDetail + Job au lieu d'utiliser Job directement ? En effet, les tâches peuvent être exécutées simultanément Si le planificateur utilise le Job directement, il y aura un problème d'accès simultané à la même instance du Job. Dans la méthode JobDetail & Job, chaque fois que le planificateur est exécuté, une nouvelle instance de Job sera créée sur la base de JobDetail, afin d'éviter le problème de l'accès simultané.

Scheduler

Scheduler est le cerveau de Quartz, et toutes les tâches sont mises en œuvre par lui.

Schduelr contient deux composants importants : JobStore et ThreadPool.

JobStore stockera les informations d'exécution, notamment le déclencheur, le planificateur, le JobDetail, le verrouillage professionnel, etc. Il a plusieurs implémentations RAMJob (implémentation de la mémoire), JobStoreTX (JDBC, les transactions sont gérées par Quartz), JobStoreCMT (JDBC, utilisant des transactions de conteneurs), ClusteredJobStore (implémentation de cluster), TerracottaJobStore (Qu'est-ce que Terraractta ).

ThreadPool est un pool de threads et Quartz a sa propre implémentation de pool de threads. Toutes les tâches seront exécutées par le pool de threads.

SchedulerFactory

SchdulerFactory, comme son nom l'indique, est utilisé pour créer Schduler. Il existe deux implémentations : DirectSchedulerFactory et StdSchdulerFactory. Le premier peut être utilisé pour personnaliser vos propres paramètres Schduler dans le code. Ce dernier lit directement la configuration quartz.properties sous le classpath (utilisez la valeur par défaut si elle n'existe pas) pour instancier Schduler. D'une manière générale, il nous suffit d'utiliser StdSchdulerFactory.

SchdulerFactory lui-même prend en charge la création de stubs RMI, qui peuvent être utilisés pour gérer les planificateurs distants. Ses fonctions sont les mêmes que celles des planificateurs locaux et il peut soumettre des tâches à distance.

1.job

classe d'implémentation JobDetail

    JobDetail job = JobBuilder.newJob(RemindJob.class)
            .withIdentity("job1", "group1").build();//创建一个任务
     /**
      * 创建触发器
      * 第一种方式  不太好      */SimpleTrigger trigger = TriggerBuilder.newTrigger().withIdentity("myTrigger", "myTriggerGroup").
    withSchedule(SimpleScheduleBuilder.simpleSchedule().
            withIntervalInSeconds(3).
            repeatForever()).
            startAt(new Date(System.currentTimeMillis()+1000)).build();    
    /**
     * 创建触发器
     * 第二种 方式  非常好
     * 可以 好用  2013年每月的第三个星期五上午10:30触发  0 30 10 ? * 6#3 2013
     * 2016年每月的第一个星期四下午16:17触发   0 17 16 ? * 5#1 2016
     * 每天15点到16点每5分钟运行一次,此外,每天17点到18点每5分钟运行一次  

     *//*CronTrigger trigger=TriggerBuilder.newTrigger() 
            .withIdentity("myTrigger", "myTriggerGroup")
            .withSchedule(CronScheduleBuilder.cronSchedule("0 18 16 ? * 5#1 2016")).build();*/
    SchedulerFactory sf=new StdSchedulerFactory();//创建调度者工厂Scheduler scheduler = sf.getScheduler();//创建一个调度者scheduler.scheduleJob(job,trigger);//注册并进行调度scheduler.start();//启动调度    //Thread.sleep(millis)    //scheduler.shutdown();//关闭调度

RemindJob 类的定义

 */public class RemindJob implements Job {private RemindService service=new RemindService();
    @Overridepublic void execute(JobExecutionContext context) throws JobExecutionException {
        service.printPlan("你好!");
        
        Date date=new Date();
        String time = date.toString();
        System.out.println(time+"job is starting");
    }

Comme vous pouvez le voir, nous transmettons une instance JobDetail au planificateur, car lorsque nous créons le JobDetail, nous transmettons le nom de classe du travail à exécuter au JobDetail, pour que le planificateur sache quel type de travail exécuter ; chaque fois que le planificateur exécute le travail, une nouvelle instance de la classe sera créée avant d'appeler sa méthode execute(...) après l'exécution, la référence à l'instance est ; L'instance sera récupérée ; une conséquence de cette stratégie d'exécution est que le travail doit avoir un constructeur sans paramètre (lors de l'utilisation de JobFactory par défaut, une autre conséquence est que stateful ne doit pas être défini dans les attributs de données de la classe de travail en raison des valeurs) ; ​​Certains de ces attributs ne sont pas conservés lors de plusieurs exécutions de la tâche.

Alors, comment ajouter des attributs ou une configuration à l'instance de travail ? Comment suivre l'état d'un travail lors de plusieurs exécutions du travail ? La réponse est : JobDataMap, une partie de l’objet JobDetail.

JobDataMap

JobDataMap peut contenir un nombre illimité d'objets de données (sérialisés), et les données peuvent être utilisées lorsque l'instance de travail est exécutée. JobDataMap est une implémentation de l'interface Java Map. ajouté pour faciliter l’accès aux types de données de base.

Avant d'ajouter le travail au planificateur, lors de la construction du JobDetail, vous pouvez mettre les données dans le JobDataMap, comme indiqué dans l'exemple suivant :

    JobDetail job=JobBuilder.newJob(RemindJob.class)
            .withIdentity("job1", "group1")
            .usingJobData("hello", "we are family")
            .build();

in Lors de l'exécution du travail, les données peuvent être récupérées du JobDataMap, comme le montre l'exemple suivant :

@Overridepublic 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:

@Overridepublic 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);

 

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn