Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Boot: Using a @Service in Quartz job execution

In an application, since I converted it from a classical Spring webapp (deployed in a system Tomcat) to a Spring Boot (V1.2.1) application I face the problem that the Quartz-based scheduled jobs are not working anymore.

I schedule these Quartz jobs like this:

// My own Schedule object which holds data about what to schedule when
Schedule schedule = scheduleService.get(id of the schedule);

String scheduleId = schedule.getId();

JobKey jobKey = new JobKey(scheduleId);
TriggerKey triggerKey = new TriggerKey(scheduleId);

JobDataMap jobData = new JobDataMap();
jobData.put("scheduleId", scheduleId);

JobBuilder jobBuilder = JobBuilder.newJob(ScheduledActionRunner.class)
    .withIdentity(jobKey)
    .withDescription(schedule.getName())
    .usingJobData(jobData);

JobDetail job = jobBuilder.build();

TriggerBuilder triggerBuilder = TriggerBuilder.newTrigger()
    .forJob(jobKey)
    .withIdentity(triggerKey)
    .withDescription(schedule.getName());

triggerBuilder = triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(schedule.toCronExpression()));

Trigger trigger = triggerBuilder.build();

org.quartz.Scheduler scheduler = schedulerFactoryBean.getScheduler();

scheduler.scheduleJob(job, trigger);

ScheduledActionRunner:

@Component
public class ScheduledActionRunner extends QuartzJobBean {

    @Autowired
    private ScheduleService scheduleService;

    public ScheduledActionRunner() {
    }

    @Override
    public void executeInternal(final JobExecutionContext context) throws JobExecutionException {
        SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
        final JobDataMap jobDataMap = context.getMergedJobDataMap();
        final String scheduleId = jobDataMap.getString("scheduleId");
        final Schedule schedule = scheduleService.get(scheduleId);
        // here it goes BANG since scheduleService is null
    }
}

ScheduleService is a classical Spring service which fetches data from Hibernate. As I said above, this worked fine until I moved to Spring Boot.

When I implemented this code with the classical Spring application, SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this); did the trick to take care of autowiring the service.

What is needed to make this work again in the Spring Boot environment ?

Edit:

At the end I chose to move away from using Quartz in favour of Spring's ThreadPoolTaskScheduler.The code was much simplified and it works as expected.

like image 630
yglodt Avatar asked Jan 25 '15 09:01

yglodt


People also ask

Does Spring Boot for quartz work with multiple instances of service?

By default, the Spring Boot library for Quartz doesn’t work correctly if you start up two instances of service in parallel. In this case, each one of the services starts the execution of the same jobs.

What is the quartz it-self library in Spring Boot?

The library is the Quartz it-self for Spring Boot and it brings auto-configuration and new classes to our project and allows us to create scheduled jobs. With the libraries configured, now we can start creating your first job. There are other ways to create jobs, but I chose to create a new job extending the class QuartzJobBean.

How to implement quartz scheduler in spring with JDBC?

Start by creating your project with the spring shell so to include quartz, jpa and h2 dependencies (replace with your actual JDBC driver implementation): Now the classes. Let’s add first two Job classes that will be triggered by Quartz scheduler: System.out.println("Hello from Job One!");

What is a jobdetail in quartz?

the first one is the JobDetail: job detail specify the job we want to execute when a new trigger happens, in your case, we created the JobDetail using your job class ATestJob. The identity is the identifier of the JobDetail and will be the “name” of your job. The use of storeDurably tells Quartz to persist this job when is impossible.


1 Answers

The SpringBeanAutowiringSupport uses the web application context, which is not available in your case. If you need a spring managed beans in the quartz you should use the quartz support provided by spring. This will give you full access to all the managed beans. For more info see the quartz section at spring docs at http://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html. Also see following example of usage quartz with spring managed beans. Example is based on your code. So you can change the first code snippet (where the quartz initialization is done) with follwoing spring alternatives.

Create job detail factory

@Component
public class ScheduledActionRunnerJobDetailFactory extends JobDetailFactoryBean {

    @Autowired
    private ScheduleService scheduleService;

    @Override
    public void afterPropertiesSet() {
       setJobClass(ScheduledActionRunner.class);
       Map<String, Object> data = new HashMap<String, Object>();
       data.put("scheduleService", scheduleService);
       setJobDataAsMap(data);
       super.afterPropertiesSet();
   }
}

Create the trigger factory

@Component
public class ActionCronTriggerFactoryBean extends CronTriggerFactoryBean {

   @Autowired
   private ScheduledActionRunnerJobDetailFactory jobDetailFactory;

   @Value("${cron.pattern}")
   private String pattern;

   @Override
   public void afterPropertiesSet() throws ParseException {
       setCronExpression(pattern);
       setJobDetail(jobDetailFactory.getObject());
       super.afterPropertiesSet();
   }

}

And finally create the SchedulerFactory

@Component
public class ActionSchedulerFactoryBean extends SchedulerFactoryBean {

   @Autowired
   private ScheduledActionRunnerJobDetailFactory jobDetailFactory;

   @Autowired
   private ActionCronTriggerFactoryBean triggerFactory;

   @Override
   public void afterPropertiesSet() throws Exception {
       setJobDetails(jobDetailFactory.getObject());
       setTriggers(triggerFactory.getObject());
       super.afterPropertiesSet();
   }

}
like image 200
Babl Avatar answered Nov 03 '22 00:11

Babl