2017-09-06 1 views
0

次のコードでは、@PreDestroy注釈付きメソッド(CacheManager#doCleanup)の呼び出し後にCacheManagerがまだ「生きている」のは不思議です(この記事の最後の出力を参照してください)。 まだ参照されていることをWeldは認識していませんか?オブジェクトが実際にはもう使用されていないときにこのメソッドを呼び出す方法は?Java SEのWeld CDI:PreDestroy注釈付きメソッドがあまりに早く呼び出されましたか?

メインクラス

public class Main { 
    public static void main(String[] parameters) { 
     //Init weld container   
     Weld weld = new Weld(); 
     WeldContainer container = weld.initialize(); 
     container.select(MyLauncher.class).get().startScanner(); 
     weld.shutdown(); 
    } 
} 

MyLaucherクラス

@Singleton 
public class MyLauncher { 

    @Inject 
    private Logger logger; 
    @Inject 
    private PeriodicScanner periodicScanner; 

    public Future startScanner() { 
     logger.info("Starting file producers..."); 
     return periodicScanner.doScan(); 
    } 
} 

PeriodicScannerクラス...

@Singleton 
public class PeriodicScanner { 

    @Inject 
    private Logger logger; 
    @Inject 
    private CacheManager myCacheMgr; 
    private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(new ThreadFactoryBuilder() 
      .setNameFormat("periodic-%d") 
      .build()); 

    public Future doScan() { 
     return scheduledExecutorService.scheduleAtFixedRate(() -> { 
      myCacheMgr.doStuff(); 
      logger.info("Hello from PeriodicScanner"); 
     }, 1, 15, TimeUnit.SECONDS); 
    } 

} 

そして、のCacheManagerクラス

@Singleton 
public class CacheManager { 
    @Inject 
    Logger logger; 

    @PostConstruct 
    private void doInit(){ 
     logger.info("PostConstruct called for ID {}", this.hashCode()); 
    } 

    @PreDestroy 
    private void doCleanup(){ 
     logger.info("Cleaning up for ID {}", this.hashCode()); 
    } 

    public int doStuff(){ 
     logger.info("Doing stuff from instance ID {}", this.hashCode()); 
     return 1; 
    } 
} 

出力は次のようになります。

Sep 06, 2017 3:47:51 PM org.jboss.weld.bootstrap.WeldStartup <clinit> 
INFO: WELD-000900: 2.4.4 (Final) 
Sep 06, 2017 3:47:51 PM org.jboss.weld.bootstrap.WeldStartup startContainer 
INFO: WELD-000101: Transactional services not available. Injection of @Inject UserTransaction not available. Transactional observers will be invoked synchronously. 
Sep 06, 2017 3:47:52 PM org.jboss.weld.environment.se.WeldContainer fireContainerInitializedEvent 
INFO: WELD-ENV-002003: Weld SE container 2d18aac9-f66d-4373-b581-9c5cababd65a initialized 
[main] INFO com.mycompany.cdiplayground.CacheManager - PostConstruct called for ID 611572016 
[main] INFO com.mycompany.cdiplayground.MyLauncher - Starting file producers... 
[main] INFO com.mycompany.cdiplayground.CacheManager - Cleaning up for ID 611572016 
Sep 06, 2017 3:47:52 PM org.jboss.weld.environment.se.WeldContainer shutdown 
INFO: WELD-ENV-002001: Weld SE container 2d18aac9-f66d-4373-b581-9c5cababd65a shut down 
[periodic-0] INFO com.mycompany.cdiplayground.CacheManager - Doing stuff from instance ID 611572016 
[periodic-0] INFO com.mycompany.cdiplayground.PeriodicScanner - Hello from PeriodicScanner 
[periodic-0] INFO com.mycompany.cdiplayground.CacheManager - Doing stuff from instance ID 611572016 
[periodic-0] INFO com.mycompany.cdiplayground.PeriodicScanner - Hello from PeriodicScanner 

あなたが見ることができるように、定期的なスキャナは、コンテナのシャットダウン後にまだ生きています。瞬間のために、私は早すぎると呼ばれるようにdoCleanup()を防止するための唯一の方法は、(取得呼び出すことです)startScanner()で返されるFutureオブジェクト上:

container.select(MyLauncher.class).get().startScanner().get(); 

この方法では、メインのアプリケーションスレッドは終了しません。

誰かがそれを行うためのよりよい方法を知っていますか?

おかげ

I

+0

私はこのbevaiourが妥当だと思います。 CDIはBeanを呼び出す*スレッド*について何も知らない。そして、CDIによる豆の「破壊」は、ガベージコレクションを意味するものではなく、CDIが '@ PreDestroy'フックを呼び出して忘れてしまっただけです。 CDIがシャットダウンされた後に 'PeriodicScanner'を停止したい場合は、' PeriodicScanner'の '@ PreDestroy'フックで' ScheduledExecutorService'をシャットダウンしてみてください。 –

答えて

1

出力が期待されている - 溶接は、あなたがスピンアップし、それがcontainer.shutdown()に到達するまで、メインスレッドが単にいっている他のスレッドについて知ることができません。

このメソッド(驚くべきことに)は、@PreDestroyメソッドを呼び出すことを意味するコンテナを終了し、それらのBeanの参照を削除します。しかし、他のスレッドはこれらのインスタンスを使用し続けます。あなたは何ができるか

は次のとおりです。main()方法は

  • を出た後

    • 移動container.shutdown()
      • mainメソッドのうち溶接コンテナが動作し続けるであろうあなたがなる方法に container.shutdown()を配置する必要があります実行者が終了した後に呼び出されます(コードに依存します)
    • すべて
      • 溶接自体は、このソリューションの生存率は、あなたのプログラム
      • を終了する方法によって異なります。また、独自のシャットダウンフックを実装し、登録することができますJVM終了
      • 時にトリガshutdown hookを登録するにcontainer.shutdown()を呼び出すことはありません側の注意点として、代わりに

    その1 - あなただけのちょうど別のthreaをできるようにあなたのメインスレッドで「待つ」を作成する方法を探している場合仕事をしていると、そのロジックをメインスレッドに入れる方が良いかもしれません。

  • 関連する問題