1
1
/*
2
- * Copyright 2002-2017 the original author or authors.
2
+ * Copyright 2002-2018 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
@@ -105,11 +105,10 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
105
105
new ThreadLocal <DataSource >();
106
106
107
107
/**
108
- * Return the ResourceLoader for the currently configured Quartz Scheduler,
109
- * to be used by ResourceLoaderClassLoadHelper.
110
- * <p>This instance will be set before initialization of the corresponding
111
- * Scheduler, and reset immediately afterwards. It is thus only available
112
- * during configuration.
108
+ * Return the {@link ResourceLoader} for the currently configured Quartz Scheduler,
109
+ * to be used by {@link ResourceLoaderClassLoadHelper}.
110
+ * <p>This instance will be set before initialization of the corresponding Scheduler,
111
+ * and reset immediately afterwards. It is thus only available during configuration.
113
112
* @see #setApplicationContext
114
113
* @see ResourceLoaderClassLoadHelper
115
114
*/
@@ -118,11 +117,11 @@ public static ResourceLoader getConfigTimeResourceLoader() {
118
117
}
119
118
120
119
/**
121
- * Return the TaskExecutor for the currently configured Quartz Scheduler,
122
- * to be used by LocalTaskExecutorThreadPool.
123
- * <p>This instance will be set before initialization of the corresponding
124
- * Scheduler, and reset immediately afterwards. It is thus only available
125
- * during configuration.
120
+ * Return the {@link Executor} for the currently configured Quartz Scheduler,
121
+ * to be used by {@link LocalTaskExecutorThreadPool} .
122
+ * <p>This instance will be set before initialization of the corresponding Scheduler,
123
+ * and reset immediately afterwards. It is thus only available during configuration.
124
+ * @since 2.0
126
125
* @see #setTaskExecutor
127
126
* @see LocalTaskExecutorThreadPool
128
127
*/
@@ -131,11 +130,11 @@ public static Executor getConfigTimeTaskExecutor() {
131
130
}
132
131
133
132
/**
134
- * Return the DataSource for the currently configured Quartz Scheduler,
135
- * to be used by LocalDataSourceJobStore.
136
- * <p>This instance will be set before initialization of the corresponding
137
- * Scheduler, and reset immediately afterwards. It is thus only available
138
- * during configuration.
133
+ * Return the {@link DataSource} for the currently configured Quartz Scheduler,
134
+ * to be used by {@link LocalDataSourceJobStore} .
135
+ * <p>This instance will be set before initialization of the corresponding Scheduler,
136
+ * and reset immediately afterwards. It is thus only available during configuration.
137
+ * @since 1.1
139
138
* @see #setDataSource
140
139
* @see LocalDataSourceJobStore
141
140
*/
@@ -144,11 +143,11 @@ public static DataSource getConfigTimeDataSource() {
144
143
}
145
144
146
145
/**
147
- * Return the non-transactional DataSource for the currently configured
148
- * Quartz Scheduler, to be used by LocalDataSourceJobStore.
149
- * <p>This instance will be set before initialization of the corresponding
150
- * Scheduler, and reset immediately afterwards. It is thus only available
151
- * during configuration.
146
+ * Return the non-transactional {@link DataSource} for the currently configured
147
+ * Quartz Scheduler, to be used by {@link LocalDataSourceJobStore} .
148
+ * <p>This instance will be set before initialization of the corresponding Scheduler,
149
+ * and reset immediately afterwards. It is thus only available during configuration.
150
+ * @since 1.1
152
151
* @see #setNonTransactionalDataSource
153
152
* @see LocalDataSourceJobStore
154
153
*/
@@ -157,6 +156,8 @@ public static DataSource getConfigTimeNonTransactionalDataSource() {
157
156
}
158
157
159
158
159
+ private SchedulerFactory schedulerFactory ;
160
+
160
161
private Class <? extends SchedulerFactory > schedulerFactoryClass = StdSchedulerFactory .class ;
161
162
162
163
private String schedulerName ;
@@ -165,14 +166,12 @@ public static DataSource getConfigTimeNonTransactionalDataSource() {
165
166
166
167
private Properties quartzProperties ;
167
168
168
-
169
169
private Executor taskExecutor ;
170
170
171
171
private DataSource dataSource ;
172
172
173
173
private DataSource nonTransactionalDataSource ;
174
174
175
-
176
175
private Map <String , ?> schedulerContextMap ;
177
176
178
177
private ApplicationContext applicationContext ;
@@ -183,7 +182,6 @@ public static DataSource getConfigTimeNonTransactionalDataSource() {
183
182
184
183
private boolean jobFactorySet = false ;
185
184
186
-
187
185
private boolean autoStartup = true ;
188
186
189
187
private int startupDelay = 0 ;
@@ -194,19 +192,38 @@ public static DataSource getConfigTimeNonTransactionalDataSource() {
194
192
195
193
private boolean waitForJobsToCompleteOnShutdown = false ;
196
194
197
-
198
195
private Scheduler scheduler ;
199
196
200
197
201
198
/**
202
- * Set the Quartz SchedulerFactory implementation to use.
203
- * <p>Default is {@link StdSchedulerFactory}, reading in the standard
204
- * {@code quartz.properties} from {@code quartz.jar}.
205
- * To use custom Quartz properties, specify the "configLocation"
206
- * or "quartzProperties" bean property on this FactoryBean.
199
+ * Set an external Quartz {@link SchedulerFactory} instance to use.
200
+ * <p>Default is an internal {@link StdSchedulerFactory} instance. If this method is
201
+ * called, it overrides any class specified through {@link #setSchedulerFactoryClass}
202
+ * as well as any settings specified through {@link #setConfigLocation},
203
+ * {@link #setQuartzProperties}, {@link #setTaskExecutor} or {@link #setDataSource}.
204
+ * <p><b>NOTE:</b> With an externally provided {@code SchedulerFactory} instance,
205
+ * local settings such as {@link #setConfigLocation} or {@link #setQuartzProperties}
206
+ * will be ignored here in {@code SchedulerFactoryBean}, expecting the external
207
+ * {@code SchedulerFactory} instance to get initialized on its own.
208
+ * @since 4.3.15
209
+ * @see #setSchedulerFactoryClass
210
+ */
211
+ public void setSchedulerFactory (SchedulerFactory schedulerFactory ) {
212
+ this .schedulerFactory = schedulerFactory ;
213
+ }
214
+
215
+ /**
216
+ * Set the Quartz {@link SchedulerFactory} implementation to use.
217
+ * <p>Default is the {@link StdSchedulerFactory} class, reading in the standard
218
+ * {@code quartz.properties} from {@code quartz.jar}. For applying custom Quartz
219
+ * properties, specify {@link #setConfigLocation "configLocation"} and/or
220
+ * {@link #setQuartzProperties "quartzProperties"} etc on this local
221
+ * {@code SchedulerFactoryBean} instance.
207
222
* @see org.quartz.impl.StdSchedulerFactory
208
223
* @see #setConfigLocation
209
224
* @see #setQuartzProperties
225
+ * @see #setTaskExecutor
226
+ * @see #setDataSource
210
227
*/
211
228
public void setSchedulerFactoryClass (Class <? extends SchedulerFactory > schedulerFactoryClass ) {
212
229
this .schedulerFactoryClass = schedulerFactoryClass ;
@@ -244,14 +261,14 @@ public void setQuartzProperties(Properties quartzProperties) {
244
261
this .quartzProperties = quartzProperties ;
245
262
}
246
263
247
-
248
264
/**
249
- * Set the Spring TaskExecutor to use as Quartz backend.
265
+ * Set a Spring-managed {@link Executor} to use as Quartz backend.
250
266
* Exposed as thread pool through the Quartz SPI.
251
- * <p>Can be used to assign a JDK 1.5 ThreadPoolExecutor or a CommonJ
267
+ * <p>Can be used to assign a local JDK ThreadPoolExecutor or a CommonJ
252
268
* WorkManager as Quartz backend, to avoid Quartz's manual thread creation.
253
269
* <p>By default, a Quartz SimpleThreadPool will be used, configured through
254
270
* the corresponding Quartz properties.
271
+ * @since 2.0
255
272
* @see #setQuartzProperties
256
273
* @see LocalTaskExecutorThreadPool
257
274
* @see org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor
@@ -262,8 +279,8 @@ public void setTaskExecutor(Executor taskExecutor) {
262
279
}
263
280
264
281
/**
265
- * Set the default DataSource to be used by the Scheduler. If set,
266
- * this will override corresponding settings in Quartz properties.
282
+ * Set the default {@link DataSource} to be used by the Scheduler.
283
+ * If set, this will override corresponding settings in Quartz properties.
267
284
* <p>Note: If this is set, the Quartz settings should not define
268
285
* a job store "dataSource" to avoid meaningless double configuration.
269
286
* <p>A Spring-specific subclass of Quartz' JobStoreCMT will be used.
@@ -276,6 +293,7 @@ public void setTaskExecutor(Executor taskExecutor) {
276
293
* argument is sufficient. In case of an XA DataSource and global JTA transactions,
277
294
* SchedulerFactoryBean's "nonTransactionalDataSource" property should be set,
278
295
* passing in a non-XA DataSource that will not participate in global transactions.
296
+ * @since 1.1
279
297
* @see #setNonTransactionalDataSource
280
298
* @see #setQuartzProperties
281
299
* @see #setTransactionManager
@@ -286,20 +304,20 @@ public void setDataSource(DataSource dataSource) {
286
304
}
287
305
288
306
/**
289
- * Set the DataSource to be used by the Scheduler <i>for non-transactional access</i>.
307
+ * Set the {@link DataSource} to be used <i>for non-transactional access</i>.
290
308
* <p>This is only necessary if the default DataSource is an XA DataSource that will
291
309
* always participate in transactions: A non-XA version of that DataSource should
292
310
* be specified as "nonTransactionalDataSource" in such a scenario.
293
311
* <p>This is not relevant with a local DataSource instance and Spring transactions.
294
312
* Specifying a single default DataSource as "dataSource" is sufficient there.
313
+ * @since 1.1
295
314
* @see #setDataSource
296
315
* @see LocalDataSourceJobStore
297
316
*/
298
317
public void setNonTransactionalDataSource (DataSource nonTransactionalDataSource ) {
299
318
this .nonTransactionalDataSource = nonTransactionalDataSource ;
300
319
}
301
320
302
-
303
321
/**
304
322
* Register objects in the Scheduler context via a given Map.
305
323
* These objects will be available to any Job that runs in this Scheduler.
@@ -315,7 +333,7 @@ public void setSchedulerContextAsMap(Map<String, ?> schedulerContextAsMap) {
315
333
}
316
334
317
335
/**
318
- * Set the key of an ApplicationContext reference to expose in the
336
+ * Set the key of an {@link ApplicationContext} reference to expose in the
319
337
* SchedulerContext, for example "applicationContext". Default is none.
320
338
* Only applicable when running in a Spring ApplicationContext.
321
339
* <p>Note: When using persistent Jobs whose JobDetail will be kept in the
@@ -335,7 +353,7 @@ public void setApplicationContextSchedulerContextKey(String applicationContextSc
335
353
}
336
354
337
355
/**
338
- * Set the Quartz JobFactory to use for this Scheduler.
356
+ * Set the Quartz {@link JobFactory} to use for this Scheduler.
339
357
* <p>Default is Spring's {@link AdaptableJobFactory}, which supports
340
358
* {@link java.lang.Runnable} objects as well as standard Quartz
341
359
* {@link org.quartz.Job} instances. Note that this default only applies
@@ -344,6 +362,7 @@ public void setApplicationContextSchedulerContextKey(String applicationContextSc
344
362
* <p>Specify an instance of Spring's {@link SpringBeanJobFactory} here
345
363
* (typically as an inner bean definition) to automatically populate a job's
346
364
* bean properties from the specified job data map and scheduler context.
365
+ * @since 2.0
347
366
* @see AdaptableJobFactory
348
367
* @see SpringBeanJobFactory
349
368
*/
@@ -352,7 +371,6 @@ public void setJobFactory(JobFactory jobFactory) {
352
371
this .jobFactorySet = true ;
353
372
}
354
373
355
-
356
374
/**
357
375
* Set whether to automatically start the scheduler after initialization.
358
376
* <p>Default is "true"; set this to "false" to allow for manual startup.
@@ -372,11 +390,12 @@ public boolean isAutoStartup() {
372
390
}
373
391
374
392
/**
375
- * Specify the phase in which this scheduler should be started and
376
- * stopped. The startup order proceeds from lowest to highest, and
377
- * the shutdown order is the reverse of that. By default this value
378
- * is Integer.MAX_VALUE meaning that this scheduler starts as late
379
- * as possible and stops as soon as possible.
393
+ * Specify the phase in which this scheduler should be started and stopped.
394
+ * The startup order proceeds from lowest to highest, and the shutdown order
395
+ * is the reverse of that. By default this value is {@code Integer.MAX_VALUE}
396
+ * meaning that this scheduler starts as late as possible and stops as soon
397
+ * as possible.
398
+ * @since 3.0
380
399
*/
381
400
public void setPhase (int phase ) {
382
401
this .phase = phase ;
@@ -424,7 +443,6 @@ public void setWaitForJobsToCompleteOnShutdown(boolean waitForJobsToCompleteOnSh
424
443
this .waitForJobsToCompleteOnShutdown = waitForJobsToCompleteOnShutdown ;
425
444
}
426
445
427
-
428
446
@ Override
429
447
public void setBeanName (String name ) {
430
448
if (this .schedulerName == null ) {
@@ -452,9 +470,8 @@ public void afterPropertiesSet() throws Exception {
452
470
this .resourceLoader = this .applicationContext ;
453
471
}
454
472
455
- // Create SchedulerFactory instance...
456
- SchedulerFactory schedulerFactory = BeanUtils .instantiateClass (this .schedulerFactoryClass );
457
- initSchedulerFactory (schedulerFactory );
473
+ // Initialize the SchedulerFactory instance...
474
+ SchedulerFactory schedulerFactory = prepareSchedulerFactory ();
458
475
459
476
if (this .resourceLoader != null ) {
460
477
// Make given ResourceLoader available for SchedulerFactory configuration.
@@ -512,22 +529,34 @@ public void afterPropertiesSet() throws Exception {
512
529
513
530
514
531
/**
515
- * Load and/or apply Quartz properties to the given SchedulerFactory .
516
- * @param schedulerFactory the SchedulerFactory to initialize
532
+ * Create a SchedulerFactory if necessary and apply locally defined Quartz properties to it .
533
+ * @return the initialized SchedulerFactory
517
534
*/
518
- private void initSchedulerFactory (SchedulerFactory schedulerFactory ) throws SchedulerException , IOException {
519
- if (!(schedulerFactory instanceof StdSchedulerFactory )) {
520
- if (this .configLocation != null || this .quartzProperties != null ||
535
+ private SchedulerFactory prepareSchedulerFactory () throws SchedulerException , IOException {
536
+ SchedulerFactory schedulerFactory = this .schedulerFactory ;
537
+ if (schedulerFactory == null ) {
538
+ // Create local SchedulerFactory instance (typically a StdSchedulerFactory)
539
+ schedulerFactory = BeanUtils .instantiateClass (this .schedulerFactoryClass );
540
+ if (schedulerFactory instanceof StdSchedulerFactory ) {
541
+ initSchedulerFactory ((StdSchedulerFactory ) schedulerFactory );
542
+ }
543
+ else if (this .configLocation != null || this .quartzProperties != null ||
521
544
this .taskExecutor != null || this .dataSource != null ) {
522
545
throw new IllegalArgumentException (
523
546
"StdSchedulerFactory required for applying Quartz properties: " + schedulerFactory );
524
547
}
525
- // Otherwise assume that no initialization is necessary...
526
- return ;
548
+ // Otherwise, no local settings to be applied via StdSchedulerFactory.initialize(Properties)
527
549
}
550
+ // Otherwise, assume that externally provided factory has been initialized with appropriate settings
551
+ return schedulerFactory ;
552
+ }
528
553
554
+ /**
555
+ * Initialize the given SchedulerFactory, applying locally defined Quartz properties to it.
556
+ * @param schedulerFactory the SchedulerFactory to initialize
557
+ */
558
+ private void initSchedulerFactory (StdSchedulerFactory schedulerFactory ) throws SchedulerException , IOException {
529
559
Properties mergedProps = new Properties ();
530
-
531
560
if (this .resourceLoader != null ) {
532
561
mergedProps .setProperty (StdSchedulerFactory .PROP_SCHED_CLASS_LOAD_HELPER_CLASS ,
533
562
ResourceLoaderClassLoadHelper .class .getName ());
@@ -552,17 +581,14 @@ private void initSchedulerFactory(SchedulerFactory schedulerFactory) throws Sche
552
581
}
553
582
554
583
CollectionUtils .mergePropertiesIntoMap (this .quartzProperties , mergedProps );
555
-
556
584
if (this .dataSource != null ) {
557
585
mergedProps .put (StdSchedulerFactory .PROP_JOB_STORE_CLASS , LocalDataSourceJobStore .class .getName ());
558
586
}
559
-
560
- // Make sure to set the scheduler name as configured in the Spring configuration.
561
587
if (this .schedulerName != null ) {
562
588
mergedProps .put (StdSchedulerFactory .PROP_SCHED_INSTANCE_NAME , this .schedulerName );
563
589
}
564
590
565
- (( StdSchedulerFactory ) schedulerFactory ) .initialize (mergedProps );
591
+ schedulerFactory .initialize (mergedProps );
566
592
}
567
593
568
594
/**
@@ -619,7 +645,7 @@ protected Scheduler createScheduler(SchedulerFactory schedulerFactory, String sc
619
645
private void populateSchedulerContext () throws SchedulerException {
620
646
// Put specified objects into Scheduler context.
621
647
if (this .schedulerContextMap != null ) {
622
- this . scheduler .getContext ().putAll (this .schedulerContextMap );
648
+ getScheduler () .getContext ().putAll (this .schedulerContextMap );
623
649
}
624
650
625
651
// Register ApplicationContext in Scheduler context.
@@ -629,7 +655,7 @@ private void populateSchedulerContext() throws SchedulerException {
629
655
"SchedulerFactoryBean needs to be set up in an ApplicationContext " +
630
656
"to be able to handle an 'applicationContextSchedulerContextKey'" );
631
657
}
632
- this . scheduler .getContext ().put (this .applicationContextSchedulerContextKey , this .applicationContext );
658
+ getScheduler () .getContext ().put (this .applicationContextSchedulerContextKey , this .applicationContext );
633
659
}
634
660
}
635
661
@@ -659,6 +685,7 @@ public void run() {
659
685
Thread .sleep (startupDelay * 1000 );
660
686
}
661
687
catch (InterruptedException ex ) {
688
+ Thread .currentThread ().interrupt ();
662
689
// simply proceed
663
690
}
664
691
if (logger .isInfoEnabled ()) {
@@ -762,8 +789,10 @@ public boolean isRunning() throws SchedulingException {
762
789
*/
763
790
@ Override
764
791
public void destroy () throws SchedulerException {
765
- logger .info ("Shutting down Quartz Scheduler" );
766
- this .scheduler .shutdown (this .waitForJobsToCompleteOnShutdown );
792
+ if (this .scheduler != null ) {
793
+ logger .info ("Shutting down Quartz Scheduler" );
794
+ this .scheduler .shutdown (this .waitForJobsToCompleteOnShutdown );
795
+ }
767
796
}
768
797
769
798
}
0 commit comments