В бобе пружины возможно ли иметь метод выключения, который может использовать транзакции? - PullRequest
13 голосов
/ 05 мая 2011

В методе уничтожения Spring Bean я хочу выполнить несколько запросов, чтобы очистить некоторые вещи в базе данных. Похоже, Spring не позволяет этого ни при каких обстоятельствах.

Ошибка всегда что-то вроде:

Не удалось вызвать метод уничтожения bean с именем 'someBean': org.springframework.beans.factory.BeanCreationNotAllowedException: Ошибка создания бина с именем 'actionManager ': компонент Singleton создание не допускается, пока синглтоны этой фабрики находятся в уничтожение (не запрашивать боб из BeanFactory в методе уничтожения реализация!)

Следующая команда скажет Spring вызывать shutdownDestroy после того, как bean-компонент больше не нужен. Но я получаю вышеуказанную ошибку при попытке использовать транзакции.

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

То же самое верно, когда я включаю общие аннотации жизненного цикла, используя:

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

, а затем пометьте метод с помощью @PreDestroy. Этот метод также не может использовать транзакции.

Есть ли способ сделать это?

EDIT: Спасибо! У меня был 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 ]

14 голосов
/ 05 мая 2011

Интересный вопрос.Я бы сказал, что вы сможете сделать это, позволив вашему бину реализовать SmartLifeCycle.

Таким образом, если ваш метод int getPhase(); вернет Integer.MAX_VALUE, он будет одним из первых, который будет вызван, когда ApplicationContext наконец завершит работу.

Ссылка:

1 голос
/ 12 декабря 2013

Я сталкиваюсь с этой же проблемой. После проверки исходного кода Spring, U может попытаться реализовать

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

onApplicationEvent будет вызываться перед удалением компонента, вы можете проверить это в методе org.springframework.context.support.AbstractApplicationContext # doClose. Я вставляю его ниже, поэтому ContextEvent -> LifeCycle -> 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();
...