Spring Quartz Настройка инжектора на основе конструктора с помощью конструктора родительского класса

У меня есть весенний загрузочный проект, с которым я хочу использовать кварц для выполнения определенных заданий в определенное время. У меня есть этот макет класса:

abstract public class AbstractFoo {
    protected final FooB fooB;

    public AbstractFoo(FooB fooB) {
        this.fooB = fooB;
    }
}

@Service
public class SomeJob extends AbstractFoo implements Job {
    public SomeJob(FooB fooB) {
        super(fooB);
    }

    @Override
    public void execute(final JobExecutionContext context) throws JobExecutionException {
        //do stuff
    }
}

Однако, когда я запускаю это задание, я получаю следующую ошибку:

2017-12-06 14:18:01,383  ERROR --- [quartz-jobs] org.quartz.core.ErrorLogger                                                                : An error occured instantiating job to be executed. job= 'jobGroup.someJob' 
org.quartz.SchedulerException: Job instantiation failed
    at org.springframework.scheduling.quartz.AdaptableJobFactory.newJob(AdaptableJobFactory.java:45)
    at org.quartz.core.JobRunShell.initialize(JobRunShell.java:127)
    at org.quartz.core.QuartzSchedulerThread.run(QuartzSchedulerThread.java:375)
Caused by: java.lang.InstantiationException: com.jobs.SomeJob
    at java.lang.Class.newInstance(Class.java:427)
    at org.springframework.scheduling.quartz.AdaptableJobFactory.createJobInstance(AdaptableJobFactory.java:58)
    at org.springframework.scheduling.quartz.SpringBeanJobFactory.createJobInstance(SpringBeanJobFactory.java:74)
    at com.config.AutowiringSpringBeanJobFactory.createJobInstance(AutowiringSpringBeanJobFactory.java:27)
    at org.springframework.scheduling.quartz.AdaptableJobFactory.newJob(AdaptableJobFactory.java:41)
    ... 2 common frames omitted
Caused by: java.lang.NoSuchMethodException: com.jobs.SomeJob.<init>()
    at java.lang.Class.getConstructor0(Class.java:3082)
    at java.lang.Class.newInstance(Class.java:412)
    ... 6 common frames omitted

У меня уже есть завод по производству автопроводов, вот так:

public final class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements
        ApplicationContextAware {

    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);
        beanFactory.autowireBean(job);
        return job;
    }
}

И вот мой кварцевый конфиг:

@Configuration
public class QuartzConfig {
    @Autowired
    private DataSource dataSource;
    @Autowired
    private PlatformTransactionManager transactionManager;
    @Autowired
    private ApplicationContext applicationContext;

    @Bean
    public SchedulerFactoryBean quartzScheduler() {
        SchedulerFactoryBean quartzScheduler = new SchedulerFactoryBean();

        quartzScheduler.setDataSource(dataSource);
        quartzScheduler.setTransactionManager(transactionManager);
        quartzScheduler.setOverwriteExistingJobs(true);
        quartzScheduler.setSchedulerName("quartz-jobs");

        AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();
        jobFactory.setApplicationContext(applicationContext);
        quartzScheduler.setJobFactory(jobFactory);

        quartzScheduler.setQuartzProperties(quartzProperties());

        Trigger[] triggers = {someJobTrigger().getObject();
        quartzScheduler.setTriggers(triggers);

        return quartzScheduler;
    }

    @Bean
    public CronTriggerFactoryBean someJobTrigger() {
        CronTriggerFactoryBean cronTriggerFactoryBean = new CronTriggerFactoryBean();
        cronTriggerFactoryBean.setJobDetail(someJob().getObject());
        cronTriggerFactoryBean.setCronExpression(cronExp);
        cronTriggerFactoryBean.setGroup(someGroup);
        return cronTriggerFactoryBean;
    }

    @Bean
    public JobDetailFactoryBean someJob() {
        JobDetailFactoryBean jobDetailFactory = new JobDetailFactoryBean();
        jobDetailFactory.setJobClass(SomeJob.class);
        jobDetailFactory.setGroup(someGroup);
        jobDetailFactory.setDurability(true);
        return jobDetailFactory;
    }

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

        return properties;
    }
}

Как мне заставить Quartz подключаться в соответствующих зависимостях через конструктор?

3 ответа

Как указано в документации:

Одним из последствий такого поведения является тот факт, что задания должны иметь конструктор без аргументов (при использовании реализации JobFactory по умолчанию).

Вы, по сути, используете JobFactory по умолчанию с добавленной возможностью автоматического подключения Из моих личных тестов я обнаружил, что автоматическое подключение не будет работать с инжектором конструктора. Также не помечайте свою работу аннотациями Spring (Component, Service, ect), так как это не имеет никакого эффекта.

Чтобы решить вашу проблему, сделайте рефакторинг вашей работы, чтобы иметь зависимости конструктора по умолчанию и автоматическую привязку с инжекцией поля (возможно, инсталляция установки также будет работать).

abstract public class AbstractFoo {
    @Autowired
    protected FooB fooB;
}

public class SomeJob extends AbstractFoo implements Job {

    @Override
    public void execute(final JobExecutionContext context) throws JobExecutionException {
        //do stuff
    }
}

Я только что опубликовал здесь ответ с обычным кварцем с возможностью автоматической проводки. Тем не менее, обратите внимание, что вам нужен конструктор без аргументов (в вашем случае используйте конструктор без аргументов и аргумент). Кварц использует имя класса для создания экземпляра, поэтому ваш конструктор с аргументом работать не будет.

Если вы все еще работаете над той же проблемой, попробуйте мой подход, при котором вы можете автоматически связать требуемую зависимость, а не переходить через super(foo);

/questions/5365933/dobavit-ssyilku-na-komponent-v-rabotu-quartz-vesnoj/5365966#5365966

Эта проблема возникает, когда класс не содержит конструктора по умолчанию.

Пример: YourJob расширяет QuartzJobBean , тогда класс должен содержать конструктор по умолчанию. Добавьте аннотацию @Component и @NoArgsConstructor , если вы используете ломбок. Другие необходимые bean-компоненты должны быть автоматически подключены к этому классу с помощью @Autowired.

Другие вопросы по тегам