Spring 可缓​​存注释在部署完成之前不起作用

Spring cacheable annotation doesn't work before deployment completes

我有以下 类 和接口(为了清楚起见进行了简化)。

@Serivce
class Service1 {

    @Cacheable("cacheName")
    public Metadata preLoadMetadata() {
        // load data from database
    }
}

@Service
class Service2 implements Loader {

    @Autowired @Lazy
    private Service1 service1;

    @Overrride
    public CacheWrapper getCacheWrapper() {
        return new CacheWrapper(() -> service1.preLoadMetadata());
    }
}

interface Loader {
    CacheWrapper getCacheWrapper();
}

class CacheWrapper {

    private Callable callable;

    public CacheWrapper(Callable callable) {
         this.callable = callable;
    }

    public getCallable() {
         return callable;
    }
}

部署时负责加载缓存的Spring bean。

@Component
class LoadCache {

    @Autowired
    private List<Loader> allLoaders;

    @PostConstruct
    public void load() {
        allLoaders.getCacheWrapper().getCallable().call();
    }
}

preLoadMetadata() 不会将数据保存在缓存中,但会执行。部署完成后,我再次调用相同的方法preLoadMetadata(),然后将数据保存在缓存中。

为什么 @Cacheable 在部署时不起作用?

如果我手动使用 Cacheput 方法在用 @PostConstruct 注释的方法中填充缓存,我可以在部署时成功完成。

我正在使用 Tomcat 作为服务器。
我在 Spring 缓存抽象之后使用 Couchbase 缓存。

如果您想预加载缓存,我建议您使用 ApplicationListener,它会在您的应用程序启动后执行:

@Component
public class CacheInitializer implements ApplicationListener<ContextRefreshedEvent>{

    @Autowired
    private List<Loader> allLoaders;

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        allLoaders.getCacheWrapper().getCallable().call();
    }
}

Cacheable注解不工作的根本原因: afterSingletonsInstantiated() 方法仅在 BeanFactory 已实例化所有 bean 时才将 initialized 标志设置为 true。如果 initialized 标志为假,则不执行缓存操作。在这里,在 post 构造中,当我们启动 pre-loading 缓存时,很可能 LoadCache 不是最后一个要实例化的 bean。因此,不执行任何缓存操作(使用缓存注释时)。

因此,在这种情况下,响应 ContextRefreshEventEventListener 注释是最好的选择,它确保上下文已经启动,然后只加载缓存。