为什么使用Java配置配置的JPAPagingItemReader的destroy方法'close'会失败? [英] Why does destroy method 'close' fail for JPAPagingItemReader configured with Java config?

查看:412
本文介绍了为什么使用Java配置配置的JPAPagingItemReader的destroy方法'close'会失败?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们正在尝试将Spring-Batch作业从XML配置转换为Java配置。我们正在使用Spring 4.0.1.RELEASE和Spring Batch 2.2.1.RELEASE。

We are trying to convert our Spring-Batch jobs from XML configuration to Java configuration. We are using Spring 4.0.1.RELEASE and Spring Batch 2.2.1.RELEASE.

转换一个作业后,以下警告开始出现在日志文件中:

After converting one job, the following warning started to appear in the log file:


2014年4月15日09:59:26.335 [Thread-2] WARN osbfsDisposableBeanAdapter - 在bean上调用destroy方法'close'失败名称为'fileReader':org.springframework.batch.item.ItemStreamException:关闭项目阅读器时出错

15-Apr-2014 09:59:26.335 [Thread-2] WARN o.s.b.f.s.DisposableBeanAdapter - Invocation of destroy method 'close' failed on bean with name 'fileReader': org.springframework.batch.item.ItemStreamException: Error while closing item reader

完整的堆栈跟踪是:

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配置的步骤如下所示:

This error only appears when using the Java configuration for the job but not the XML configuration. The step configured using XML looks like this:

<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配置时会在日志中显示此警告?

Why does this warning appear in the logs when using Java configuration but not XML configuration?

推荐答案

TLDR;

Spring在使用Java配置时尝试自动推断 destroyMethod (但在使用XML配置时不会这样做)。要禁用此自动推理,请使用:

Spring tries to automatically infer a destroyMethod when using Java configuration (but it does not do so when using XML configuration). To disable this automatic inference, use:

@Bean(destroyMethod =)

答案在 @Bean 注释的JavaDoc中;特别是在 org.springframework.context.annotation.Bean.destroyMethod()方法(强调我的):

The answer is in the JavaDoc of the @Bean annotation; specifically on the org.springframework.context.annotation.Bean.destroyMethod() method (emphasis mine):


在关闭应用程序上下文时调用bean实例的方法的可选名称,例如JDBC DataSource实现上的close()方法或Hibernate SessionFactory对象。该方法必须没有参数,但可能抛出任何异常。

The optional name of a method to call on the bean instance upon closing the application context, for example a close() method on a JDBC DataSource implementation, or a Hibernate SessionFactory object. The method must have no arguments but may throw any exception.

为了方便用户,容器将尝试针对从@Bean方法返回的对象推断出destroy方法。例如,给定@Bean方法返回Apache Commons DBCP BasicDataSource,容器将注意到该对象上可用的close()方法并自动将其注册为destroyMethod。这种破坏方法推理目前仅限于检测名为close的公共,非参数方法。该方法可以在继承层次结构的任何级别声明,并且无论@Bean方法的返回类型如何都将被检测到(即,在创建时检测发生在bean实例本身上)。

As a convenience to the user, the container will attempt to infer a destroy method against an object returned from the @Bean method. For example, given a @Bean method returning an Apache Commons DBCP BasicDataSource, the container will notice the close() method available on that object and automatically register it as the destroyMethod. This 'destroy method inference' is currently limited to detecting only public, no-arg methods named 'close'. The method may be declared at any level of the inheritance hierarchy and will be detected regardless of the return type of the @Bean method (i.e., detection occurs reflectively against the bean instance itself at creation time).

要禁用特定@Bean的destroy方法推断,请指定一个空字符串作为值,例如@Bean(destroyMethod =)。请注意,org.springframework.beans.factory.DisposableBean和java.io.Closeable / java.lang.AutoCloseable接口仍然会被检测到并且相应的destroy / close方法调用。

To disable destroy method inference for a particular @Bean, specify an empty string as the value, e.g. @Bean(destroyMethod=""). Note that the org.springframework.beans.factory.DisposableBean and the java.io.Closeable/java.lang.AutoCloseable interfaces will nevertheless get detected and the corresponding destroy/close method invoked.

注意:仅在生命周期完全由工厂控制的bean上调用,对于单身人士来说总是如此,但不保证任何其他范围。

Note: Only invoked on beans whose lifecycle is under the full control of the factory, which is always the case for singletons but not guaranteed for any other scope.

将Java配置更改为:

After changing the Java configuration to:

@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配置来确认这一点。工作。

The warning did not show up anymore. I was able to confirm this by placing a breakpoint on the org.springframework.beans.factory.support.DisposableBeanAdapter.destroy() method and launching XML configured job and the Java configured job.

对于XML配置:


  • DisposableBeanAdapter.invokeDisposableBean = false

  • DisposableBeanAdapter.destroyMethod = null

  • DisposableBeanAdapter.destroyMethodName = null

对于Java配置(没有 destroyMethod =设置):

For the Java configuration (without destroyMethod="" set):


  • 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 = set):

For the Java configuration (with destroyMethod="" set):


  • DisposableBeanAdapter.invokeDisposableBean = false

  • DisposableBeanAdapter.destroyMethod = null

  • DisposableBeanAdapter.destroyMethodName = n ull

根据这些观察结果,我得出的结论是,当通过XML配置时,容器不会尝试推断出destroy方法;但它通过Java配置时确实如此。这就是警告显示Java配置而不是XML配置的原因。

Based on these observations, I come to the conclusion that the container does not try to infer a destroy method when configured via XML; but it does when configured via Java. Which is why the warning shows up for the Java configuration and not the XML configuration.

此外,容器推断的方法是destroyMethod似乎来自 org.springframework.batch.item.ItemStreamSupport.close()。所以这可能发生在任何实现 ItemStreamSupport 接口的bean上,该接口是通过 @Bean 注释配置的。

Additionally, the method the container infers is the destroyMethod seems to come from org.springframework.batch.item.ItemStreamSupport.close(). So this could potentially happen to any bean that implements the ItemStreamSupport interface that is configured via the @Bean annotation.

@Bean的Spring Framework参考资料描述了这种行为:


默认情况下,使用Java配置定义的具有公共关闭或关闭方法的bean会自动使用销毁回调登记。如果你有一个公共关闭或关闭方法,并且你不希望在容器关闭时调用它,只需将@Bean(destroyMethod =)添加到bean定义中以禁用默认(推断)模式。 p>

By default, beans defined using Java config that have a public close or shutdown method are automatically enlisted with a destruction callback. If you have a public close or shutdown method and you do not wish for it to be called when the container shuts down, simply add @Bean(destroyMethod="") to your bean definition to disable the default (inferred) mode.

这篇关于为什么使用Java配置配置的JPAPagingItemReader的destroy方法'close'会失败?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆