SchedulerFactoryBean always ignores local factory settings in case of an external SchedulerFactory instance (expecting it to be fully initialized)

This commit includes various javadoc fixes and related refinements.

Issue: SPR-16439
This commit is contained in:
Juergen Hoeller
2018-01-30 22:35:42 +01:00
parent 6d909b013e
commit c7f60d1799
4 changed files with 82 additions and 89 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,7 +25,7 @@ import org.quartz.spi.TriggerFiredBundle;
import org.springframework.util.ReflectionUtils;
/**
* JobFactory implementation that supports {@link java.lang.Runnable}
* {@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.
@@ -43,7 +43,7 @@ public class AdaptableJobFactory implements JobFactory {
Object jobObject = createJobInstance(bundle);
return adaptJob(jobObject);
}
catch (Exception ex) {
catch (Throwable ex) {
throw new SchedulerException("Job instantiation failed", ex);
}
}
@@ -78,7 +78,8 @@ public class AdaptableJobFactory implements JobFactory {
return new DelegatingJob((Runnable) jobObject);
}
else {
throw new IllegalArgumentException("Unable to execute job class [" + jobObject.getClass().getName() +
throw new IllegalArgumentException(
"Unable to execute job class [" + jobObject.getClass().getName() +
"]: only [org.quartz.Job] and [java.lang.Runnable] supported.");
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -34,9 +34,9 @@ import org.springframework.jdbc.support.MetaDataAccessException;
import org.springframework.lang.Nullable;
/**
* Subclass of Quartz's JobStoreCMT class that delegates to a Spring-managed
* DataSource instead of using a Quartz-managed connection pool. This JobStore
* will be used if SchedulerFactoryBean's "dataSource" property is set.
* Subclass of Quartz's {@link JobStoreCMT} class that delegates to a Spring-managed
* {@link DataSource} instead of using a Quartz-managed JDBC connection pool.
* This JobStore will be used if SchedulerFactoryBean's "dataSource" property is set.
*
* <p>Supports both transactional and non-transactional DataSource access.
* With a non-XA DataSource and local Spring transactions, a single DataSource
@@ -84,15 +84,12 @@ public class LocalDataSourceJobStore extends JobStoreCMT {
@Override
public void initialize(ClassLoadHelper loadHelper, SchedulerSignaler signaler)
throws SchedulerConfigException {
public void initialize(ClassLoadHelper loadHelper, SchedulerSignaler signaler) throws SchedulerConfigException {
// Absolutely needs thread-bound DataSource to initialize.
this.dataSource = SchedulerFactoryBean.getConfigTimeDataSource();
if (this.dataSource == null) {
throw new SchedulerConfigException(
"No local DataSource found for configuration - " +
"'dataSource' property must be set on SchedulerFactoryBean");
throw new SchedulerConfigException("No local DataSource found for configuration - " +
"'dataSource' property must be set on SchedulerFactoryBean");
}
// Configure transactional connection settings for Quartz.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,8 +28,8 @@ import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Quartz ThreadPool adapter that delegates to a Spring-managed
* TaskExecutor instance, specified on SchedulerFactoryBean.
* Quartz {@link ThreadPool} adapter that delegates to a Spring-managed
* {@link Executor} instance, specified on {@link SchedulerFactoryBean}.
*
* @author Juergen Hoeller
* @since 2.0
@@ -55,12 +55,11 @@ public class LocalTaskExecutorThreadPool implements ThreadPool {
@Override
public void initialize() throws SchedulerConfigException {
// Absolutely needs thread-bound TaskExecutor to initialize.
// Absolutely needs thread-bound Executor to initialize.
this.taskExecutor = SchedulerFactoryBean.getConfigTimeTaskExecutor();
if (this.taskExecutor == null) {
throw new SchedulerConfigException(
"No local TaskExecutor found for configuration - " +
"'taskExecutor' property must be set on SchedulerFactoryBean");
throw new SchedulerConfigException("No local Executor found for configuration - " +
"'taskExecutor' property must be set on SchedulerFactoryBean");
}
}

View File

@@ -104,11 +104,10 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
/**
* Return the ResourceLoader for the currently configured Quartz Scheduler,
* to be used by ResourceLoaderClassLoadHelper.
* <p>This instance will be set before initialization of the corresponding
* Scheduler, and reset immediately afterwards. It is thus only available
* during configuration.
* Return the {@link ResourceLoader} for the currently configured Quartz Scheduler,
* to be used by {@link ResourceLoaderClassLoadHelper}.
* <p>This instance will be set before initialization of the corresponding Scheduler,
* and reset immediately afterwards. It is thus only available during configuration.
* @see #setApplicationContext
* @see ResourceLoaderClassLoadHelper
*/
@@ -118,11 +117,11 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
}
/**
* Return the TaskExecutor for the currently configured Quartz Scheduler,
* to be used by LocalTaskExecutorThreadPool.
* <p>This instance will be set before initialization of the corresponding
* Scheduler, and reset immediately afterwards. It is thus only available
* during configuration.
* Return the {@link Executor} for the currently configured Quartz Scheduler,
* to be used by {@link LocalTaskExecutorThreadPool}.
* <p>This instance will be set before initialization of the corresponding Scheduler,
* and reset immediately afterwards. It is thus only available during configuration.
* @since 2.0
* @see #setTaskExecutor
* @see LocalTaskExecutorThreadPool
*/
@@ -132,11 +131,11 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
}
/**
* Return the DataSource for the currently configured Quartz Scheduler,
* to be used by LocalDataSourceJobStore.
* <p>This instance will be set before initialization of the corresponding
* Scheduler, and reset immediately afterwards. It is thus only available
* during configuration.
* Return the {@link DataSource} for the currently configured Quartz Scheduler,
* to be used by {@link LocalDataSourceJobStore}.
* <p>This instance will be set before initialization of the corresponding Scheduler,
* and reset immediately afterwards. It is thus only available during configuration.
* @since 1.1
* @see #setDataSource
* @see LocalDataSourceJobStore
*/
@@ -146,11 +145,11 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
}
/**
* Return the non-transactional DataSource for the currently configured
* Quartz Scheduler, to be used by LocalDataSourceJobStore.
* <p>This instance will be set before initialization of the corresponding
* Scheduler, and reset immediately afterwards. It is thus only available
* during configuration.
* Return the non-transactional {@link DataSource} for the currently configured
* Quartz Scheduler, to be used by {@link LocalDataSourceJobStore}.
* <p>This instance will be set before initialization of the corresponding Scheduler,
* and reset immediately afterwards. It is thus only available during configuration.
* @since 1.1
* @see #setNonTransactionalDataSource
* @see LocalDataSourceJobStore
*/
@@ -160,11 +159,11 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
}
private Class<? extends SchedulerFactory> schedulerFactoryClass = StdSchedulerFactory.class;
@Nullable
private SchedulerFactory schedulerFactory;
private Class<? extends SchedulerFactory> schedulerFactoryClass = StdSchedulerFactory.class;
@Nullable
private String schedulerName;
@@ -174,7 +173,6 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
@Nullable
private Properties quartzProperties;
@Nullable
private Executor taskExecutor;
@@ -198,7 +196,6 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
private boolean jobFactorySet = false;
private boolean autoStartup = true;
private int startupDelay = 0;
@@ -209,35 +206,20 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
private boolean waitForJobsToCompleteOnShutdown = false;
@Nullable
private Scheduler scheduler;
/**
* Set the Quartz {@link SchedulerFactory} implementation to use.
* <p>Default is the {@link StdSchedulerFactory} class, reading in the standard
* {@code quartz.properties} from {@code quartz.jar}. For applying custom Quartz
* properties, specify {@link #setConfigLocation "configLocation"} or
* {@link #setQuartzProperties "quartzProperties"} on {@code SchedulerFactoryBean}.
* @see org.quartz.impl.StdSchedulerFactory
* @see #setConfigLocation
* @see #setQuartzProperties
*/
public void setSchedulerFactoryClass(Class<? extends SchedulerFactory> schedulerFactoryClass) {
this.schedulerFactoryClass = schedulerFactoryClass;
}
/**
* Set an external Quartz {@link SchedulerFactory} instance to use.
* <p>Default is an internal {@link StdSchedulerFactory} instance. If this method is
* called, it overrides any class specified through {@link #setSchedulerFactoryClass}.
* <p>An externally provided {@code SchedulerFactory} instance may get initialized
* from local {@code SchedulerFactoryBean} settings (such as {@link #setConfigLocation}
* or {@link #setQuartzProperties}) but only if it extends from {@link StdSchedulerFactory},
* inheriting the common {@link StdSchedulerFactory#initialize(Properties)} method.
* Otherwise, all such local settings will be ignored here in {@code SchedulerFactoryBean},
* expecting the external {@code SchedulerFactory} instance to get initialized on its own.
* called, it overrides any class specified through {@link #setSchedulerFactoryClass}
* as well as any settings specified through {@link #setConfigLocation},
* {@link #setQuartzProperties}, {@link #setTaskExecutor} or {@link #setDataSource}.
* <p><b>NOTE:</b> With an externally provided {@code SchedulerFactory} instance,
* local settings such as {@link #setConfigLocation} or {@link #setQuartzProperties}
* will be ignored here in {@code SchedulerFactoryBean}, expecting the external
* {@code SchedulerFactory} instance to get initialized on its own.
* @since 4.3.15
* @see #setSchedulerFactoryClass
*/
@@ -245,6 +227,23 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
this.schedulerFactory = schedulerFactory;
}
/**
* Set the Quartz {@link SchedulerFactory} implementation to use.
* <p>Default is the {@link StdSchedulerFactory} class, reading in the standard
* {@code quartz.properties} from {@code quartz.jar}. For applying custom Quartz
* properties, specify {@link #setConfigLocation "configLocation"} and/or
* {@link #setQuartzProperties "quartzProperties"} etc on this local
* {@code SchedulerFactoryBean} instance.
* @see org.quartz.impl.StdSchedulerFactory
* @see #setConfigLocation
* @see #setQuartzProperties
* @see #setTaskExecutor
* @see #setDataSource
*/
public void setSchedulerFactoryClass(Class<? extends SchedulerFactory> schedulerFactoryClass) {
this.schedulerFactoryClass = schedulerFactoryClass;
}
/**
* Set the name of the Scheduler to create via the SchedulerFactory.
* <p>If not specified, the bean name will be used as default scheduler name.
@@ -277,14 +276,14 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
this.quartzProperties = quartzProperties;
}
/**
* Set the Spring TaskExecutor to use as Quartz backend.
* Set a Spring-managed {@link Executor} to use as Quartz backend.
* Exposed as thread pool through the Quartz SPI.
* <p>Can be used to assign a JDK 1.5 ThreadPoolExecutor or a CommonJ
* <p>Can be used to assign a local JDK ThreadPoolExecutor or a CommonJ
* WorkManager as Quartz backend, to avoid Quartz's manual thread creation.
* <p>By default, a Quartz SimpleThreadPool will be used, configured through
* the corresponding Quartz properties.
* @since 2.0
* @see #setQuartzProperties
* @see LocalTaskExecutorThreadPool
* @see org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor
@@ -295,8 +294,8 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
}
/**
* Set the default DataSource to be used by the Scheduler. If set,
* this will override corresponding settings in Quartz properties.
* Set the default {@link DataSource} to be used by the Scheduler.
* If set, this will override corresponding settings in Quartz properties.
* <p>Note: If this is set, the Quartz settings should not define
* a job store "dataSource" to avoid meaningless double configuration.
* <p>A Spring-specific subclass of Quartz' JobStoreCMT will be used.
@@ -309,6 +308,7 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
* argument is sufficient. In case of an XA DataSource and global JTA transactions,
* SchedulerFactoryBean's "nonTransactionalDataSource" property should be set,
* passing in a non-XA DataSource that will not participate in global transactions.
* @since 1.1
* @see #setNonTransactionalDataSource
* @see #setQuartzProperties
* @see #setTransactionManager
@@ -319,12 +319,13 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
}
/**
* Set the DataSource to be used by the Scheduler <i>for non-transactional access</i>.
* Set the {@link DataSource} to be used <i>for non-transactional access</i>.
* <p>This is only necessary if the default DataSource is an XA DataSource that will
* always participate in transactions: A non-XA version of that DataSource should
* be specified as "nonTransactionalDataSource" in such a scenario.
* <p>This is not relevant with a local DataSource instance and Spring transactions.
* Specifying a single default DataSource as "dataSource" is sufficient there.
* @since 1.1
* @see #setDataSource
* @see LocalDataSourceJobStore
*/
@@ -347,7 +348,7 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
}
/**
* Set the key of an ApplicationContext reference to expose in the
* Set the key of an {@link ApplicationContext} reference to expose in the
* SchedulerContext, for example "applicationContext". Default is none.
* Only applicable when running in a Spring ApplicationContext.
* <p>Note: When using persistent Jobs whose JobDetail will be kept in the
@@ -367,7 +368,7 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
}
/**
* Set the Quartz JobFactory to use for this Scheduler.
* Set the Quartz {@link JobFactory} to use for this Scheduler.
* <p>Default is Spring's {@link AdaptableJobFactory}, which supports
* {@link java.lang.Runnable} objects as well as standard Quartz
* {@link org.quartz.Job} instances. Note that this default only applies
@@ -376,6 +377,7 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
* <p>Specify an instance of Spring's {@link SpringBeanJobFactory} here
* (typically as an inner bean definition) to automatically populate a job's
* bean properties from the specified job data map and scheduler context.
* @since 2.0
* @see AdaptableJobFactory
* @see SpringBeanJobFactory
*/
@@ -384,7 +386,6 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
this.jobFactorySet = true;
}
/**
* Set whether to automatically start the scheduler after initialization.
* <p>Default is "true"; set this to "false" to allow for manual startup.
@@ -404,11 +405,12 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
}
/**
* Specify the phase in which this scheduler should be started and
* stopped. The startup order proceeds from lowest to highest, and
* the shutdown order is the reverse of that. By default this value
* is Integer.MAX_VALUE meaning that this scheduler starts as late
* as possible and stops as soon as possible.
* Specify the phase in which this scheduler should be started and stopped.
* The startup order proceeds from lowest to highest, and the shutdown order
* is the reverse of that. By default this value is {@code Integer.MAX_VALUE}
* meaning that this scheduler starts as late as possible and stops as soon
* as possible.
* @since 3.0
*/
public void setPhase(int phase) {
this.phase = phase;
@@ -456,7 +458,6 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
this.waitForJobsToCompleteOnShutdown = waitForJobsToCompleteOnShutdown;
}
@Override
public void setBeanName(String name) {
if (this.schedulerName == null) {
@@ -548,13 +549,7 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
*/
private SchedulerFactory prepareSchedulerFactory() throws SchedulerException, IOException {
SchedulerFactory schedulerFactory = this.schedulerFactory;
if (schedulerFactory != null) {
if (schedulerFactory instanceof StdSchedulerFactory) {
initSchedulerFactory((StdSchedulerFactory) schedulerFactory);
}
// Otherwise, assume that externally provided factory has been initialized with appropriate settings...
}
else {
if (schedulerFactory == null) {
// Create local SchedulerFactory instance (typically a StdSchedulerFactory)
schedulerFactory = BeanUtils.instantiateClass(this.schedulerFactoryClass);
if (schedulerFactory instanceof StdSchedulerFactory) {
@@ -567,6 +562,7 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
}
// Otherwise, no local settings to be applied via StdSchedulerFactory.initialize(Properties)
}
// Otherwise, assume that externally provided factory has been initialized with appropriate settings
return schedulerFactory;
}