使用@Cacheable 的Spring 缓存在启动@PostConstruct 时不起作用

Posted

技术标签:

【中文标题】使用@Cacheable 的Spring 缓存在启动@PostConstruct 时不起作用【英文标题】:Spring cache using @Cacheable not working on startup @PostConstruct 【发布时间】:2017-06-01 15:41:14 【问题描述】:

我正在使用 Spring,我想在启动我的应用程序之前缓存一些数据。

我在其他帖子中找到了一些使用@PostConstruct 调用我的@Service 方法(注解为@Cacheable)的解决方案,例如。 How to load @Cache on startup in spring? 我这样做了,但是当应用程序启动后我调用 REST 端点,它再次调用此服务方法,它再次发送数据库请求(所以它还没有被缓存)。当我第二次向端点发送请求时,数据被缓存。

结论是在@PostConstruct 上调用Service 方法并没有导致从数据库缓存数据。

是否可以在启动应用程序之前缓存数据?我怎样才能做到这一点?下面是我的代码片段。

@RestController
class MyController 

    private static final Logger logger = LoggerFactory.getLogger(MyController.class);

    @Autowired
    MyService service;

    @PostConstruct
    void init() 
        logger.debug("MyController @PostConstruct started");
        MyObject o = service.myMethod("someString");
        logger.debug("@PostConstruct: " + o);
    

    @GetMapping(value = "api/param")
    MyObject myEndpoint(@PathVariable String param) 
        return service.myMethod(param);
    




@Service
@CacheConfig(cacheNames = "myCache")
class MyServiceImpl implements MyService 

    @Autowired
    MyDAO dao;

    @Cacheable(key = " #param ")
    @Override
    public MyObject myMethod(String param) 
        return dao.findByParam(param);
    



interface MyService 
    MyObject myMethod(String param);



@Repository
interface MyDAO extends JpaRepository<MyObject, Long> 
    MyObject findByParam(String param);



@SpringBootApplication
@EnableConfigurationProperties
@EnableCaching
public class MyApplication 
    public static void main(String[] args) 
        SpringApplication.run(MyApplication.class, args);
    

    @Primary
    @Bean
    public CacheManager jdkCacheManager() 
        return new ConcurrentMapCacheManager("myCache");
    

【问题讨论】:

尝试在@PostConstruct 中执行此操作通常是一个坏主意,它可能会过早运行(没有创建代理,因此没有应用 AOP)。最好在侦听ContextRefreshedEvents 的ApplicationListener 中执行此类操作。那就是告诉你一切都已经开始的触发器,你现在可以调用缓存方法了。 @M.Deinum 好的,但我需要在启动 REST 端点并侦听请求之前启动缓存。我该怎么做? 一旦 dispatcherservlet 启动,它就会在监听...如前所述,使用ApplicationListener 以确保安全。 @M.Deinum 谢谢,这解决了我的问题! 【参考方案1】:

尝试使用ApplicationStartedEvent 代替@PostConstruct 注释。

我遇到了同样的问题,这个小改动解决了它。

你应该添加 @EventListener(classes = ApplicationStartedEvent.class) 在您的方法之上并通过 ApplicationStartedEvent event 作为参数。

例子:

@EventListener(classes = ApplicationStartedEvent.class)
void init(ApplicationStartedEvent event) 
    MyObject o = service.myMethod("someString");

【讨论】:

【参考方案2】:

@PostConstruct 将适用于您的情况。带有@PostConstruct 注解的方法将在方法bean 被实例化后立即被调用。

但是,如果您依赖于其他 bean,并且您在应用程序上下文完全启动后调用您的方法?你可以像这样创建一个新的bean:

@Component
public class MyListener 
        implements ApplicationListener<ContextRefreshedEvent> 

    public void onApplicationEvent(ContextRefreshedEvent event) 
        //Here call your method of cache
        // Your methode will be called after the application context has fully started
    

【讨论】:

以上是关于使用@Cacheable 的Spring 缓存在启动@PostConstruct 时不起作用的主要内容,如果未能解决你的问题,请参考以下文章

详解Spring缓存注解@Cacheable,@CachePut , @CacheEvict使用

@Cacheable使用spring缓存

Spring 缓存注解@Cacheable的用法

使用@Cacheable 的Spring 缓存在启动@PostConstruct 时不起作用

Spring缓存注解@Cache,@CachePut , @CacheEvict,@CacheConfig使用

Spring缓存注解@Cacheable@CacheEvict@CachePut使用