1. Passing the object into JobDataMap
This is the easiest way, what we have to do is letting our class implement Serializeble interface. Then the object can be simply passed into the Quartz JobDataMap. However, there is a flaw in this method. If you use a persistent JobStore, the object in it will be serialized. And you will get a class-versioning error if your class definition is changed in future. Quartz recommends only pass primitive and String into JobDataMap. For details, see Quartz lesson 3.
Put object into JobDataMap
<bean id="object" class="com.package.MyObject"/> <bean class="org.springframework.scheduling.quartz.JobDetailFactoryBean"> <property name="jobClass" value="com.package.MyJob"/> <property name="jobDataAsMap"> <map> <entry key="myObject" value-ref="object"/> </map> </property> <property name="durability" value="true"/> </bean>
Retrieve object in Quartz job class
... MyObject obj = jobExecutionContext.getMergedJobDataMap().getString("myObject"); ...>
2. Using Spring application context
In this way, we have to define an application context key in the scheduler bean.
<bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="applicationContextSchedulerContextKey" value="applicationContext"/> <property name="jobDetails"> <list> ... </list> </property> <property name="triggers"> <list> ... </list> </property> </bean>
Then in the job class, we can get the Spring application context as below and retrieve any bean via the bean name.
try { ApplicationContext context = (ApplicationContext) jobExecutionContext.getScheduler().getContext().get("applicationContext"); if (context != null) { InjectObject obj = (InjectObject) context.getBean("geeksPearls"); if (obj != null) { System.out.println("[" + new Date() + "] I am saying hello from a Quartz job, " + obj); } } } catch (SchedulerException e) { e.printStackTrace(); }
The completed example can be found on my GitHub Example3. Have a look at InjectTask class and the Spring context XML.
3. Using Spring injection
We can also use Spring injection to inject any object into our job. However, we have to do a bit more work. I found this way in this blog. And I think it's elegant and the Spring guys should use it as the default way.
Firstly, extend the SpringBeanJobFactory class as below.
public class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware { private transient AutowireCapableBeanFactory beanFactory; public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException { beanFactory = applicationContext.getAutowireCapableBeanFactory(); } @Override protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception { final Object job = super.createJobInstance(bundle); beanFactory.autowireBean(job); return job; } }
Secondly, override the default jobFactory in Spring's SchedulerFactoryBean.
<bean id="autoWireScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="jobFactory" > <bean class="com.geekspearls.quartz.example3.AutowiringSpringBeanJobFactory"/> </property> <property name="jobDetails"> <list> <ref bean="injectJob2"/> </list> </property> <property name="triggers"> <list> <ref bean="simpleTrigger2"/> </list> </property> </bean>
Then we can autowire any object into Quartz job class.
public class AnotherInjectTask extends QuartzJobBean { @Autowired private InjectObject injectObject; @Override protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException { System.out.println("[" + new Date() + "] I am saying another hello from a Quartz job, " + injectObject); } public void setInjectObject(InjectObject injectObject) { this.injectObject = injectObject; } }
Be aware that in order to use the autowire annotation of Spring. Add either <context:annotation-config> or <context:componentscan> in the Spring context XML file. A completed example can be found on my GitHub Example3. Have a look at AnotherInjectTask and the Spring context XML.
In the example, if we run Example3 class as java application. We can see the following output in the console.
... [Sun Aug 16 16:46:12 AEST 2015] I am saying hello from a Quartz job, GeeksPearls [Sun Aug 16 16:46:12 AEST 2015] I am saying another hello from a Quartz job, null [Sun Aug 16 16:46:12 AEST 2015] I am saying another hello from a Quartz job, GeeksPearls ...
The first line is output by the job using the Spring application context way. The second line is output by the job using the default Spring SchedulerFactoryBean. You can see the object is not injected so it outputs null. The third line is output by the job using our AutowiringSpringBeanJobFactory, you can see the object is injected successfully. Enjoy!
Helped me a lot..Thank you for such wonderful content
ReplyDelete