【Spring】Spring Framework Reference Documentation中文版33

来源:互联网 发布:韩国妹子活好吗 知乎 编辑:程序博客网 时间:2024/06/06 09:48

36. Cache Abstraction

缓存抽象

 

36.1 Introduction

介绍

 

Since version 3.1, Spring Framework provides support for transparently adding caching into an existing Spring application. Similar to the transaction support, the caching abstraction allows consistent use of various caching solutions with minimal impact on the code.

自从版本3.1spring框架提供了支持用于添加缓存DAO已有的spring应用。类似于事务支持,缓存抽象允许使用不同的缓存解决方案使用最小的对代码的影响。

 

As from Spring 4.1, the cache abstraction has been significantly improved with the support of JSR-107 annotations and more customization options.

由于spring4.1,缓存抽象提高了支持对于JSR-107注解和更多自定义的选项。

 

36.2 Understanding the cache abstraction

了解缓存抽象

 

Cache vs Buffer

缓存vs缓冲

 

The terms "buffer" and "cache" tend to be used interchangeably; note however they represent different things. A buffer is used traditionally as an intermediate temporary store for data between a fast and a slow entity. As one party would have to wait for the other affecting performance, the buffer alleviates this by allowing entire blocks of data to move at once rather then in small chunks. The data is written and read only once from the buffer. Furthermore, the buffers are visible to at least one party which is aware of it.

缓冲和缓存可以交换使用:注意他们代表不同的内容。缓冲使用传统的中间数据存储在fastslow实体之间。一个要等待另其他的影响性能,缓冲减缓了使用通过允许移动数据块而不是小的块。数据被写入并且是只读的。此外,缓冲至少是可以被意识到的一部分。

 

A cache on the other hand by definition is hidden and neither party is aware that caching occurs.It as well improves performance but does that by allowing the same data to be read multiple times in a fast fashion.

对于其他方面的缓存定义是隐藏的并且没有意识到缓存。他提升了性能但是通过允许数据来读取多次以很快的方式。

 

A further explanation of the differences between two can be found here.

对两者更多的解释是在这里。

 

At its core, the abstraction applies caching to Java methods, reducing thus the number of executions based on the information available in the cache. That is, each time a targeted method is invoked, the abstraction will apply a caching behavior checking whether the method has been already executed for the given arguments. If it has, then the cached result is returned without having to execute the actual method; if it has not, then method is executed, the result cached and returned to the user so that, the next time the method is invoked, the cached result is returned. This way, expensive methods (whether CPU or IO bound) can be executed only once for a given set of parameters and the result reused without having to actually execute the method again. The caching logic is applied transparently without any interference to the invoker.

在那个分数,抽象应用缓存到Java方法,减少执行的数目基于缓存的可用性。就是每次目标方法被调用,抽象将应用缓存行为检查方法是否已经执行过对于给定的参数。就是直接使用缓存结果而不需要执行实际的方法;如果没有,方法将被执行,结果缓存和返回给用户因此下一次方法被调用则缓存结果将被返回。这个方式中方法消耗是大的(或者是CPU或者是IO)可以执行一次对于一个给定的参数集合和结果可以被重用不需要实际再次执行方法。缓存逻辑可以直接应用不需要影响调用者。

 

[Important] Important

重要

 

Obviously this approach works only for methods that are guaranteed to return the same output (result) for a given input (or arguments) no matter how many times it is being executed.

明显的这个方法是对于指定的输入或参数给定一个返回或结果不管他被执行几次。

 

Other cache-related operations are provided by the abstraction such as the ability to update the content of the cache or remove one of all entries. These are useful if the cache deals with data that can change during the course of the application.

其他相关的缓存操作被提供通过抽象例如可以更新缓存的内容或移除其中一个实体。这是有用的如果缓存处理数据可以改变由于应用的结果。

 

Just like other services in the Spring Framework, the caching service is an abstraction (not a cache implementation) and requires the use of an actual storage to store the cache data - that is, the abstraction frees the developer from having to write the caching logic but does not provide the actual stores. This abstraction is materialized by the org.springframework.cache.Cache and org.springframework.cache.CacheManager interfaces.

就像其他的spring框架中的服务,缓存服务是一个抽象(不是缓存实现)和要求使用实际的存储来存储缓存数据————就是,抽象解放了开发者不需要写缓存逻辑或提供实际的存储。这个抽象是通过org.springframework.cache.Cacheorg.springframework.cache.CacheManager接口来实现的。

 

There are a few implementations of that abstraction available out of the box: JDK java.util.concurrent.ConcurrentMap based caches, Ehcache 2.x, Gemfire cache, Caffeine, Guava caches and JSR-107 compliant caches (e.g. Ehcache 3.x). See Section 36.7,Plugging-in different back-end cachesfor more information on plugging in other cache stores/providers.

这是一个可用的抽象实现:JDK java.util.concurrent.ConcurrentMap基缓存,Ehcache2.xGemfire缓存、CaffeineGuava缓存和JSR107缓存(例如,Ehcache3.x)。见章节36.7,“插件不同于后端的缓存”来了解更多信息有关其他缓存存储的信息。

 

[Important] Important

重要

 

The caching abstraction has no special handling of multi-threaded and multi-process environments as such features are handled by the cache implementation. .

缓存抽象没有指定处理多线程和多处理环境例如这样的特性可以被处理通过缓存的实现。

 

If you have a multi-process environment (i.e. an application deployed on several nodes), you will need to configure your cache provider accordingly. Depending on your use cases, a copy of the same data on several nodes may be enough but if you change the data during the course of the application, you may need to enable other propagation mechanisms.

如果你有一个多处理缓存(例如应用部署在一些节点),你将需要配置你的缓存提供策略。依赖于你的使用,相同数据的备份对于一些节点是足够的如果你改变的数据在应用的执行期间,你可能需要语序其他的传播策略。

 

Caching a particular item is a direct equivalent of the typical get-if-not-found-then- proceed-and-put-eventually code blocks found with programmatic cache interaction: no locks are applied and several threads may try to load the same item concurrently. The same applies to eviction: if several threads are trying to update or evict data concurrently, you may use stale data. Certain cache providers offer advanced features in that area, refer to the documentation of the cache provider that you are using for more details.

缓存一个特定的项目是相同与通常的获取如果没有发现则处理和最后保存代码逻辑发现与缓存的策略:没有锁被应用和一些线程可以试图并发加载相同的项目。相同的应用,如果一些线程试图并发更新或删除数据,你可以使用过期数据。相应的缓存提供高级的特性在一些情况,缓存提供者的参考文档你可以使用来了解更多细节。

 

To use the cache abstraction, the developer needs to take care of two aspects:

为了使用缓存抽象,开发者需要关注两个方面:

 

    caching declaration - identify the methods that need to be cached and their policy

缓存声明————定义方法需要被缓存和他们的策略

    cache configuration - the backing cache where the data is stored and read from

缓存配置————后备缓存用于数据的读和写

 

36.3 Declarative annotation-based caching

声明式基于注解缓存

 

For caching declaration, the abstraction provides a set of Java annotations:

对于缓存的声明,抽象提供了一些Java注解的集合:

 

    @Cacheable triggers cache population

    @CacheEvict triggers cache eviction

    @CachePut updates the cache without interfering with the method execution

    @Caching regroups multiple cache operations to be applied on a method

    @CacheConfig shares some common cache-related settings at class-level

 

Let us take a closer look at each annotation:

让我们看一下每个注解:

 

36.3.1 @Cacheable annotation

 

As the name implies, @Cacheable is used to demarcate methods that are cacheable - that is, methods for whom the result is stored into the cache so on subsequent invocations (with the same arguments), the value in the cache is returned without having to actually execute the method. In its simplest form, the annotation declaration requires the name of the cache associated with the annotated method:

由于名字的实现,@Cacheable备用于修饰方法可以被缓存的————就是方法对于结果的缓存因此来用于后面重复的调用(使用相同的参数),缓存中的值被返回不需要实际执行方法。在最简单的情况,注解定义了名字对于缓存相关于注解方法:

 

@Cacheable("books")

public Book findBook(ISBN isbn) {...}

 

In the snippet above, the method findBook is associated with the cache named books. Each time the method is called, the cache is checked to see whether the invocation has been already executed and does not have to be repeated. While in most cases, only one cache is declared, the annotation allows multiple names to be specified so that more than one cache are being used. In this case, each of the caches will be checked before executing the method - if at least one cache is hit, then the associated value will be returned:

在上面的片段中,方法findBook是相关于缓存名字为books。每一次方法被调用,缓存检查是否调用的内容已经被缓存并且如果已经被缓存则不会重复执行方法。在大多数情况下,只有一个缓冲被定义,注解允许多个名字被指定因此多于一个缓存可以被使用。在这个例子中每个缓存将被检查在执行方法之前————如果至少有一个缓冲命中则相应的值将被返回。

 

[Note]

注意

 

All the other caches that do not contain the value will be updated as well even though the cached method was not actually executed.

所有的其他的缓存不包含值将更新由于缓存方法没有实际被执行。

 

@Cacheable({"books", "isbns"})

public Book findBook(ISBN isbn) {...}

 

Default Key Generation

默认的关键字生成

 

Since caches are essentially key-value stores, each invocation of a cached method needs to be translated into a suitable key for cache access. Out of the box, the caching abstraction uses a simple KeyGenerator based on the following algorithm:

因此缓存时相应的key-value存储,每个对于缓存方法的调用需要被转化为对于每个缓存的访问。缓存抽象使用了一个简单的KeyGenerator基于下面的算法。

 

    If no params are given, return SimpleKey.EMPTY.

如果没有参数被指定,则返回SimpleKey.EMPTY

    If only one param is given, return that instance.

如果只有一个参数被指定,则返回实例

    If more the one param is given, return a SimpleKey containing all parameters.

如果多于一个参数被指定,则返回一个SimpleKey包含所有的参数。

 

This approach works well for most use-cases; As long as parameters have natural keys and implement valid hashCode() and equals() methods. If that is not the case then the strategy needs to be changed.

这个方式对于大多数情况是有效的;由于参数有自然的key并且实现了验证方法hashCodeequals方法。如果策略没有改变的话。

 

To provide a different default key generator, one needs to implement the org.springframework.cache.interceptor.KeyGenerator interface.

为了提供一个不用的默认关键词生成器,需要实现org.springframework.cache.interceptor.KeyGenerator接口。

 

[Note]

注意

 

The default key generation strategy changed with the release of Spring 4.0. Earlier versions of Spring used a key generation strategy that, for multiple key parameters, only considered the hashCode() of parameters and not equals(); this could cause unexpected key collisions (see SPR-10237 for background). The new 'SimpleKeyGenerator' uses a compound key for such scenarios.

默认的关键字生成策略改变由于spring4.0。之前版本的spring使用了一个关键字生成策略,对于多个关键字参数,只考虑参数的hashCode和非equals方法,这将导致一定的碰撞(见SPR-10237),新的'SimpleKeyGenerator'使用了一个混合关键字使用这样的情况。

 

If you want to keep using the previous key strategy, you can configure the deprecated org.springframework.cache.interceptor.DefaultKeyGenerator class or create a custom hash-based 'KeyGenerator' implementation.

如果你希望保持使用之前的关键字策略,你可以配置废弃的org.springframework.cache.interceptor.DefaultKeyGenerator类或创建一个自定义的基于hash'KeyGenerator'实现。

 

Custom Key Generation Declaration

自定义关键字生成定义

 

Since caching is generic, it is quite likely the target methods have various signatures that cannot be simply mapped on top of the cache structure. This tends to become obvious when the target method has multiple arguments out of which only some are suitable for caching (while the rest are used only by the method logic). For example:

由于缓存时通用的,就是目标方法有不同签名不会简单的匹配缓存顶层的结构。试图变得明显当目标方法有多个参数并且一部分适用于缓存(就是剩下的只相关于代码的逻辑)。例如:

 

@Cacheable("books")

public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)

 

At first glance, while the two boolean arguments influence the way the book is found, they are no use for the cache. Further more what if only one of the two is important while the other is not?

对于第一眼,布尔类型参数影响了book被查找,他们没有使用缓存。此外如果其中一个是而另一个不是?

 

For such cases, the @Cacheable annotation allows the user to specify how the key is generated through its key attribute. The developer can use SpEL to pick the arguments of interest (or their nested properties), perform operations or even invoke arbitrary methods without having to write any code or implement any interface. This is the recommended approach over the default generator since methods tend to be quite different in signatures as the code base grows; while the default strategy might work for some methods, it rarely does for all methods.

对于这样的情况,@Cacheable注解允许指定关键字的生成通过他key属性。开发者可以使用SpEL来获取爱好的参数(或她们内置的属性),执行操作或调用任意的方法不需要书写任何代码或实现任何接口。这是推荐的方式对于默认的生成器自从方法需要不同的签名根据基本的代码,默认的策略可以工作于相同的方法,他很少适用于所有的方法。

 

Below are some examples of various SpEL declarations - if you are not familiar with it, do yourself a favor and read Chapter 10, Spring Expression Language (SpEL):

下面是一些案例对于不同SpEL定义————如果你不熟悉,你可以阅读章节10spring表达式语言(SpEL):

 

@Cacheable(cacheNames="books", key="#isbn")

public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)

 

@Cacheable(cacheNames="books", key="#isbn.rawNumber")

public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)

 

@Cacheable(cacheNames="books", key="T(someType).hash(#isbn)")

public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)

 

The snippets above show how easy it is to select a certain argument, one of its properties or even an arbitrary (static) method.

上面的片段展示了如果简单的选择一个参数,他们属性或任意的(静态)方法。

 

If the algorithm responsible to generate the key is too specific or if it needs to be shared, you may define a custom keyGenerator on the operation. To do this, specify the name of the KeyGenerator bean implementation to use:

如果算法由于生成的关键字指定或需要被共享,你可以定义一个自定义的keyGenerator对于操作。为了实现,指定KeyGeneratorbean的名字来使用

 

@Cacheable(cacheNames="books", keyGenerator="myKeyGenerator")

public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)

 

[Note]

 

The key and keyGenerator parameters are mutually exclusive and an operation specifying both will result in an exception.

关键字和keyGenerator参数被互相排斥并且每个操作都有可能产生异常。

 

Default Cache Resolution

默认的缓存解析

 

Out of the box, the caching abstraction uses a simple CacheResolver that retrieves the cache(s) defined at the operation level using the configured CacheManager.

缓存抽象使用一个简单的CacheResolver来检索缓存定义在操作级别使用配置的CacheManager

 

To provide a different default cache resolver, one needs to implement the org.springframework.cache.interceptor.CacheResolver interface.

为了提供不同默认缓存解析,需要实现org.springframework.cache.interceptor.CacheResolver接口。

 

Custom cache resolution

自定义缓存解析

 

The default cache resolution fits well for applications working with a single CacheManager and with no complex cache resolution requirements.

默认的缓存解析适合于应用对于使用单个CacheManager并且不需要复杂的解析要求。

 

For applications working with several cache managers, it is possible to set the cacheManager to use per operation:

对于应用使用不同的缓存管理,可以设置cacheManager使用每个操作:

 

@Cacheable(cacheNames="books", cacheManager="anotherCacheManager")

public Book findBook(ISBN isbn) {...}

 

It is also possible to replace the CacheResolver entirely in a similar fashion as for key generation. The resolution is requested for every cache operation, giving a chance to the implementation to actually resolve the cache(s) to use based on runtime arguments:

可以整体替换CacheResolver以相似的方式作为key的生成。解析是要求对于每个缓存操作,基于实现的机会对于实际的解析缓存来使用基于运行时参数:

 

@Cacheable(cacheResolver="runtimeCacheResolver")

public Book findBook(ISBN isbn) {...}

 

[Note]

注意

 

Since Spring 4.1, the value attribute of the cache annotations are no longer mandatory since this particular information can be provided by the CacheResolver regardless of the content of the annotation.

由于spring4.1,缓存注解的value属性不在有意义因为这个特殊的信息可以被提供通过CacheResolver而不是注解的内容。

 

Similarly to key and keyGenerator, the cacheManager and cacheResolver parameters are mutually exclusive and an operation specifying both will result in an exception as a custom cacheResolver will be ignored by the CacheResolver implementation. This is probably not what you expect.

相似对于keykeyGeneratorcacheManagercacheResolver参数必须排除并且将导致异常作为一个定义并且指定了异常的结果将被忽略并且操作支持由于一个自定义cacheResolver实现被忽略通过CacheResolver实现。这是你所不期望的。

 

Synchronized caching

同步缓存

 

In a multi-threaded environment, certain operations might be concurrently invoked for the same argument (typically on startup). By default, the cache abstraction does not lock anything and the same value may be computed several times, defeating the purpose of caching.

在一个多线程的环境中,相应的操作可以是并发的调用对于相同的参数(通常矮开始的时候),缓存抽象不像其他的事务可以被多次进行计算,定义缓存的目的。

 

For those particular cases, the sync attribute can be used to instruct the underlying cache provider to lock the cache entry while the value is being computed. As a result, only one thread will be busy computing the value while the others are blocked until the entry is updated in the cache.

对于这些特定的场合,同步属性可以被使用来结构化底层的缓存提供者锁定缓存实体当值被计算后。因此,当一个线程处于繁忙的计算值则其他的被阻塞直到实体被更新在缓存中。

 

@Cacheable(cacheNames="foos", sync="true")

public Foo executeExpensiveOperation(String id) {...}

 

[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. Check the documentation of your cache provider for more details.

这是一个可选的特性并且你的缓存库可能不支持他。所有的CacheManager实现由核心框架提供支持。可以参考相关文档了解更多。

 

Conditional caching

条件缓存

 

Sometimes, a method might not be suitable for caching all the time (for example, it might depend on the given arguments). The cache annotations support such functionality through the condition parameter which takes a SpEL expression that is evaluated to either true or false. If true, the method is cached - if not, it behaves as if the method is not cached, that is executed every time no matter what values are in the cache or what arguments are used. A quick example - the following method will be cached only if the argument name has a length shorter than 32:

有时,一个方法可能不适合于缓存所有(例如,他可能依赖给定的参数)。缓存注解支持这样的功能通过条件参数使用SpEL表达式是否为真或假。如果是真则缓存否则不缓存,他会每次都被执行不管参数是否被缓存过。一个例子————下面的方法将被缓存只有参数名的长度小于32的时候。

 

@Cacheable(cacheNames="book", condition="#name.length < 32")

public Book findBook(String name)

 

In addition the condition parameter, the unless parameter can be used to veto the adding of a value to the cache. Unlike condition, unless expressions are evaluated after the method has been called. Expanding on the previous example - perhaps we only want to cache paperback books:

此外对于条件参数,除非参数可以被使用来关闭添加值到缓存。除非表达式在方法执行后被调用。扩展前面的那个例子————或许我们希望缓存纸质的书籍。

 

@Cacheable(cacheNames="book", condition="#name.length < 32", unless="#result.hardback")

public Book findBook(String name)

 

The cache abstraction supports java.util.Optional, using its content as cached value only if it present. #result always refers to the business entity and never on a supported wrapper so the previous example can be rewritten as follows:

缓存抽象支持java.util.Optional,使用它的内容作为缓存值如果可以。#result经常引用业务实体对于一个支持的处理器因此之前的例子可以按照下面的方式重写:

 

@Cacheable(cacheNames="book", condition="#name.length < 32", unless="#result.hardback")

public Optional<Book> findBook(String name)

 

Note that result still refers to Book and not Optional.

注意结果依然引用BookOptional

 

Available caching SpEL evaluation context

可用的缓存SpEL表达式内容

 

Each SpEL expression evaluates again a dedicated context. In addition to the build in parameters, the framework provides dedicated caching related metadata such as the argument names. The next table lists the items made available to the context so one can use them for key and conditional computations:

每个SpEL表达式计算对于指定的内容。此外对于参数,框架提供了缓存细节依赖于元数据作为参数名。下面的表格列出了项目可以作为内容因此可以使用关键字和条件计算:

 

Table 36.1. Cache SpEL available metadata

缓存SpEL可用的元数据

Name

名字

Location

位置

Description

描述

Example

样例

methodName

root object

The name of the method being invoked

被调用的方法的名字

#root.methodName

method

root object

The method being invoked

被调用的方法

#root.method.name

target

root object

The target object being invoked

被调用的对象

#root.target

targetClass

root object

The class of the target being invoked

被调用的类

#root.targetClass

args

root object

The arguments (as array) used for invoking the target

类似于数组的参数用于调用目标

#root.args[0]

caches

root object

Collection of caches against which the current method is executed

缓存的集合对于当前方法的执行

#root.caches[0].name

argument name

evaluation context

Name of any of the method arguments. If for some reason the names are not available (e.g. no debug information), the argument names are also available under the #a<#arg> where #arg stands for the argument index (starting from 0).

方法参数的名字。如果由于某些原因导致无法获取方法参数名(例如非调试信息),参数名可用类似于#a<#arg>其中#arg代表参数的下标

#iban or #a0 (one can also use #p0 or #p<#arg> notation as an alias).

result

evaluation context

The result of the method call (the value to be cached). Only available in unless expressions, cache put expressions (to compute the key), or cache evict expressions (whenbeforeInvocation is false). For supported wrappers such as Optional, #result refers to the actual object, not the wrapper.

方法调用的结果(缓存的值)。只能用于表达式,缓存放入表达式(为了计算),或缓存计算表达式(当beforeInvocation是false的时候)。支持可选的处理器,#result代表引用的实际Object

#result

 

36.3.2 @CachePut annotation

@CachePut注解

 

For cases where the cache needs to be updated without interfering with the method execution, one can use the @CachePut annotation. That is, the method will always be executed and its result placed into the cache (according to the @CachePut options). It supports the same options as @Cacheable and should be used for cache population rather than method flow optimization:

对于需求缓存需要被更新在不影响方法执行的前提下,可以使用@CachePut注解。就是方法将被执行并且他的结果会放入缓存(通过@CachePut的选项)。他支持相同的选项类似于@Cacheable并且应当被使用缓存而不是方法优化:

 

@CachePut(cacheNames="book", key="#isbn")

public Book updateBook(ISBN isbn, BookDescriptor descriptor)

 

[Important] Important

重要

 

Note that using @CachePut and @Cacheable annotations on the same method is generally strongly discouraged because they have different behaviors. While the latter causes the method execution to be skipped by using the cache, the former forces the execution in order to execute a cache update. This leads to unexpected behavior and with the exception of specific corner-cases (such as annotations having conditions that exclude them from each other), such declaration should be avoided. Note also that such condition should not rely on the result object (i.e. the #result variable) as these are validated upfront to confirm the exclusion.

注意使用@CachePut@Cacheable注解对于同一个方法是不推荐的因此他们有不同的行为。可能导致表达式被跳过在使用缓存的时候,前者强制执行用于缓存的更新。这导致异常行为的发生及异常(例如注解有条件且包含在他们之外),这样的情况应该被避免。注意这样的条件不应当依赖于结果的object(例如,#result变量)作为可用的确认。

 

36.3.3 @CacheEvict annotation

@CacheEvict注解

 

The cache abstraction allows not just population of a cache store but also eviction. This process is useful for removing stale or unused data from the cache. Opposed to @Cacheable, annotation @CacheEvict demarcates methods that perform cache eviction, that is methods that act as triggers for removing data from the cache. Just like its sibling, @CacheEvict requires specifying one (or multiple) caches that are affected by the action, allows a custom cache and key resolution or a condition to be specified but in addition, features an extra parameter allEntries which indicates whether a cache-wide eviction needs to be performed rather then just an entry one (based on the key):

缓存抽象不只允许缓存的存储也包括清楚。这个程序是有用的对于取出不需要的数据。相对于@Cacheable注解@CacheEvict修饰的方法执行缓存删除,就是方法扮演一个触发器的角色对于从缓存中删除数据。就像他的伙伴,@CacheEvict要求制定一个(或多个)缓存由活动来影响,允许一个自定义缓存处理或条件被指定但是在额外的条件一个额外的参数allEntries指示了缓存的删除需要被执行对于一个实体(基于关键字)。

 

@CacheEvict(cacheNames="books", allEntries=true)

public void loadBooks(InputStream batch)

 

This option comes in handy when an entire cache region needs to be cleared out - rather then evicting each entry (which would take a long time since it is inefficient), all the entries are removed in one operation as shown above. Note that the framework will ignore any key specified in this scenario as it does not apply (the entire cache is evicted not just one entry).

这个选项是有用的当缓存需要被清除————而不是清除每个实体(会花费一定的时间),所有的实体被清楚基于上面展示的一个操作。注意框架将忽略指定的key在这些场景中并且不会应用(整体的缓存被删除而不只是一个实体)。

 

One can also indicate whether the eviction should occur after (the default) or before the method executes through the beforeInvocation attribute. The former provides the same semantics as the rest of the annotations - once the method completes successfully, an action (in this case eviction) on the cache is executed. If the method does not execute (as it might be cached) or an exception is thrown, the eviction does not occur. The latter ( beforeInvocation=true) causes the eviction to occur always, before the method is invoked - this is useful in cases where the eviction does not need to be tied to the method outcome.

可以指定是否删除在方法执行的前后通过beforeInvocation属性。前者提供了相同的语义作为注解的设置————一旦方法完成缓存的操作会被执行。如果方法没有执行或抛出异常则删除操作不会发生。后者表示删除操作一直执行,在方法运行前如果调用————好处就是删除操作不取决于方法的输出。

 

It is important to note that void methods can be used with @CacheEvict - as the methods act as triggers, the return values are ignored (as they dont interact with the cache) - this is not the case with @Cacheable which adds/updates data into the cache and thus requires a result.

这是重要的就是void的方法可以使用@CacheEvict————使得方法作为触发器,返回值被忽略(因此他们不用参与缓存)————就是不需要使用@Cacheable来添加或更新数据到缓存中并且这要求一个结果。

 

36.3.4 @Caching annotation

@Caching注解

 

There are cases when multiple annotations of the same type, such as @CacheEvict or @CachePut need to be specified, for example because the condition or the key expression is different between different caches. @Caching allows multiple nested @Cacheable, @CachePut and @CacheEvict to be used on the same method:

这用于多个相同类型的注解,例如@CacheEvict@CachePut需要被指定,例如因此条件或关键字表达式是不同的。@Caching允许多个内置的@Cacheable@CachePut@CacheEvict被使用于相同的方法:

 

@Caching(evict = { @CacheEvict("primary"), @CacheEvict(cacheNames="secondary", key="#p0") })

public Book importBooks(String deposit, Date date)

 

36.3.5 @CacheConfig annotation

@CacheConfig注解

 

So far we have seen that caching operations offered many customization options and these can be set on an operation basis. However, some of the customization options can be tedious to configure if they apply to all operations of the class. For instance, specifying the name of the cache to use for every cache operation of the class could be replaced by a single class-level definition. This is where @CacheConfig comes into play.

至今我们看到了缓存操作的多个选择并且他们可以被设置。然而一些自定义的操作可以是冗长的配置如果他们应用于所有的类的操作。例如,指定缓存的名字用于每个缓存类的操作应当被替代通过一个类级别的定义。就是@CacheConfig的工作。

 

@CacheConfig("books")

public class BookRepositoryImpl implements BookRepository {

 

    @Cacheable

    public Book findBook(ISBN isbn) {...}

}

 

@CacheConfig is a class-level annotation that allows to share the cache names, the custom KeyGenerator, the custom CacheManager and finally the custom CacheResolver. Placing this annotation on the class does not turn on any caching operation.

@CacheConfig是一个类级别的注解允许共享缓存名、自定义的KeyGenerator、自定义的CacheManager和自定义的CacheResolver。在类上修饰注解没有返回任何缓存操作。

 

An operation-level customization will always override a customization set on @CacheConfig. This gives therefore three levels of customizations per cache operation:

一个操作级别的自定义将覆盖自定义的设置对于@CacheConfig。这给予了三个自定义级别的缓存操作:

 

    Globally configured, available for CacheManager, KeyGenerator

全局的配置,适用于CacheManagerKeyGenerator

    At class level, using @CacheConfig

修饰于类级别,使用@CacheConfig

    At the operation level

修饰于操作级别

 

36.3.6 Enable caching annotations

允许缓存的注解

 

It is important to note that even though declaring the cache annotations does not automatically trigger their actions - like many things in Spring, the feature has to be declaratively enabled (which means if you ever suspect caching is to blame, you can disable it by removing only one configuration line rather than all the annotations in your code).

注意定义缓存注解不需要自动触发他们的行为————类似于许多在spring中的内容,这个特定被定义为开启(意味着如果你需要可以关闭它通过去除一个配置行而不是所有代码中的注解)。

 

To enable caching annotations add the annotation @EnableCaching to one of your @Configuration classes:

为了开启缓存注解添加@EnableCaching到其中一个@Configuration的类上:

 

@Configuration

@EnableCaching

public class AppConfig {

}

 

Alternatively for XML configuration use the cache:annotation-driven element:

作为XML的配置可以使用cache:annotation-driven元素:

 

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xmlns:cache="http://www.springframework.org/schema/cache"

    xsi:schemaLocation="

        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd

        http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">

 

        <cache:annotation-driven />

 

</beans>

 

Both the cache:annotation-driven element and @EnableCaching annotation allow various options to be specified that influence the way the caching behavior is added to the application through AOP. The configuration is intentionally similar with that of @Transactional:

cache:annotation-driven元素和@EnableCaching注解允许不同操作来被指定影响缓存的行为被添加到应用上通过AOP。配置是相似的对于@Transactional

 

[Note]

注意

 

Advanced customizations using Java config require to implement CachingConfigurer, refer to the javadoc for more details.

高级的自定义使用Java配置是实现CachingConfigurer,参考javadocs了解更多。

 

Table 36.2. Cache annotation settings

缓存注解设置

XML Attribute

XML属性

Annotation Attribute

注解属性

Default

默认值

Description

描述

cache-manager

N/A (See CachingConfigurer javadocs)

cacheManager

Name of cache manager to use. A default CacheResolver will be initialized behind the scenes with this cache manager (or `cacheManager`if not set). For more fine-grained management of the cache resolution, consider setting the 'cache-resolver' attribute.

使用的缓存管理的名字。默认的CacheResolver将被初始化对于这个缓存管理器(或者不设置的话)。对于更加细节的配置见cache-resolver属性。

cache-resolver

N/A (See CachingConfigurer javadocs)

A SimpleCacheResolver using the configured cacheManager.

The bean name of the CacheResolver that is to be used to resolve the backing caches. This attribute is not required, and only needs to be specified as an alternative to the 'cache-manager' attribute.

CacheResolverbean的名字被使用来解析后备的缓存。这个属性不是必须的并且需要被指定座位cache-manager属性的替代。

key-generator

N/A (See CachingConfigurer javadocs)

SimpleKeyGenerator

Name of the custom key generator to use.

使用的自定义关键字生成器。

error-handler

N/A (See CachingConfigurer javadocs)

SimpleCacheErrorHandler

Name of the custom cache error handler to use. By default, any exception throw during a cache related operations are thrown back at the client.

使用的自定义缓存错误处理器的名字,任意异常在抛出依赖于返回给客户端的操作。

mode

mode

proxy

The default mode "proxy" processes annotated beans to be proxied using Springs AOP framework (following proxy semantics, as discussed above, applying to method calls coming in through the proxy only). The alternative mode "aspectj" instead weaves the affected classes with Springs AspectJ caching aspect, modifying the target class byte code to apply to any kind of method call. AspectJ weaving requires spring-aspects.jar in the classpath as well as load-time weaving (or compile-time weaving) enabled. (See the section calledSpring configurationfor details on how to set up load-time weaving.)

默认的代理处理注解被使用spirngAOP框架(符合代理语义,讨论如上,应用于方法调用和属性)。作为aspectj的替代支持印象springAspectJ缓存方面的类,修改目标类的字节码应用方法调用。AspectJ处理要求spring-aspects.jarclass中在加载的时候(或编译的时候)。(将章节spring的配置来了解加载时的相关内容。)

proxy-target-class

proxyTargetClass

FALSE

Applies to proxy mode only. Controls what type of caching proxies are created for classes annotated with the @Cacheable or @CacheEvict annotations. If the proxy-target-class attribute is set to true, then class-based proxies are created. If proxy-target-class is false or if the attribute is omitted, then standard JDK interface-based proxies are created. (See Section 11.6,Proxying mechanismsfor a detailed examination of the different proxy types.)

只应用于代理模式。控制缓存代理的类型被使用@Cacheable@CacheEvict注解创建。如果proxy-target-class设置为true则类基本代理被创建。如果proxy-target-class设置为false或属性没有被设置则标准的JDK基于接个口的代理被创建(见章节11.6,代理的策略来了解细节)。

order

order

Ordered.LOWEST_PRECEDENCE

Defines the order of the cache advice that is applied to beans annotated with @Cacheable or @CacheEvict. (For more information about the rules related to ordering of AOP advice, see the section called Advice ordering.) No specified ordering means that the AOP subsystem determines the order of the advice.

定义缓存advice的属性应用于bean的注解通过@Cacheable@CacheEvict。(更多的信息参考AOPadvice的顺序见章节Advice的顺序。)如果没有指定则AOP子系统决定advice的顺序。

[Note]

注意

 

<cache:annotation-driven/> only looks for @Cacheable/@CachePut/@CacheEvict/@Caching on beans in the same application context it is defined in. This means that, if you put <cache:annotation-driven/> in a WebApplicationContext for a DispatcherServlet, it only checks for beans in your controllers, and not your services. See Section 22.2, The DispatcherServletfor more information.

<cache:annotation-driven/>查找相同应用的bean上的@Cacheable/@CachePut/@CacheEvict/@Caching定义。意味着如果你声明<cache:annotation-driven/>WebApplicationContext用于DispatcherServlet,他只会检查控制器中的bean而不是你的service。见章节22.2,“DispatcherServlet”来了解更多细节。

 

Method visibility and cache annotations

方法可见和缓存注解

 

When using proxies, you should apply the cache annotations only to methods with public visibility. If you do annotate protected, private or package-visible methods with these annotations, no error is raised, but the annotated method does not exhibit the configured caching settings. Consider the use of AspectJ (see below) if you need to annotate non-public methods as it changes the bytecode itself.

当使用代理,你应当应用缓存缓存注解对于公共可见的方法。如果你的方法是protectedprivate或包可见的方法使用这些注解,虽然没有错误会发生但是注解方法不会被指定配置缓存设置。考虑使用AspectJ(见下面)如果你需要修饰一个非公共的方法而改变字节码本身。

 

[Tip]

提示

 

Spring recommends that you only annotate concrete classes (and methods of concrete classes) with the @Cache* annotation, as opposed to annotating interfaces. You certainly can place the @Cache* annotation on an interface (or an interface method), but this works only as you would expect it to if you are using interface-based proxies. The fact that Java annotations are not inherited from interfaces means that if you are using class-based proxies ( proxy-target-class="true") or the weaving-based aspect ( mode="aspectj"), then the caching settings are not recognized by the proxying and weaving infrastructure, and the object will not be wrapped in a caching proxy, which would be decidedly bad.

spring建议你修饰类(和方法)使用@Cache*注解,由于注解接口。你可以替换@Cache*注解对于接口(或一个接口方法),但是他们根据你的期望来工作如果你使用基于接口的代理。实际上Java注解不会继承借款购意味着如果你使用基于类的代理( proxy-target-class="true")或基于处理器的方面( mode="aspectj")。则缓存设置不会被处理通过代理并且object将不会被缓存代理处理,可能会更坏。

 

[Note]

注意

 

In proxy mode (which is the default), only external method calls coming in through the proxy are intercepted. This means that self-invocation, in effect, a method within the target object calling another method of the target object, will not lead to an actual caching at runtime even if the invoked method is marked with @Cacheable - considering using the aspectj mode in this case. Also, the proxy must be fully initialized to provide the expected behaviour so you should not rely on this feature in your initialization code, i.e. @PostConstruct.

在代理模式(默认下),只有外部的方法调用通过代理会被拦截。这意味着自我保护,因此一个方法对于调用目标object的另一个目标object的方法将导致一个运行时的缓存如果调用的方法使用@Cacheable注解————考虑使用AspectJ模式在例子中。因此代理必须初始化提供明确的行为因此你不应当依赖于这个在你初始化代码中的特性,例如@PostConstruct

 

36.3.7 Using custom annotations

使用自定义的注解

 

Custom annotation and AspectJ

自定义的注解和AspectJ

 

This feature only works out-of-the-box with the proxy-based approach but can be enabled with a bit of extra effort using AspectJ.

这个特性用于基于注解的方式当时可以允许一些额外的影响使用AspectJ

 

The spring-aspects module defines an aspect for the standard annotations only. If you have defined your own annotations, you also need to define an aspect for those. Check AnnotationCacheAspect for an example.

spring-aspects模块定义一个aspect只用于标准的注解。如果你定义自己的注解,你应当需要定义一个aspect用于他们。参考AnnotationCacheAspect中的例子。

 

The caching abstraction allows you to use your own annotations to identify what method triggers cache population or eviction. This is quite handy as a template mechanism as it eliminates the need to duplicate cache annotation declarations (especially useful if the key or condition are specified) or if the foreign imports (org.springframework) are not allowed in your code base. Similar to the rest of the stereotype annotations, @Cacheable, @CachePut, @CacheEvict and @CacheConfig can be used as meta-annotations, that is annotations that can annotate other annotations. To wit, let us replace a common @Cacheable declaration with our own, custom annotation:

缓存抽象允许你使用自己的注解来定义方法触发器缓存的存储或删除。就是处理一个模板策略需要重复缓存注解定义(尤其是有用的如果关键字或条件被指定)或他的外部导入(org.springframework)不允许在你的代码中。类似的其他的注解,@Cacheable@CachePut@CacheEvict@CacheConfig可以被使用作为一个元注解,就是注解可以注解多个注解。就是意味着我们替换一个通用的@Cacheable定义使用你自定义的注解:

 

@Retention(RetentionPolicy.RUNTIME)

@Target({ElementType.METHOD})

@Cacheable(cacheNames="books", key="#isbn")

public @interface SlowService {

}

 

Above, we have defined our own SlowService annotation which itself is annotated with @Cacheable - now we can replace the following code:

上面,我们定义了我们自己的SlowService注解使用了注解@Cacheable————现在我们可以替换下面的代码:

 

@Cacheable(cacheNames="books", key="#isbn")

public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)

 

with:

 

@SlowService

public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)

 

Even though @SlowService is not a Spring annotation, the container automatically picks up its declaration at runtime and understands its meaning. Note that as mentioned above, the annotation-driven behavior needs to be enabled.

因此@SlowService不是spring的注解,容器自动使用它的定义并且理解他的含义。注意上面提到的,基于注解的行为需要被设置为允许。

 

36.4 JCache (JSR-107) annotations

JCache注解

 

Since the Spring Framework 4.1, the caching abstraction fully supports the JCache standard annotations: these are @CacheResult, @CachePut, @CacheRemove and @CacheRemoveAll as well as the @CacheDefaults, @CacheKey and @CacheValue companions. These annotations can be used right the way without migrating your cache store to JSR-107: the internal implementation uses Springs caching abstraction and provides default CacheResolver and KeyGenerator implementations that are compliant with the specification. In other words, if you are already using Springs caching abstraction, you can switch to these standard annotations without changing your cache storage (or configuration, for that matter).

自从spring框架4.1,缓存抽象全面支持JCache标准注解:就是@CacheResult@CachePut@CacheRemove@CacheRemoveAll以及@CacheDefaults@CacheKey@CacheValue。这些注解可以使用不需要组合存储对于JSR-107:内部的实现使用spring的缓存抽象并且提供了默认的CacheResolverKeyGenerator实现符合规范。也就是说如果你已经使用了spring的缓存抽象,你可以切换标准注解而不需要改变你的缓存存储(配置)。

 

36.4.1 Features summary

特性总结

 

For those who are familiar with Springs caching annotations, the following table describes the main differences between the Spring annotations and the JSR-107 counterpart:

对于熟悉spring缓存的注解,下面的表格展示了主要的差异对于spring的注解和JSR-107的部分:

 

Table 36.3. Spring vs. JSR-107 caching annotations

spring vs JSR-107缓存注解

Spring

JSR-107

Remark

注意

@Cacheable

@CacheResult

Fairly similar. @CacheResult can cache specific exceptions and force the execution of the method regardless of the content of the cache.

十分相似。@CacheResult可以缓存指定的异常并且强制执行方法忽略缓存的内容

@CachePut

@CachePut

While Spring updates the cache with the result of the method invocation, JCache requires to pass it as an argument that is annotated with @CacheValue. Due to this difference, JCache allows to update the cache before or after the actual method invocation.

spring根据方法的调用更新缓存。JCache要求传递参数使用@CacheValue。由于这个不同,JCache允许更新缓存在方法调用的前后。

@CacheEvict

@CacheRemove

Fairly similar. @CacheRemove supports a conditional evict in case the method invocation results in an exception.

十分相似,@CacheRemove支持条件删除缓存由于方法调用的结果以及异常。

@CacheEvict(allEntries=true)

@CacheRemoveAll

See @CacheRemove.

@CacheRemove

@CacheConfig

@CacheDefaults

Allows to configure the same concepts, in a similar fashion.

允许配置相同的内容以相同的方式。

JCache has the notion of javax.cache.annotation.CacheResolver that is identical to the Springs CacheResolver interface, except that JCache only supports 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, check the javadoc of @CacheResult#cacheName() for more information.

JCache意识到javax.cache.annotation.CacheResolverspringCacheResolver的接口相同,除了JCache支持单个缓存。默认的,一个简单的实现处理缓存使用用基于名字的定义对于注解。应当意识到如果缓存名被指定则默认是自动生成的,可以查看@CacheResult来了解更多信息。

 

CacheResolver instances are retrieved by a CacheResolverFactory. It is possible to customize the factory per cache operation:

CacheResolver实例处理CacheResolverFactory。可以自定义工厂对于每个操作。

 

@CacheResult(cacheNames="books", cacheResolverFactory=MyCacheResolverFactory.class)

public Book findBook(ISBN isbn)

 

[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.

对于所有的引用类,spring试图定位给定类型的bean。如果有多个匹配,一个新的实例被创建并且可以使用正常的bean的生命周期回调例如依赖注入。

 

Keys are generated by a javax.cache.annotation.CacheKeyGenerator that serves the same purpose as Springs KeyGenerator. By default, all method arguments are taken into account unless at least one parameter is annotated with @CacheKey. This is similar to Springs custom key generation declaration. For instance these are identical operations, one using Springs abstraction and the other with JCache:

Keys通过javax.cache.annotation.CacheKeyGenerator生成服务的目的和springKeyGenerator相同。默认的,所有的方法参数被考虑除了至少一个参数被声明使用了@CacheKey。这和spring的自定义key生成定义是相似的。例如他们的操作一个使用了spring的抽象而另一个使用了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)

 

The CacheKeyResolver to use can also be specified on the operation, in a similar fashion as the CacheResolverFactory.

CacheKeyResolver被使用可以修饰一个操作,类似于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. Lets 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 parameter. The following caches the exception so that further calls with the same, invalid ISBN, throws the cached exception directly instead of invoking the method again.

JCache可以管理抛出的异常通过注解方法:可以阻止缓存的更新但是也可以换成异常作为错误的只是代替再次回调方法。我们假设InvalidIsbnNotFoundException被抛出由于ISBN不合法。这是一个永久性的错误,没有书可以匹配这样的参数。下面缓存的异常因此再次调用相同的非法ISBN时会抛出缓存的异常替代方法的再次执行。

 

@CacheResult(cacheName="books", exceptionCacheName="failures"

             cachedExceptions = InvalidIsbnNotFoundException.class)

public Book findBook(ISBN isbn)

 

36.4.2 Enabling JSR-107 support

启用JSR-107支持

 

Nothing specific needs to be done to enable the JSR-107 support alongside Springs declarative annotation support. Both @EnableCaching and the cache:annotation-driven element will enable automatically the JCache support if both the JSR-107 API and the spring-context-support module are present in the classpath.

对于启用JSR-107支持没有额外的操作对于spring的声明式注解支持。@EnableCachingcache:annotation-driven元素将自动启用JCache支持包括JSR-107APIspring-context-support模块在classpath中。

 

[Note]

注意

 

Depending of your use case, the choice is basically yours. You can even mix and match services using the JSR-107 API and others using Springs own annotations. Be aware however that if these services are impacting the same caches, a consistent and identical key generation implementation should be used.

依赖于你的使用,选择权在于你。你可以混合并且匹配服务使用JSR-107API或使用spring自己的注解。注意如果服务是相同的缓存,一致性和确定的key生成实现应当被使用。

 

36.5 Declarative XML-based caching

声明式基于XML的缓存

 

If annotations are not an option (no access to the sources or no external code), one can use XML for declarative caching. So instead of annotating the methods for caching, one specifies the target method and the caching directives externally (similar to the declarative transaction management advice). The previous example can be translated into:

如果注解不是一个可选项(不能访问源码或其他代码),可以使用XML用于声明缓存。因此为了替代对于缓存方法的声明,可以指定目标方法和外部缓存指令(类似于声明式的事务管理通知)。之前的例子可以被转换为:

 

<!-- the service we want to make cacheable -->

<bean id="bookService" class="x.y.service.DefaultBookService"/>

 

<!-- cache definitions -->

<cache:advice id="cacheAdvice" cache-manager="cacheManager">

    <cache:caching cache="books">

        <cache:cacheable method="findBook" key="#isbn"/>

        <cache:cache-evict method="loadBooks" all-entries="true"/>

    </cache:caching>

</cache:advice>

 

<!-- apply the cacheable behavior to all BookService interfaces -->

<aop:config>

    <aop:advisor advice-ref="cacheAdvice" pointcut="execution(* x.y.BookService.*(..))"/>

</aop:config>

 

<!-- cache manager definition omitted -->

 

In the configuration above, the bookService is made cacheable. The caching semantics to apply are encapsulated in the cache:advice definition which instructs method findBooks to be used for putting data into the cache while method loadBooks for evicting data. Both definitions are working against the books cache.

在上面的配置中,bookService是可以缓存的。缓存语义被保存在cache:advice定义中指定了方法findBooks使用放入的数据到缓存中当方法loadBooks抛弃数据时。这两个定义都可以使用book缓存。

 

The aop:config definition applies the cache advice to the appropriate points in the program by using the AspectJ pointcut expression (more information is available in Chapter 11, Aspect Oriented Programming with Spring). In the example above, all methods from the BookService are considered and the cache advice applied to them.

aop:config定义应用于缓存通知对于适当的程序的位置通过使用AspectJ的表达式(在第一章中有更多的相关信息,使用spring的面向切面的编程)。在上面的例子中,所有的方法来自BookService可以被考虑使用缓存通知。

 

The declarative XML caching supports all of the annotation-based model so moving between the two should be fairly easy - further more both can be used inside the same application. The XML based approach does not touch the target code however it is inherently more verbose; when dealing with classes with overloaded methods that are targeted for caching, identifying the proper methods does take an extra effort since the method argument is not a good discriminator - in these cases, the AspectJ pointcut can be used to cherry pick the target methods and apply the appropriate caching functionality. However through XML, it is easier to apply a package/group/interface-wide caching (again due to the AspectJ pointcut) and to create template-like definitions (as we did in the example above by defining the target cache through the cache:definitions cache attribute).

声明式的XML缓存支持所有的基于注解的模型因此可以在两个之间移动数据————也可以在相同的应用中使用他们。基于XML的方式不需要生成目标代码然而其内部是复杂的,当处理重载的方法是目标可以用于缓存,定义适当的方法使用额外的方法参数不是一个好的决定————在这些例子中AspectJ的切点可以使用来获取目标方法和应用适当的缓存功能。然而通过XML可以简单的应用包、组、接口范围的缓存(对于AspectJ的切点)和创建类似于模板的定义(就像我们在上面的例子中定义了目标缓存通过cache:definitions的属性)。

 

36.6 Configuring the cache storage

配置缓存的存储

 

Out of the box, the cache abstraction provides several storage integration. To use them, one needs to simply declare an appropriate CacheManager - an entity that controls and manages Caches and can be used to retrieve these for storage.

缓存抽象提供了一些存储集成。为了使用他们,需要简单的定义一个适当的CacheManager————一个实体控制和管理缓存并且可以使用来接收他们。

 

36.6.1 JDK ConcurrentMap-based Cache

JDK基于ConcurrentMap的缓存

 

The JDK-based Cache implementation resides under org.springframework.cache.concurrent package. It allows one to use ConcurrentHashMap as a backing Cache store.

基于JDK的缓存实现存在于org.springframework.cache.concurrent包中。他允许使用ConcurrentHashMap作为后备的缓存存储。

 

<!-- simple cache manager -->

<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">

    <property name="caches">

        <set>

            <bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="default"/>

            <bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="books"/>

        </set>

    </property>

</bean>

 

The snippet above uses the SimpleCacheManager to create a CacheManager for the two nested ConcurrentMapCache instances named default and books. Note that the names are configured directly for each cache.

上面的片段使用了SimpleCacheManager来创建一个CacheManager用于两个内置的ConcurrentMapCache实例名字为defaultbooks。注意他们的名字被直接配置用于每个缓存。

 

As the cache is created by the application, it is bound to its lifecycle, making it suitable for basic use cases, tests or simple applications. The cache scales well and is very fast but it does not provide any management or persistence capabilities nor eviction contracts.

由于缓存被创建通过应用,他绑定到生命周期使得可以适合于基本的使用情况、测试和简单的应用。缓存范围当时他不支持任何参数和持久化的能力不需要被废弃。

 

36.6.2 Ehcache-based Cache

基于Ehcache的缓存

 

[Note]

注意

 

Ehcache 3.x is fully JSR-107 compliant and no dedicated support is required for it.

Ehcache3.x版本是全面支持JSR-107并且没有强制的支持被要求。

 

The Ehcache 2.x implementation is located under org.springframework.cache.ehcache package. Again, to use it, one simply needs to declare the appropriate CacheManager:

Ehcache2.x实现定位到org.springframework.cache.ehcache包中。再次为了使用它,可以简单是需要定义适当的CacheManager

 

<bean id="cacheManager"

      class="org.springframework.cache.ehcache.EhCacheCacheManager" p:cache-manager-ref="ehcache"/>

 

<!-- EhCache library setup -->

<bean id="ehcache"

      class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:config-location="ehcache.xml"/>

 

This setup bootstraps the ehcache library inside Spring IoC (through the ehcache bean) which is then wired into the dedicated CacheManager implementation. Note the entire ehcache-specific configuration is read from ehcache.xml.

设置启动ehcache库在springIOC中(通过ehcachebean)处理定义的CacheManager实现。注意整个指定ehcache的配置可以从ehcache.xml中阅读。

 

36.6.3 Caffeine Cache

 

Caffeine is a Java 8 rewrite of Guavas cache and its implementation is located under org.springframework.cache.caffeine package and provides access to several features of Caffeine.

CaffeineJava重写Guava的缓存并且他的实现被放置在org.springframework.cache.caffeine包中并且提供了访问对于一些Caffeine的特性。

 

Configuring a CacheManager that creates the cache on demand is straightforward:

配置一个CacheManager来直接创建一个缓冲:

 

<bean id="cacheManager"

      class="org.springframework.cache.caffeine.CaffeineCacheManager"/>

 

It is also possible to provide the caches to use explicitly. In that case, only those will be made available by the manager:

他也明确提供了缓存来使用。在这个例子中,其中一个使用管理器来配置。

 

<bean id="cacheManager" class="org.springframework.cache.caffeine.CaffeineCacheManager">

    <property name="caches">

        <set>

            <value>default</value>

            <value>books</value>

        </set>

    </property>

</bean>

 

The Caffeine CacheManager also supports customs Caffeine and CacheLoader. See the Caffeine documentation for more information about those.

CaffeineCacheManager也支持自定义的CaffeineCacheLoader。见Caffeine文档来了解更多内容。

 

36.6.4 Guava Cache

 

The Guava implementation is located under org.springframework.cache.guava package and provides access to several features of Guava.

Guava实现配置在org.springframework.cache.guava包中并且提供了一些Guava的特性。

 

Configuring a CacheManager that creates the cache on demand is straightforward:

配置一个CacheManager创建可以直接创建缓存。

 

<bean id="cacheManager"

      class="org.springframework.cache.guava.GuavaCacheManager"/>

 

It is also possible to provide the caches to use explicitly. In that case, only those will be made available by the manager:

他可以提供直接使用的缓存。在这个例子中,将可以通过管理器来实现。

 

<bean id="cacheManager" class="org.springframework.cache.guava.GuavaCacheManager">

    <property name="caches">

        <set>

            <value>default</value>

            <value>books</value>

        </set>

    </property>

</bean>

 

The Guava CacheManager also supports customs CacheBuilder and CacheLoader. See the Guava documentation for more information about those.

Guava的缓存管理器也支持自定义的CacheBuilderCacheLoader。见Guava的文档来了解更多内容。

 

36.6.5 GemFire-based Cache

基于GemFire的缓存

 

GemFire is a memory-oriented/disk-backed, elastically scalable, continuously available, active (with built-in pattern-based subscription notifications), globally replicated database and provides fully-featured edge caching. For further information on how to use GemFire as a CacheManager (and more), please refer to the Spring Data GemFire reference documentation.

GemFire是一个面向内存以磁盘作为后备的伸缩性强、持久可用、活动的(内置基于模式的定义通知),全局的备份数据库提供了全功能的边缘缓存。对于更多的信息关于如何使用GemFire作为缓存管理器,请参考spring DataGemFire参考文档。

 

36.6.6 JSR-107 Cache

JSR-107缓存

 

JSR-107 compliant caches can also be used by Springs caching abstraction. The JCache implementation is located under org.springframework.cache.jcache package.

JSR-107缓存可以使用通过spring的缓存抽象。JCache实现在org.springframework.cache.jcache包中。

 

Again, to use it, one simply needs to declare the appropriate CacheManager:

使用它,需要定义适当的缓存管理器:

 

<bean id="cacheManager"

      class="org.springframework.cache.jcache.JCacheCacheManager"

      p:cache-manager-ref="jCacheManager"/>

 

<!-- JSR-107 cache manager setup  -->

<bean id="jCacheManager" .../>

 

36.6.7 Dealing with caches without a backing store

处理没有后备的缓存

 

Sometimes when switching environments or doing testing, one might have cache declarations without an actual backing cache configured. As this is an invalid configuration, at runtime an exception will be thrown since the caching infrastructure is unable to find a suitable store. In situations like this, rather then removing the cache declarations (which can prove tedious), one can wire in a simple, dummy cache that performs no caching - that is, forces the cached methods to be executed every time:

有时当切换环境或在测试中,可以使用缓存定义不需要一个实际的后备配置。因此一个无效的配置在运行时会抛出异常因为缓存不能找到一个合适的存储。在这样的情况下,需要删除缓存定义(可以提供冗余),可以使用简单的虚拟的缓存来实现无缓存————就是强制缓存方法每次都执行。

 

<bean id="cacheManager" class="org.springframework.cache.support.CompositeCacheManager">

    <property name="cacheManagers">

        <list>

            <ref bean="jdkCache"/>

            <ref bean="gemfireCache"/>

        </list>

    </property>

    <property name="fallbackToNoOpCache" value="true"/>

</bean>

 

The CompositeCacheManager above chains multiple CacheManagers and additionally, through the fallbackToNoOpCache flag, adds a no op cache that for all the definitions not handled by the configured cache managers. That is, every cache definition not found in either jdkCache or gemfireCache (configured above) will be handled by the no op cache, which will not store any information causing the target method to be executed every time.

上面的CompositeCacheManager使用了多个CacheManagers,通过fallbackToNoOpCache标志,添加的无操作缓存对于所有的定义配置过缓存管理器。就是每个缓存定义没有在jdkCache中或gemfireCache中(配置如上)将被处理为无缓存,并且不会存储目标方法的信息并且方法每次都会被执行。

 

36.7 Plugging-in different back-end caches

插件不同的后备缓存

 

Clearly there are plenty of caching products out there that can be used as a backing store. To plug them in, one needs to provide a CacheManager and Cache implementation since unfortunately there is no available standard that we can use instead. This may sound harder than it is since in practice, the classes tend to be simple adapters that map the caching abstraction framework on top of the storage API as the ehcache classes can show. Most CacheManager classes can use the classes in org.springframework.cache.support package, such as AbstractCacheManager which takes care of the boiler-plate code leaving only the actual mapping to be completed. We hope that in time, the libraries that provide integration with Spring can fill in this small configuration gap.

有许多缓存产品可以被用于后备缓存。为了实现插件话,需要提供CacheManagerCache实现对于我们使用的非标准化缓存。就是存储起来,类绑定一个适配器匹配缓存抽象框架对于存储API的顶层作为缓存类可以被展示。大部分CacheManager的类可以使用在org.springframework.cache.support包中的类,例如AbstractCacheManager可以处理boiler-palte代码不需要实际的匹配。我们同时希望,spring中提供的集成可以处理这个小的配置。

 

36.8 How can I set the TTL/TTI/Eviction policy/XXX feature?

我可以如何设置TTL/TTI/Eviction policy/XXX特性?

 

Directly through your cache provider. The cache abstraction is…​well, an abstraction not a cache implementation. The solution you are using might support various data policies and different topologies which other solutions do not (take for example the JDK ConcurrentHashMap) - exposing that in the cache abstraction would be useless simply because there would no backing support. Such functionality should be controlled directly through the backing cache, when configuring it or through its native API.

通过你的缓存提供者。缓存抽象,一个缓存抽象不是一个缓存实现。你可以使用的解决方法支持不同的数据策略和不同的拓扑结构并且其他的解决方案不会(考虑JDKConcurrentHashMap)————暴露缓存抽象除非很简单因此他们没有后备的支持,例如功能可以被直接控制通过后备缓存当使用本地的API来配置他的时候。

 

 

阅读全文
0 0
原创粉丝点击