2013-07-09 73 views
2

Env:JBoss AS 7.1.1.Final。JBoss AS 7关闭 - 在WAR部署停止之前关闭连接管理器

我有一个使用从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.s[email protected]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子系统,我可能需要)等待,直到应用程序停止?

+0

你写道:“连接管理器在应用程序部署之前关闭”,但你确定吗?您不能在JEE应用程序中启动自己的线程,但这基本上就是Spring调度程序所做的,这使应用程序服务器无法意识到应用程序的某些部分仍在运行。 – jarnbjo

+0

我的意思是“在应用程序* un *部署之前”,对不起,我纠正了它。 我必须承认你是正确的 - spec禁止产生我自己的线程。但是,我期望Web应用程序成为Spring调度的有效用例。有没有办法让容器知道仍在使用数据源的应用程序? –

+0

同样在这里。我使用''将数据源作为Spring bean获取。 –

回答

2

我有同样的问题,我现在发现https://issues.jboss.org/browse/WFLY-944中描述的原因。为了避免这个问题,为了避免这个问题,我们提出的解决方案是将jndi声明为Web应用程序中的资源,以便在应用程序终止之前不会从jboss服务器解除绑定。

为了达到这个目的,将以下部分添加到您的web.xml中,它将名为“jdbc/myDS”的jboss jndi设置为引用。

<resource-ref> 
<res-ref-name>jdbc/myDS</res-ref-name> 
<res-type>javax.sql.DataSource</res-type> 
<res-auth>Container</res-auth> 
<lookup-name>java:/my/DS1</lookup-name> 
</resource-ref> 

然后,而不是仰视的“java:/我的/ DS1”从你的代码的一部分指向实际的JNDI,现在应改为一看,这将“Java的comp/env的/ JDBC/myDS”参考你把实际指向实际的JNDI(我们之前指定为部分“查找名” xml属性在web.xml中添加)web.xml中的资源:

数据源DS =(DataSource) ctx.lookup(“java:comp/env/jdbc/myDS”);

0

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

1

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

恕我直言,更好的解决方案可能是避免在Java EE应用程序中使用Spring,至少在Java EE应用程序服务器提供完全相同的功能时也是如此。

+0

容器通知Spring上下文,该应用程序正在取消部署(由于“正常”取消部署或服务器关闭)。 Spring Scheduling执行器是一个在单线程上工作的JDK ScheduledThreadPoolExecutor。它有一个正在被应用程序取消部署调用的destroyMethod。在这个方法中,我执行正常的执行程序关闭 - 就像你写的 - shutdown(); awaitTermination(someTime,TimeUnit.SECONDS)。 因此,这工作正常,执行器是关闭的,但由于当前队列中的任务被允许完成,他们仍然尝试使用数据库 –

0

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