Java SE中的焊接CDI:过早调用PreDestroy注释方法?

时间:2017-09-06 12:56:24

标签: java cdi weld-se

给出以下代码,我想知道为什么CacheManager仍然是" alive"在调用@PreDestroy注释方法(CacheManager#doCleanup)之后(参见本文末尾的输出)。 不是Weld意识到它仍然被引用的事实吗?当对象真的不再使用时,如何调用此方法?

主要课程

null

MyLaucher课程

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();
    } 
}

PeriodicScanner类......

@Singleton
public class MyLauncher {

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

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

CacheManager类

@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;
    }
}

正如您所看到的,定期扫描程序在容器关闭后仍处于活动状态。目前,阻止 doCleanup()过早调用的唯一方法是在 startScanner()返回的Future对象上调用get(): / p>

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

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

有人知道更好的方法吗?

由于

1 个答案:

答案 0 :(得分:1)

预期输出 - Weld无法了解您启动的其他线程,主线程一直持续到达container.shutdown()

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

你能做的是:

  • container.shutdown()移出主要方法
    • 焊接容器将在main()方法退出后继续工作
    • 您应该将container.shutdown()放在将在执行程序完成后调用的方法(取决于您的代码)
  • 根本不要致电container.shutdown()
    • Weld自身注册{J}终止后触发的shutdown hook
    • 此解决方案的可行性取决于您如何终止程序
    • 你也可以实现自己的关闭钩子并注册一个

作为旁注 - 如果你只想找到一种方法来创造一个&#34;等待&#34;在你的主线程中只是让另一个线程完成这项工作,你可能最好把这个逻辑放到主线程中。