Зачем уничтожать способ "закрыть" не для JPAPagingItemReader настроен с Java конфиг?

мы пытаемся преобразовать наши весенние пакетные задания из конфигурации XML в конфигурацию Java. Мы используем весну 4.0.1.Выпуск и пружинная партия 2.2.1.ОСВОБОЖДАТЬ.

после преобразования одного задания в файле журнала начало появляться следующее предупреждение:

15-апр-2014 09:59:26.335 [потока-2] предупредить о.С. б.Ф.С. DisposableBeanAdapter - вызов destroy метод "закрыть" рухнули на фасоли с именем 'fileReader': орг.springframework.партия.пункт.ItemStreamException: ошибка при закрытии элемента чтения

полный stacktrace является:

org.springframework.batch.item.ItemStreamException: Error while closing item reader
    at org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader.close(AbstractItemCountingItemStreamItemReader.java:131) ~[spring-batch-infrastructure-2.2.1.RELEASE.jar:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.6.0_25]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) ~[na:1.6.0_25]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) ~[na:1.6.0_25]
    at java.lang.reflect.Method.invoke(Method.java:597) ~[na:1.6.0_25]
    at org.springframework.beans.factory.support.DisposableBeanAdapter.invokeCustomDestroyMethod(DisposableBeanAdapter.java:349) [spring-beans-4.0.1.RELEASE.jar:4.0.1.RELEASE]
    at org.springframework.beans.factory.support.DisposableBeanAdapter.destroy(DisposableBeanAdapter.java:272) [spring-beans-4.0.1.RELEASE.jar:4.0.1.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroyBean(DefaultSingletonBeanRegistry.java:540) [spring-beans-4.0.1.RELEASE.jar:4.0.1.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingleton(DefaultSingletonBeanRegistry.java:516) [spring-beans-4.0.1.RELEASE.jar:4.0.1.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.destroySingleton(DefaultListableBeanFactory.java:824) [spring-beans-4.0.1.RELEASE.jar:4.0.1.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingletons(DefaultSingletonBeanRegistry.java:485) [spring-beans-4.0.1.RELEASE.jar:4.0.1.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.destroyBeans(AbstractApplicationContext.java:921) [spring-context-4.0.1.RELEASE.jar:4.0.1.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.doClose(AbstractApplicationContext.java:895) [spring-context-4.0.1.RELEASE.jar:4.0.1.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.run(AbstractApplicationContext.java:809) [spring-context-4.0.1.RELEASE.jar:4.0.1.RELEASE]
Caused by: java.lang.IllegalStateException: EntityManager is closed
    at org.hibernate.ejb.EntityManagerImpl.close(EntityManagerImpl.java:132) ~[hibernate-entitymanager-4.2.5.Final.jar:4.2.5.Final]
    at sun.reflect.GeneratedMethodAccessor14.invoke(Unknown Source) ~[na:na]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) ~[na:1.6.0_25]
    at java.lang.reflect.Method.invoke(Method.java:597) ~[na:1.6.0_25]
    at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:334) ~[spring-orm-4.0.1.RELEASE.jar:4.0.1.RELEASE]
    at $Proxy67.close(Unknown Source) ~[na:na]
    at org.springframework.batch.item.database.JpaPagingItemReader.doClose(JpaPagingItemReader.java:236) ~[spring-batch-infrastructure-2.2.1.RELEASE.jar:na]
    at org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader.close(AbstractItemCountingItemStreamItemReader.java:128) ~[spring-batch-infrastructure-2.2.1.RELEASE.jar:na]
    ... 13 common frames omitted

эта ошибка появляется только при использовании конфигурации Java для задания, но не конфигурации XML. Шаг, настроенный с помощью XML, выглядит следующим образом:

<batch:step id="createFile" next="insertFile">
    <batch:tasklet>
        <batch:chunk reader="fileReader" writer="fileWriter"
            commit-interval="#{jobProperties[commit_interval]}" />
    </batch:tasklet>
</batch:step>

<bean id="fileReader"
    class="org.springframework.batch.item.database.JpaPagingItemReader">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
    <property name="queryString"
        value="select mt from MyTable mt where status in ('1','2','3')" />
    <property name="pageSize" value="1000" />
</bean>

конфигурация Java:

@Bean
public Job fileProcessJob(JobBuilderFactory jobBuilders,
        Step loadConfig,
        Step createFile,
        Step insertFile
        ) {
    return jobBuilders.get(moduleName)
            .start(loadConfig)
            .next(createFile)
            .next(insertFile)
            .build()
            .build();
}

@Bean
public ItemReader<MyTable> cetFileReader(EntityManagerFactory entityManagerFactory) {
    JpaPagingItemReader<MyTable> itemReader = new JpaPagingItemReader<MyTable>();
    itemReader.setEntityManagerFactory(entityManagerFactory);
    itemReader.setQueryString("select mt from MyTable mt where status in ('1','2','3')");
    itemReader.setPageSize(1000);
    return itemReader;
}

почему это предупреждение появляется в журналах при использовании конфигурации Java, но не конфигурации XML?

1 ответов


TLDR;

Spring пытается автоматически вывести destroyMethod при использовании конфигурации Java (но это не делает этого при использовании конфигурации XML). Чтобы отключить этот автоматический вывод, используйте:

@Bean(destroyMethod="")


ответ находится в JavaDoc @Bean аннотация; в частности, на org.springframework.context.annotation.Bean.destroyMethod() метод (выделено мной):

необязательное имя метода для вызова экземпляра компонента при закрытии контекст приложения, например метод close () в реализации источника данных JDBC или объект Hibernate SessionFactory. Метод не должен иметь аргументов, но может вызвать любое исключение.

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

чтобы отключить вывод метода destroy для a в частности @Bean, укажите пустую строку в качестве значения, например @Bean (destroyMethod=""). обратите внимание, что орг.springframework.зернышки.фабрика.DisposableBean и java.Ио.Closeable / java.Лэнг.Автоклавируемые интерфейсы, тем не менее, будут обнаружены и вызван соответствующий метод destroy/close.

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

после изменения конфигурации Java на:

@Bean(destroyMethod="")
public ItemReader<MyTable> cetFileReader(EntityManagerFactory entityManagerFactory) {
    JpaPagingItemReader<MyTable> itemReader = new JpaPagingItemReader<MyTable>();
    itemReader.setEntityManagerFactory(entityManagerFactory);
    itemReader.setQueryString("select mt from MyTable mt where status in ('1','2','3')");
    itemReader.setPageSize(1000);
    return itemReader;
}

предупреждение больше не появится. Я смог подтвердить это, поместив точку останова на org.springframework.beans.factory.support.DisposableBeanAdapter.destroy() метод и запуск настроенного задания XML и настроенного задания Java.

для конфигурации XML:

  • DisposableBeanAdapter.invokeDisposableBean = false
  • DisposableBeanAdapter.destroyMethod = значение null
  • DisposableBeanAdapter.destroyMethodName = null

для конфигурации Java (без destroyMethod="" set):

  • DisposableBeanAdapter.invokeDisposableBean = false
  • DisposableBeanAdapter.destroyMethod = public void org.springframework.партия.пункт.поддержка.AbstractItemCountingItemStreamItemreader.close () броски орг.springframework.партия.пункт.ItemStreamException
  • DisposableBeanAdapter.destroyMethodName = закрыть

для конфигурации Java (с destroyMethod="" set):

  • DisposableBeanAdapter.invokeDisposableBean = false
  • DisposableBeanAdapter.destroyMethod = null
  • DisposableBeanAdapter.destroyMethodName = null

основываясь на этих наблюдениях, я пришел к выводу, что контейнер не пытается вывести метод destroy при настройке через XML; но он делает это при настройке через Java. Вот почему предупреждение появляется для конфигурации Java, а не для конфигурации XML.

кроме того, метод, который выводит контейнер, - это destroyMethod, похоже, происходит от org.springframework.batch.item.ItemStreamSupport.close(). Таким образом, это потенциально может произойти с любым Бобом, который реализует ItemStreamSupport интерфейс, который настроен через @Bean Примечание.


Примечание добавлено в Spring Framework справочный материал для @Bean описывающая такое поведение:

по умолчанию бобы, определенные с помощью Java config, которые имеют открытый метод закрытия или выключения, автоматически зачисляются с обратным вызовом уничтожения. Если у вас есть открытый метод закрытия или выключения, и вы не хотите, чтобы он вызывался при завершении работы контейнера, просто добавьте @Bean (destroyMethod="") в определение bean, чтобы отключить значение по умолчанию (выводится) режим.