与spring框架https://github.com/spring-projects/spring-framework/commit/5aefcc802ef05abc51bbfbeb4a78b3032ff9eee3
中的提交有关初始化设置为稍后阶段,从 afterPropertiesSet()到 afterSingletonsInstantiated()
简而言之: 这可以防止在@PostConstruct用例中使用缓存时缓存工作。
更长版本: 这可以防止用于
的用例在methodB上使用@Cacheable创建serviceB
使用@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个框架按预期)
我的问题是: “这是一个安全的解决方法,因为初始提交者似乎只有使用afterPropertiesSet()的问题”
答案 0 :(得分:5)
正如Marten所说,你不应该在PostConstruct
阶段使用任何这些服务,因为你无法保证代理拦截器已经完全启动了。
您预先加载缓存的最佳方法是收听ContextRefreshedEvent
(4.2中的更多支持)并在那里开展工作。话虽如此,我知道可能不清楚这种用法是否被禁止,因此我创建了SPR-12700来改进文档。我不确定你指的是什么javadoc。
回答你的问题:不,这不是一个安全的解决方法。您之前使用的“副作用”(即它不应该工作,如果您的bean在CacheInterceptor
之前初始化,您将遇到与旧版本框架相同的问题)。不要在自己的代码中调用这样的低级基础结构。
答案 1 :(得分:4)
与OP完全相同的问题并且监听ContextRefreshedEvent
导致我的初始化方法被调用两次。听ApplicationReadyEvent
对我来说效果最好。
这是我使用的代码
@Component
public class MyInitializer implements ApplicationListener<ApplicationReadyEvent> {
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
//doing things
}
}
答案 2 :(得分:0)
自动连接ApplicationContext
并使用调用方法调用:
applicationContext.getBean(RBService.class).getRawBundle(bundleName, DEFAULT_REQUEST_LANG);
其中getRawBundle
是Cacheable
方法。