JBoss AS 7关闭 – 在WAR部署停止之前关闭连接管理器

环境:JBoss AS 7.1.1.Final。

我有一个WAR应用程序使用从JBoss AS JNDI获取的数据源。 当我关闭服务器(控制台中的Ctrl + C)时,应用程序会收到一个shutdown命令并开始销毁它的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 []; 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中,我有

    jdbc:oracle:thin:@10.172.1.1:1521:ABCD oracle  1 10 true false   xxx xxx   5   500 true        

然后,我在代码中查找数据源:

 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()方法调用期间停止服务器时,应处理和删除所有检索到的记录。 当应用程序尝试删除它们时,连接管理器已经关闭,因此exception。

有没有办法让连接管理器(或我可能需要的任何其他JBoss AS子系统)等到应用程序停止?

我遇到了同样的问题,现在我已经找到了https://issues.jboss.org/browse/WFLY-944中描述的原因。 为避免这种情况而在那里提出的解决方案是将jndi声明为Web应用程序中的资源,以便在应用程序终止之前不与jboss服务器解除绑定。

为此,请将以下部分添加到web.xml中,该部分设置对名为“jdbc / myDS”的jboss jndi的引用。

  jdbc/myDS javax.sql.DataSource Container java:/my/DS1  

然后你不应该从你的代码部分查找指向实际jndi的“java:/ my / DS1”,而应该查找“java:comp / env / jdbc / myDS”,它将引用你放入的资源。 web.xml实际上指向实际的jndi(我们之前在web.xml中添加的部分中指定为’lookup-name’xml属性):

DataSource ds =(DataSource)ctx.lookup(“java:comp / env / jdbc / myDS”);

我不知道Spring Scheduling提供了哪些function,但是如果您使用了标准API中的执行程序,那么解决方案就是将ServletContextListener添加到Web应用程序中,当取消部署或停止时,容器会调用它。应用。 在contextDestroyed(ServletContextEvent sce)方法中,您将调用executor.shutdown(); executor.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS) executor.shutdown(); executor.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS) ,它将停止执行程序并等待所有挂起的任务完成。 您可能需要考虑在调用awaitTermination时使用较短的超时。

恕我直言,更好的解决方案可能是避免在Java EE应用程序中使用Spring,至少在Java EE应用程序服务器提供完全相同的function时,就像在这种情况下一样。

您是否考虑过使用EJB Scheduled bean? 这样jboss就会产生工作线程。

我发现了这个JBoss AS问题 ,这反映了我的问题。 看来如果数据源没有以静态方式绑定,通过@Resource,则服务器不知道数据源仍在使用中。 我一直让Spring自己管理数据源,这可能不是Java EE的方式,但是完成工作并且在我的情况下是合适的。