2013-08-29 1 views
9

У меня есть приложение командной строки, которая использует Spring-управляемый компонент, который, состоящие из Java ExecutorService созданных с:Как правильно отключить службы-исполнители с помощью Spring?

ExecutorService service = Executors.newFixedThreadPool(4); 

Теперь, я хочу, чтобы мой сервис для завершения работы, когда мое приложение завершает работу, так что я сделал свой боб реализовать интерфейс DisposableBean и есть метод уничтожения, такие как:

public void destroy(){ 
    service.shutdown(); 
} 

Тогда я мог бы соблазниться, чтобы сделать что-то вроде зарегистрировать выключение крючок контекста Spring. Однако я обнаружил (жесткий способ, т. Е. В предварительном выпуске), что это не сработает: крюк остановки не вызывается до того, как вызывается метод ExecutorService.shutdown(), вызывающий классическую проблему catch 22 (он получает вызванное прерыванием, т. е. если я нажму Ctrl-C во время работы приложения). Это ускользнуло от моих модульных тестов, потому что по какой-то причине кажется, что он работает отлично от JUnit, который все еще озадачивает меня: что делает JUnit по-другому?

Решение, которое я нашел до сих пор, заключается в явном вызове ApplicationContext.close() прямо перед тем, как выйти из моей основной функции. Мне было интересно, есть ли лучшее решение для этого, и каковы наилучшие методы для гибких пулов потоков, управляемых Spring. Также, если мой bean не, управляемый непосредственно весной, а созданный bean-управлением, управляемым Spring? Должен ли я просто каскадировать вызовы на destroy()? Разве это не было бы очень склонно к ошибкам?

Я ценю любые комментарии, предложения, дальнейшие исследования, RTFM, магические рецепты.

Спасибо!

+0

PS: что делать, если я хочу перенести приложение с командной строкой на сервер приложений, такой как Tomcat? Что-нибудь изменилось? –

+0

В том числе название и ваш PS Я считаю * семь * (7!) Вопросительных знаков. :-) Можете получить более эффективные ответы, если вы зададите только один конкретный вопрос. – Keith

ответ

24

Вы знаете, что это:

ExecutorService service = Executors.newFixedThreadPool(4); 

можно заменить следующим образом:

<bean id="service" class="java.util.concurrent.Executors" 
     factory-method="newFixedThreadPool" destroy-method="shutdown"> 
    <constructor-arg value="4"/> 
</bean> 

Контекст весна затем управляет, более непосредственно, закрытие вашего сервиса исполнителя - и он может более легко использовать повторно.

+0

Я знаю об этом. Однако в некоторых случаях я предпочитаю создавать свои бобы программно, а не через конфигурацию, например, если я не буду знать, сколько бобов мне понадобится до тех пор, пока среда выполнения или определение конкретного компонента не будут получены из внешнего источника, например базы данных или очереди сообщений. –

+0

Подсчитайте мою верхнюю часть вниз, это неверно. Это не работает, но приводит к 'InvalidArgumentException' при инициализации контекста Spring. – Powerslave

1

Рассмотрите использование Spring TaskExecutor, который можно настроить с помощью пула потоков. http://static.springsource.org/spring/docs/3.0.x/reference/scheduling.html

+0

Я не думаю, что это подойдет моему прецеденту. У меня есть много межзадачной синхронизации, которая должна выполняться (например, барьеры), и я бы предпочел больше контролировать ее, явно используя исполнителей и пользовательские задачи. –

1

За официальной Спринг документации, при использовании конфигурации аннотаций на основе, для destroyMethod области @Bean, поведение Spring по умолчанию для автоматического вызова общественности, без аргументов методы, названной close или shutdown когда контекст приложения закрываются.

Для удобства пользователя, контейнер будет пытаться логически вывести уничтожить метод против объект, возвращаемый из @Bean метода. Для примера , учитывая метод @Bean, возвращающий базу данных Apache Commons DBCP BasicDataSource, контейнер заметит метод close() , доступный на этом объекте, и автоматически зарегистрирует его как метод уничтожения . Этот «метод вывода метода уничтожения» в настоящее время ограничен , обнаруживающий только общедоступные методы без аргумента «close» или «shutdown». Метод может быть объявлен на любом уровне иерархии наследования, и будет обнаружен независимо от типа возвращаемого значения метода @Bean (т.е., обнаружение происходит рефлексивно против самого экземпляра компонента во время создания).

Для повторной итерации, это поведение по умолчанию для аннотаций управляемой конфигурации, когда уничтожить метод явным образом не установлено. Если такое поведение нежелательно, явно устанавливая метод уничтожения пустой строкой будет отключить эту «особенность»:

Чтобы отключить уничтожить метод вывода для конкретного @Bean, указать пустую строку в качестве значения, например, @Bean (destroyMethod = ""). Обратите внимание, что DisposableBean и Closeable/AutoCloseable интерфейсы будут , тем не менее, будут обнаружены и вызван соответствующий метод destroy/close .

С другой стороны, при использовании конфигурации XML, это не поведение по умолчанию ... Для того, чтобы достичь паритета, destroy-method может быть явно установлен в (inferred). Подробные сведения см. В разделах Destruction callbacks и Default initialization and destroy methods в официальных документах.

Смежные вопросы