Integrate Quarz Job with Spring using SchedulerFactoryBean

This article describes the integration of Quartz Job with Spring.


This integration mainly uses the
org.springframework.scheduling.quartz.SchedulerFactoryBean provided by Spring, which enables the Spring application context to create or manage Quartz's Scheduler, including registering JobDetails, Calendars, and Triggers.
With this class, you can Retire the Listener org.quartz.ee.servlet.QuartzInitializerListener.

Note: This class is compatible with Quartz 2.1.4 and above, and Spring 4.1 and above.


1. Example (using Annotation):
quartz_jobs.xml: omitted
quartz.properties: omitted

import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
import org.springframework.stereotype.Component;
@Component
public class MyJobFactory extends AdaptableJobFactory {  

    @Autowired  
    private AutowireCapableBeanFactory capableBeanFactory;  

    @Override  
    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {  
        Object jobInstance = super.createJobInstance(bundle);  
        capableBeanFactory.autowireBean(jobInstance);  
        return jobInstance;  
    }  
}

Implement the JobFactory class of the AdaptableJobFactory interface and override the createJobInstance method.

import java.util.Properties;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Component;
@Component
public class ComponentFactory {

	@Bean
	public SchedulerFactoryBean getSchedulerFactoryBean(JobFactory myJobFactory) throws Exception {
		SchedulerFactoryBean bean = new SchedulerFactoryBean();
		bean.setJobFactory(myJobFactory);
		bean.setSchedulerName("myscheduler");
		Properties quartzProperties = new Properties();
		quartzProperties.load(this.getClass().getResourceAsStream("/quartz.properties"));
		bean.setQuartzProperties(quartzProperties);
		return bean;
	}	
}

Define bean: schedulerFactoryBean.

public class DumpJob implements Job {
	
	@Autowired
	private ServiceA serviceA;

	public void execute(JobExecutionContext context) throws JobExecutionException {
        assertNotNull("Service should be injected.", serviceA);
	}
}

Define a Job and inject a Service for Test.


2. Source code analysis:
First, the SchedulerFactoryBean class:
public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBean<Scheduler>,
		BeanNameAware, ApplicationContextAware, InitializingBean, DisposableBean, SmartLifecycle {

	// Implementation of InitializingBean interface
	@Override
	public void afterPropertiesSet() throws Exception {
		// excerpt
		// Create SchedulerFactory instance...
		SchedulerFactory schedulerFactory = BeanUtils.instantiateClass(this.schedulerFactoryClass);
		initSchedulerFactory(schedulerFactory);
	}
}

First look at the interface of this class, which implements InitializingBean (this interface only defines one method, called afterPropertiesSet(). Looking at the source code, SchedulerFactoryBean rewrites the afterPropertiesSet() method and does a lot of things in it, such as:
a. Created SchedulerFactory
b. Create Scheduler
c. If there is a jobFactory property, then set
d. Register the listener listener of Scheduler, Job, and Trigger (if defined)
e. Register Job and Trigger

In addition, our parameter settings for Quartz Job are also It is implemented through the SchedulerFactoryBean class. The following are some common properties of this class:
  • public static final int DEFAULT_THREAD_COUNT = 10; The default number of threads is 10.
  • private String schedulerName; Scheduler name, if not defined, the bean name (name) is used by default.
  • private Resource configLocation; Quartz's configuration is the storage location of quartz.properties. If it is configured in xml, it can be written as <property name="configLocation" value="classpath:quartz.properties"/>.
  • private Properties quartzProperties; If you use Annotation to define beans, you can use bean.setQuartzProperties(Properties) to initialize quartz.properties.
  • private JobFactory jobFactory; injects a JobFactory object.


Introduce org.quartz.spi.JobFactory:
public interface JobFactory {
	Job newJob(TriggerFiredBundle bundle, Scheduler scheduler) throws SchedulerException;
}


介绍:org.springframework.scheduling.quartz.AdaptableJobFactory:
public class AdaptableJobFactory implements JobFactory {
	protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
		return bundle.getJobDetail().getJobClass().newInstance();
	}
}


If we generate a class to implement AdaptableJobFactory, the Job will call AdaptableJobFactory#createJobInstance() when it is instantiated, and this method is overridden in the above custom MyJobFactory:
a. Get the current jobInstance instance.
b. Using AutowireCapableBeanFactory, set the job instance as an auto wired bean.

AutowireCapableBeanFactory is an interface that inherits BeanFactory. Although it is a sub-interface of BeanFacoty, it is far less famous than ListableBeanFactory (the parent interface of ApplicationContext). The main function of this class is to add some instance instances other than ApplicationContext to the Spring Application context. Such as adding JobInstance into it.

This class is obtained by: org.springframework.context.ApplicationContext#getAutowireCapableBeanFactory()

This is why we can use this bean directly in MyJobFacoty.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326383824&siteId=291194637