Spring boot 缓存在@PostConstruct 中不起作用

问题描述 投票:0回答:1

我正在构建一个“类缓存”,其中包含我想稍后调用的类。

主要目标是我不想每次需要类实例时都扫描上下文。

# 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);
        }
    }
}

现在缓存已正确填充,但问题是,这是最好的解决方案吗?

谢谢。

spring-boot concurrenthashmap spring-cache spring-boot-starter
1个回答
0
投票

您不能在

@PostConstruct
中使用某个方面,因为它可能尚未创建(并且 顺便记录了)。

完成这项工作的一种可能方法是实施

SmartInitializingBean
,因为它会在所有单例都已完全初始化(包括它们的方面)时提供回调。在您的原始服务上更改它应该有效。

话虽如此,您的这段代码对启动时间有影响。你为什么不让你的缓存被延迟填充呢?

© www.soinside.com 2019 - 2024. All rights reserved.