我们知道Spring支持与Quartz框架集成。
但是到目前为止,Spring仅支持静态XML声明方法。
如果想了解如何将Spring与Quartz集成,可以参考Spring + Quartz + JavaMail集成教程 。
作为宠物项目要求的一部分,我必须动态安排工作,并且想到了以下两个选项:
1.使用注释提供作业元数据
2.从数据库加载作业元数据
现在,我想到了继续使用基于注释的方法,并且也希望将其与Spring集成。 这是我的方法。
1.创建一个自定义注解QuartzJob
package com.sivalabs.springsamples.jobscheduler;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.stereotype.Component;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
@Scope("prototype")
public @interface QuartzJob
{
String name();
String group() default "DEFAULT_GROUP";
String cronExp();
}
2.创建一个ApplicationListener来扫描所有Job实施类,并使用Quartz Scheduler调度它们。
package com.sivalabs.springsamples.jobscheduler;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.quartz.Job;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.scheduling.quartz.CronTriggerBean;
import org.springframework.scheduling.quartz.JobDetailBean;
public class QuartJobSchedulingListener
implements ApplicationListener<ContextRefreshedEvent>
{
@Autowired
private Scheduler scheduler;
@Override
public void onApplicationEvent(ContextRefreshedEvent event)
{
try
{
ApplicationContext applicationContext = event.getApplicationContext();
List<CronTriggerBean> cronTriggerBeans = this.loadCronTriggerBeans(applicationContext);
this.scheduleJobs(cronTriggerBeans);
}
catch (Exception e)
{
e.printStackTrace();
}
}
private List<CronTriggerBean> loadCronTriggerBeans(ApplicationContext applicationContext)
{
Map<String, Object> quartzJobBeans =
applicationContext.getBeansWithAnnotation(QuartzJob.class);
Set<String> beanNames = quartzJobBeans.keySet();
List<CronTriggerBean> cronTriggerBeans = new ArrayList<CronTriggerBean>();
for (String beanName : beanNames)
{
CronTriggerBean cronTriggerBean = null;
Object object = quartzJobBeans.get(beanName);
System.out.println(object);
try
{
cronTriggerBean = this.buildCronTriggerBean(object);
}
catch (Exception e)
{
e.printStackTrace();
}
if(cronTriggerBean != null)
{
cronTriggerBeans.add(cronTriggerBean);
}
}
return cronTriggerBeans;
}
public CronTriggerBean buildCronTriggerBean(Object job) throws Exception
{
CronTriggerBean cronTriggerBean = null;
QuartzJob quartzJobAnnotation =
AnnotationUtils.findAnnotation(job.getClass(), QuartzJob.class);
if(Job.class.isAssignableFrom(job.getClass()))
{
System.out.println("It is a Quartz Job");
cronTriggerBean = new CronTriggerBean();
cronTriggerBean.setCronExpression(quartzJobAnnotation.cronExp());
cronTriggerBean.setName(quartzJobAnnotation.name()+"_trigger");
//cronTriggerBean.setGroup(quartzJobAnnotation.group());
JobDetailBean jobDetail = new JobDetailBean();
jobDetail.setName(quartzJobAnnotation.name());
//jobDetail.setGroup(quartzJobAnnotation.group());
jobDetail.setJobClass(job.getClass());
cronTriggerBean.setJobDetail(jobDetail);
}
else
{
throw new RuntimeException(job.getClass()+" doesn't implemented "+Job.class);
}
return cronTriggerBean;
}
protected void scheduleJobs(List<CronTriggerBean> cronTriggerBeans)
{
for (CronTriggerBean cronTriggerBean : cronTriggerBeans)
{
JobDetail jobDetail = cronTriggerBean.getJobDetail();
try
{
scheduler.scheduleJob(jobDetail, cronTriggerBean);
}
catch (SchedulerException e)
{
e.printStackTrace();
}
}
}
}
3.创建一个自定义的JobFactory,以将Spring bean用作Job实现对象。
package com.sivalabs.springsamples.jobscheduler;
import org.quartz.Job;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyAccessorFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.quartz.SpringBeanJobFactory;
public class SpringQuartzJobFactory extends SpringBeanJobFactory
{
@Autowired
private ApplicationContext ctx;
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception
{
@SuppressWarnings("unchecked")
Job job = ctx.getBean(bundle.getJobDetail().getJobClass());
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(job);
MutablePropertyValues pvs = new MutablePropertyValues();
pvs.addPropertyValues(bundle.getJobDetail().getJobDataMap());
pvs.addPropertyValues(bundle.getTrigger().getJobDataMap());
bw.setPropertyValues(pvs, true);
return job;
}
}
4.创建Job实施类,并使用@QuartzJob对其进行批注
package com.sivalabs.springsamples.jobscheduler;
import java.util.Date;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;
@QuartzJob(name="HelloJob", cronExp="0/5 * * * * ?")
public class HelloJob extends QuartzJobBean
{
@Override
protected void executeInternal(JobExecutionContext context)
throws JobExecutionException
{
System.out.println("Hello Job is running @ "+new Date());
System.out.println(this.hashCode());
}
}
5.在applicationContext.xml中配置SchedulerFactoryBean和QuartJobSchedulingListener
<beans>
<context:annotation-config></context:annotation-config>
<context:component-scan base-package="com.sivalabs"></context:component-scan>
<bean class="com.sivalabs.springsamples.jobscheduler.QuartJobSchedulingListener"></bean>
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="jobFactory">
<bean class="com.sivalabs.springsamples.jobscheduler.SpringQuartzJobFactory"></bean>
</property>
</bean>
</beans>
6.使用测试客户端启动上下文
package com.sivalabs.springsamples;
import org.quartz.Job;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.sivalabs.springsamples.jobscheduler.HowAreYouJob;
import com.sivalabs.springsamples.jobscheduler.InvalidJob;
public class TestClient
{
public static void main(String[] args)
{
ApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println(context);
}
}
参考: JCG合作伙伴 Siva在“我的技术实验”博客上的 使用自定义批注进行Spring和Quartz集成 。
相关文章 :
翻译自: https://www.javacodegeeks.com/2011/10/spring-quartz-integration-with-custom.html