2015-02-05 103 views
5

在Spring框架涉及提交https://github.com/spring-projects/spring-framework/commit/5aefcc802ef05abc51bbfbeb4a78b3032ff9eee3春缓存不起作用

初始化设置为后一阶段从的afterPropertiesSet()afterSingletonsInstantiated()

简而言之: 这可以防止在@PostConstruct用例中使用它时缓存工作。

加长版: 这可防止使用情况下,你会

  1. 上的methodB创建@Cacheable serviceB

  2. 创建@PostConstruct调用serviceB.methodB

    serviceA
    @Component 
    public class ServiceA{ 
    
    @Autowired 
    private ServiceB serviceB; 
    
    @PostConstruct 
    public void init() { 
        List<String> list = serviceB.loadSomething(); 
    } 
    

这会导致org.springframework.cache.interceptor.CacheAspectSupport现在不被初始化,因此不会缓存结果。

protected Object execute(CacheOperationInvoker invoker, Object target, Method method, Object[] args) { 
    // check whether aspect is enabled 
    // to cope with cases where the AJ is pulled in automatically 
    if (this.initialized) { 
//>>>>>>>>>>>> NOT Being called 
     Class<?> targetClass = getTargetClass(target); 
     Collection<CacheOperation> operations = getCacheOperationSource().getCacheOperations(method, targetClass); 
     if (!CollectionUtils.isEmpty(operations)) { 
     return execute(invoker, new CacheOperationContexts(operations, method, args, target, targetClass)); 
     } 
    } 
//>>>>>>>>>>>> Being called 
    return invoker.invoke(); 
} 

我的解决方法是手动调用初始化方法:

@Configuration 
public class SomeConfigClass{ 

    @Inject 
    private CacheInterceptor cacheInterceptor; 

    @PostConstruct 
    public void init() { 
    cacheInterceptor.afterSingletonsInstantiated(); 
    } 

当然,这解决了我的问题,但它有其他的副作用,只是被称为2倍(1本说明书和1个由框架意)

我的问题是: “这是一个安全的解决方法做作为初始commiter似乎有一个问题,只需使用的afterPropertiesSet()”

+0

代码中的'@ PostConstruct'没有给出保证代理已创建(也就是同样的道理,为什么'@ Transactional'不会为'@ PostConstruct'方法的工作。'@ PostConstruct'方法在构建之后和注入依赖之后立即调用,但几乎总是在代理创建之前调用。你为什么需要'@ PostConstruct'方法?一般来说'ApplicationListener '是实现'SmartInitializingSingleton'接口而不是'@ PostConstruct'的好方法。 – 2015-02-05 20:23:51

+0

谢谢你的回复。我们使用postconstruct来使用从另一个服务(其方法上有@Cacheable)取得的值初始化一个bean。我们期望即使在使用postconstruct时这些值也会被缓存。如果情况并非如此,那么java文档将会使框架受益,因为其他开发人员可能也不会意识到这一点。将尝试使用SmartInitializingSingleton。谢谢! – user2966436 2015-02-06 22:23:26

+0

这在[参考指南]中进行了解释(http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-factory-lifecycle-default-init-destroy-methods)阅读该部分的最后一段。 – 2015-02-08 14:40:37

回答

3

正如Marten所说,您不应该在PostConstruct阶段使用任何这些服务,因为您无法保证代理拦截器在此时已完全启动。

预加载缓存的最佳方法是听取ContextRefreshedEvent(更多支持来自4.2)并在那里进行工作。这就是说,我知道可能不清楚这种用法是否被禁止,所以我创建了SPR-12700来改进文档。我不确定你指的是什么javadoc。

要回答你的问题:不,这不是一个安全的解决方法。你在使用“副作用”之前所使用的东西(即它不应该工作,如果你的bean在CacheInterceptor之前被初始化,那么你将会有与老版本的框架相同的问题)。不要在您自己的代码中调用这样的底层基础架构。

2

刚刚有与OP完全相同的问题,并且正在监听ContextRefreshedEvent正在导致我的初始化方法被调用两次。听ApplicationReadyEvent最适合我。 下面是我用

@Component 
public class MyInitializer implements ApplicationListener<ApplicationReadyEvent> { 
    @Override 
    public void onApplicationEvent(ApplicationReadyEvent event) { 
     //doing things 
    } 
}