我无法使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”),那么缓存设置是代理和编织基础设施无法识别,并且该对象不会被包装在缓存代理中,这将是非常糟糕的。