我正在构建一个“类缓存”,其中包含我想稍后调用的类。
主要目标是我不想每次需要类实例时都扫描上下文。
# Model / Repository classes
@Getter
@RequiredArgsConstructor
public class Block implements Serializable {
private final String className;
private final Set<String> classCandidates = new HashSet<>();
public boolean addCandidate(final String classCandidate) {
return this.classCandidates.add(classCandidate);
}
}
@Slf4j
@Component
@CacheConfig(cacheNames = ConstantsCache.CACHE_BLOCK)
public class BlockRepository {
@Cacheable(key = "#className")
public Block findByInputClass(final String className) {
log.info("---> Loading classes for class '{}'", className);
val block = new Block(className);
findCandidates(block);
return block;
}
}
首先评估缓存,我将缓存方法 @Autowired 放在 @RestController 中,效果很好。当我调用 rest 方法时缓存被填充。
@RestController
public class Controller {
@Autowired
BlockRepository blockRepository;
@RequestMapping("/findByInputClass")
public Block findByInputClass(@RequestParam("className") final String className) {
return blockRepository.findByInputClass(className);
}
}
这样做之后,我将 @Autowired 对象移动到 @Service,创建一个自填充缓存的方法。但这不起作用。调用 @PostConstructor 方法时不会填充缓存。
@Slf4j
@Component
public class BlockCacheService {
@Autowired
BlockRepository blockRepository;
@PostConstruct
private void postConstruct() {
log.info("*** {} PostConstruct called.", this.getClass().getTypeName());
val block = blockRepository.findByInputClass(ConstantsGenerics.BLOCK_PARENT_CLASS);
final Set<String> inputClasses = getInputFromCandidates(block.getClassCandidates());
appendClassesToCache(inputClasses);
}
private void appendClassesToCache(final Set<String> inputClasses) {
for (val inputClass : inputClasses) {
blockRepository.findByInputClass(inputClass);
}
}
}
如何使用必须从应用程序开始的服务或组件正确填充缓存。
提前致谢。
编辑:
我在这里找到了一个可能的解决方案:https://stackoverflow.com/a/28311225/1703546
比起我已经更改了 @Service 代码以手动放置缓存,而不是使用 @Cacheable 魔法抽象。
现在的班级是这样的
@Slf4j
@Component
public class BlockCacheService {
@Autowired
CacheManager cacheManager;
@Autowired
BlockRepository blockRepository;
@PostConstruct
private void postConstruct() {
log.info("*** {} PostConstruct called.", this.getClass().getTypeName());
val block = blockRepository.findByInputClass(ConstantsGenerics.BLOCK_PARENT_CLASS);
final Set<String> inputClasses = getInputFromCandidates(block.getClassCandidates());
appendClassesToCache(inputClasses);
}
private void appendClassesToCache(final Set<String> inputClasses) {
for (val inputClass : inputClasses) {
val block = blockRepository.findByInputClass(inputClass);
cacheManager.getCache(ConstantsCache.CACHE_BLOCK).put(block.getClassName(), block);
}
}
}
现在缓存已正确填充,但问题是,这是最好的解决方案吗?
谢谢。
您不能在
@PostConstruct
中使用某个方面,因为它可能尚未创建(并且 顺便记录了)。
完成这项工作的一种可能方法是实施
SmartInitializingBean
,因为它会在所有单例都已完全初始化(包括它们的方面)时提供回调。在您的原始服务上更改它应该有效。
话虽如此,您的这段代码对启动时间有影响。你为什么不让你的缓存被延迟填充呢?