public class MyApplicationListener implements ApplicationListener<ContextRefreshedEvent> {
public void onApplicationEvent(ContextRefreshedEvent event) {
// do startup code ..
}
}
@Service
public class InitService {
@Autowired
MyDAO myDAO;
@EventListener(ContextRefreshedEvent.class)
public void onApplicationEvent(ContextRefreshedEvent event) {
event.getApplicationContext().getBean(InitService.class).initialize();
}
@Transactional
public void initialize() {
// use the DAO
}
}
7条答案
按热度按时间jvidinwx1#
引用自legacy(已关闭)Spring论坛:
在@PostConstruct中(与InitializingBean接口中的afterProperties Set一样),没有办法确保所有的后处理都已经完成,因此(实际上)不可能有Transactions。确保其工作的唯一方法是使用TransactionTemplate。
因此,如果您希望在transaction中执行
@PostConstruct
中的某些内容,则必须执行以下操作:字符串
jckbn6z72#
我认为
@PostConstruct
只是确保当前类的预处理/注入完成,并不意味着整个应用程序上下文的初始化完成。但是,您可以使用spring事件系统在应用程序上下文初始化完成时接收事件:
字符串
有关详细信息,请参阅文档部分标准和自定义事件。
x6h2sr283#
作为Spring 4.2的更新,
@EventListener
annotation允许更清晰的实现:字符串
55ooxyrt4#
注入self并调用
@Transactional
方法字符串
对于不支持自注入的旧版Spring,inject
BeanFactory
并获取self
作为beanFactory.getBean(AccountService.class)
编辑
看起来,自从这个解决方案在1.5年前发布以来,开发人员仍然有这样的印象,即如果在Bean初始化时从
@PostContruct
注解的方法调用一个用@Transactional
注解的方法,那么它实际上不会在Spring Transaction内部执行,并且很尴尬。(过时?)解决方案得到讨论和接受,而不是这个非常简单和直接的,后者甚至得到否决。欢迎持怀疑态度的人:)查看实现上述解决方案的example Spring Boot application at GitHub。
IMHO,实际上导致混淆的原因是:对
@Transactional
方法的调用应该通过定义了这种方法的Bean的代理版本来完成。1.当
@Transactional
方法从另一个Bean调用时,另一个Bean通常会注入这个方法并调用它的代理(例如通过@Autowired)版本,一切正常。1.当
@Transactional
方法直接从同一Bean调用时,通过通常的Java调用,不涉及Spring AOP/Proxy机制,并且该方法不在Transaction内部执行。1.在建议的解决方案中,当
@Transactional
方法通过自注入代理从同一Bean调用(self
字段)时,情况基本上等同于情况1。hpxqektj5#
@Platon Serbin的答案对我不起作用。所以我继续搜索,找到了以下拯救我生命的答案。:D
答案在这里No Session Hibernate in @PostConstruct,我冒昧地转录:
字符串
xn1cxnb46#
spring的transaction部分可能没有在
@PostConstruct
上完全初始化。使用
ContextRefreshedEvent
事件的侦听器来确保事务可用:字符串
oyt4ldly7#
在
@PostConstruct
或@NoTransaction
方法中使用transactionOperations.execute()
都可以工作字符串