2

Env: JBoss AS 7.1.1.Final。

JBoss AS JNDI から取得したデータ ソースを使用する WAR アプリケーションがあります。サーバーをシャットダウンすると (コンソールで Ctrl+C)、アプリケーションはシャットダウン コマンドを受け取り、Spring コンテキストの破棄を開始します。ただし、スケジューラを使用して一部の DB 操作を実行しています。アプリケーションが閉じているときに、現在キューにあるタスクを終了したい (ただし、新しいタスクは受け入れられない - 標準の 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);

複数のデータ ソースが存在する可能性があり、それらの JNDI 名は、アプリケーションが起動時にスキャンする外部プロパティ ファイルで構成されているため、データ ソースはプログラムで検索する必要があり、spring.xml でハードコーディングする必要はありません。

次に、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 サブシステム) を待機させる方法はありますか?

4

4 に答える 4

2

私は同じ問題を抱えていましたが、https://issues.jboss.org/browse/WFLY-944に記載されている原因を見つけました。これを回避するために提案されている解決策は、jndi を Web アプリケーションのリソースとして宣言し、アプリケーションが終了する前に jboss サーバーからアンバインドしないようにすることです。

これを実現するには、「jdbc/myDS」という名前の jboss jndi への参照を設定する web.xml に次の部分を追加します。

<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>

次に、実際の jndi を指すコード部分から「java:/my/DS1」を検索する代わりに、「java:comp/env/jdbc/myDS」を検索する必要があります。実際に実際の jndi を指している web.xml (web.xml に追加された部分の「lookup-name」xml プロパティとして以前に指定したもの):

データソース ds = (データソース) ctx.lookup("java:comp/env/jdbc/myDS");

于 2015-01-09T14:47:35.030 に答える
1

Spring Scheduling が提供する機能はわかりませんが、標準 API のエグゼキューターを使用していた場合、解決策は、ServletContextListenerアプリケーションのアンデプロイまたは停止時にコンテナーによって呼び出される Web アプリケーションにを追加することでした。 . このメソッドでは、エグゼキュータを停止し、保留中のすべてのタスクが完了するまで待機する のcontextDestroyed(ServletContextEvent sce)ようなものを呼び出します。executor.shutdown(); executor.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS)を呼び出すときは、タイムアウトを短くすることを検討してawaitTerminationください。

この場合のように、少なくともJava EEアプリケーションサーバーによってまったく同じ機能が提供されている場合は、Java EEアプリケーション内でSpringを使用しないことをお勧めします。

于 2013-07-09T08:55:30.010 に答える
0

この JBoss AS issueを見つけました。これは私の問題を反映しています。データ ソースが @Resource を介して静的な方法でバインドされていない場合、サーバーはデータ ソースがまだ使用中であることを認識していないようです。私は Spring にデータ ソースを独自に管理させることにしました。これは Java EE の方法ではないかもしれませんが、作業は完了し、私の状況では適切です。

于 2013-07-11T03:14:19.430 に答える
0

EJB スケジュール Bean の使用を検討しましたか? このようにして、jboss はワーカー スレッドを生成します。

于 2013-07-09T08:53:47.027 に答える