Skip to content

Commit d7b9270

Browse files
committed
Clarify SchedulerFactoryBean's LocalDataSourceJobStore overriding
Includes clarification of interface-level cache annotations for target-class proxies. Closes gh-27709 See gh-27726
1 parent c44447f commit d7b9270

File tree

4 files changed

+66
-16
lines changed

4 files changed

+66
-16
lines changed

spring-context-support/src/main/java/org/springframework/scheduling/quartz/LocalDataSourceJobStore.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
* Subclass of Quartz's {@link JobStoreCMT} class that delegates to a Spring-managed
4040
* {@link DataSource} instead of using a Quartz-managed JDBC connection pool.
4141
* This JobStore will be used if SchedulerFactoryBean's "dataSource" property is set.
42+
* You may also configure it explicitly, possibly as a custom subclass of this class.
4243
*
4344
* <p>Supports both transactional and non-transactional DataSource access.
4445
* With a non-XA DataSource and local Spring transactions, a single DataSource
@@ -58,6 +59,8 @@
5859
* @since 1.1
5960
* @see SchedulerFactoryBean#setDataSource
6061
* @see SchedulerFactoryBean#setNonTransactionalDataSource
62+
* @see SchedulerFactoryBean#getConfigTimeDataSource()
63+
* @see SchedulerFactoryBean#getConfigTimeNonTransactionalDataSource()
6164
* @see org.springframework.jdbc.datasource.DataSourceUtils#doGetConnection
6265
* @see org.springframework.jdbc.datasource.DataSourceUtils#releaseConnection
6366
*/

spring-context-support/src/main/java/org/springframework/scheduling/quartz/SchedulerFactoryBean.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,9 +310,11 @@ public void setTaskExecutor(Executor taskExecutor) {
310310

311311
/**
312312
* Set the default {@link DataSource} to be used by the Scheduler.
313-
* If set, this will override corresponding settings in Quartz properties.
314313
* <p>Note: If this is set, the Quartz settings should not define
315314
* a job store "dataSource" to avoid meaningless double configuration.
315+
* Also, do not define a "org.quartz.jobStore.class" property at all.
316+
* (You may explicitly define Spring's {@link LocalDataSourceJobStore}
317+
* but that's the default when using this method anyway.)
316318
* <p>A Spring-specific subclass of Quartz' JobStoreCMT will be used.
317319
* It is therefore strongly recommended to perform all operations on
318320
* the Scheduler within Spring-managed (or plain JTA) transactions.

spring-context/src/test/java/org/springframework/cache/config/EnableCachingIntegrationTests.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,19 @@ private void fooGetSimple(FooService service) {
8383
assertCacheHit(key, value, cache);
8484
}
8585

86+
@Test
87+
public void barServiceWithCacheableInterfaceCglib() {
88+
this.context = new AnnotationConfigApplicationContext(BarConfigCglib.class);
89+
BarService service = this.context.getBean(BarService.class);
90+
Cache cache = getCache();
91+
92+
Object key = new Object();
93+
assertCacheMiss(key, cache);
94+
95+
Object value = service.getSimple(key);
96+
assertCacheHit(key, value, cache);
97+
}
98+
8699
@Test
87100
public void beanConditionOff() {
88101
this.context = new AnnotationConfigApplicationContext(BeanConditionConfig.class);
@@ -185,6 +198,36 @@ public Object getWithCondition(Object key) {
185198
}
186199

187200

201+
@Configuration
202+
@Import(SharedConfig.class)
203+
@EnableCaching(proxyTargetClass = true)
204+
static class BarConfigCglib {
205+
206+
@Bean
207+
public BarService barService() {
208+
return new BarServiceImpl();
209+
}
210+
}
211+
212+
213+
interface BarService {
214+
215+
@Cacheable(cacheNames = "testCache")
216+
Object getSimple(Object key);
217+
}
218+
219+
220+
static class BarServiceImpl implements BarService {
221+
222+
private final AtomicLong counter = new AtomicLong();
223+
224+
@Override
225+
public Object getSimple(Object key) {
226+
return this.counter.getAndIncrement();
227+
}
228+
}
229+
230+
188231
@Configuration
189232
@Import(FooConfig.class)
190233
@EnableCaching

src/docs/asciidoc/integration.adoc

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5396,6 +5396,7 @@ You can use these macros instead of the six-digit value, thus: `@Scheduled(cron
53965396
|===
53975397

53985398

5399+
53995400
[[scheduling-quartz]]
54005401
=== Using the Quartz Scheduler
54015402

@@ -5451,7 +5452,6 @@ has it applied automatically:
54515452
protected void executeInternal(JobExecutionContext ctx) throws JobExecutionException {
54525453
// do the actual work
54535454
}
5454-
54555455
}
54565456
----
54575457

@@ -5571,11 +5571,19 @@ seconds and one running every morning at 6 AM. To finalize everything, we need t
55715571
</bean>
55725572
----
55735573

5574-
More properties are available for the `SchedulerFactoryBean`, such as the calendars
5575-
used by the job details, properties to customize Quartz with, and others. See the
5576-
{api-spring-framework}/scheduling/quartz/SchedulerFactoryBean.html[`SchedulerFactoryBean`]
5574+
More properties are available for the `SchedulerFactoryBean`, such as the calendars used by the
5575+
job details, properties to customize Quartz with, and a Spring-provided JDBC DataSource. See
5576+
the {api-spring-framework}/scheduling/quartz/SchedulerFactoryBean.html[`SchedulerFactoryBean`]
55775577
javadoc for more information.
55785578

5579+
NOTE: `SchedulerFactoryBean` also recognizes a `quartz.properties` file in the classpath,
5580+
based on Quartz property keys, as with regular Quartz configuration. Please note that many
5581+
`SchedulerFactoryBean` settings interact with common Quartz settings in the properties file;
5582+
it is therefore not recommended to specify values at both levels. For example, do not set
5583+
an "org.quartz.jobStore.class" property if you mean to rely on a Spring-provided DataSource,
5584+
or specify an `org.springframework.scheduling.quartz.LocalDataSourceJobStore` variant which
5585+
is a full-fledged replacement for the standard `org.quartz.impl.jdbcjobstore.JobStoreTX`.
5586+
55795587

55805588

55815589

@@ -5877,7 +5885,6 @@ is updated in the cache. The following example shows how to use the `sync` attri
58775885
----
58785886
<1> Using the `sync` attribute.
58795887

5880-
58815888
NOTE: This is an optional feature, and your favorite cache library may not support it.
58825889
All `CacheManager` implementations provided by the core framework support it. See the
58835890
documentation of your cache provider for more details.
@@ -6035,7 +6042,6 @@ all entries from the `books` cache:
60356042
----
60366043
<1> Using the `allEntries` attribute to evict all entries from the cache.
60376044

6038-
60396045
This option comes in handy when an entire cache region needs to be cleared out.
60406046
Rather than evicting each entry (which would take a long time, since it is inefficient),
60416047
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
60946100
----
60956101
<1> Using `@CacheConfig` to set the name of the cache.
60966102

6097-
60986103
`@CacheConfig` is a class-level annotation that allows sharing the cache names,
60996104
the custom `KeyGenerator`, the custom `CacheManager`, and the custom `CacheResolver`.
61006105
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.
62356240
****
62366241

62376242
TIP: Spring recommends that you only annotate concrete classes (and methods of concrete
6238-
classes) with the `@Cache{asterisk}` annotation, as opposed to annotating interfaces.
6239-
You certainly can place the `@Cache{asterisk}` annotation on an interface (or an interface
6240-
method), but this works only as you would expect it to if you use interface-based proxies.
6241-
The fact that Java annotations are not inherited from interfaces means that, if you use
6242-
class-based proxies (`proxy-target-class="true"`) or the weaving-based aspect
6243-
(`mode="aspectj"`), the caching settings are not recognized by the proxying and weaving
6244-
infrastructure, and the object is not wrapped in a caching proxy.
6243+
classes) with the `@Cache{asterisk}` annotations, as opposed to annotating interfaces.
6244+
You certainly can place an `@Cache{asterisk}` annotation on an interface (or an interface
6245+
method), but this works only if you use the proxy mode (`mode="proxy"`). If you use the
6246+
weaving-based aspect (`mode="aspectj"`), the caching settings are not recognized on
6247+
interface-level declarations by the weaving infrastructure.
62456248

62466249
NOTE: In proxy mode (the default), only external method calls coming in through the
62476250
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
63786381
----
63796382
<1> Customizing the factory for this operation.
63806383

6381-
63826384
NOTE: For all referenced classes, Spring tries to locate a bean with the given type.
63836385
If more than one match exists, a new instance is created and can use the regular
63846386
bean lifecycle callbacks, such as dependency injection.

0 commit comments

Comments
 (0)