春/春ブーツが適切クォーツを統合し、障害を解決する@Autowired

前の金曜日をチェックし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 Beanclass適切な作成する反射Job新規作成するたびに、あるJob時間が、対応もたらすJob例ことにより、これUnprocessedTaskJob单例競合する。
コードの表示レコードを提出し、追加されることはありません、その時ので@Component注釈を、あなたが通過することができない@Autowiredの導入Spring IOCホストされているtaskMapper、それはインスタンスを達成することはできません依赖注入

しかし、驚くべきは、私はに加えて、開発環境に行くときということで、以下の注意事項、プログラムを実行した後に見つかったインスタンスがまだに注入することができるプログラムを実行...UnprocessedTaskJob@ComponentTaskMapperJob

Spring管理クォーツ

コード分​​析

オンライン検索SpringホスティングQuartzの記事は、ほとんどのSpring MVCプロジェクトでは、解決する方法に焦点を当てJobて実装クラスを@Autowired実現Springする依赖注入
ほとんどが達成するために、インターネットに頼るSpringBeanJobFactory達成するための統合を。SpringQuartz

/**
 * 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実装ApplicationContextAwareSchedulerContextAwareインターフェース(Quartzタスクスケジューリングコンテキスト)は、で作成することができるJob Bean噴射時間ApplicationContexSchedulerContext

ヒント:
基づいて上記コードSpring5.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;
    }
}

上記のコードによって、それによって達成される作成インスタンス、得られた送達によるインスタンスホストへ。に設定されている(実際にはパッケージの内部)、及び(データソース、設定されていない場合、デフォルト)。SpringBeanJobFactorycreateJobInstanceJobJobAutowireCapableBeanFactory
schedulerFactoryBeanJobFactoryAutowiringSpringBeanJobFactoryapplicationContextDataSourceQuartzRamJobStore

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-schedulerQuartz自動化された構成がまだ有効になります(これが問題の最初の分析で、削除される@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:
あなたはあなたに私の記事が参考と思われる場合は、赤い封筒またはスキャンコードの下で支援を受けるために、コードをスキャンすることができます(、ペニーは愛乱数である)、ありがとうございました!

アリペイ赤い封筒 アリペイ マイクロ手紙

おすすめ

転載: www.cnblogs.com/jason1990/p/11110196.html