>  기사  >  Java  >  Quartz의 Job 및 JobDetail에 대한 심층 분석

Quartz의 Job 및 JobDetail에 대한 심층 분석

怪我咯
怪我咯원래의
2017-07-02 10:43:202318검색

아래 편집기는 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가지 기본 요소를 잘 다루고 있습니다:

스케줄러: 스케줄러. 모든 일정은 이에 의해 제어됩니다.

트리거: 트리거 조건을 정의합니다. 예제에서는 해당 유형이 SimpleTrigger이며 1초마다 실행됩니다(SimpleTrigger가 무엇인지는 아래에서 자세히 설명합니다).

JobDetail & Job: JobDetail은 작업 데이터를 정의하며 실제 실행 로직은 Job에 있습니다. 예에서는 HelloQuartz입니다. Job을 직접 사용하지 않고 JobDetail + Job으로 설계한 이유는 무엇인가요? Scheduler가 Job을 직접 사용하게 되면 동일한 Job 인스턴스에 동시에 접근하는 문제가 발생할 수 있기 때문이다. JobDetail & Job 메소드에서는 sheduler가 실행될 때마다 JobDetail을 기반으로 새로운 Job 인스턴스가 생성되므로 동시 접근 문제를 피할 수 있습니다.

Scheduler

Scheduler는 Quartz의 두뇌이며 모든 작업이 이에 의해 구현됩니다.

Schduelr에는 JobStore와 ThreadPool이라는 두 가지 중요한 구성 요소가 포함되어 있습니다.

JobStore는 Trigger, Scheduler, JobDetail, 비즈니스 잠금 등을 포함한 런타임 정보를 저장합니다. RAMJob(메모리 구현), JobStoreTX(JDBC, 트랜잭션은 Quartz에 의해 관리됨), JobStoreCMT(JDBC, 컨테이너 트랜잭션 사용), ClusteredJobStore(클러스터 구현), TerracottaJobStore(Terraractta란 무엇입니까) 등 여러 구현이 있습니다.

ThreadPool은 스레드 풀이고 Quartz에는 자체 스레드 풀 구현이 있습니다. 모든 작업은 스레드 풀에 의해 실행됩니다.

SchedulerFactory

SchdulerFactory는 이름에서 알 수 있듯이 Schduler를 생성하는 데 사용됩니다. DirectSchedulerFactory와 StdSchdulerFactory라는 두 가지 구현이 있습니다. 전자는 코드에서 Schduler 매개변수를 사용자 정의하는 데 사용할 수 있습니다. 후자는 클래스 경로 아래의 quartz.properties 구성을 직접 읽어(존재하지 않는 경우 기본값 사용) Schduler를 인스턴스화합니다. 일반적으로 StdSchdulerFactory를 사용하면 충분합니다.

SchdulerFactory 자체는 원격 스케줄러를 관리하는 데 사용할 수 있는 RMI 스텁 생성을 지원합니다. 기능은 로컬 기능과 동일하며 작업을 원격으로 제출할 수 있습니다.

1.job

구현 클래스 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();
  @Override
  public void execute(JobExecutionContext context) throws JobExecutionException {
    service.printPlan("你好!");
    
    Date date=new Date();
    String time = date.toString();
    System.out.println(time+"job is starting");
  }


보시다시피 JobDetail 인스턴스를 스케줄러에 전달합니다. 왜냐하면 JobDetail을 생성할 때 원하는 것이 있기 때문입니다. 실행된 작업의 클래스 이름이 JobDetail에 전달되므로 스케줄러는 실행할 작업 유형을 알 수 있습니다. 스케줄러가 작업을 실행할 때마다 해당 클래스의 새 인스턴스가 실행(...) 메서드를 호출하기 전에 생성됩니다. ;실행 후 인스턴스에 대한 참조는 삭제되고 인스턴스는 가비지 수집됩니다. 이 실행 전략의 한 가지 결과는 작업에 매개변수가 없는

생성자가 있어야 한다는 것입니다(기본 JobFactory를 사용하는 경우). 데이터 속성은 작업 클래스에 정의되어서는 안 됩니다. 왜냐하면 이러한 속성의 값은 여러 작업 실행에서 유지되지 않기 때문입니다.

그럼 작업 인스턴스에 속성이나 구성을 추가하는 방법은 무엇입니까? 작업을 여러 번 실행하는 동안 작업 상태를 추적하는 방법은 무엇입니까? 대답은 JobDetail

개체의 일부인 JobDataMap입니다.

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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.