SpringでJobStoreTX永続ストアを使用してQuartzジョブを構成およびスケジュールできました。私はSpringのQuartzジョブを使用しません。実行時にそれらを動的にスケジュールする必要があり、SpringをQuartzと統合するすべての例はSpring構成ファイルでスケジュールをハードコーディングしていたからです...とにかく、ここに方法があります私は仕事をスケジュールします:
JobDetail emailJob = JobBuilder.newJob(EMailJob.class)
.withIdentity("someJobKey", "immediateEmailsGroup")
.storeDurably()
.build();
SimpleTrigger trigger = (SimpleTrigger) TriggerBuilder.newTrigger()
.withIdentity("someTriggerKey", "immediateEmailsGroup")
.startAt(fireTime)
.build();
// pass initialization parameters into the job
emailJob.getJobDataMap().put(NotificationConstants.MESSAGE_PARAMETERS_KEY, messageParameters);
emailJob.getJobDataMap().put(NotificationConstants.RECIPIENT_KEY, recipient);
if (!scheduler.checkExists(jobKey) && scheduler.getTrigger(triggerKey) != null) {
// schedule the job to run
Date scheduleTime1 = scheduler.scheduleJob(emailJob, trigger);
}
EMailJobは、SpringのJavaMailSenderImplクラスを使用して電子メールを送信する単純なジョブです。
public class EMailJob implements Job {
@Autowired
private JavaMailSenderImpl mailSenderImpl;
public EMailJob() {
}
public void execute(JobExecutionContext context)
throws JobExecutionException {
....
try {
mailSenderImpl.send(mimeMessage);
} catch (MessagingException e) {
....
throw new JobExecutionException("EMailJob failed: " + jobKey.getName(), e);
}
logger.info("EMailJob finished OK");
}
問題は、EMailJobクラスでこのクラスのインスタンス(JavaMailSenderImpl)への参照を取得する必要があることです。このように注入しようとすると:
@Autowired
private JavaMailSenderImpl mailSenderImpl;
挿入されません-参照はNULLです。 EMailJobクラスをインスタンス化するのはSpringではなく、QuartzとQuartzが依存性注入について何も知らないため、これが起こっていると思います...
それで、この注入を強制する方法はありますか?
ありがとう!
更新1:@Aaron:これは、スタートアップからのスタックトレースの関連部分で、EMailJobが2回インスタンス化されたことを示しています。
2011-08-15 14:16:38,687 [main] INFO org.springframework.context.support.GenericApplicationContext - Bean 'org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler#0' is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2011-08-15 14:16:38,734 [main] INFO org.springframework.beans.factory.support.DefaultListableBeanFactory - Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1328c7a: defining beans [...]; root of factory hierarchy
2011-08-15 14:16:39,734 [main] INFO com.cambridgedata.notifications.EMailJob - EMailJob() - initializing ...
2011-08-15 14:16:39,937 [main] INFO org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor - Validated configuration attributes
2011-08-15 14:16:40,078 [main] INFO org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Validated configuration attributes
2011-08-15 14:16:40,296 [main] INFO org.springframework.jdbc.datasource.init.ResourceDatabasePopulator - Executing SQL script from class path resource ...
2011-08-15 14:17:14,031 [main] INFO com.mchange.v2.log.MLog - MLog clients using log4j logging.
2011-08-15 14:17:14,109 [main] INFO com.mchange.v2.c3p0.C3P0Registry - Initializing c3p0-0.9.1.1 [built 15-March-2007 01:32:31; debug? true; trace: 10]
2011-08-15 14:17:14,171 [main] INFO org.quartz.core.SchedulerSignalerImpl - Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImpl
2011-08-15 14:17:14,171 [main] INFO org.quartz.core.QuartzScheduler - Quartz Scheduler v.2.0.1 created.
2011-08-15 14:17:14,187 [main] INFO org.quartz.impl.jdbcjobstore.JobStoreTX - Using thread monitor-based data access locking (synchronization).
2011-08-15 14:17:14,187 [main] INFO org.quartz.impl.jdbcjobstore.JobStoreTX - JobStoreTX initialized.
2011-08-15 14:17:14,187 [main] INFO org.quartz.core.QuartzScheduler - Scheduler meta-data: Quartz Scheduler (v2.0.1) 'NotificationsScheduler' with instanceId 'NON_CLUSTERED'
Scheduler class: 'org.quartz.core.QuartzScheduler' - running locally.
NOT STARTED.
Currently in standby mode.
Number of jobs executed: 0
Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with 3 threads.
Using job-store 'org.quartz.impl.jdbcjobstore.JobStoreTX' - which supports persistence. and is not clustered.
2011-08-15 14:17:14,187 [main] INFO org.quartz.impl.StdSchedulerFactory - Quartz scheduler 'NotificationsScheduler' initialized from the specified file : 'spring/quartz.properties' from the class resource path.
2011-08-15 14:17:14,187 [main] INFO org.quartz.impl.StdSchedulerFactory - Quartz scheduler version: 2.0.1
2011-08-15 14:17:14,234 [main] INFO com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource - Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 0, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, dataSourceName -> 2sajb28h1lcabf28k3nr1|13af084, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> com.mysql.jdbc.Driver, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, identityToken -> 2sajb28h1lcabf28k3nr1|13af084, idleConnectionTestPeriod -> 50, initialPoolSize -> 3, jdbcUrl -> jdbc:mysql://localhost:3306/2010rewrite2, lastAcquisitionFailureDefaultUser -> null, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 0, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 5, maxStatements -> 0, maxStatementsPerConnection -> 120, minPoolSize -> 1, numHelperThreads -> 3, numThreadsAwaitingCheckoutDefaultUser -> 0, preferredTestQuery -> select 0 from dual, properties -> {user=******, password=******}, propertyCycle -> 0, testConnectionOnCheckin -> true, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, usesTraditionalReflectiveProxies -> false ]
2011-08-15 14:17:14,312 [main] INFO org.quartz.impl.jdbcjobstore.JobStoreTX - Freed 0 triggers from 'acquired' / 'blocked' state.
2011-08-15 14:17:14,328 [main] INFO org.quartz.impl.jdbcjobstore.JobStoreTX - Recovering 0 jobs that were in-progress at the time of the last shut-down.
2011-08-15 14:17:14,328 [main] INFO org.quartz.impl.jdbcjobstore.JobStoreTX - Recovery complete.
2011-08-15 14:17:14,328 [main] INFO org.quartz.impl.jdbcjobstore.JobStoreTX - Removed 0 'complete' triggers.
2011-08-15 14:17:14,328 [main] INFO org.quartz.impl.jdbcjobstore.JobStoreTX - Removed 0 stale fired job entries.
2011-08-15 14:17:14,328 [main] INFO org.quartz.core.QuartzScheduler - Scheduler NotificationsScheduler_$_NON_CLUSTERED started.
2011-08-15 14:17:14,515 [NotificationsScheduler_QuartzSchedulerThread] INFO com.cambridgedata.notifications.EMailJob - EMailJob() - initializing ...
ありがとう!
アップデート#2:@Ryan:
SpringBeanJobFactoryを次のように使用しようとしました。
<bean id="jobFactoryBean" class="org.springframework.scheduling.quartz.SpringBeanJobFactory">
</bean>
<bean id="schedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="configLocation" value="classpath:spring/quartz.properties"/>
<property name="jobFactory" ref="jobFactoryBean"/>
</bean>
そして、クォーツの代わりにこのファクトリからスケジューラを取得するようにメインクラスを変更しました。
@PostConstruct
public void initNotificationScheduler() {
try {
//sf = new StdSchedulerFactory("spring/quartz.properties");
//scheduler = sf.getScheduler();
scheduler = schedulerFactoryBean.getScheduler();
scheduler.start();
....
しかし、アプリを実行すると、エラーが発生します。以下を参照してください。これは、Springのスタートアップからのスタックトレースです。スケジューラ自体はうまく作成されているようですが、EMailJobをインスタンス化しようとするとエラーが発生します。
2011-08-15 21:49:42,968 [main] INFO org.springframework.scheduling.quartz.SchedulerFactoryBean - Loading Quartz config from [class path resource [spring/quartz.properties]]
2011-08-15 21:49:43,031 [main] INFO com.mchange.v2.log.MLog - MLog clients using log4j logging.
2011-08-15 21:49:43,109 [main] INFO com.mchange.v2.c3p0.C3P0Registry - Initializing c3p0-0.9.1.1 [built 15-March-2007 01:32:31; debug? true; trace: 10]
2011-08-15 21:49:43,187 [main] INFO org.quartz.core.SchedulerSignalerImpl - Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImpl
2011-08-15 21:49:43,187 [main] INFO org.quartz.core.QuartzScheduler - Quartz Scheduler v.2.0.1 created.
2011-08-15 21:49:43,187 [main] INFO org.quartz.impl.jdbcjobstore.JobStoreTX - Using thread monitor-based data access locking (synchronization).
2011-08-15 21:49:43,187 [main] INFO org.quartz.impl.jdbcjobstore.JobStoreTX - JobStoreTX initialized.
2011-08-15 21:49:43,187 [main] INFO org.quartz.core.QuartzScheduler - Scheduler meta-data: Quartz Scheduler (v2.0.1) 'schedulerFactoryBean' with instanceId 'NON_CLUSTERED'
Scheduler class: 'org.quartz.core.QuartzScheduler' - running locally.
NOT STARTED.
Currently in standby mode.
Number of jobs executed: 0
Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with 3 threads.
Using job-store 'org.quartz.impl.jdbcjobstore.JobStoreTX' - which supports persistence. and is not clustered.
2011-08-15 21:49:43,187 [main] INFO org.quartz.impl.StdSchedulerFactory - Quartz scheduler 'schedulerFactoryBean' initialized from an externally provided properties instance.
2011-08-15 21:49:43,187 [main] INFO org.quartz.impl.StdSchedulerFactory - Quartz scheduler version: 2.0.1
2011-08-15 21:49:43,187 [main] INFO org.quartz.core.QuartzScheduler - JobFactory set to: org.springframework.scheduling.quartz.SpringBeanJobFactory@566633
2011-08-15 21:49:43,265 [main] INFO com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource - Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 0, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, dataSourceName -> 1hge13f8h1lsg7py1rg0iu0|1956391, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> com.mysql.jdbc.Driver, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, identityToken -> 1hge13f8h1lsg7py1rg0iu0|1956391, idleConnectionTestPeriod -> 50, initialPoolSize -> 3, jdbcUrl -> jdbc:mysql://localhost:3306/2010rewrite2, lastAcquisitionFailureDefaultUser -> null, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 0, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 5, maxStatements -> 0, maxStatementsPerConnection -> 120, minPoolSize -> 1, numHelperThreads -> 3, numThreadsAwaitingCheckoutDefaultUser -> 0, preferredTestQuery -> select 0 from dual, properties -> {user=******, password=******}, propertyCycle -> 0, testConnectionOnCheckin -> true, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, usesTraditionalReflectiveProxies -> false ]
2011-08-15 21:49:43,343 [main] INFO org.quartz.impl.jdbcjobstore.JobStoreTX - Freed 0 triggers from 'acquired' / 'blocked' state.
2011-08-15 21:49:43,359 [main] INFO org.quartz.impl.jdbcjobstore.JobStoreTX - Recovering 0 jobs that were in-progress at the time of the last shut-down.
2011-08-15 21:49:43,359 [main] INFO org.quartz.impl.jdbcjobstore.JobStoreTX - Recovery complete.
2011-08-15 21:49:43,359 [main] INFO org.quartz.impl.jdbcjobstore.JobStoreTX - Removed 0 'complete' triggers.
2011-08-15 21:49:43,359 [main] INFO org.quartz.impl.jdbcjobstore.JobStoreTX - Removed 0 stale fired job entries.
2011-08-15 21:49:43,359 [main] INFO org.quartz.core.QuartzScheduler - Scheduler schedulerFactoryBean_$_NON_CLUSTERED started.
2011-08-15 21:49:43,562 [schedulerFactoryBean_QuartzSchedulerThread] ERROR org.quartz.core.ErrorLogger - An error occured instantiating job to be executed. job= 'immediateEmailsGroup.DEFAULT.jobFor_1000new1'
org.quartz.SchedulerException: Problem instantiating class 'com.cambridgedata.notifications.EMailJob' - [See nested exception: Java.lang.AbstractMethodError: org.springframework.scheduling.quartz.SpringBeanJobFactory.newJob(Lorg/quartz/spi/TriggerFiredBundle;Lorg/quartz/Scheduler;)Lorg/quartz/Job;]
at org.quartz.core.JobRunShell.initialize(JobRunShell.Java:141)
at org.quartz.core.QuartzSchedulerThread.run(QuartzSchedulerThread.Java:381)
Caused by: Java.lang.AbstractMethodError: org.springframework.scheduling.quartz.SpringBeanJobFactory.newJob(Lorg/quartz/spi/TriggerFiredBundle;Lorg/quartz/Scheduler;)Lorg/quartz/Job;
at org.quartz.core.JobRunShell.initialize(JobRunShell.Java:134)
ありがとう!
このSpringBeanJobFactory
を使用して、スプリングを使用してクォーツオブジェクトを自動的に自動配線できます。
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.scheduling.quartz.SpringBeanJobFactory;
public final class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements
ApplicationContextAware {
private transient AutowireCapableBeanFactory beanFactory;
@Override
public void setApplicationContext(final ApplicationContext context) {
beanFactory = context.getAutowireCapableBeanFactory();
}
@Override
protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
final Object job = super.createJobInstance(bundle);
beanFactory.autowireBean(job);
return job;
}
}
次に、それをSchedulerBean
に添付します(この場合、Java-configを使用):
@Bean
public SchedulerFactoryBean quartzScheduler() {
SchedulerFactoryBean quartzScheduler = new SchedulerFactoryBean();
...
AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();
jobFactory.setApplicationContext(applicationContext);
quartzScheduler.setJobFactory(jobFactory);
...
return quartzScheduler;
}
Spring-3.2.1とquartz-2.1.6を使用して、私のために働いています。
完全な要点を確認してください こちら 。
私はこれで解決策を見つけました ブログ投稿
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
メソッドの最初の行としてJob.execute(JobExecutionContext context)
を追加しました。
同じ問題が LINK で解決されました:
SpringFactoryの投稿から、SchedulerFactoryBeanを介してSpringアプリケーションコンテキストへの参照を渡すことができる他のオプションを見つけることができました。以下に示す例のように:
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<propertyy name="triggers">
<list>
<ref bean="simpleTrigger"/>
</list>
</property>
<property name="applicationContextSchedulerContextKey">
<value>applicationContext</value>
</property>
次に、ジョブクラスで以下のコードを使用して、applicationContextを取得し、必要なBeanを取得できます。
appCtx = (ApplicationContext)context.getScheduler().getContext().get("applicationContextSchedulerContextKey");
それが役に立てば幸い。 Mark Mclaren'sBlog から詳細情報を取得できます。
SpringとQuartzがクラスをインスタンス化することについてのあなたの仮定は正しいです。ただし、Springには、Quartzでいくつかのプリミティブな依存性注入を実行できるクラスが用意されています。 SchedulerFactoryBean.setJobFactory() と一緒に SpringBeanJobFactory をチェックしてください。基本的に、SpringBeanJobFactoryを使用することで、すべてのJobプロパティに対する依存性注入を有効にしますが、Quartz scheduler context または job data map にある値に対してのみです。サポートするすべてのDIスタイル(コンストラクター、注釈、セッターなど)がわかりませんが、セッターインジェクションをサポートすることは知っています。
将来これを試すすべての人に。
org.springframework.scheduling.quartz.JobDetailBeanはオブジェクトのマップを提供し、それらのオブジェクトはSpring Beanである場合があります。
のような定義
<bean name="myJobDetail" class="org.springframework.scheduling.quartz.JobDetailBean">
<property name="jobClass"
value="my.cool.class.myCoolJob" />
<property name="jobDataAsMap">
<map>
<entry key="myBean" value-ref="myBean" />
</map>
</property>
</bean>
そして、内部
public void executeInternal(JobExecutionContext context)
myBean = (myBean) context.getMergedJobDataMap().get("myBean");
を呼び出すと、すべて設定できます。 knowいように見えますが、回避策としては機能します
ApplicationContext springContext =
WebApplicationContextUtils.getWebApplicationContext(ContextLoaderListener .getCurrentWebApplicationContext().getServletContext());
Bean bean = (Bean) springContext.getBean("beanName");
bean.method();
ありがとう、リッポン!多くの苦労の末、ようやくこれも機能するようになりました。私の解決策はあなたが提案したものに非常に近いです!キーは、QuartzJobBeanを拡張するために自分のJobを作成し、schedulerContextAsMapを使用することでした。
ApplicationContextSchedulerContextKeyプロパティを指定せずに逃げました-それがなくても機能しました。
他の人の利益のために、ここに私のために働いた最終的な構成があります:
<bean id="quartzScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="configLocation" value="classpath:spring/quartz.properties"/>
<property name="jobFactory">
<bean class="org.springframework.scheduling.quartz.SpringBeanJobFactory" />
</property>
<property name="schedulerContextAsMap">
<map>
<entry key="mailService" value-ref="mailService" />
</map>
</property>
</bean>
<bean id="jobTriggerFactory"
class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
<property name="targetBeanName">
<idref local="jobTrigger" />
</property>
</bean>
<bean id="jobTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean"
scope="prototype">
<property name="group" value="myJobs" />
<property name="description" value="myDescription" />
<property name="repeatCount" value="0" />
</bean>
<bean id="jobDetailFactory"
class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
<property name="targetBeanName">
<idref local="jobDetail" />
</property>
</bean>
<bean id="jobDetail" class="org.springframework.scheduling.quartz.JobDetailBean"
scope="prototype">
<property name="jobClass" value="com.cambridgedata.notifications.EMailJob" />
<property name="volatility" value="false" />
<property name="durability" value="false" />
<property name="requestsRecovery" value="true" />
</bean>
<bean id="notificationScheduler" class="com.cambridgedata.notifications.NotificationScheduler">
<constructor-arg ref="quartzScheduler" />
<constructor-arg ref="jobDetailFactory" />
<constructor-arg ref="jobTriggerFactory" />
</bean>
「mailService」Beanは、Springが管理する独自のサービスBeanであることに注意してください。次のように、ジョブでアクセスできました。
public void executeInternal(JobExecutionContext context)
throws JobExecutionException {
logger.info("EMailJob started ...");
....
SchedulerContext schedulerContext = null;
try {
schedulerContext = context.getScheduler().getContext();
} catch (SchedulerException e1) {
e1.printStackTrace();
}
MailService mailService = (MailService)schedulerContext.get("mailService");
....
また、この構成では、ファクトリーを使用してトリガーとジョブの詳細を取得し、プログラムでそれらに必要なパラメーターを設定することで、ジョブを動的にスケジューラーすることもできました。
public NotificationScheduler(final Scheduler scheduler,
final ObjectFactory<JobDetail> jobDetailFactory,
final ObjectFactory<SimpleTrigger> jobTriggerFactory) {
this.scheduler = scheduler;
this.jobDetailFactory = jobDetailFactory;
this.jobTriggerFactory = jobTriggerFactory;
...
// create a trigger
SimpleTrigger trigger = jobTriggerFactory.getObject();
trigger.setRepeatInterval(0L);
trigger.setStartTime(new Date());
// create job details
JobDetail emailJob = jobDetailFactory.getObject();
emailJob.setName("new name");
emailJob.setGroup("immediateEmailsGroup");
...
助けてくれたすべての人に感謝します。
マリーナ
@Componentを使用したコードは次のようになります。
ジョブをスケジュールするメインクラス:
public class NotificationScheduler {
private SchedulerFactory sf;
private Scheduler scheduler;
@PostConstruct
public void initNotificationScheduler() {
try {
sf = new StdSchedulerFactory("spring/quartz.properties");
scheduler = sf.getScheduler();
scheduler.start();
// test out sending a notification at startup, prepare some parameters...
this.scheduleImmediateNotificationJob(messageParameters, recipients);
try {
// wait 20 seconds to show jobs
logger.info("sleeping...");
Thread.sleep(40L * 1000L);
logger.info("finished sleeping");
// executing...
} catch (Exception ignore) {
}
} catch (SchedulerException e) {
e.printStackTrace();
throw new RuntimeException("NotificationScheduler failed to retrieve a Scheduler instance: ", e);
}
}
public void scheduleImmediateNotificationJob(){
try {
JobKey jobKey = new JobKey("key");
Date fireTime = DateBuilder.futureDate(delayInSeconds, IntervalUnit.SECOND);
JobDetail emailJob = JobBuilder.newJob(EMailJob.class)
.withIdentity(jobKey.toString(), "immediateEmailsGroup")
.build();
TriggerKey triggerKey = new TriggerKey("triggerKey");
SimpleTrigger trigger = (SimpleTrigger) TriggerBuilder.newTrigger()
.withIdentity(triggerKey.toString(), "immediateEmailsGroup")
.startAt(fireTime)
.build();
// schedule the job to run
Date scheduleTime1 = scheduler.scheduleJob(emailJob, trigger);
} catch (SchedulerException e) {
logger.error("error scheduling job: " + e.getMessage(), e);
e.printStackTrace();
}
}
@PreDestroy
public void cleanup(){
sf = null;
try {
scheduler.shutdown();
} catch (SchedulerException e) {
e.printStackTrace();
}
}
EmailJobは、@ Componentアノテーションを除いて、最初の投稿と同じです。
@Component
public class EMailJob implements Job {
@Autowired
private JavaMailSenderImpl mailSenderImpl;
... }
また、Springの構成ファイルには次のものがあります。
...
<context:property-placeholder location="classpath:spring/*.properties" />
<context:spring-configured/>
<context:component-scan base-package="com.mybasepackage">
<context:exclude-filter expression="org.springframework.stereotype.Controller"
type="annotation" />
</context:component-scan>
<bean id="mailSenderImpl" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="Host" value="${mail.Host}"/>
<property name="port" value="${mail.port}"/>
...
</bean>
<bean id="notificationScheduler" class="com.mybasepackage.notifications.NotificationScheduler">
</bean>
すべての助けてくれてありがとう!
マリーナ
Hary https://stackoverflow.com/a/37797575/4252764 のソリューションは非常にうまく機能します。シンプルで、それほど多くの特別なファクトリBeanを必要とせず、複数のトリガーとジョブをサポートします。 Quartzジョブを一般的なものにでき、特定のジョブを通常のSpring Beanとして実装できることを追加します。
public interface BeanJob {
void executeBeanJob();
}
public class GenericJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
JobDataMap dataMap = context.getMergedJobDataMap();
((BeanJob)dataMap.get("beanJob")).executeBeanJob();
}
}
@Component
public class RealJob implements BeanJob {
private SomeService service;
@Autowired
public RealJob(SomeService service) {
this.service = service;
}
@Override
public void executeBeanJob() {
//do do job with service
}
}
簡単な解決策は、ジョブデータマップでSpring Beanを設定してから、ジョブクラスでBeanを取得することです。たとえば、
// the class sets the configures the MyJob class
SchedulerFactory sf = new StdSchedulerFactory();
Scheduler sched = sf.getScheduler();
Date startTime = DateBuilder.nextGivenSecondDate(null, 15);
JobDetail job = newJob(MyJob.class).withIdentity("job1", "group1").build();
job.getJobDataMap().put("processDataDAO", processDataDAO);
`
// this is MyJob Class
ProcessDataDAO processDataDAO = (ProcessDataDAO) jec.getMergedJobDataMap().get("processDataDAO");
それを行う簡単な方法は、Quartz Jobsに@Component
注釈を付けるだけです。そうすれば、SpringはSpring Beanとして認識されるため、すべてのDIマジックを自動的に実行します。 AspectJ
アスペクトについても同様のことをしなければなりませんでした。Spring@Component
ステレオタイプで注釈を付けるまではSpring Beanではありませんでした。
これは非常に古い投稿であり、まだ有用です。これら2つを提案するすべてのソリューションには、すべてに適した条件はほとんどありませんでした。
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
これは、スプリングであることが前提または必要です-WebベースのプロジェクトAutowiringSpringBeanJobFactory
ベースのアプローチは非常に役立ちますが、答えは純粋なバニラクオーツAPIを使用せず、クオーツ用のSpringのラッパーを使用して同じことを行うユーザーに固有です。スケジューリング用の純粋なQuartz実装(SpringでのAutowiring機能を備えたQuartz)を使い続けたい場合、次のようにできました:
私はできる限りクォーツ方式でそれをやろうとしていたので、ハックはほとんど役に立たなかった。
public final class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory{
private AutowireCapableBeanFactory beanFactory;
public AutowiringSpringBeanJobFactory(final ApplicationContext applicationContext){
beanFactory = applicationContext.getAutowireCapableBeanFactory();
}
@Override
protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
final Object job = super.createJobInstance(bundle);
beanFactory.autowireBean(job);
beanFactory.initializeBean(job, job.getClass().getName());
return job;
}
}
@Configuration
public class SchedulerConfig {
@Autowired private ApplicationContext applicationContext;
@Bean
public AutowiringSpringBeanJobFactory getAutowiringSpringBeanJobFactory(){
return new AutowiringSpringBeanJobFactory(applicationContext);
}
}
private void initializeAndStartScheduler(final Properties quartzProperties)
throws SchedulerException {
//schedulerFactory.initialize(quartzProperties);
Scheduler quartzScheduler = schedulerFactory.getScheduler();
//Below one is the key here. Use the spring autowire capable job factory and inject here
quartzScheduler.setJobFactory(autowiringSpringBeanJobFactory);
quartzScheduler.start();
}
quartzScheduler.setJobFactory(autowiringSpringBeanJobFactory);
は自動配線されたジョブインスタンスを提供します。 AutowiringSpringBeanJobFactory
はJobFactory
を暗黙的に実装するため、自動配線可能なソリューションを有効にしました。お役に立てれば!
私は同様の問題に直面し、次のアプローチでそこから出てきました:
<!-- Quartz Job -->
<bean name="JobA" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<!-- <constructor-arg ref="dao.DAOFramework" /> -->
<property name="jobDataAsMap">
<map>
<entry key="daoBean" value-ref="dao.DAOFramework" />
</map>
</property>
<property name="jobClass" value="com.stratasync.jobs.JobA" />
<property name="durability" value="true"/>
</bean>
上記のコードでは、dao.DAOFramework BeanをJobA Beanに注入し、ExecuteInternalメソッド内で次のようにBeanを注入できます。
daoFramework = (DAOFramework)context.getMergedJobDataMap().get("daoBean");
私はそれが役立つことを願っています!ありがとうございました。
上記の解決策は素晴らしいですが、私の場合、注入は機能していませんでした。代わりにautowireBeanPropertiesを使用する必要がありました。おそらく、コンテキストの構成方法が原因です。
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.scheduling.quartz.SpringBeanJobFactory;
public final class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements
ApplicationContextAware {
private transient AutowireCapableBeanFactory beanFactory;
@Override
public void setApplicationContext(final ApplicationContext context) {
beanFactory = context.getAutowireCapableBeanFactory();
}
@Override
protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
final Object job = super.createJobInstance(bundle);
//beanFactory.autowireBean(job);
beanFactory.autowireBeanProperties(job, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true);
return job;
}
}
QuartzJobBean
からジョブを拡張するだけです
public class MyJob extends QuartzJobBean {
@Autowired
private SomeBean someBean;
@Override
protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("Some bean is " + someBean.toString());
}
}
プロジェクトで実際のAspectJを既に使用している場合は、@Configurable
でジョブBeanクラスに注釈を付けることができます。その後、Springは、new
を介して構築された場合でも、このクラスに注入します
Jdbcジョブストア
Jdbcジョブストアを使用している場合、Quartzは異なるクラスローダーを使用します。スプリングからのオブジェクトはクォーツ側で互換性がないため、自動配線のすべての回避策が回避されます。これは、それらが異なるクラスローダーから発生したためです。
これを修正するには、クォーツプロパティファイルでデフォルトのクラスローダーを次のように設定する必要があります。
org.quartz.scheduler.classLoadHelper.class=org.quartz.simpl.ThreadContextClassLoadHelper
参考として: https://github.com/quartz-scheduler/quartz/issues/221
これが正しい答えです http://stackoverflow.com/questions/6990767/inject-bean-reference-into-a-quartz-job-in-spring/15211030#152110 そして、ほとんどの人々のために働くでしょう。ただし、web.xmlがすべてのapplicationContext.xmlファイルを認識していない場合、クォーツジョブはそれらのBeanを呼び出すことができません。追加のapplicationContextファイルを注入するには、追加のレイヤーを作成する必要がありました
public class MYSpringBeanJobFactory extends SpringBeanJobFactory
implements ApplicationContextAware {
private transient AutowireCapableBeanFactory beanFactory;
@Override
public void setApplicationContext(final ApplicationContext context) {
try {
PathMatchingResourcePatternResolver pmrl = new PathMatchingResourcePatternResolver(context.getClassLoader());
Resource[] resources = new Resource[0];
GenericApplicationContext createdContext = null ;
resources = pmrl.getResources(
"classpath*:my-abc-integration-applicationContext.xml"
);
for (Resource r : resources) {
createdContext = new GenericApplicationContext(context);
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(createdContext);
int i = reader.loadBeanDefinitions(r);
}
createdContext.refresh();//important else you will get exceptions.
beanFactory = createdContext.getAutowireCapableBeanFactory();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
protected Object createJobInstance(final TriggerFiredBundle bundle)
throws Exception {
final Object job = super.createJobInstance(bundle);
beanFactory.autowireBean(job);
return job;
}
}
クォーツに認識させたいコンテキストファイルをいくつでも追加できます。
確認してください
AutowiringSpringBeanJobFactory extends SpringBeanJobFactory
依存関係は
"org.springframework:spring-context-support:4..."
からではなく
"org.springframework:spring-support:2..."
使いたかった
@Override
public Job newJob(TriggerFiredBundle bundle, Scheduler scheduler)
の代わりに
@Override
protected Object createJobInstance(final TriggerFiredBundle bundle)
ジョブインスタンスの自動配線に失敗していました。
上記のすべてのソリューションは、トランザクションメソッドを呼び出したいときに、Spring 5とHibernate 5およびQuartz 2.2.3では機能しません。
したがって、スケジューラを自動的に開始し、ジョブをトリガーするこのソリューションを実装しました。 dzone で多くのコードを見つけました。トリガーとジョブを動的に作成する必要がないため、静的トリガーをSpring Configurationで事前定義し、ジョブのみをSpringコンポーネントとして公開する必要がありました。
私の基本的な構成は次のようになります
@Configuration
public class QuartzConfiguration {
@Autowired
ApplicationContext applicationContext;
@Bean
public SchedulerFactoryBean scheduler(@Autowired JobFactory jobFactory) throws IOException {
SchedulerFactoryBean sfb = new SchedulerFactoryBean();
sfb.setOverwriteExistingJobs(true);
sfb.setAutoStartup(true);
sfb.setJobFactory(jobFactory);
Trigger[] triggers = new Trigger[] {
cronTriggerTest().getObject()
};
sfb.setTriggers(triggers);
return sfb;
}
@Bean
public JobFactory cronJobFactory() {
AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();
jobFactory.setApplicationContext(applicationContext);
return jobFactory;
}
@Bean
public CronTriggerFactoryBean cronTriggerTest() {
CronTriggerFactoryBean tfb = new CronTriggerFactoryBean();
tfb.setCronExpression("0 * * ? * * *");
JobDetail jobDetail = JobBuilder.newJob(CronTest.class)
.withIdentity("Testjob")
.build()
;
tfb.setJobDetail(jobDetail);
return tfb;
}
}
ご覧のとおり、スケジューラと、cron式で定義された簡単なテストトリガーがあります。あなたが好きなスケジューリング式を選択できます。次に、このようなAutowiringSpringBeanJobFactoryが必要です。
public final class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware {
@Autowired
private ApplicationContext applicationContext;
private SchedulerContext schedulerContext;
@Override
public void setApplicationContext(final ApplicationContext context) {
this.applicationContext = context;
}
@Override
protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
Job job = applicationContext.getBean(bundle.getJobDetail().getJobClass());
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(job);
MutablePropertyValues pvs = new MutablePropertyValues();
pvs.addPropertyValues(bundle.getJobDetail().getJobDataMap());
pvs.addPropertyValues(bundle.getTrigger().getJobDataMap());
if (this.schedulerContext != null)
{
pvs.addPropertyValues(this.schedulerContext);
}
bw.setPropertyValues(pvs, true);
return job;
}
public void setSchedulerContext(SchedulerContext schedulerContext) {
this.schedulerContext = schedulerContext;
super.setSchedulerContext(schedulerContext);
}
}
ここでは、通常のアプリケーションコンテキストとジョブを結び付けます。これは重要なギャップです。通常、Quartzはアプリケーションコンテキストに接続していないワーカースレッドを開始するためです。それが、トランザクションの方法を実行できない理由です。最後に不足しているのは仕事です。それはそのように見えることができます
@Component
public class CronTest implements Job {
@Autowired
private MyService s;
public CronTest() {
}
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
s.execute();
}
}
サービスメソッドを呼び出すためだけの余分なクラスであるため、完璧なソリューションではありません。しかし、それでも動作します。