java - Java Spring 4.2.5 Guava Cache 无法添加额外的@Cacheable 注解
问题描述
我正在开发一个现有的 Java 8/Spring 4.2.5 Web 应用程序,并尝试将其使用 Spring 对 Guava Cache 的支持的已经工作的缓存扩展到更多功能,以期提高性能。该应用程序使用 Spring 4 的内置缓存,如在其 CacheConfig 文件中设置的那样:
CacheConfig.java
import com.google.common.cache.CacheBuilder;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurer;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.guava.GuavaCache;
import org.springframework.cache.interceptor.CacheErrorHandler;
import org.springframework.cache.interceptor.CacheResolver;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.cache.support.SimpleCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableCaching
public class CacheConfig implements CachingConfigurer {
@Bean
@Override
public CacheManager cacheManager() {
SimpleCacheManager simpleCacheManager = new SimpleCacheManager();
GuavaCache cache1 = new GuavaCache("hourCache", CacheBuilder.newBuilder()
.expireAfterWrite(60, TimeUnit.MINUTES)
.build());
simpleCacheManager.setCaches(Arrays.asList(cache1));
return simpleCacheManager;
}
@Override
public CacheResolver cacheResolver() {
return null;
}
@Bean
@Override
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object o, Method method, Object... params) {
StringBuilder sb = new StringBuilder();
sb.append(o.getClass().getName());
sb.append(method.getName());
for (Object param : params) {
sb.append(param.toString());
}
return sb.toString();
}
};
}
@Override
public CacheErrorHandler errorHandler() {
return null;
}
}
先前的缓存内容声明是通过注释完成的:
调度响应服务.java
@Cacheable(value = "hourCache", unless="#result == null")
public ScheduleResponse getYearsTypeSummary(HttpServletRequest request) {
ScheduleResponse scheduleResponse = new ScheduleResponse();
YearsType yearsType = null;
String exceptionMsg ="Could not retrieve list of summary years for Schedule.";
scheduleResponse.setMessageText(exceptionMsg);
try {
yearsType = scheduleApiClient.getYears(authenticator.getAuthorizationToken(request), SUMMARY);
} catch (ClientResponseFailure ex) {
handleClientResponseFailure(scheduleResponse, ex.getResponse(), exceptionMsg);
} catch (PrivilegedActionException | GSSException ex) {
handleGenericException(scheduleResponse, ex.getMessage(), exceptionMsg);
} catch (Exception ex) {
handleGenericResponseException(scheduleResponse, ex.getMessage(), exceptionMsg, request);
}
scheduleResponse.setYearsType(yearsType);
return scheduleResponse;
}
但是,当我尝试为以前未缓存的同一个 Java 文件中的另一个函数扩展相同的基于注释的缓存声明时,即:
@Cacheable(value = "hourCache")
public ScheduleResponse getTermTypeSummary(HttpServletRequest request, String year, String term, String sess) {
ScheduleResponse scheduleResponse = new ScheduleResponse();
TermType termType = null;
String exceptionMsg = "Sorry! Could not retrieve the " + term.toUpperCase() + " " + year + " term.";
scheduleResponse.setMessageText(exceptionMsg);
try {
termType = scheduleApiClient.getTerm(authenticator.getAuthorizationToken(request), year, term, SUMMARY, sess);
} catch (ClientResponseFailure ex) {
handleClientResponseFailure(scheduleResponse, ex.getResponse(), exceptionMsg);
} catch (PrivilegedActionException | GSSException ex) {
handleGenericException(scheduleResponse, ex.getMessage(), exceptionMsg);
} catch (Exception ex) {
handleGenericResponseException(scheduleResponse, ex.getMessage(), exceptionMsg, request);
}
scheduleResponse.setTermType(termType);
return scheduleResponse;
}
我收到 NullPointerException 错误:
webmvc.config.CacheConfig$1.generate(CacheConfig.java:48) org.springframework.cache.interceptor.CacheAspectSupport$CacheOperationContext.generateKey(CacheAspectSupport.java:637)
org.springframework.cache.interceptor.CacheAspectSupport.generateKey(CacheAspectSupport.java:490)
org.springframework.cache.interceptor.CacheAspectSupport.findCachedItem(CacheAspectSupport.java:434)
org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:336)
org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:302)
org.springframework.cache.interceptor.CacheInterceptor.invoke(CacheInterceptor.java:61)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:655)
webmvc.response.ScheduleResponseService$$EnhancerBySpringCGLIB$$952eed68.getTermTypeSummary()
webmvc.courses.controller.ScheduleController.displayScheduleTerm(ScheduleController.java:79)
我可以将@Cacheable... 注释添加到任何函数以接收NullPointerException。我不明白为什么我无法将缓存扩展到新函数,因为它没有出现额外的声明或注释来支持代码中其他任何地方的缓存。
有人可以指出我在以这种方式扩展缓存时可能做错了什么,以及如何纠正它?
解决方案
正如 M. Deinum 所说,自定义密钥生成器是问题所在。当其中一个参数为空时,keygenerator 会触发空指针异常。为了纠正这个问题,我将代码修改为:
@Bean
@Override
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object o, Method method, Object... params) {
StringBuilder sb = new StringBuilder();
sb.append(o.getClass().getName());
sb.append(method.getName());
for (Object param : params) {
if (param != null) {
sb.append(param.toString());
}
}
return sb.toString();
}
};
}
它解决了迄今为止我测试过的所有情况的空指针异常。
推荐阅读
- java - 在 Jenkins 上运行测试时桌面应用程序不启动
- angular - Angular 11 构建没有生成足够的延迟块文件
- ruby-on-rails - 根据特定值对记录进行排序 postresql
- excel - 如何将整个txt文件复制到Excel
- vba - 如何将 SentMail 文件夹设置为文件夹?
- javascript - 不符合 Tailwind 自定义颜色
- c++ - 在结构内添加人员信息时出现 C++ 错误
- linux-kernel - DMA 区域足够空闲,但带有 GFP_DMA 的 vmalloc 仍然失败
- sql - 按 JSON 列中的值搜索
- mysql - SQL 查询性能改进