带有 key="#id" 的 @CacheEvict 抛出 NullPointerException
@CacheEvict with key="#id" throws NullPointerException
我正在尝试将 Spring 缓存注释 @Cacheable
和 @CacheEvict
与 GuavaCacheManager 一起使用。
我已经用这两个测试创建了一个测试用例:
cachesById
- 验证对使用 @Cacheable
returns 注释的方法的两次调用是同一个对象
evict
- 如果在这两个调用之间调用了带有 @CacheEvict
注释的方法,则验证是否返回了两个不同的实例
当我没有为 @CacheEvict
指定密钥时,两者都工作正常,但是当我这样做时,我得到以下异常:
java.lang.NullPointerException
at com.google.common.base.Preconditions.checkNotNull(Preconditions.java:210)
at com.google.common.cache.LocalCache$LocalManualCache.invalidate(LocalCache.java:4764)
at org.springframework.cache.guava.GuavaCache.evict(GuavaCache.java:135)
at org.springframework.cache.interceptor.AbstractCacheInvoker.doEvict(AbstractCacheInvoker.java:95)
at org.springframework.cache.interceptor.CacheAspectSupport.performCacheEvict(CacheAspectSupport.java:409)
at org.springframework.cache.interceptor.CacheAspectSupport.processCacheEvicts(CacheAspectSupport.java:392)
at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:362)
at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:299)
at org.springframework.cache.interceptor.CacheInterceptor.invoke(CacheInterceptor.java:61)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:653)
at com.myorg.caching.CacheTest$Repo$$EnhancerBySpringCGLIB$$eed50f3e.update(<generated>)
at com.myorg.caching.CacheTest.evict(CacheTest.java:50)
这可以通过执行以下测试来重现。
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
classes = { Repo.class, CacheTest.SpringConfig.class },
loader = AnnotationConfigContextLoader.class)
public class CacheTest {
private static final String CACHE_NAME = "cacheName";
@Inject
private Repo repo;
@Test
public void cachesById() {
Entity aResult1 = repo.getEntity(1);
Entity aResult2 = repo.getEntity(1);
assertEquals(aResult1.getId(), aResult2.getId());
assertSame(aResult1, aResult2);
}
@Test
public void evict() {
Entity aResult1 = repo.getEntity(1);
repo.update(aResult1);
Entity aResult2 = repo.getEntity(1);
assertEquals(aResult1.getId(), aResult2.getId());
assertNotSame(aResult1, aResult2);
}
/** Mock repository/entity classes below. */
@Component
public static class Repo {
@Cacheable(value = CACHE_NAME, key = "#id")
public Entity getEntity(int id) {
return new Entity(id);
}
@CacheEvict(value = CACHE_NAME, key = "#id")
public void update(Entity e) {
}
}
public static class Entity {
private int id;
public Entity(int id) {
super();
this.id = id;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
/** Guava Cachemanager Spring configuration */
@Configuration
@EnableCaching
public static class SpringConfig {
@Bean
public CacheManager cacheManager() {
GuavaCacheManager manager = new GuavaCacheManager(CACHE_NAME);
manager.setCacheBuilder(CacheBuilder.newBuilder().expireAfterWrite(
1, TimeUnit.MINUTES).recordStats());
return manager;
}
}
}
但是如果我改变测试通过
@CacheEvict(value = CACHE_NAME, key = "#id")
public void update(Entity e) {
进入:
@CacheEvict(value = CACHE_NAME)
public void update(Entity e) {
..但是我错过了需要为 Entity
指定缓存键的地方。有谁知道我错过了什么?
谢谢!
您必须从
修复组件 class
@Component
public static class Repo {
@Cacheable(value = CACHE_NAME, key = "#id")
public Entity getEntity(int id) {
return new Entity(id);
}
@CacheEvict(value = CACHE_NAME, key = "#id")
public void update(Entity e) {
}
}
到
@Component
public static class Repo {
@Cacheable(value = CACHE_NAME, key = "#id")
public Entity getEntity(int id) {
return new Entity(id);
}
@CacheEvict(value = CACHE_NAME, key = "#e?.id")
public void update(Entity e) {
}
}
为什么?在 getEntity
方法中,您使用 int id
缓存一个 Entity
对象,您必须将相同的 int id
传递到 @CacheEvict
注释方法中。您不必更改方法的签名 - 通过使用 SPEL,您可以 "get into" 实体并使用其 id 字段。
希望我有所帮助。
我正在尝试将 Spring 缓存注释 @Cacheable
和 @CacheEvict
与 GuavaCacheManager 一起使用。
我已经用这两个测试创建了一个测试用例:
cachesById
- 验证对使用@Cacheable
returns 注释的方法的两次调用是同一个对象evict
- 如果在这两个调用之间调用了带有@CacheEvict
注释的方法,则验证是否返回了两个不同的实例
当我没有为 @CacheEvict
指定密钥时,两者都工作正常,但是当我这样做时,我得到以下异常:
java.lang.NullPointerException
at com.google.common.base.Preconditions.checkNotNull(Preconditions.java:210)
at com.google.common.cache.LocalCache$LocalManualCache.invalidate(LocalCache.java:4764)
at org.springframework.cache.guava.GuavaCache.evict(GuavaCache.java:135)
at org.springframework.cache.interceptor.AbstractCacheInvoker.doEvict(AbstractCacheInvoker.java:95)
at org.springframework.cache.interceptor.CacheAspectSupport.performCacheEvict(CacheAspectSupport.java:409)
at org.springframework.cache.interceptor.CacheAspectSupport.processCacheEvicts(CacheAspectSupport.java:392)
at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:362)
at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:299)
at org.springframework.cache.interceptor.CacheInterceptor.invoke(CacheInterceptor.java:61)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:653)
at com.myorg.caching.CacheTest$Repo$$EnhancerBySpringCGLIB$$eed50f3e.update(<generated>)
at com.myorg.caching.CacheTest.evict(CacheTest.java:50)
这可以通过执行以下测试来重现。
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
classes = { Repo.class, CacheTest.SpringConfig.class },
loader = AnnotationConfigContextLoader.class)
public class CacheTest {
private static final String CACHE_NAME = "cacheName";
@Inject
private Repo repo;
@Test
public void cachesById() {
Entity aResult1 = repo.getEntity(1);
Entity aResult2 = repo.getEntity(1);
assertEquals(aResult1.getId(), aResult2.getId());
assertSame(aResult1, aResult2);
}
@Test
public void evict() {
Entity aResult1 = repo.getEntity(1);
repo.update(aResult1);
Entity aResult2 = repo.getEntity(1);
assertEquals(aResult1.getId(), aResult2.getId());
assertNotSame(aResult1, aResult2);
}
/** Mock repository/entity classes below. */
@Component
public static class Repo {
@Cacheable(value = CACHE_NAME, key = "#id")
public Entity getEntity(int id) {
return new Entity(id);
}
@CacheEvict(value = CACHE_NAME, key = "#id")
public void update(Entity e) {
}
}
public static class Entity {
private int id;
public Entity(int id) {
super();
this.id = id;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
/** Guava Cachemanager Spring configuration */
@Configuration
@EnableCaching
public static class SpringConfig {
@Bean
public CacheManager cacheManager() {
GuavaCacheManager manager = new GuavaCacheManager(CACHE_NAME);
manager.setCacheBuilder(CacheBuilder.newBuilder().expireAfterWrite(
1, TimeUnit.MINUTES).recordStats());
return manager;
}
}
}
但是如果我改变测试通过
@CacheEvict(value = CACHE_NAME, key = "#id")
public void update(Entity e) {
进入:
@CacheEvict(value = CACHE_NAME)
public void update(Entity e) {
..但是我错过了需要为 Entity
指定缓存键的地方。有谁知道我错过了什么?
谢谢!
您必须从
修复组件 class@Component
public static class Repo {
@Cacheable(value = CACHE_NAME, key = "#id")
public Entity getEntity(int id) {
return new Entity(id);
}
@CacheEvict(value = CACHE_NAME, key = "#id")
public void update(Entity e) {
}
}
到
@Component
public static class Repo {
@Cacheable(value = CACHE_NAME, key = "#id")
public Entity getEntity(int id) {
return new Entity(id);
}
@CacheEvict(value = CACHE_NAME, key = "#e?.id")
public void update(Entity e) {
}
}
为什么?在 getEntity
方法中,您使用 int id
缓存一个 Entity
对象,您必须将相同的 int id
传递到 @CacheEvict
注释方法中。您不必更改方法的签名 - 通过使用 SPEL,您可以 "get into" 实体并使用其 id 字段。
希望我有所帮助。