将 quartz 与 spring 调度程序一起使用时未创建 Bean 引用 - 作业实例化失败

Bean references are not creating when using quartz with spring scheduler - Job instantiation failed

在升级调度程序未按预期工作后,我已将我的 spring-boot 应用程序从 1.x 更新为 2.x。得到以下异常。

org.quartz.SchedulerException: Job instantiation failed
        at org.springframework.scheduling.quartz.AdaptableJobFactory.newJob(AdaptableJobFactory.java:47)
        at org.quartz.core.JobRunShell.initialize(JobRunShell.java:127)
        at org.quartz.core.QuartzSchedulerThread.run(QuartzSchedulerThread.java:392) Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.schedulers.simplejobs.SimpleJobExecutions': Unsatisfied dependency expressed through field 'sampleService'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.service.SampleService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:596)
        at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:90)
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:374)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1411)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:592)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:351)
        at org.springframework.scheduling.quartz.SpringBeanJobFactory.createJobInstance(SpringBeanJobFactory.java:90)
        at com.scheduler.factory.JobFactory.createJobInstance(JobFactory.java:35)
        at org.springframework.scheduling.quartz.AdaptableJobFactory.newJob(AdaptableJobFactory.java:43)
        ... 2 common frames omitted Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.service.SampleService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1655)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1214)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1168)
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:593)
        ... 11 common frames omitted

我已经尝试了很多来自 SO 的参考资料,但建议的配置没有帮助。

下面是堆栈的详细信息。

Spring 引导 2.1.5

Spring 5.1.7

石英 2.3.1

这是我的代码库。


public final class JobFactory  extends SpringBeanJobFactory {

    private transient AutowireCapableBeanFactory beanFactory;

    private static final Logger LOGGER = LoggerFactory.getLogger(JobFactory.class);

    public void setApplicationContext(final ApplicationContext context) {
        Stream.of(context.getBeanDefinitionNames())
            .filter(s -> s.startsWith("sample"))
            .forEach(beanName -> LOGGER.debug("applicationContext beans {}",beanName));
        beanFactory = context.getAutowireCapableBeanFactory();
    }

    @Override
    protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
        final Object job = super.createJobInstance(bundle);
        LOGGER.debug("createJobInstance job {}",job);
        beanFactory.autowireBean(job);
        LOGGER.debug("createJobInstance autowireBean job {}",job);
        return job;
    }
@Component
public class SimpleJobExecutions extends QuartzJobBean {


    @Autowired
    public SampleService sampleService;

    @Override
    public void executeInternal(JobExecutionContext context)  throws JobExecutionException {
        try {
            SampleDTO sample = new SampleDTO();
            sample.setName("Name");
            sample.setAge(25);
            SampleDTO sampleObj = sampleService.save(sample);
        } catch (Exception ex) {
            throw new JobExecutionException(ex);
        }
    }
@Service("sampleService")
public class SampleServiceImpl implements SampleService {

    @Autowired
    SampleRepository sampleRepository;

    @Autowired
    SampleMapper sampleMapper;

   @Override
   public SampleDTO save(SampleDTO sampleDTO) {
      log.info("Request to save Sample : {}", sampleDTO);
      Sample sample = sampleMapper.toEntity(sampleDTO);
      sample = sampleRepository.save(sample);
      return sampleMapper.toDto(sample);
  }

}

我可以打印应用程序上下文中的所有 bean,但它不会在作业执行时注入。

首先,关于 SimpleJobExecutions class 中的 @Autowired public SampleServiceImpl sampleService; 行,编写接口代码是一个很好的做法。

我觉得容器中有一个代理 bean 实现了 SimpleService 并且因为你试图注入 SimpleServiceImpl 它没有被注入。(注意代理对象不是 'SimpleServiceImp').

要测试这是否是您的情况,只需尝试通过接口注入 SimpleServiceImpl

只需替换:

@Autowired public SampleServiceImpl sampleService;

@Autowired public SampleService sampleService;

希望对您有所帮助。

更新:(只是做一些说明)

当你的 bean 被代理包装时,代理对象实现了你的 bean 的接口,因为在你的问题的前一个版本中(编辑之前)你通过 class(而不是接口)注入了一个 bean ),没有这样的 class 的 bean(但是有一个具有接口类型的 bean),因此容器无法找到这样的 bean,它抛出:

org.springframework.beans.factory.NoSuchBeanDefinitionException:  No qualifying bean of type 'com.service.SampleService' available

你好我会尽量回答这个问题

默认情况下,您的 SchedulerFactoryBean 使用 AdaptableJobFactory( https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/scheduling/quartz/SchedulerFactoryBean.html#setJobFactory-org.quartz.spi.JobFactory),它没有自动装配功能,因此您需要指定 Spring 的实例Spring这里基本上是BeanJobFactory 您需要将其指定给调度程序。 例如:

@Autowired
private ApplicationContext applicationContext;

@Bean
public SchedulerFactoryBean schedulerFactoryBean() {
    SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
    JobFactory jobFactory = new JobFactory();
    jobFactory.setApplicationContext(applicationContext);
    schedulerFactoryBean.setJobFactory(jobFactory);
    return schedulerFactoryBean;
}

替代方法:

如果上面的代码不起作用,那么您可以简单地尝试从 executeInternal() 方法中的应用程序上下文中获取 bean

 @Component
public class SimpleJobExecutions extends QuartzJobBean {

    @Override
    public void executeInternal(JobExecutionContext context)  throws JobExecutionException {
        try {
            ApplicationContext applicationContext = (ApplicationContext)
                        context.getScheduler().getContext().get("applicationContext");
            SampleService sampleService = (SampleService) applicationContext.getBean(SampleService.class);
            SampleDTO sample = new SampleDTO();
            sample.setName("Name");
            sample.setAge(25);
            SampleDTO sampleObj = sampleService.save(sample);
        } catch (Exception ex) {
            throw new JobExecutionException(ex);
        }
    }

终于找到了这个问题的根本原因。

自动装配其他 bean 引用在删除以下依赖项后开始工作。

  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <version>2.1.5.RELEASE</version>
  </dependency>

开发工具依赖项正在与应用程序依赖项产生冲突,并且它不允许仅在 QuartzJobBean 执行中创建 bean 引用。