JavaSE中的Weld CDI:PreDestroy注释方法调用得太早?

JavaSE中的Weld CDI:PreDestroy注释方法调用得太早?,java,cdi,weld-se,Java,Cdi,Weld Se,给定以下代码,我想知道为什么在调用@PreDestroy注释的方法CacheManagerdoCleanup之后CacheManager仍然是活动的,请参见本文末尾的输出。 Weld不知道它仍然被引用吗?当对象真的不再使用时,如何调用这个方法 主类 迈劳彻班 周期扫描类 和CacheManager类: 输出为: Sep 06, 2017 3:47:51 PM org.jboss.weld.bootstrap.WeldStartup <clinit> INFO: WELD-000900

给定以下代码,我想知道为什么在调用@PreDestroy注释的方法CacheManagerdoCleanup之后CacheManager仍然是活动的,请参见本文末尾的输出。 Weld不知道它仍然被引用吗?当对象真的不再使用时,如何调用这个方法

主类

迈劳彻班

周期扫描类

和CacheManager类:

输出为:

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
这样,主应用程序线程就不会退出

有人知道更好的方法吗

谢谢

I

输出是预期的-Weld无法知道您旋转的其他线程,主线程只是继续运行,直到它到达container.shutdown

这个方法意外地终止了容器,这意味着调用@PreDestroy方法,然后放弃对这些bean的引用。但是另一个线程仍然在使用这些实例

你能做的是:

将container.shutdown移出main方法 主方法退出后,焊接容器将继续工作 您应该将container.shutdown放在一个方法中,该方法将在执行器完成后调用,具体取决于您的代码 根本不要调用container.shutdown 焊接本身注册一个在JVM终止时触发的 此解决方案的可行性取决于您终止程序的方式 您还可以实现自己的关闭钩子并注册该钩子
顺便说一句——如果你只是想在主线程中创建一个等待,让另一个线程来完成任务,那么最好将这个逻辑放到主线程中。

我认为这是合理的。CDI对调用其bean的线程一无所知。CDI对豆子的破坏并不意味着垃圾收集,只是CDI调用了它们的@PreDestroy hook并忘记了它们。如果要在CDI关闭后停止PeriodicScanner,请尝试在PeriodicScanner中的@PreDestroy钩子中关闭ScheduledExecutorService。
@Singleton
public class MyLauncher {

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

    public Future startScanner() {
        logger.info("Starting file producers...");
        return periodicScanner.doScan();
    }
}
@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);
    }

}
@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
container.select(MyLauncher.class).get().startScanner().get();