전과 금요일을 확인 Spring boot
통합 Quartz
탐구하는 소스 코드 방식 읽고, 프로젝트 및 발견 구성 오류 때문에 Spring
올바른 통합 Quartz
방법.
문제 발견
에있는 프로젝트 코드의 마지막 해 확인 QuartzJobBean
존재가 부당 깨달았다.
(1) 프로젝트 종속성 :
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
</dependency>
</dependencies>
(2) 코드의 문제 :
@Component
public class UnprocessedTaskJob extends QuartzJobBean {
private TaskMapper taskMapper;
@Autowired
public UnprocessedTaskJob(TaskMapper taskMapper){
this.taskMapper = taskMapper;
}
}
private JobDetail generateUnprocessedJobDetail(Task task) {
JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put(UnprocessedTaskJob.TASK_ID, task.getId());
return JobBuilder.newJob(UnprocessedTaskJob.class)
.withIdentity(UnprocessedTaskJob.UNPROCESSED_TASK_KEY_PREFIX + task.getId(), UnprocessedTaskJob.UNPROCESSED_TASK_JOB_GROUP)
.usingJobData(jobDataMap)
.storeDurably()
.build();
}
(3) 정제 질문 :
코드보다 오류의 원인 UnprocessedTaskJob
추가 @Component
나타내는, 주석 Spring IOC
컨테이너 单例
클래스.
그러나, Quartz
생성 된 Job
각에서 Quartz Job Bean
의 class
반사하는 적절한 만들 Job
. 즉, 매번 새로 생성 Job
시간, 해당 산출한다 Job
예가. 이에 , 이는 UnprocessedTaskJob
입니다 单例
충돌.
코드보기 때문에 추가하지 않는 시간에 기록을 제출 @Component
주석, 당신은을 통해 할 수 @Autowired
a의 도입 Spring IOC
호스팅 taskMapper
, 즉 얻을 수없는 인스턴스를 依赖注入
.
그러나 놀라운 내가뿐만 아니라 개발 환경에 갈 때이다 다음과 같은주의 사항, 프로그램을 실행 한 후 발견 인스턴스가 여전히 주입 할 수 프로그램 실행 ...UnprocessedTaskJob
@Component
TaskMapper
Job
Spring 관리 석영
코드 분석
온라인 검색 Spring
호스팅 Quartz
기사, 대부분의 Spring MVC
프로젝트는 해결하는 방법에 초점을 Job
관통 구현 클래스를 @Autowired
실현 Spring
의 依赖注入
.
대부분 달성하기 위해 인터넷에 의존 SpringBeanJobFactory
달성하기 위해 통합.Spring
Quartz
/**
* Subclass of {@link AdaptableJobFactory} that also supports Spring-style
* dependency injection on bean properties. This is essentially the direct
* equivalent of Spring's {@link QuartzJobBean} in the shape of a Quartz
* {@link org.quartz.spi.JobFactory}.
*
* <p>Applies scheduler context, job data map and trigger data map entries
* as bean property values. If no matching bean property is found, the entry
* is by default simply ignored. This is analogous to QuartzJobBean's behavior.
*
* <p>Compatible with Quartz 2.1.4 and higher, as of Spring 4.1.
*
* @author Juergen Hoeller
* @since 2.0
* @see SchedulerFactoryBean#setJobFactory
* @see QuartzJobBean
*/
public class SpringBeanJobFactory extends AdaptableJobFactory
implements ApplicationContextAware, SchedulerContextAware {
}
/**
* {@link JobFactory} implementation that supports {@link java.lang.Runnable}
* objects as well as standard Quartz {@link org.quartz.Job} instances.
*
* <p>Compatible with Quartz 2.1.4 and higher, as of Spring 4.1.
*
* @author Juergen Hoeller
* @since 2.0
* @see DelegatingJob
* @see #adaptJob(Object)
*/
public class AdaptableJobFactory implements JobFactory {
}
그것은 위의 코드 및 코멘트를 찾을 수 있습니다 :
(1) AdaptableJobFactory
를 구현 JobFactory
인터페이스, 당신은 표준 생성하기 위해 수행 할 수있는 Quartz
경우 (단 Quartz
위 2.1.4 등);
(2) SpringBeanJobFactory
유전 AdaptableJobFactory
목적을 달성하기 위해 Quartz
특성 의존적 패키지 인스턴스 주입.
(3) SpringBeanJobFactory
구현 ApplicationContextAware
및 SchedulerContextAware
인터페이스 ( Quartz
태스크 스케줄링 상황), 이것은 생성 될 수있는 Job Bean
분사 시간 ApplicationContex
과 SchedulerContext
.
팁 :
위의 코드를 기반으로 Spring
5.1.8 버전
에서 Spring 4.1.0
버전, SpringBeanJobFactory
다음 코드와 같이 구현을 :
public class SpringBeanJobFactory extends AdaptableJobFactory
implements SchedulerContextAware{
// 具体代码省略
}
따라서, 초기에 Spring
프로젝트의 필요성은 패키지 SpringBeanJobFactory
및 구현 ApplicationContextAware
인터페이스 (놀랄 서프라이즈?).
봄 이전 버전의 솔루션
이전 버전을 기반 Spring
으로하는 솔루션 제공 Spring
통합 Quartz
솔루션을.
로부터 솔루션 제 39 장 : SpringBoot 및 석영은 단일 노드 지속성이 배포 작업의 완료의 타이밍을 바탕으로 (일련의 품질 위대한 하나님은 위대) 제공.
@Configuration
public class QuartzConfiguration
{
/**
* 继承org.springframework.scheduling.quartz.SpringBeanJobFactory
* 实现任务实例化方式
*/
public static class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements
ApplicationContextAware {
private transient AutowireCapableBeanFactory beanFactory;
@Override
public void setApplicationContext(final ApplicationContext context) {
beanFactory = context.getAutowireCapableBeanFactory();
}
/**
* 将job实例交给spring ioc托管
* 我们在job实例实现类内可以直接使用spring注入的调用被spring ioc管理的实例
* @param bundle
* @return
* @throws Exception
*/
@Override
protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
final Object job = super.createJobInstance(bundle);
/**
* 将job实例交付给spring ioc
*/
beanFactory.autowireBean(job);
return job;
}
}
/**
* 配置任务工厂实例
* @param applicationContext spring上下文实例
* @return
*/
@Bean
public JobFactory jobFactory(ApplicationContext applicationContext)
{
/**
* 采用自定义任务工厂 整合spring实例来完成构建任务
* see {@link AutowiringSpringBeanJobFactory}
*/
AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();
jobFactory.setApplicationContext(applicationContext);
return jobFactory;
}
/**
* 配置任务调度器
* 使用项目数据源作为quartz数据源
* @param jobFactory 自定义配置任务工厂(其实就是AutowiringSpringBeanJobFactory)
* @param dataSource 数据源实例
* @return
* @throws Exception
*/
@Bean(destroyMethod = "destroy",autowire = Autowire.NO)
public SchedulerFactoryBean schedulerFactoryBean(JobFactory jobFactory, DataSource dataSource) throws Exception
{
SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
//将spring管理job自定义工厂交由调度器维护
schedulerFactoryBean.setJobFactory(jobFactory);
//设置覆盖已存在的任务
schedulerFactoryBean.setOverwriteExistingJobs(true);
//项目启动完成后,等待2秒后开始执行调度器初始化
schedulerFactoryBean.setStartupDelay(2);
//设置调度器自动运行
schedulerFactoryBean.setAutoStartup(true);
//设置数据源,使用与项目统一数据源
schedulerFactoryBean.setDataSource(dataSource);
//设置上下文spring bean name
schedulerFactoryBean.setApplicationContextSchedulerContextKey("applicationContext");
//设置配置文件位置
schedulerFactoryBean.setConfigLocation(new ClassPathResource("/quartz.properties"));
return schedulerFactoryBean;
}
}
위의 코드에서,이를 달성된다 생성 인스턴스, 생성 된 전달하여 인스턴스 호스트는. 으로 설정된다 (실제로는 , 패키지의 내측 ) 및 (설정되어 있지 않은 경우, 데이터 소스는 디폴트 ).SpringBeanJobFactory
createJobInstance
Job
Job
AutowireCapableBeanFactory
schedulerFactoryBean
JobFactory
AutowiringSpringBeanJobFactory
applicationContext
DataSource
Quartz
RamJobStore
RamJobStore
장점은 단점이 스케줄링 작업을 지속적으로 저장할 수 없다는 것입니다, 빠릅니다.
따라서, 우리는 정기적으로 작업 내에서 사용할 수 Spring IOC
의 @Autowired
같은 음 依赖注入
.
봄 솔루션의 새로운 버전
(1) 설명
당신이 사용하는 경우 Spring boot
, 그리고 버전이 좋은보다 큰 2.0
, 그것은 권장합니다 spring-boot-starter-quartz
.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
자동 구성 지원은 이제 Quartz 스케쥴러에 대한 (가) 있습니다. 우리는 또한 새로운 스프링 부팅 스타터 - 석영 스타터 POM을 추가했습니다.
당신은 메모리 JobStores, 또는 전체 JDBC 기반 저장소를 사용할 수 있습니다. 당신의 Spring 애플리케이션 컨텍스트의 모든 JobDetail에, 일정 및 트리거 콩은 자동 스케줄러에 등록됩니다.
자세한 내용은 참조 문서의 새로운 "Quartz 스케쥴러"절을 참조하십시오.
이들은입니다 spring-boot-starter-quartz
프레젠테이션을 기반으로 도입, 당신은 해제하지 않을 경우 보여줍니다 Quartz
자동 구성을, SpringBoot
당신이 완료하는 데 도움이 Scheduler
같은 자동화 된 구성, JobDetail
/ Calendar
/ Trigger
, 등을하는 것은 Bean
자동으로 등록됩니다 Shceduler
에 있습니다. 당신은 할 수 있습니다 QuartzJobBean
무료 사용 @Autowired
및 기타 依赖注入
주석을.
사실, 소개하지 않습니다 spring-boot-starter-quartz
,하지만 수입 org.quartz-scheduler
, Quartz
자동화 된 구성이 여전히 적용됩니다 (다음은이 문제의 첫 번째 분석이다 제거 @Bean
의견을, 프로그램이 여전히 이유를 실행, 비극 운).
(2) 분석 코드
/**
* {@link EnableAutoConfiguration Auto-configuration} for Quartz Scheduler.
*
* @author Vedran Pavic
* @author Stephane Nicoll
* @since 2.0.0
*/
@Configuration
@ConditionalOnClass({ Scheduler.class, SchedulerFactoryBean.class, PlatformTransactionManager.class })
@EnableConfigurationProperties(QuartzProperties.class)
@AutoConfigureAfter({ DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class })
public class QuartzAutoConfiguration{
// 此处省略部分代码
@Bean
@ConditionalOnMissingBean
public SchedulerFactoryBean quartzScheduler() {
// 因为新版本SchedulerFactoryBean已经实现ApplicationContextAware接口
// 因此相对于老版本Spring解决方案中的AutowiringSpringBeanJobFactory进行封装
SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
SpringBeanJobFactory jobFactory = new SpringBeanJobFactory();
// SpringBeanJobFactory中注入applicationContext,为依赖注入创造条件
jobFactory.setApplicationContext(this.applicationContext);
// schedulerFactoryBean中注入setJobFactory(注意此处没有配置DataSource,DataSource详见`JdbcStoreTypeConfiguration`)
// 以上这几个步骤,与老版本的Spring解决方案类似
schedulerFactoryBean.setJobFactory(jobFactory);
// 后续都是Quartz的配置属性设置,不再叙述
if (this.properties.getSchedulerName() != null) {
schedulerFactoryBean.setSchedulerName(this.properties.getSchedulerName());
}
schedulerFactoryBean.setAutoStartup(this.properties.isAutoStartup());schedulerFactoryBean.setStartupDelay((int) this.properties.getStartupDelay().getSeconds());
schedulerFactoryBean.setWaitForJobsToCompleteOnShutdown(this.properties.isWaitForJobsToCompleteOnShutdown());
schedulerFactoryBean.setOverwriteExistingJobs(this.properties.isOverwriteExistingJobs());
if (!this.properties.getProperties().isEmpty()) {
schedulerFactoryBean.setQuartzProperties(asProperties(this.properties.getProperties()));
}
if (this.jobDetails != null && this.jobDetails.length > 0) {
schedulerFactoryBean.setJobDetails(this.jobDetails);
}
if (this.calendars != null && !this.calendars.isEmpty()) {
schedulerFactoryBean.setCalendars(this.calendars);
}
if (this.triggers != null && this.triggers.length > 0) {
schedulerFactoryBean.setTriggers(this.triggers);
}
customize(schedulerFactoryBean);
return schedulerFactoryBean;
}
@Configuration
@ConditionalOnSingleCandidate(DataSource.class)
protected static class JdbcStoreTypeConfiguration {
// 为Quartz的持久化配置DataSource,具体代码可以翻阅Spring源码得到
}
}
이어서, SpringBeanJobFactory
생성 분석, Job
예를 수행하고 依赖注入
키 조작 형.
/**
* Subclass of {@link AdaptableJobFactory} that also supports Spring-style
* dependency injection on bean properties. This is essentially the direct
* equivalent of Spring's {@link QuartzJobBean} in the shape of a Quartz
* {@link org.quartz.spi.JobFactory}.
*
* <p>Applies scheduler context, job data map and trigger data map entries
* as bean property values. If no matching bean property is found, the entry
* is by default simply ignored. This is analogous to QuartzJobBean's behavior.
*
* <p>Compatible with Quartz 2.1.4 and higher, as of Spring 4.1.
*
* @author Juergen Hoeller
* @since 2.0
* @see SchedulerFactoryBean#setJobFactory
* @see QuartzJobBean
*/
public class SpringBeanJobFactory extends AdaptableJobFactory
implements ApplicationContextAware, SchedulerContextAware {
@Nullable
private String[] ignoredUnknownProperties;
@Nullable
private ApplicationContext applicationContext;
@Nullable
private SchedulerContext schedulerContext;
/**
* Specify the unknown properties (not found in the bean) that should be ignored.
* <p>Default is {@code null}, indicating that all unknown properties
* should be ignored. Specify an empty array to throw an exception in case
* of any unknown properties, or a list of property names that should be
* ignored if there is no corresponding property found on the particular
* job class (all other unknown properties will still trigger an exception).
*/
public void setIgnoredUnknownProperties(String... ignoredUnknownProperties) {
this.ignoredUnknownProperties = ignoredUnknownProperties;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Override
public void setSchedulerContext(SchedulerContext schedulerContext) {
this.schedulerContext = schedulerContext;
}
/**
* Create the job instance, populating it with property values taken
* from the scheduler context, job data map and trigger data map.
*/
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
// 创建Job实例
// (1) 包含applicationContext,则通过AutowireCapableBeanFactory()创建相应Job实例,实现依赖注入
// (2) 如果applicationContext为空,则使用AdaptableJobFactory创建相应的Bean(无法实现依赖注入)
Object job = (this.applicationContext != null ?
this.applicationContext.getAutowireCapableBeanFactory().createBean(
bundle.getJobDetail().getJobClass(), AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, false) :
super.createJobInstance(bundle));
if (isEligibleForPropertyPopulation(job)) {
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(job);
MutablePropertyValues pvs = new MutablePropertyValues();
if (this.schedulerContext != null) {
pvs.addPropertyValues(this.schedulerContext);
}
pvs.addPropertyValues(bundle.getJobDetail().getJobDataMap());
pvs.addPropertyValues(bundle.getTrigger().getJobDataMap());
if (this.ignoredUnknownProperties != null) {
for (String propName : this.ignoredUnknownProperties) {
if (pvs.contains(propName) && !bw.isWritableProperty(propName)) {
pvs.removePropertyValue(propName);
}
}
bw.setPropertyValues(pvs);
}
else {
bw.setPropertyValues(pvs, true);
}
}
return job;
}
// 省略部分代码
}
/**
* {@link JobFactory} implementation that supports {@link java.lang.Runnable}
* objects as well as standard Quartz {@link org.quartz.Job} instances.
*
* <p>Compatible with Quartz 2.1.4 and higher, as of Spring 4.1.
*
* @author Juergen Hoeller
* @since 2.0
* @see DelegatingJob
* @see #adaptJob(Object)
*/
public class AdaptableJobFactory implements JobFactory {
/**
* Create an instance of the specified job class.
* <p>Can be overridden to post-process the job instance.
* @param bundle the TriggerFiredBundle from which the JobDetail
* and other info relating to the trigger firing can be obtained
* @return the job instance
* @throws Exception if job instantiation failed
*/
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
// 获取`QuartzJobBean`的实现`class`,通过反射工具创建相应的类实例(自然无法注入Spring托管的Bean实例)
Class<?> jobClass = bundle.getJobDetail().getJobClass();
return ReflectionUtils.accessibleConstructor(jobClass).newInstance();
}
}
다음은 설명 할 필요 AutowireCapableBeanFactory
. 조치를
프로젝트, 일부는 달성하지 않은 Spring
통합의 깊이를, 그것의 예없는 Spring
컨테이너 관리.
그러나, 대한 필요성이되지 않은 Spring
에서 관리 Bean
도입 할 필요가 Spring
컨테이너를 Bean
.
이 때, 우리는 달성하는 데 필요한 AutowireCapableBeanFactory
, 그래서 Spring
의존성 주입 및 기타 기능.
우리는 당신이 이전 버전과 새 버전이 방법을 알려 주시기, 위의 설명과 코드 분석을 희망 Spring
에 바로 통합 Quartz
.
또한, Spring boot
자동화 된 구성이 구성 문제의 대부분을 해결할 수 있지만, 충분한 시간, 그것은 등, 소스 코드를 읽어 권장 이해 配置细节
함으로써 더 많은 자신감을 선도.
추신 :
당신이 내 기사가 도움이 생각한다면, 당신은 (페니 사랑은 임의의 숫자) 빨간 봉투 또는 스캔 코드에서 지원을받을 수있는 코드를 스캔 할 수 있습니다, 감사합니다!
Alipay의 빨간 봉투 | Alipay의 | 마이크로 편지 |
---|---|---|