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