java - Spring缓存不适用于子类中的覆盖方法
问题描述
我无法让 Spring 缓存与在超类中实现的子类中重写的方法正常工作。例如,我有这个抽象服务:
public interface CrudService<E, I> {
void deleteById(I id);
E create(E item);
}
public abstract class CrudServiceImpl<E, I> {
void deleteById(I id) { // do things }
...
}
我有几个服务为不同的实体 (E) 和 id 类型 (I) 扩展了这个抽象类。我只想缓存其中一个:
public interface LocationService extends CrudService<Location, String> {
@CacheEvict("location")
@Override
void deleteById(String id);
@Cacheable("location")
List<Location> find();
}
@Service
public class LocationServiceImpl extends CrudServiceImpl<Location, String> implements LocationService {
public List<Location> find() { // do things }
}
方法find只定义在 LocationService 中,不在抽象类中。当我从也具有抽象类的组件中调用这些方法时:
public abstract class CrudManager<E, I> {
@Autowired
private CrudService<E, I> crudService;
public void doDelete(I id) {
crudService.deleteById(id);
}
}
@Component
public class LocationManager extends CrudManager<Location, String> {
@Autowired
private LocationService locationService;
public List<Location> doFind() {
return locationService.find();
}
}
我已经确认,当LocationManager.doFind
被调用时,它会触发 LocationService 中定义的缓存操作,但LocationManager.doDelete
不会。
我一直调试到 AbstractFallbackCacheOperationSource.getCacheOperations 意识到它正在搜索操作的方法是:
public default void com.ontech.plantcore.service.LocationService.deleteById(java.lang.Object)
使用 targetClass = LocationServiceImpl.class,而不是我的注释方法 LocationService.deleteById(java.lang.String)。所以 ClassUtils.getMostSpecificMethod 找不到注解的方法,没有操作返回。它发生在 Spring 4.3.14 和 4.1.9 中。
如果我在 LocationManager 中将特定调用添加到 locationService.deleteById 它可以工作,但这只会破坏继承。
我看到它是由于类型擦除,但我不知道如何使它正常工作?
解决方案
在Spring Cache Documentation中@Cache*
,接口方法上的注释不适用于基于类的代理。所以你应该添加@Cache*
到每个想要缓存的类方法。
Spring 建议您仅使用 @Cache* 注释来注释具体类(和具体类的方法),而不是注释接口。您当然可以将 @Cache* 注释放在接口(或接口方法)上,但这仅在您使用基于接口的代理时才起作用。Java 注释不是从接口继承的事实意味着,如果您使用基于类的代理 (proxy-target-class="true") 或基于编织的方面 (mode="aspectj"),则缓存设置为代理和编织基础设施无法识别,并且对象不会被包装在缓存代理中,这将是非常糟糕的。
推荐阅读
- reactjs - document.getElementById(...).getElementsByTagName 不是函数
- google-closure-library - plovr 是否支持最新的闭包库?
- lc3 - 我如何输出用户输入字符串
- javascript - 如何在发送后立即从 RabbitMQ 中的队列中删除消息
- dart - 像 Excel 单元格一样的小部件(可以输入公式,显示的文本是公式的结果)?
- javascript - 如何从作为地图列表的 jquery ajax 响应中检索数据?
- django - Django Admin 查看表子集
- swift - Swift:将base64转换为图像不起作用
- c# - 如何从后台任务在主应用程序上执行功能
- google-maps - google chart geochart 可以免费使用吗?