环境:JBoss AS 7.1.1.Final。
我有一个使用从 JBoss AS JNDI 获取的数据源的 WAR 应用程序。当我关闭服务器(控制台中的 Ctrl+C)时,应用程序收到关闭命令并开始销毁其 Spring 上下文。但是,我使用调度程序来执行一些数据库操作。当应用程序关闭时,我希望完成当前队列中的任务(但不接受新任务 - 标准 JDK Executor.shutdown() 行为)。当我在不停止服务器的情况下取消部署应用程序时,这可以正常工作。但是,当我停止整个服务器时,连接管理器会在应用程序取消部署之前关闭,这会导致
14:31:51,604 INFO [org.jboss.as.logging] JBAS011503: Restored bootstrap log handlers
14:31:51,617 INFO [org.apache.coyote.http11.Http11Protocol] Stopping Coyote HTTP/1.1 on http-127.0.0.1-127.0.0.1-18080
14:31:51,638 INFO [org.hornetq.ra.HornetQResourceAdapter] HornetQ resource adapter stopped
14:31:51,653 INFO [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/MY-APP]] Closing Spring root WebApplicationContext
14:31:51,656 INFO [org.springframework.web.context.support.XmlWebApplicationContext] Closing Root WebApplicationContext: startup date [Tue Jul 09 14:30:56 CST 2013]; root of context hierarchy
14:31:51,659 INFO [org.springframework.beans.factory.support.DefaultListableBeanFactory] Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@2c591927: defining beans [<snipped>]; root of factory hierarchy
14:31:51,662 INFO [org.hornetq.core.server.impl.HornetQServerImpl] HornetQ Server version 2.2.13.Final (HQ_2_2_13_FINAL_AS7, 122) [5f713ff6-5f86-11e2-a25d-1f3857764d50] stopped
14:31:51,673 INFO [MY-APP.Shutdown] Initializing shutdown. Already running tasks will be finished, new tasks will not be executed.
14:31:53,626 ERROR [org.springframework.scheduling.support.TaskUtils$LoggingErrorHandler] Unexpected error occurred in scheduled task.: org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is java.sql.SQLException: javax.resource.ResourceException: IJ000451: The connection manager is shutdown: java:/my/DS1
at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:80) [spring-jdbc-3.2.3.RELEASE.jar:3.2.3.RELEASE]
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:575) [spring-jdbc-3.2.3.RELEASE.jar:3.2.3.RELEASE]
at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:818) [spring-jdbc-3.2.3.RELEASE.jar:3.2.3.RELEASE]
at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:874) [spring-jdbc-3.2.3.RELEASE.jar:3.2.3.RELEASE]
at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:882) [spring-jdbc-3.2.3.RELEASE.jar:3.2.3.RELEASE]
at com.my.app.scanner.db.SyncEntryRepository.deleteById(SyncEntryRepository.java:26) [classes:]
at com.my.app.rules.orphanentries.OrphanedEntriesProcessor.process(OrphanedEntriesProcessor.java:22) [classes:]
at com.my.app.routing.Router$RoutingWorker.performRouting(Router.java:49) [classes:]
at com.my.app.routing.Router$RoutingWorker.route(Router.java:32) [classes:]
at com.my.app.routing.Router.route(Router.java:18) [classes:]
at com.my.app.transformation.Transformation.perform(Transformation.java:21) [classes:]
at com.my.app.MyApp.run(MyApp.java:18) [classes:]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [rt.jar:1.6.0_45]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) [rt.jar:1.6.0_45]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) [rt.jar:1.6.0_45]
at java.lang.reflect.Method.invoke(Method.java:597) [rt.jar:1.6.0_45]
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:64) [spring-context-3.2.3.RELEASE.jar:3.2.3.RELEASE]
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:53) [spring-context-3.2.3.RELEASE.jar:3.2.3.RELEASE]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:439) [rt.jar:1.6.0_45]
at java.util.concurrent.FutureTask$Sync.innerRunAndReset(FutureTask.java:317) [rt.jar:1.6.0_45]
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:150) [rt.jar:1.6.0_45]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$101(ScheduledThreadPoolExecutor.java:98) [rt.jar:1.6.0_45]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.runPeriodic(ScheduledThreadPoolExecutor.java:180) [rt.jar:1.6.0_45]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:204) [rt.jar:1.6.0_45]
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895) [rt.jar:1.6.0_45]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918) [rt.jar:1.6.0_45]
at java.lang.Thread.run(Thread.java:662) [rt.jar:1.6.0_45]
Caused by: java.sql.SQLException: javax.resource.ResourceException: IJ000451: The connection manager is shutdown: java:/my/DS1
at org.jboss.jca.adapters.jdbc.WrapperDataSource.getConnection(WrapperDataSource.java:137)
at org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:111) [spring-jdbc-3.2.3.RELEASE.jar:3.2.3.RELEASE]
at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:77) [spring-jdbc-3.2.3.RELEASE.jar:3.2.3.RELEASE]
... 26 more
Caused by: javax.resource.ResourceException: IJ000451: The connection manager is shutdown: java:/my/DS1
at org.jboss.jca.core.connectionmanager.AbstractConnectionManager.getManagedConnection(AbstractConnectionManager.java:321)
at org.jboss.jca.core.connectionmanager.tx.TxConnectionManagerImpl.getManagedConnection(TxConnectionManagerImpl.java:368)
at org.jboss.jca.core.connectionmanager.AbstractConnectionManager.allocateConnection(AbstractConnectionManager.java:464)
at org.jboss.jca.adapters.jdbc.WrapperDataSource.getConnection(WrapperDataSource.java:129)
... 28 more
14:31:53,640 INFO [MY-APP.Shutdown] Shutdown complete
14:31:53,651 INFO [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean] Closing JPA EntityManagerFactory for persistence unit 'default'
14:31:53,656 INFO [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean] Closing JPA EntityManagerFactory for persistence unit 'default'
14:31:53,837 INFO [org.jboss.as.server.deployment] JBAS015877: Stopped deployment MY-APP.war in 2259ms
14:31:56,158 INFO [com.arjuna.ats.jbossatx] ARJUNA032018: Destroying TransactionManagerService
14:31:56,158 INFO [com.arjuna.ats.jbossatx] ARJUNA032014: Stopping transaction recovery manager
14:31:56,160 INFO [org.jboss.as] JBAS015950: JBoss AS 7.1.1.Final "Brontes" stopped in 4567ms
在我的standalone.xml中我有
<subsystem xmlns="urn:jboss:domain:datasources:1.0">
<datasources>
<datasource jndi-name="java:/my/DS1" pool-name="My1" enabled="true" use-java-context="true">
<connection-url>jdbc:oracle:thin:@10.172.1.1:1521:ABCD</connection-url>
<driver>oracle</driver>
<pool>
<min-pool-size>1</min-pool-size>
<max-pool-size>10</max-pool-size>
<prefill>true</prefill>
<use-strict-min>false</use-strict-min>
</pool>
<security>
<user-name>xxx</user-name>
<password>xxx</password>
</security>
<timeout>
<idle-timeout-minutes>5</idle-timeout-minutes>
</timeout>
<statement>
<prepared-statement-cache-size>500</prepared-statement-cache-size>
<share-prepared-statements>true</share-prepared-statements>
</statement>
</datasource>
<drivers>
<driver name="oracle" module="com.oracle"/>
</drivers>
</datasources>
</subsystem>
然后,我在代码中查找数据源:
DataSource ds = new InitialContext().lookup("java:/my/DS1");
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
必须以编程方式查找数据源,而不是在 spring.xml 中硬编码,因为可以有多个数据源,并且它们的 JNDI 名称在应用程序启动时扫描的外部属性文件中配置。
然后,将 jdbcTemplate 传递给使用 Spring 调度调用的 TableScanner:
public TableScanner(JdbTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Scheduled(fixedDelay = 5000)
public void run() {
// query a table using jdbcTemplate and process the retrieved records, deleting them at the end of processing
}
在 run() 方法调用期间发生服务器停止时,应处理并删除所有检索到的记录。当应用程序尝试删除它们时,连接管理器已经关闭,因此出现异常。
有没有办法让连接管理器(或我可能需要的任何其他 JBoss AS 子系统)等到应用程序停止?