web-dev-qa-db-ja.com

SpringBootが機能しないQuartzの複数のジョブでの自動配線

春にクォーツスケジューラを使おうとしています。複数のジョブを構成すると、以下の例外が発生します

Job2のメソッドjobTriggerのパラメーター0には、タイプ 'org.quartz.JobDetail'のBeanが必要でしたが、見つかりませんでした。

クォーツ-v2.3、スプリング-v4.2.x

構成クラス

@Configuration
 public class SchedulerConfig {

private static final Logger LOG = LoggerFactory.getLogger(SchedulerConfig.class);

@Autowired
List<Trigger> triggers;

@Bean
public JobFactory jobFactory(ApplicationContext applicationContext) {
    AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();
    jobFactory.setApplicationContext(applicationContext);
    return jobFactory;
}

@Bean
public SchedulerFactoryBean schedulerFactoryBean(JobFactory jobFactory)  throws IOException {
    SchedulerFactoryBean factory = new SchedulerFactoryBean();
          factory.setAutoStartup(true);
    factory.setJobFactory(jobFactory);
         factory.setQuartzProperties(quartzProperties());
    if (triggers != null && !triggers.isEmpty()) {
         LOG.info("starting jobs... Total Triggers - " + triggers.size());
        factory.setTriggers(triggers.toArray(new Trigger[triggers.size()]));
    }

    return factory;
}

@Bean
public Properties quartzProperties() throws IOException {
    PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
    propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
    propertiesFactoryBean.afterPropertiesSet();
    return propertiesFactoryBean.getObject();
}


public static CronTriggerFactoryBean createCronTrigger(JobDetail jobDetail, String cronExpression) {
    CronTriggerFactoryBean factoryBean = new CronTriggerFactoryBean();
    factoryBean.setJobDetail(jobDetail);
    factoryBean.setCronExpression(cronExpression);
    factoryBean.setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_FIRE_NOW);
    return factoryBean;
}

public static JobDetailFactoryBean createJobDetail(Class jobClass) {
    JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();
    factoryBean.setJobClass(jobClass);
    factoryBean.setDurability(true);
    return factoryBean;
}

SpringBeanJobFactory

public final class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware {

private static final Logger LOG = LoggerFactory.getLogger(AutowiringSpringBeanJobFactory.class);

private transient AutowireCapableBeanFactory beanFactory;

@Override
public void setApplicationContext(final ApplicationContext context) {
    beanFactory = context.getAutowireCapableBeanFactory();
}

@Override
protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
    final Object job = super.createJobInstance(bundle);
    LOG.info("create job instance");
    beanFactory.autowireBean(job);
    return job;
}

}

仕事1

@Component
@DisallowConcurrentExecution
public class Job1 implements Job {

private final Logger log = LoggerFactory.getLogger(this.getClass());

@Value("${schedule}")
private String frequency;

@Autowired
private Service service;

@Override
public void execute(JobExecutionContext jobExecutionContext) {
    log.info("execute");
}

@Bean(name = "jobBean1")
public JobDetailFactoryBean job() {
    return SchedulerConfig.createJobDetail(this.getClass());
}

@Bean(name = "jobBean1Trigger")
public CronTriggerFactoryBean jobTrigger(@Qualifier("jobBean1")JobDetail jobDetail) {
    return SchedulerConfig.createCronTrigger(jobDetail, frequency);
}

仕事2

@Component
@DisallowConcurrentExecution
public class Job2 implements Job {

private final Logger log = LoggerFactory.getLogger(this.getClass());

@Value("${schedule}")
private String frequency;

@Autowired
private Service service;

@Override
public void execute(JobExecutionContext jobExecutionContext) {
    log.info("execute");
}

@Bean(name = "jobBean2")
public JobDetailFactoryBean job() {
    return SchedulerConfig.createJobDetail(this.getClass());
}

@Bean(name = "jobBean2Trigger")
public CronTriggerFactoryBean jobTrigger(@Qualifier("jobBean2")JobDetail jobDetail) {
    return SchedulerConfig.createCronTrigger(jobDetail, frequency);
}

ServiceクラスにはSpringJPAリポジトリがあります。問題の根本的な原因は、以下の自動配線サービスです。以下の自動配線サービスを両方のジョブから削除すると、正常に機能します。

@Autowiredプライベートサービスサービス;

この自動配線されたBeanのジョブが1つしかない場合、例外はありません。同じ自動配線依存関係を使用して複数のジョブを構成するにはどうすればよいですか?この問題の原因は何ですか?

5
Zire

これは、1つの構成ファイルで複数のQuartzジョブを処理するために参照した http://www.baeldung.com/spring-quartz-schedule の修正バージョンです。簡潔にするために、QrtzShedulerクラス全体を含めているのではなく、スケジューラメソッドの代わりに、トリガーで@Qualifier参照を使用しています。

...
@Bean
public Scheduler scheduler(Map<String, JobDetail> jobMap, Set<? extends Trigger> triggers) throws SchedulerException, IOException {

    StdSchedulerFactory factory = new StdSchedulerFactory();
    factory.initialize(new ClassPathResource("quartz.properties").getInputStream());

    logger.debug("Getting a handle to the Scheduler");
    Scheduler scheduler = factory.getScheduler();
    scheduler.setJobFactory(springBeanJobFactory());
    Map<JobDetail,Set<? extends Trigger>> triggersAndJobs = new HashMap<JobDetail,Set<? extends Trigger>>;
    for(JobDetail jobDetail : jobMap.getValues()){
        for(Trigger trigger : triggers){
            if(trigger.getJobKey().equals(jobDetail.getKey())){
               Set<Trigger> set = new HashSet<>();
               set.add(trigger);
               triggerAndJobs.put(jobDetail,set);
            }
        }
    }
    scheduler.scheduleJobs(triggersAndJobs, false);

    logger.debug("Starting Scheduler threads");
    scheduler.start();
    return scheduler;
}

@Bean(name="jobOne")
public JobDetail jobDetailOne() {

    ...
}

@Bean(name="jobTwo")
public JobDetail jobDetailTwo() {

   ...
}

@Bean
public Trigger triggerOne(@Qualifier("jobOne")JobDetail jobDetail) {

   ...
}

@Bean
public Trigger triggerTwo(@Qualifier("jobTwo")JobDetail jobDetail) {

   ...
}
3
Rob Cullen

私は同じ問題に直面し、少し苦労した後、それを解決することができました。おそらく、ジョブクラスで使用されるアノテーションに対応しています。私の場合と同じように、あなたは@Componentを使用しているようです。代わりに、クォーツスケジューラ構成には@Configurationタグが付けられます。

解決策は、ジョブに@Configurationタグで注釈を付けることです。私の推測では、@Beanアノテーション付きクラスで構築された@Componentは、@Configurationアノテーション付きクラスが初期化されるフェーズでは完全に構築/マッピングされていません。

1
NiVeR

Spring4.2でSpringBoot構成を使用しようとしています。

Jobクラス内の次のメソッドを次のように変更してみてください

@Bean(name = "jobBean1")
public JobDetail job() {
    return SchedulerConfig.createJobDetail(this.getClass()).getObject();
}

@Bean(name = "jobBean1Trigger")
public CronTrigger jobTrigger(@Qualifier("jobBean1")JobDetail jobDetail) {
    return SchedulerConfig.createCronTrigger(jobDetail, frequency).getObject();
}

必要なのでSpring4.3も使用してください

@Autowired
List<Trigger> triggers;

CollectionAutowireは4.3でのみ機能すると思います

0
Shanoj S

jobTriggerメソッドは引数としてJobDetailを期待しますが、渡されるBeanのタイプはJobDetailFactoryBeanです。

たぶん、次のような変更を加える必要があります。

@Bean(name = "jobBean1")
public JobDetail job() {
    return SchedulerConfig.createJobDetail(this.getClass()).getObject();
}

そしてjob2についても同じです。

ちなみに、Spring-v1.5についておっしゃっていますね。実際に使用しているSpringのバージョンはどれですか?

0
lzagkaretos