gpt4 book ai didi

java - Java SE 中的焊接 CDI : PreDestroy annotated method called too early?

转载 作者:行者123 更新时间:2023-12-02 12:17:18 25 4
gpt4 key购买 nike

给出以下代码,我想知道为什么 CacheManager 在调用 @PreDestroy 注释方法 (CacheManager#doCleanup) 后仍然“Activity ”(请参阅​​本文末尾的输出)。难道 Weld 没有意识到它仍然被引用吗?当对象确实不再被使用时如何调用这个方法?

主类

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

如您所见,容器关闭后定期扫描器仍然处于 Activity 状态。目前,防止过早调用 doCleanup() 的唯一方法是对 startScanner() 返回的 Future 对象调用 get():

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

这样,主应用程序线程就不会退出。

有人知道更好的方法吗?

谢谢

最佳答案

输出符合预期 - Weld 无法知道您启动的其他线程,主线程只是继续运行,直到到达 container.shutdown()

这个方法(令人惊讶地)终止了容器,这意味着调用 @PreDestroy方法,然后放弃这些 bean 的引用。但另一个线程仍然继续使用这些实例。

你可以做的是:

  • 移动container.shutdown()主方法之外
    • 焊接容器将在 main() 之后继续工作方法退出
    • 您应该放置 container.shutdown()执行程序完成后将调用的方法(取决于您的代码)
  • 请勿调用container.shutdown()根本不
    • Weld 本身注册了 shutdown hook在 JVM 终止时触发
    • 此解决方案的可行性取决于您终止程序的方式
    • 您还可以实现自己的关闭 Hook 并注册该 Hook

作为旁注 - 如果您只是在寻找一种在主线程中创建“等待”的方法,只是为了让另一个线程完成这项工作,那么您最好将该逻辑放入主线程中。

关于java - Java SE 中的焊接 CDI : PreDestroy annotated method called too early?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46075865/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com