i am using quartz with spring and i want to inject/use another class in the job class and i don\'t know how to do it correctly
the xml:
this is my solution:
public class MySpringBeanJobFactory extends
org.springframework.scheduling.quartz.SpringBeanJobFactory implements
ApplicationContextAware {
private ApplicationContext ctx;
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.ctx = applicationContext;
}
@Override
protected Object createJobInstance(TriggerFiredBundle bundle)
throws Exception {
Object jobInstance = super.createJobInstance(bundle);
ctx.getAutowireCapableBeanFactory().autowireBean(jobInstance);
return jobInstance;
}
}
then config the class of MySpringBeanJobFactory in the xml:
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="jobFactory">
<bean class="com.xxxx.MySpringBeanJobFactory" />
</property>
<property name="configLocation" value="classpath:quartz.properties" />
<property name="triggers">
<list>
<ref bean="cronTrigger"/>
</list>
</property>
</bean>
Good luck ! :)
In your solution you are using the spring @Autowired annotation in a class that is not instantiated by Spring. Your solution will still work if you remove the @Autowired annotation because Quartz is setting the property, not Spring.
Quartz will try to set every key within the JobDataMap as a property. E.g. since you have a key "myDao" Quartz will look for a method called "setMyDao" and pass the key's value into that method.
If you want Spring to inject spring beans into your jobs, create a SpringBeanJobFactory and set this into your SchedulerFactoryBean with the jobFactory property within your spring context.
SpringBeanJobFactory javadoc:
Applies scheduler context, job data map and trigger data map entries as bean property values
As mentioned in inject bean reference into a Quartz job in Spring? you can use spring SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
@Named
public class SampleJob implements Job {
@Inject
private AService aService;
@Override
public void execute(JobExecutionContext context)
throws JobExecutionException {
//Do injection with spring
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
aService.doIt();
}
}
As mentioned it may not wotk on some spring version but I have tested it on 4.2.1.RELEASE which worked fine.
ApplicationContext springContext =
WebApplicationContextUtils.getWebApplicationContext(
ContextLoaderListener.getCurrentWebApplicationContext().getServletContext()
);
Bean bean = (Bean) springContext.getBean("beanName");
bean.method();
Not sure if this is what you want, but you can pass some configuration values to the Quartz job. I believe in your case you could take advantage of the jobDataAsMap
property you already set up, e.g.:
<property name="jobDataAsMap">
<map>
<entry key="schedulerTask" value-ref="schedulerTask" />
<entry key="param1" value="com.custom.package.ClassName"/>
</map>
</property>
Then you should be able to access it in your actual Java code in manual way:
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
schedulerTask.printSchedulerMessage();
System.out.println(context.getJobDetail().getJobDataMap().getString("param1"));
}
Or using the magic Spring approach - have the param1
property defined with getter/setter. You could try defining it with java.lang.Class
type then and have the done automatically (Spring would do it for you):
private Class<?> param1;
// getter & setter
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
schedulerTask.printSchedulerMessage();
System.out.println("Class injected" + getParam1().getName());
}
I haven't tested it though.