Clarify SchedulerFactoryBean's LocalDataSourceJobStore overriding

Includes clarification of interface-level cache annotations for target-class proxies.

Closes gh-27709
See gh-27726
This commit is contained in:
Juergen Hoeller 2021-12-14 16:46:13 +01:00
parent c44447f622
commit d7b9270672
4 changed files with 66 additions and 16 deletions

View File

@ -39,6 +39,7 @@ import org.springframework.lang.Nullable;
* 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.
* You may also configure it explicitly, possibly as a custom subclass of this class.
*
* <p>Supports both transactional and non-transactional DataSource access.
* With a non-XA DataSource and local Spring transactions, a single DataSource
@ -58,6 +59,8 @@ import org.springframework.lang.Nullable;
* @since 1.1
* @see SchedulerFactoryBean#setDataSource
* @see SchedulerFactoryBean#setNonTransactionalDataSource
* @see SchedulerFactoryBean#getConfigTimeDataSource()
* @see SchedulerFactoryBean#getConfigTimeNonTransactionalDataSource()
* @see org.springframework.jdbc.datasource.DataSourceUtils#doGetConnection
* @see org.springframework.jdbc.datasource.DataSourceUtils#releaseConnection
*/

View File

@ -310,9 +310,11 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
/**
* 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.
* Also, do not define a "org.quartz.jobStore.class" property at all.
* (You may explicitly define Spring's {@link LocalDataSourceJobStore}
* but that's the default when using this method anyway.)
* <p>A Spring-specific subclass of Quartz' JobStoreCMT will be used.
* It is therefore strongly recommended to perform all operations on
* the Scheduler within Spring-managed (or plain JTA) transactions.

View File

@ -83,6 +83,19 @@ public class EnableCachingIntegrationTests {
assertCacheHit(key, value, cache);
}
@Test
public void barServiceWithCacheableInterfaceCglib() {
this.context = new AnnotationConfigApplicationContext(BarConfigCglib.class);
BarService service = this.context.getBean(BarService.class);
Cache cache = getCache();
Object key = new Object();
assertCacheMiss(key, cache);
Object value = service.getSimple(key);
assertCacheHit(key, value, cache);
}
@Test
public void beanConditionOff() {
this.context = new AnnotationConfigApplicationContext(BeanConditionConfig.class);
@ -185,6 +198,36 @@ public class EnableCachingIntegrationTests {
}
@Configuration
@Import(SharedConfig.class)
@EnableCaching(proxyTargetClass = true)
static class BarConfigCglib {
@Bean
public BarService barService() {
return new BarServiceImpl();
}
}
interface BarService {
@Cacheable(cacheNames = "testCache")
Object getSimple(Object key);
}
static class BarServiceImpl implements BarService {
private final AtomicLong counter = new AtomicLong();
@Override
public Object getSimple(Object key) {
return this.counter.getAndIncrement();
}
}
@Configuration
@Import(FooConfig.class)
@EnableCaching

View File

@ -5396,6 +5396,7 @@ You can use these macros instead of the six-digit value, thus: `@Scheduled(cron
|===
[[scheduling-quartz]]
=== Using the Quartz Scheduler
@ -5451,7 +5452,6 @@ has it applied automatically:
protected void executeInternal(JobExecutionContext ctx) throws JobExecutionException {
// do the actual work
}
}
----
@ -5571,11 +5571,19 @@ seconds and one running every morning at 6 AM. To finalize everything, we need t
</bean>
----
More properties are available for the `SchedulerFactoryBean`, such as the calendars
used by the job details, properties to customize Quartz with, and others. See the
{api-spring-framework}/scheduling/quartz/SchedulerFactoryBean.html[`SchedulerFactoryBean`]
More properties are available for the `SchedulerFactoryBean`, such as the calendars used by the
job details, properties to customize Quartz with, and a Spring-provided JDBC DataSource. See
the {api-spring-framework}/scheduling/quartz/SchedulerFactoryBean.html[`SchedulerFactoryBean`]
javadoc for more information.
NOTE: `SchedulerFactoryBean` also recognizes a `quartz.properties` file in the classpath,
based on Quartz property keys, as with regular Quartz configuration. Please note that many
`SchedulerFactoryBean` settings interact with common Quartz settings in the properties file;
it is therefore not recommended to specify values at both levels. For example, do not set
an "org.quartz.jobStore.class" property if you mean to rely on a Spring-provided DataSource,
or specify an `org.springframework.scheduling.quartz.LocalDataSourceJobStore` variant which
is a full-fledged replacement for the standard `org.quartz.impl.jdbcjobstore.JobStoreTX`.
@ -5877,7 +5885,6 @@ is updated in the cache. The following example shows how to use the `sync` attri
----
<1> Using the `sync` attribute.
NOTE: This is an optional feature, and your favorite cache library may not support it.
All `CacheManager` implementations provided by the core framework support it. See the
documentation of your cache provider for more details.
@ -6035,7 +6042,6 @@ all entries from the `books` cache:
----
<1> Using the `allEntries` attribute to evict all entries from the cache.
This option comes in handy when an entire cache region needs to be cleared out.
Rather than evicting each entry (which would take a long time, since it is inefficient),
all the entries are removed in one operation, as the preceding example shows.
@ -6094,7 +6100,6 @@ comes into play. The following examples uses `@CacheConfig` to set the name of t
----
<1> Using `@CacheConfig` to set the name of the cache.
`@CacheConfig` is a class-level annotation that allows sharing the cache names,
the custom `KeyGenerator`, the custom `CacheManager`, and the custom `CacheResolver`.
Placing this annotation on the class does not turn on any caching operation.
@ -6235,13 +6240,11 @@ if you need to annotate non-public methods, as it changes the bytecode itself.
****
TIP: Spring recommends that you only annotate concrete classes (and methods of concrete
classes) with the `@Cache{asterisk}` annotation, as opposed to annotating interfaces.
You certainly can place the `@Cache{asterisk}` annotation on an interface (or an interface
method), but this works only as you would expect it to if you use interface-based proxies.
The fact that Java annotations are not inherited from interfaces means that, if you use
class-based proxies (`proxy-target-class="true"`) or the weaving-based aspect
(`mode="aspectj"`), the caching settings are not recognized by the proxying and weaving
infrastructure, and the object is not wrapped in a caching proxy.
classes) with the `@Cache{asterisk}` annotations, as opposed to annotating interfaces.
You certainly can place an `@Cache{asterisk}` annotation on an interface (or an interface
method), but this works only if you use the proxy mode (`mode="proxy"`). If you use the
weaving-based aspect (`mode="aspectj"`), the caching settings are not recognized on
interface-level declarations by the weaving infrastructure.
NOTE: In proxy mode (the default), only external method calls coming in through the
proxy are intercepted. This means that self-invocation (in effect, a method within the
@ -6378,7 +6381,6 @@ to customize the factory for each cache operation, as the following example show
----
<1> Customizing the factory for this operation.
NOTE: For all referenced classes, Spring tries to locate a bean with the given type.
If more than one match exists, a new instance is created and can use the regular
bean lifecycle callbacks, such as dependency injection.