0
# Scheduler Customization
1
2
Interfaces and annotations for customizing scheduler behavior, data sources, and transaction managers. Enables fine-grained control over Quartz configuration beyond what's available through standard properties.
3
4
## Capabilities
5
6
### SchedulerFactoryBeanCustomizer
7
8
Functional interface that allows programmatic customization of the SchedulerFactoryBean before it's fully initialized.
9
10
```java { .api }
11
/**
12
* Callback interface for customizing SchedulerFactoryBean
13
* Implement this interface to apply custom configuration that cannot be achieved through properties
14
*/
15
@FunctionalInterface
16
public interface SchedulerFactoryBeanCustomizer {
17
18
/**
19
* Customize the SchedulerFactoryBean before initialization
20
* @param schedulerFactoryBean The scheduler factory bean to customize
21
*/
22
void customize(SchedulerFactoryBean schedulerFactoryBean);
23
}
24
```
25
26
**Usage Examples:**
27
28
```java
29
@Configuration
30
public class QuartzCustomizerConfiguration {
31
32
@Bean
33
public SchedulerFactoryBeanCustomizer schedulerCustomizer() {
34
return schedulerFactoryBean -> {
35
// Set custom scheduler context data
36
Map<String, Object> schedulerContextMap = new HashMap<>();
37
schedulerContextMap.put("applicationName", "MyApplication");
38
schedulerContextMap.put("environment", "production");
39
schedulerFactoryBean.setSchedulerContextAsMap(schedulerContextMap);
40
41
// Set custom configuration location
42
schedulerFactoryBean.setConfigLocation(new ClassPathResource("quartz-custom.properties"));
43
44
// Configure application context integration
45
schedulerFactoryBean.setApplicationContextSchedulerContextKey("applicationContext");
46
47
// Set custom scheduler listeners
48
schedulerFactoryBean.setGlobalJobListeners(new CustomJobListener());
49
schedulerFactoryBean.setGlobalTriggerListeners(new CustomTriggerListener());
50
};
51
}
52
53
@Bean
54
public SchedulerFactoryBeanCustomizer dataSourceCustomizer(
55
@Qualifier("quartzDataSource") DataSource quartzDataSource) {
56
return schedulerFactoryBean -> {
57
schedulerFactoryBean.setDataSource(quartzDataSource);
58
schedulerFactoryBean.setNonTransactionalDataSource(quartzDataSource);
59
};
60
}
61
62
@Bean
63
public SchedulerFactoryBeanCustomizer threadPoolCustomizer() {
64
return schedulerFactoryBean -> {
65
Properties quartzProperties = new Properties();
66
quartzProperties.setProperty("org.quartz.threadPool.threadCount", "20");
67
quartzProperties.setProperty("org.quartz.threadPool.threadPriority", "5");
68
quartzProperties.setProperty("org.quartz.threadPool.class",
69
"org.quartz.simpl.SimpleThreadPool");
70
71
schedulerFactoryBean.setQuartzProperties(quartzProperties);
72
};
73
}
74
}
75
```
76
77
### QuartzDataSource Annotation
78
79
Qualifier annotation for specifying a dedicated DataSource for Quartz operations, separate from the application's primary DataSource.
80
81
```java { .api }
82
/**
83
* Qualifier annotation for DataSource to be injected into Quartz auto-configuration
84
* Used when you want to use a separate database for Quartz job storage
85
* Can be applied to secondary DataSource when another is marked as @Primary
86
*/
87
@Target({
88
ElementType.FIELD,
89
ElementType.METHOD,
90
ElementType.PARAMETER,
91
ElementType.TYPE,
92
ElementType.ANNOTATION_TYPE
93
})
94
@Retention(RetentionPolicy.RUNTIME)
95
@Documented
96
@Qualifier
97
public @interface QuartzDataSource {
98
}
99
```
100
101
**Usage Examples:**
102
103
```java
104
@Configuration
105
public class DataSourceConfiguration {
106
107
// Primary DataSource for application data
108
@Bean
109
@Primary
110
@ConfigurationProperties("spring.datasource")
111
public DataSource primaryDataSource() {
112
return DataSourceBuilder.create().build();
113
}
114
115
// Dedicated DataSource for Quartz
116
@Bean
117
@QuartzDataSource
118
@ConfigurationProperties("spring.datasource.quartz")
119
public DataSource quartzDataSource() {
120
return DataSourceBuilder.create().build();
121
}
122
123
// Using QuartzDataSource in custom components
124
@Service
125
public class QuartzManagementService {
126
127
private final JdbcTemplate quartzJdbcTemplate;
128
129
public QuartzManagementService(@QuartzDataSource DataSource quartzDataSource) {
130
this.quartzJdbcTemplate = new JdbcTemplate(quartzDataSource);
131
}
132
133
public List<String> getJobNames() {
134
return quartzJdbcTemplate.queryForList(
135
"SELECT JOB_NAME FROM QRTZ_JOB_DETAILS", String.class);
136
}
137
}
138
}
139
```
140
141
```properties
142
# Primary database configuration
143
spring.datasource.url=jdbc:postgresql://localhost:5432/myapp
144
spring.datasource.username=app_user
145
spring.datasource.password=app_password
146
147
# Quartz database configuration
148
spring.datasource.quartz.url=jdbc:postgresql://localhost:5432/quartz
149
spring.datasource.quartz.username=quartz_user
150
spring.datasource.quartz.password=quartz_password
151
```
152
153
### QuartzTransactionManager Annotation
154
155
Qualifier annotation for specifying a dedicated PlatformTransactionManager for Quartz operations.
156
157
```java { .api }
158
/**
159
* Qualifier annotation for TransactionManager to be injected into Quartz auto-configuration
160
* Used when you want to use a separate transaction manager for Quartz operations
161
* Can be applied to secondary transaction manager when another is marked as @Primary
162
*/
163
@Target({
164
ElementType.FIELD,
165
ElementType.METHOD,
166
ElementType.PARAMETER,
167
ElementType.TYPE,
168
ElementType.ANNOTATION_TYPE
169
})
170
@Retention(RetentionPolicy.RUNTIME)
171
@Documented
172
@Qualifier
173
public @interface QuartzTransactionManager {
174
}
175
```
176
177
**Usage Examples:**
178
179
```java
180
@Configuration
181
@EnableTransactionManagement
182
public class TransactionManagerConfiguration {
183
184
// Primary transaction manager for application
185
@Bean
186
@Primary
187
public PlatformTransactionManager primaryTransactionManager(
188
@Primary DataSource primaryDataSource) {
189
return new DataSourceTransactionManager(primaryDataSource);
190
}
191
192
// Dedicated transaction manager for Quartz
193
@Bean
194
@QuartzTransactionManager
195
public PlatformTransactionManager quartzTransactionManager(
196
@QuartzDataSource DataSource quartzDataSource) {
197
DataSourceTransactionManager txManager = new DataSourceTransactionManager(quartzDataSource);
198
txManager.setNestedTransactionAllowed(true);
199
return txManager;
200
}
201
202
// JTA transaction manager for distributed transactions
203
@Bean
204
@QuartzTransactionManager
205
public JtaTransactionManager quartzJtaTransactionManager() {
206
JtaTransactionManager jtaTxManager = new JtaTransactionManager();
207
jtaTxManager.setAllowCustomIsolationLevels(true);
208
return jtaTxManager;
209
}
210
}
211
212
// Using in a custom job with transaction support
213
@Component
214
public class TransactionalJob implements Job {
215
216
@Autowired
217
@QuartzTransactionManager
218
private PlatformTransactionManager quartzTransactionManager;
219
220
@Override
221
public void execute(JobExecutionContext context) throws JobExecutionException {
222
TransactionTemplate transactionTemplate =
223
new TransactionTemplate(quartzTransactionManager);
224
225
transactionTemplate.execute(status -> {
226
// Perform transactional operations
227
processData();
228
updateJobStatus();
229
return null;
230
});
231
}
232
}
233
```
234
235
## Advanced Customization Patterns
236
237
### Custom Job Factory
238
239
```java
240
@Configuration
241
public class CustomJobFactoryConfiguration {
242
243
@Bean
244
public SchedulerFactoryBeanCustomizer jobFactoryCustomizer(
245
ApplicationContext applicationContext) {
246
return schedulerFactoryBean -> {
247
CustomSpringBeanJobFactory jobFactory = new CustomSpringBeanJobFactory();
248
jobFactory.setApplicationContext(applicationContext);
249
schedulerFactoryBean.setJobFactory(jobFactory);
250
};
251
}
252
}
253
254
public class CustomSpringBeanJobFactory extends SpringBeanJobFactory {
255
256
@Override
257
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
258
Object jobInstance = super.createJobInstance(bundle);
259
260
// Apply custom initialization logic
261
if (jobInstance instanceof CustomInitializable) {
262
((CustomInitializable) jobInstance).initialize();
263
}
264
265
return jobInstance;
266
}
267
}
268
```
269
270
### Scheduler Listeners
271
272
```java
273
@Configuration
274
public class SchedulerListenerConfiguration {
275
276
@Bean
277
public SchedulerFactoryBeanCustomizer listenerCustomizer() {
278
return schedulerFactoryBean -> {
279
schedulerFactoryBean.setSchedulerListeners(
280
new CustomSchedulerListener()
281
);
282
283
schedulerFactoryBean.setGlobalJobListeners(
284
new CustomJobListener(),
285
new AuditJobListener()
286
);
287
288
schedulerFactoryBean.setGlobalTriggerListeners(
289
new CustomTriggerListener()
290
);
291
};
292
}
293
}
294
295
public class CustomSchedulerListener implements SchedulerListener {
296
private static final Logger logger = LoggerFactory.getLogger(CustomSchedulerListener.class);
297
298
@Override
299
public void schedulerStarted() {
300
logger.info("Scheduler started successfully");
301
// Perform startup tasks
302
}
303
304
@Override
305
public void schedulerShutdown() {
306
logger.info("Scheduler shutting down");
307
// Perform cleanup tasks
308
}
309
310
// Other methods...
311
}
312
```
313
314
### Plugin Configuration
315
316
```java
317
@Configuration
318
public class QuartzPluginConfiguration {
319
320
@Bean
321
public SchedulerFactoryBeanCustomizer pluginCustomizer() {
322
return schedulerFactoryBean -> {
323
Properties properties = new Properties();
324
325
// Job initialization plugin
326
properties.setProperty("org.quartz.plugin.jobInitializer.class",
327
"org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin");
328
properties.setProperty("org.quartz.plugin.jobInitializer.fileNames",
329
"jobs.xml");
330
properties.setProperty("org.quartz.plugin.jobInitializer.failOnFileNotFound",
331
"true");
332
333
// Logging plugin
334
properties.setProperty("org.quartz.plugin.triggHistory.class",
335
"org.quartz.plugins.history.LoggingTriggerHistoryPlugin");
336
properties.setProperty("org.quartz.plugin.triggHistory.triggerFiredMessage",
337
"Trigger {1}.{0} fired job {6}.{5} at: {4, date, HH:mm:ss MM/dd/yyyy}");
338
339
schedulerFactoryBean.setQuartzProperties(properties);
340
};
341
}
342
}
343
```
344
345
### Conditional Customization
346
347
```java
348
@Configuration
349
public class ConditionalQuartzConfiguration {
350
351
@Bean
352
@ConditionalOnProperty(name = "app.quartz.clustering.enabled", havingValue = "true")
353
public SchedulerFactoryBeanCustomizer clusteringCustomizer() {
354
return schedulerFactoryBean -> {
355
Properties clusterProps = new Properties();
356
clusterProps.setProperty("org.quartz.jobStore.isClustered", "true");
357
clusterProps.setProperty("org.quartz.jobStore.clusterCheckinInterval", "20000");
358
clusterProps.setProperty("org.quartz.scheduler.instanceId", "AUTO");
359
360
schedulerFactoryBean.setQuartzProperties(clusterProps);
361
};
362
}
363
364
@Bean
365
@ConditionalOnMissingBean(name = "quartzDataSource")
366
public SchedulerFactoryBeanCustomizer memoryJobStoreCustomizer() {
367
return schedulerFactoryBean -> {
368
Properties memoryProps = new Properties();
369
memoryProps.setProperty("org.quartz.jobStore.class",
370
"org.quartz.simpl.RAMJobStore");
371
372
schedulerFactoryBean.setQuartzProperties(memoryProps);
373
};
374
}
375
}
376
```
377
378
## Error Handling and Best Practices
379
380
### Customizer Ordering
381
382
```java
383
@Configuration
384
public class OrderedCustomizerConfiguration {
385
386
@Bean
387
@Order(1)
388
public SchedulerFactoryBeanCustomizer dataSourceCustomizer() {
389
return schedulerFactoryBean -> {
390
// Configure DataSource first
391
};
392
}
393
394
@Bean
395
@Order(2)
396
public SchedulerFactoryBeanCustomizer propertiesCustomizer() {
397
return schedulerFactoryBean -> {
398
// Configure properties after DataSource
399
};
400
}
401
402
@Bean
403
@Order(3)
404
public SchedulerFactoryBeanCustomizer listenersCustomizer() {
405
return schedulerFactoryBean -> {
406
// Configure listeners last
407
};
408
}
409
}
410
```
411
412
### Error Handling
413
414
```java
415
@Bean
416
public SchedulerFactoryBeanCustomizer safeCustomizer() {
417
return schedulerFactoryBean -> {
418
try {
419
// Apply customizations
420
schedulerFactoryBean.setSchedulerName("CustomScheduler");
421
} catch (Exception e) {
422
logger.error("Failed to customize scheduler", e);
423
// Fallback to default configuration
424
}
425
};
426
}
427
```