前の金曜日をチェックし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
の導入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
ソリューション。
からソリューション第三十九章: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>
自動設定のサポートは現在、クォーツスケジューラ用などがあります。我々はまた、新しい春・ブート・スターター・石英スターターPOMを追加しました。
あなたは、メモリ内JobStores、または完全なJDBCベースのストアを使用することができます。SpringアプリケーションコンテキストからのすべてのJobDetail、カレンダーやトリガー豆は自動的にスケジューラに登録されます。
詳細については、リファレンスドキュメントの新しい「クォーツスケジューラ」セクションをお読みください。
これらは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
自動化された構成は、構成上の問題の大半を解決することができますが、多くの時間で、それはなど、ソースコードを読んで推奨されています理解配置细节
、それによって、より多くの自信につながります。
PS:
あなたはあなたに私の記事が参考と思われる場合は、赤い封筒またはスキャンコードの下で支援を受けるために、コードをスキャンすることができます(、ペニーは愛乱数である)、ありがとうございました!
アリペイ赤い封筒 | アリペイ | マイクロ手紙 |
---|---|---|