@EnableCaching
@EnableCaching注释在应用程序中启用注释驱动的缓存管理功能,并允许我们在应用程序中使用@Cacheable和@CacheEvict注释。
具有类似功能的 XML 等效项是cache:*命名空间:
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public CacheManager cacheManager() {
SimpleCacheManager cacheManager = new SimpleCacheManager();
cacheManager.setCaches(
Arrays.asList(new ConcurrentMapCache("default")));
return cacheManager;
}
}
该注释还有以下选项:
mode — 指示应如何应用缓存建议
order — 指示在特定连接点应用时执行缓存顾问的顺序
proxyTargetClass — 指示是否要创建基于子类 (CGLIB) 的代理,而不是基于标准 Java 接口的代理
此配置再次可以通过实现CachingConfigurerSupport类的@Configuration类进行自定义:
@Configuration
@EnableCaching
public class CacheConfig extends CachingConfigurerSupport {
@Bean
@Override
public CacheManager cacheManager() {
SimpleCacheManager cacheManager = new SimpleCacheManager();
cacheManager.setCaches(
Arrays.asList(new ConcurrentMapCache("default")));
return cacheManager;
}
@Bean
@Override
public KeyGenerator keyGenerator() {
return new MyKeyGenerator();
}
}
当然,我们也可以通过 XML 配置启用缓存管理:
<beans>
<cache:annotation-driven />
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
<property name="caches">
<set>
<bean
class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean"
name="addresses"/>
</set>
</property>
</bean>
</beans>
当然,我们也可以通过 XML 配置启用缓存管理:
@Component
public class SimpleCacheCustomizer
implements CacheManagerCustomizer<ConcurrentMapCacheManager> {
@Override
public void customize(ConcurrentMapCacheManager cacheManager) {
cacheManager.setCacheNames(asList("users", "transactions"));
}
}
CacheAutoConfiguration 自动配置会 选取这些定制器,并在完成初始化之前将它们应用到当前的CacheManager 。
为方法启用缓存行为的最简单方法是使用@Cacheable对其进行划分,并使用将存储结果的缓存名称对其进行参数化:
getAddress ()调用将在实际调用该方法之前首先检查缓存地址,然后缓存结果。
虽然在大多数情况下一个缓存就足够了,但 Spring 框架还支持将多个缓存作为参数传递:
@Cacheable("addresses")
public String getAddress(Customer customer) {...}
@Cacheable({"addresses", "directory"})
public String getAddress(Customer customer) {...}
现在,将所有方法设置为@Cacheable会出现什么问题?
问题是尺寸。我们不想用不经常需要的值填充缓存。缓存可能会变得非常大、非常快,我们可能会保留大量陈旧或未使用的数据。
我们可以使用@CacheEvict注解来指示删除一个或多个/所有值,以便可以将新值再次加载到缓存中:
@CacheEvict(value="addresses", allEntries=true)
public String getAddress(Customer customer) {...}
这里我们使用附加参数allEntries结合要清空的缓存;这将清除缓存地址中的所有条目并为新数据做好准备。
虽然@CacheEvict通过删除陈旧和未使用的条目来减少在大型缓存中查找条目的开销,但我们希望避免从缓存中逐出太多数据。
相反,每当我们更改条目时,我们都会有选择地更新它们。
通过@CachePut注解,我们可以在不干扰方法执行的情况下更新缓存的内容。也就是说,该方法将始终被执行并缓存结果:
@CachePut(value="addresses")
public String getAddress(Customer customer) {...}
@Cacheable和@CachePut之间的区别在于,@Cacheable将跳过运行该方法,而@CachePut将实际运行该方法,然后将其结果放入缓存中。
如果我们想使用多个相同类型的注解来缓存一个方法怎么办?我们来看一个错误的例子:
@CacheEvict("addresses")
@CacheEvict(value="directory", key=customer.name)
public String getAddress(Customer customer) {...}
上面的代码将无法编译,因为 Java 不允许为给定方法声明相同类型的多个注释。
上述问题的解决方法是:`
@Caching(evict = {
@CacheEvict("addresses"),
@CacheEvict(value="directory", key="#customer.name") })
public String getAddress(Customer customer) {...}
如上面的代码片段所示,我们可以使用@Caching将多个缓存注解分组,并使用它来实现我们自己定制的缓存逻辑。
使用@CacheConfig注释,我们可以将一些缓存配置简化到类级别的单个位置,这样我们就不必多次声明:
@CacheConfig(cacheNames={"addresses"})
public class CustomerDataService {
@Cacheable
public String getAddress(Customer customer) {...}
}
有时,缓存可能并不适用于所有情况下的方法。
重用@CachePut注释中的示例,这将每次执行该方法并缓存结果:
@CachePut(value="addresses")
public String getAddress(Customer customer) {...}
果我们想要更多地控制注释何时处于活动状态,我们可以使用条件参数参数化@CachePut,该条件参数采用 SpEL 表达式,并确保根据评估该表达式来缓存结果:
@CachePut(value="addresses", condition="#customer.name=='Tom'")
public String getAddress(Customer customer) {...}
我们还可以根据方法的输出而不是通过except参数的输入来控制缓存:
@CachePut(value="addresses", unless="#result.length()<64")
public String getAddress(Customer customer) {...}`
上述注释将缓存地址,除非它们短于 64 个字符。
重要的是要知道条件和除非参数可以与所有缓存注释结合使用。
这种条件缓存对于管理大型结果非常有效。它对于根据输入参数自定义行为也很有用,而不是对所有操作强制执行通用行为。
基于 XML 的声明式缓存
如果我们无法访问应用程序的源代码,或者想要从外部注入缓存行为,我们还可以使用基于 XML 的声明性缓存。
这是我们的 XML 配置:
<!-- the service that you wish to make cacheable -->
<bean id="customerDataService"
class="com.your.app.namespace.service.CustomerDataService"/>
<bean id="cacheManager"
class="org.springframework.cache.support.SimpleCacheManager">
<property name="caches">
<set>
<bean
class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean"
name="directory"/>
<bean
class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean"
name="addresses"/>
</set>
</property>
</bean>
<!-- define caching behavior -->
<cache:advice id="cachingBehavior" cache-manager="cacheManager">
<cache:caching cache="addresses">
<cache:cacheable method="getAddress" key="#customer.name"/>
</cache:caching>
</cache:advice>
<!-- apply the behavior to all the implementations of CustomerDataService interface->
<aop:config>
<aop:advisor advice-ref="cachingBehavior"
pointcut="execution(* com.your.app.namespace.service.CustomerDataService.*(..))"/>
</aop:config>
这是等效的 Java 配置
@Configuration
@EnableCaching
public class CachingConfig {
@Bean
public CacheManager cacheManager() {
SimpleCacheManager cacheManager = new SimpleCacheManager();
cacheManager.setCaches(Arrays.asList(
new ConcurrentMapCache("directory"),
new ConcurrentMapCache("addresses")));
return cacheManager;
}
}
这是我们的CustomerDataService:
@Component
public class CustomerDataService {
@Cacheable(value = "addresses", key = "#customer.name")
public String getAddress(Customer customer) {
return customer.getAddress();
}
}
标签:customer,缓存,addresses,springmvc,spring,getAddress,EnableCaching,cacheManager,pub
From: https://www.cnblogs.com/dkpp/p/18059730