将 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 引用。
在升级调度程序未按预期工作后,我已将我的 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 引用。