Home  >  Article  >  Java  >  What can Quartz be used for?

What can Quartz be used for?

零下一度
零下一度Original
2018-05-22 09:28:404552browse

What can Quartz be used for?

Quartz is a task scheduling framework. For example, if you encounter such a problem

  • You want to automatically repay your credit card on the 25th of every month

  • You want to pay yourself on April 1st of each year. The goddess of secret love sends an anonymous greeting card

  • I want to back up my love action movie study notes to the cloud disk every hour

These The problem can be summed up as: do something at a regular time. And the time trigger conditions can be very complex (such as 17:50 on the last working day of each month), so complex that a special framework is needed to do this. Quartz is here to do this kind of thing. You give it a definition of a trigger condition, and it is responsible for triggering the corresponding job to work at the time point.

No more nonsense, the code is awesome. . .

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 package:

This example covers the three most important basic elements of Quartz very well:

  • Scheduler: scheduler. All scheduling is controlled by it.

  • Trigger: Define the conditions for triggering. In the example, its type is SimpleTrigger, which is executed every 1 second (what is SimpleTrigger will be described in detail below).

  • JobDetail & Job: JobDetail defines task data, and the real execution logic is in the Job, in the example it is HelloQuartz. Why is it designed as JobDetail + Job instead of using Job directly? This is because tasks may be executed concurrently. If the Scheduler uses Job directly, there will be a problem of concurrent access to the same Job instance. In the JobDetail & Job method, every time sheduler is executed, a new Job instance will be created based on JobDetail, so that the problem of concurrent access can be avoided.

Scheduler

Scheduler is the brain of Quartz, and all tasks are implemented by it.

Schduelr contains two important components: JobStore and ThreadPool.

JobStore will store runtime information, including Trigger, Scheduler, JobDetail, business locks, etc. It has multiple implementations: RAMJob (memory implementation), JobStoreTX (JDBC, transactions are managed by Quartz), JobStoreCMT (JDBC, using container transactions), ClusteredJobStore (cluster implementation), TerracottaJobStore (What is Terraractta ).

ThreadPool is a thread pool, and Quartz has its own thread pool implementation. All tasks will be executed by the thread pool.

SchedulerFactory

SchdulerFactory, as the name suggests, is used to create Schduler. There are two implementations: DirectSchedulerFactory and StdSchdulerFactory. The former can be used to customize your own Schduler parameters in code. The latter directly reads the quartz.properties configuration under the classpath (use the default value if it does not exist) to instantiate Schduler. Generally speaking, it is enough for us to use StdSchdulerFactory.

SchdulerFactory itself supports the creation of RMI stubs, which can be used to manage remote Schedulers. Its functions are the same as those of local ones, and it can submit jobs remotely.

1.job

##Implementation class 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");
    }

As you can see, we pass a JobDetail instance to the scheduler. Because when we create the JobDetail, we pass the class name of the job to be executed to the JobDetail, so the scheduler knows what kind of job to execute. type of job; each time the scheduler executes the job, a new instance of the class will be created before calling its execute(...) method; after execution is completed, the reference to the instance will be discarded, and the instance will be garbage collected; One consequence of this execution strategy is that the job must have a parameterless constructor (when using the default JobFactory); another consequence is that stateful data attributes should not be defined in the job class, because in The values ​​of these properties are not retained across multiple executions of the job.

So how to add attributes or configuration to the job instance? How to track the status of a job during multiple executions of the job? The answer is: JobDataMap, part of the JobDetail object.

JobDataMap

JobDataMap can contain unlimited (serialized) data objects, and the data can be used when the job instance is executed; JobDataMap is an implementation of the Java Map interface. Additional methods have been added to facilitate accessing basic types of data.

Before adding the job to the scheduler, when building the JobDetail, you can put the data into the JobDataMap, as shown in the following example:

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

In the job During execution, data can be retrieved from JobDataMap, as shown in the following example:

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

 

The above is the detailed content of What can Quartz be used for?. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn