在Spring Bean中,是否可以有一个关闭方法来使用事务?

15
在 Spring Bean 的 destroy 方法中,我想执行一些查询以清除数据库中的一些东西。似乎Spring不允许通过任何我能找到的方式来实现这一点。
错误总是类似于:
'某些Bean' 上调用 destroy 方法失败: org.springframework.beans.factory.BeanCreationNotAllowedException: 在单例工厂销毁时不允许创建 'transactionManager' bean(不要在 destroy 方法实现中从 BeanFactory 请求bean!)
以下代码将告诉 Spring 在 Bean 不再需要时调用 shutdownDestroy。但是,在尝试使用事务时,我会遇到上述错误。
<bean id="someId" name="someName" class="someClass"
 destroy-method="shutdownDestroy"/>

当我使用以下方式启用常见的生命周期注释时,情况也是如此:

<bean class="org.springframework. ... .CommonAnnotationBeanPostProcessor"/>

然后使用@PreDestroy标注该方法。此方法也不能使用事务。

有没有其他方法可以做到这一点?

编辑: 谢谢!我让bean实现了SmartLifecycle并添加了以下内容,它非常好用。

private boolean isRunning = false;

@Override
public boolean isAutoStartup() {return true;}

@Override
public boolean isRunning() {return isRunning;}

/** Run as early as possible so the shutdown method can still use transactions. */
@Override
public int getPhase() {return Integer.MIN_VALUE;}

@Override
public void start() {isRunning = true;}

@Override
public void stop(Runnable callback) {
    shutdownDestroy();
    isRunning = false;
    callback.run();
}

@Override
public void stop() {
    shutdownDestroy();
    isRunning = false;
}

我假设你的方法shutdownDestroy()有@Transactional注解?你是如何在该方法中执行查询的?我正试图使用由Spring自动装配的EntityManager来执行此操作。自动装配工作正常,但当我尝试执行查询时,我会收到javax.persistence.TransactionRequiredException:执行更新/删除查询。 - mag382
2个回答

15

1
实际上,启动过程从Integer.MIN_VALUE开始,以Integer.MAX_VALUE结束,而关闭过程将应用相反的顺序,因此如果您希望在关闭时首先执行方法,则应使用Integer.MAX_VALUE而不是Integer.MIN_VALUE。但是,在这种特殊情况下,任何值都允许从“停止”使用事务。 - John29

2

我遇到了同样的问题。在查看Spring源代码后,您可以尝试实现以下内容:

public class SomeBean implements ApplicationListener<ContextClosedEvent> {
    public void onApplicationEvent(ContextClosedEvent event) {
        stopHook();
    }
}

在bean销毁之前,onApplicationEvent将被调用。您可以在Spring的org.springframework.context.support.AbstractApplicationContext#doClose方法中进行检查。我在下面粘贴了它,因此ContextEvent -> LifeCycle -> Bean销毁。

        try {
            // Publish shutdown event.
            publishEvent(new ContextClosedEvent(this));
        }
        catch (Throwable ex) {
            logger.warn("Exception thrown from ApplicationListener handling ContextClosedEvent", ex);
        }

        // Stop all Lifecycle beans, to avoid delays during individual destruction.
        try {
            getLifecycleProcessor().onClose();
        }
        catch (Throwable ex) {
            logger.warn("Exception thrown from LifecycleProcessor on context close", ex);
        }

        // Destroy all cached singletons in the context's BeanFactory.
        destroyBeans();

        // Close the state of this context itself.
        closeBeanFactory();

        // Let subclasses do some final clean-up if they wish...
        onClose();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接