web-dev-qa-db-ja.com

Java configで構成されたJPAPagingItemReaderに対してdestroyメソッド 'close'が失敗するのはなぜですか?

Spring-BatchジョブをXML構成からJava構成に変換しようとしています。Spring4.0.1.RELEASEおよびSpring Batch 2.2.1.RELEASEを使用しています。

1つのジョブを変換すると、次の警告がログファイルに表示され始めました。

2014年4月15日09:59:26.335 [スレッド2]警告o.s.b.f.s.DisposableBeanAdapter-名前 'fileReader'のBeanで破棄メソッド 'close'の呼び出しに失敗しました:org.springframework.batch.item.ItemStreamException:アイテムリーダーを閉じる際のエラー

完全なスタックトレースは次のとおりです。

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$1.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構成を使用していないときに、この警告がログに表示されるのはなぜですか?

21
FGreg

TLDR;

Springは、Java構成を使用する場合はdestroyMethodを自動的に推測しようとします(ただし、XML構成を使用する場合はそうしません)。この自動推論を無効にするには、次を使用します。

@Bean(destroyMethod="")


答えは_@Bean_アノテーションのJavaDocにあります。特にorg.springframework.context.annotation.Bean.destroyMethod()メソッド(エンファシスマイニング):

JDBC DataSource実装のclose()メソッドやHibernate SessionFactoryオブジェクトなど、アプリケーションコンテキストを閉じるときにBeanインスタンスで呼び出すメソッドのオプション名。メソッドには引数が必要ではありませんが、例外がスローされる場合があります。

ユーザーの便宜のために、コンテナは@Beanメソッドから返されたオブジェクトに対してdestroyメソッドを推測しようとします。たとえば、@ Apache Commons DBCP BasicDataSourceを返すBeanメソッドは、コンテナがそのオブジェクトで使用可能なclose()メソッドに気付き、それをdestroyMethodとして自動的に登録します。この「メソッド推論の破棄」は現在、「close」という名前の引数のないパブリックメソッドのみの検出に限定されています。メソッドは継承階層の任意のレベルで宣言でき、@ Beanメソッドの戻り値のタイプに関係なく検出されます(つまり、検出はBeanインスタンス自体に対して作成時に反映されます)。

特定の@Beanのdestroyメソッドの推論を無効にするには、値として空の文字列を指定します。 @Bean(destroyMethod = "")。org.springframework.beans.factory.DisposableBeanおよびJava.io.Closeable/Java.lang.AutoCloseableインターフェースは検出されますが、対応するdestroy/closeメソッドが呼び出されました。

注:ライフサイクルがファクトリーの完全制御下にあるBeanでのみ呼び出されます。これは常にシングルトンの場合ですが、他のスコープでは保証されません。

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=""_セットなし))の場合:

  • DisposableBeanAdapter.invokeDisposableBean = false
  • DisposableBeanAdapter.destroyMethod =public void org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader.close()throws org.springframework.batch.item.ItemStreamException
  • DisposableBeanAdapter.destroyMethodName = close

Java構成(_destroyMethod=""_が設定されている場合):

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

これらの観察に基づいて、XML経由で構成された場合、コンテナーはdestroyメソッドを推測しようとしないという結論に達しました。ただし、Javaを介して構成されている場合は実行されます。 Java構成ではなくXML構成では警告が表示されるのはこのためです。

さらに、コンテナが推測するメソッドはdestroyMethodがorg.springframework.batch.item.ItemStreamSupport.close()から来ているようです。したがって、これは、_@Bean_アノテーションを介して構成されたItemStreamSupportインターフェースを実装するBeanに潜在的に発生する可能性があります。


@ Beanのスプリングフレームワーク参照資料 にこの動作を説明するメモが追加されました。

デフォルトでは、Java configを使用して定義され、パブリックのクローズまたはシャットダウンメソッドを持つBeanは、自動的に破棄コールバックに登録されます。パブリックのクローズまたはシャットダウンメソッドがあり、コンテナがシャットダウンしたときに呼び出されるようにするには、@ Bean(destroyMethod = "")をBean定義に追加して、デフォルト(推論)モードを無効にします。

28
FGreg