在spring bean中,是否可能有一个可以使用事务的关机方法?

时间:2020-12-27 07:27:29

In the destroy method of a spring bean I want to execute some queries to clean up some stuff in the database. Spring doesn't seem to allow this by any means I can find.

在spring bean的销毁方法中,我希望执行一些查询来清理数据库中的某些内容。春天似乎不允许我这样做。

The error is always something like:

错误通常是这样的:

Invocation of destroy method failed on bean with name 'someBean': org.springframework.beans.factory.BeanCreationNotAllowedException: Error creating bean with name 'transactionManager': Singleton bean creation not allowed while the singletons of this factory are in destruction (Do not request a bean from a BeanFactory in a destroy method implementation!)

调用销毁方法在bean上失败,名称为“someBean”:org.springframework.beans.factory。BeanCreationNotAllowedException:错误地创建名为“transactionManager”的bean:当这个工厂的单例被破坏时,不允许创建单例bean(不要在销毁方法实现中请求来自BeanFactory的bean !)

The following will tell spring to call shutdownDestroy after the bean is no longer needed. But, I get the above error when trying to use transactions.

下面将告诉spring在不再需要bean之后调用shutdownDestroy。但是,在尝试使用事务时,我得到了上面的错误。

<bean id="someId" name="someName" class="someClass"
 destroy-method="shutdownDestroy"/>

The same is true when I enable common lifecycle annotations using:

当我使用:

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

and then mark the method with @PreDestroy. That method can't use transactions either.

然后用@PreDestroy标记方法。那个方法也不能使用事务。

Is there any way to do this?

有什么办法吗?

EDIT: Thanks! I had the bean implement SmartLifecycle and adding the following and it works very nicely.

编辑:谢谢!我让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;
}

2 个解决方案

#1


13  

Interesting Question. I'd say you should be able to do it by letting your bean implement SmartLifeCycle.

有趣的问题。我认为您应该能够通过让您的bean实现SmartLifeCycle实现它。

That way, if your int getPhase(); method returns Integer.MAX_VALUE, it will be among the first to be called when the ApplicationContext finally shuts down.

这样,如果您的int getPhase();方法返回整数。MAX_VALUE将在应用程序上下文最终关闭时首先被调用。

Reference:

参考:

#2


1  

I come across this same issue. After check spring's source code, U can try to implements

我遇到了同样的问题。检查完spring的源代码后,您可以尝试实现

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

onApplicationEvent will be call before bean destory, you can check it on spring's org.springframework.context.support.AbstractApplicationContext#doClose method. I paste it below, so ContextEvent -> LifeCycle -> Bean destory.

onApplicationEvent将在bean destory之前调用,您可以在spring的org.springframe .context.support上检查它。AbstractApplicationContext # doClose方法。我将它粘贴在下面,所以context ->生命周期-> Bean destory。

        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();

#1


13  

Interesting Question. I'd say you should be able to do it by letting your bean implement SmartLifeCycle.

有趣的问题。我认为您应该能够通过让您的bean实现SmartLifeCycle实现它。

That way, if your int getPhase(); method returns Integer.MAX_VALUE, it will be among the first to be called when the ApplicationContext finally shuts down.

这样,如果您的int getPhase();方法返回整数。MAX_VALUE将在应用程序上下文最终关闭时首先被调用。

Reference:

参考:

#2


1  

I come across this same issue. After check spring's source code, U can try to implements

我遇到了同样的问题。检查完spring的源代码后,您可以尝试实现

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

onApplicationEvent will be call before bean destory, you can check it on spring's org.springframework.context.support.AbstractApplicationContext#doClose method. I paste it below, so ContextEvent -> LifeCycle -> Bean destory.

onApplicationEvent将在bean destory之前调用,您可以在spring的org.springframe .context.support上检查它。AbstractApplicationContext # doClose方法。我将它粘贴在下面,所以context ->生命周期-> Bean destory。

        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();