JCache (JSR-107) Annotations
Since version 4.1, Spring’s caching abstraction fully supports the JCache standard
(JSR-107) annotations: @CacheResult
, @CachePut
, @CacheRemove
, and @CacheRemoveAll
as well as the @CacheDefaults
, @CacheKey
, and @CacheValue
companions.
You can use these annotations even without migrating your cache store to JSR-107.
The internal implementation uses Spring’s caching abstraction and provides default
CacheResolver
and KeyGenerator
implementations that are compliant with the
specification. In other words, if you are already using Spring’s caching abstraction,
you can switch to these standard annotations without changing your cache storage
(or configuration, for that matter).
Feature Summary
For those who are familiar with Spring’s caching annotations, the following table describes the main differences between the Spring annotations and their JSR-107 counterparts:
Spring | JSR-107 | Remark |
---|---|---|
|
|
Fairly similar. |
|
|
While Spring updates the cache with the result of the method invocation, JCache
requires that it be passed it as an argument that is annotated with |
|
|
Fairly similar. |
|
|
See |
|
|
Lets you configure the same concepts, in a similar fashion. |
JCache has the notion of javax.cache.annotation.CacheResolver
, which is identical
to the Spring’s CacheResolver
interface, except that JCache supports only a single
cache. By default, a simple implementation retrieves the cache to use based on the
name declared on the annotation. It should be noted that, if no cache name is
specified on the annotation, a default is automatically generated. See the javadoc
of @CacheResult#cacheName()
for more information.
CacheResolver
instances are retrieved by a CacheResolverFactory
. It is possible
to customize the factory for each cache operation, as the following example shows:
@CacheResult(cacheNames="books", cacheResolverFactory=MyCacheResolverFactory.class) (1)
public Book findBook(ISBN isbn)
1 | Customizing the factory for this operation. |
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. |
Keys are generated by a javax.cache.annotation.CacheKeyGenerator
that serves the
same purpose as Spring’s KeyGenerator
. By default, all method arguments are taken
into account, unless at least one parameter is annotated with @CacheKey
. This is
similar to Spring’s custom key generation declaration
. For instance, the following are identical operations, one using
Spring’s abstraction and the other using JCache:
@Cacheable(cacheNames="books", key="#isbn")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
@CacheResult(cacheName="books")
public Book findBook(@CacheKey ISBN isbn, boolean checkWarehouse, boolean includeUsed)
You can also specify the CacheKeyResolver
on the operation, similar to how you can
specify the CacheResolverFactory
.
JCache can manage exceptions thrown by annotated methods. This can prevent an update of
the cache, but it can also cache the exception as an indicator of the failure instead of
calling the method again. Assume that InvalidIsbnNotFoundException
is thrown if the
structure of the ISBN is invalid. This is a permanent failure (no book could ever be
retrieved with such a parameter). The following caches the exception so that further
calls with the same, invalid, ISBN throw the cached exception directly instead of
invoking the method again:
@CacheResult(cacheName="books", exceptionCacheName="failures"
cachedExceptions = InvalidIsbnNotFoundException.class)
public Book findBook(ISBN isbn)
Enabling JSR-107 Support
You do not need to do anything specific to enable the JSR-107 support alongside Spring’s
declarative annotation support. Both @EnableCaching
and the cache:annotation-driven
XML element automatically enable the JCache support if both the JSR-107 API and the
spring-context-support
module are present in the classpath.
Depending on your use case, the choice is basically yours. You can even mix and match services by using the JSR-107 API on some and using Spring’s own annotations on others. However, if these services impact the same caches, you should use a consistent and identical key generation implementation. |