spring - 同一类中的 Spring @Cachable 方法(自调用,代理问题) - 解决它的最佳方法是什么?
问题描述
我正在尝试从同一个类中调用 @Cacheable 方法。
它没有用。因为:
在代理模式(默认)下,仅拦截通过代理传入的外部方法调用。这意味着自调用(实际上,目标对象中的一个方法调用目标对象的另一个方法)不会导致运行时的实际缓存,即使调用的方法标记有@Cacheable。在这种情况下考虑使用 aspectj 模式。此外,代理必须完全初始化以提供预期的行为,因此您不应在初始化代码(即@PostConstruct)中依赖此功能。
这意味着,@Cachable(也称为@Transactional)由 Spring AOP 中的代理类工作。同一类中的内部调用通过“this”而不是代理类进行调用。
为了解决这个问题,我应该通过代理或使用AspectJ(另一个AOP)调用一个方法。所以,我找到了 4 个解决方案。
你的选择是什么?为什么不推荐其他人?
请分享您的意见!
- 使用 AspectJ(另一个 AOP)
- 从 ApplicationContext 获取 Bean 并使用它
@Service
public class UserService implements Service {
@Autowired
private ApplicationContext applicationContext;
private Service self;
@PostConstruct
private void init() {
self = applicationContext.getBean(UserService.class);
}
}
- 使用 @Resource 自动装配 //自 Spring 4.3
@Component
@CacheConfig(cacheNames = "SphereClientFactoryCache")
public class CacheableSphereClientFactoryImpl implements SphereClientFactory {
/**
* 1. Self-autowired reference to proxified bean of this class.
*/
@Resource
private SphereClientFactory self;
@Override
@Cacheable(sync = true)
public SphereClient createSphereClient(@Nonnull TenantConfig tenantConfig) {
// 2. call cached method using self-bean
return self.createSphereClient(tenantConfig.getSphereClientConfig());
}
@Override
@Cacheable(sync = true)
public SphereClient createSphereClient(@Nonnull SphereClientConfig clientConfig) {
return CtpClientConfigurationUtils.createSphereClient(clientConfig);
}
}
- 将类的 Bean 范围设为“原型”而不是“单例”
@Service
@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
class AService {
private final AService _aService;
@Autowired
public AService(AService aService) {
_aService = aService;
}
@Cacheable("employeeData")
public List<EmployeeData> getEmployeeData(Date date){
..println("Cache is not being used");
...
}
public List<EmployeeEnrichedData> getEmployeeEnrichedData(Date date){
List<EmployeeData> employeeData = _aService.getEmployeeData(date);
...
}
}
我是春天的新手:)
实际上,我选择了第4种解决方案,但我觉得这不是一个好方法。因为我只需要通过代理调用缓存方法,它会做几个bean来实现它。
看完文章,我觉得AspectJ是最好的选择。看起来很酷,Spring推荐,很多人也推荐。
但是我不明白 AspectJ 的工作原理(我会学习),我也不知道为什么不推荐其他人。