我们正在尝试将Spring-Batch作业从XML配置转换为Java配置。我们使用的是Spring 4.0.1.RELEASE和Spring Batch 2.2.1.RELEASE。
转换一个作业后,以下警告开始出现在日志文件中:
2014年4月15日09:59:26.335 [Thread-2] WARN osbfsDisposableBeanAdapter - 在名为'fileReader'的bean上调用destroy方法'close'失败:org.springframework.batch.item.ItemStreamException:Error while关闭项目读者
完整的堆栈跟踪是:
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配置时会在日志中显示此警告?
答案 0 :(得分:27)
<强> TLDR; 强>
Spring在使用Java配置时尝试自动推断destroyMethod
(但在使用XML配置时不会这样做)。要禁用此自动推理,请使用:
@Bean(destroyMethod="")
答案在@Bean
注释的JavaDoc中;特别是org.springframework.context.annotation.Bean.destroyMethod()
方法(强调我的):
在关闭应用程序上下文时调用bean实例的方法的可选名称,例如JDBC DataSource实现上的close()方法或Hibernate SessionFactory对象。该方法必须没有参数,但可能抛出任何异常。
为了方便用户,容器将尝试针对从@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配置:
对于Java配置(没有设置destroyMethod=""
):
对于Java配置(设置destroyMethod=""
):
基于这些观察,我得出的结论是,容器在通过XML配置时不会尝试推断出destroy方法;但是在通过Java配置时会这样做。这就是警告显示Java配置而不是XML配置的原因。
此外,容器推断的方法是destroyMethod似乎来自org.springframework.batch.item.ItemStreamSupport.close()
。因此,这可能发生在实现通过ItemStreamSupport
注释配置的@Bean
接口的任何bean上。
已在Spring Framework Reference material for @Bean中添加了一条说明此行为的注释:
默认情况下,使用Java配置定义的具有公共关闭或关闭方法的bean会自动使用销毁回调登记。如果你有一个公共关闭或关闭方法,并且你不希望在容器关闭时调用它,只需将@Bean(destroyMethod =“”)添加到bean定义中以禁用默认(推断)模式。 p>