我最终制作了自己的弹簧石英“桥”。我打算建议将其作为春季的改进。
首先,我创建了一个新注释,该注释将放置在实现quartz Job接口的类上:
@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)@Component@Scope("prototype")public @interface ScheduledJob { String cronexpression() default ""; long fixedRate() default -1; boolean durable() default false; boolean shouldRecover() default true; String name() default ""; String group() default "";}(请注意原型作用域-石英假定每个作业执行都是一个新实例。我不是石英专家,所以我符合那个期望。如果发现多余,则可以简单地删除@Scope注释)
然后,我定义了一个ApplicationListener,每当刷新(或启动)上下文时,都将查找所有带有@ScheduledJob注释的类,并将它们注册在石英调度程序中:
public class QuartzScheduledJobRegistrar implements EmbeddedValueResolverAware, ApplicationContextAware, ApplicationListener<ContextRefreshedEvent> {private Scheduler scheduler;private StringValueResolver embeddedValueResolver;private Map<JobListener, String> jobListeners;private ApplicationContext applicationContext;public void setEmbeddedValueResolver(StringValueResolver resolver) { this.embeddedValueResolver = resolver;}public void setApplicationContext(ApplicationContext applicationContext) { this.applicationContext = applicationContext;}@SuppressWarnings("unchecked")@Overridepublic void onApplicationEvent(ContextRefreshedEvent event) { if (event.getApplicationContext() == this.applicationContext) { try { scheduler.clear(); for (Map.Entry<JobListener, String> entry : jobListeners.entrySet()) { scheduler.getListenerManager().addJobListener(entry.getKey(), NameMatcher.nameStartsWith(entry.getValue())); } } catch (SchedulerException ex) { throw new IllegalStateException(ex); } DefaultListableBeanFactory factory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory(); String[] definitionNames = factory.getBeanDefinitionNames(); for (String definitionName : definitionNames) { BeanDefinition definition = factory.getBeanDefinition(definitionName); try { if (definition.getBeanClassName() != null) { Class<?> beanClass = Class.forName(definition.getBeanClassName()); registerJob(beanClass); } } catch (ClassNotFoundException e) { throw new IllegalArgumentException(e); } } }}public void registerJob(Class<?> targetClass) { ScheduledJob annotation = targetClass.getAnnotation(ScheduledJob.class); if (annotation != null) { Assert.isTrue(Job.class.isAssignableFrom(targetClass), "only classes implementing the quartz Job interface can be annotated with @ScheduledJob"); @SuppressWarnings("unchecked") // checked on the previous line Class<? extends Job> jobClass = (Class<? extends Job>) targetClass; JobDetail jobDetail = JobBuilder.newJob() .ofType(jobClass) .withIdentity( annotation.name().isEmpty() ? targetClass.getSimpleName() : annotation.name(), annotation.group().isEmpty() ? targetClass.getPackage().getName() : annotation.group()) .storeDurably(annotation.durable()) .requestRecovery(annotation.shouldRecover()) .build(); TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger() .withIdentity(jobDetail.getKey().getName() + "_trigger", jobDetail.getKey().getGroup() + "_triggers") .startNow(); String cronexpression = annotation.cronexpression(); long fixedRate = annotation.fixedRate(); if (!BooleanUtils.xor(new boolean[] {!cronexpression.isEmpty(), fixedRate >=0})) { throw new IllegalStateException("Exactly one of 'cronexpression', 'fixedRate' is required. Offending class " + targetClass.getName()); } if (!cronexpression.isEmpty()) { if (embeddedValueResolver != null) { cronexpression = embeddedValueResolver.resolveStringValue(cronexpression); } try { triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cronexpression)); } catch (ParseException e) { throw new IllegalArgumentException(e); } } if (fixedRate >= 0) { triggerBuilder.withSchedule( SimpleScheduleBuilder.simpleSchedule() .withIntervalInMilliseconds(fixedRate) .repeatForever()) .withIdentity(jobDetail.getKey().getName() + "_trigger", jobDetail.getKey().getGroup() + "_triggers"); } try { scheduler.scheduleJob(jobDetail, triggerBuilder.build()); } catch (SchedulerException e) { throw new IllegalStateException(e); } }}public void setScheduler(Scheduler scheduler) { this.scheduler = scheduler;}public void setJobListeners(Map<JobListener, String> jobListeners) { this.jobListeners = jobListeners;}}然后,我需要一个自定义的JobFactory来插入石英,以便通过spring上下文创建作业:
public class QuartzSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware {private SchedulerContext schedulerContext;private ApplicationContext ctx;@Overrideprotected Object createJobInstance(TriggerFiredBundle bundle) throws Exception { 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()); if (this.schedulerContext != null) { pvs.addPropertyValues(this.schedulerContext); } bw.setPropertyValues(pvs, true); return job;}public void setSchedulerContext(SchedulerContext schedulerContext) { this.schedulerContext = schedulerContext; super.setSchedulerContext(schedulerContext);}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.ctx = applicationContext;}}最后,xml配置:
<bean id="quartzScheduler" > <property name="jobFactory"> <bean /> </property></bean><bean id="scheduledJobRegistrar" > <property name="scheduler" ref="quartzScheduler" /> <property name="jobListeners"> <map> <entry value=""> <!-- empty string = match all jobs --> <key><bean /></key> </entry> </map> </property></bean>



