【问题标题】:How to write main() using CDI in Java EE?如何在 Java EE 中使用 CDI 编写 main()?
【发布时间】:2013-05-05 16:02:27
【问题描述】:

我有一个想要运行的无客户端应用程序。它没有客户端,但会进行 HTTP 调用并充当其他服务的客户端。它可能会运行几个小时或几天(但它不需要定期运行——只需一次)。

我想在 Java EE 7 容器中运行它,因为标准上下文依赖注入 (CD) 和标准 JAX-RS 客户端(自 Java EE 7 以来的新功能)的好处。有JMS、JPA等服务也不错。

问题是如何以标准方式编写/注释 main 方法? @Inject 在方法上是不好的,因为这样的方法必须快速返回。 @Schedule 并不理想,因为它会定期运行,除非我以编程方式确定当前系统时间。

我能想到的最好办法是在 @Inject 方法中设置一次性 Timer 并用 @Timeout 注释我的主要方法。

不知何故,这似乎有点脆弱或不雅。 是否有更好的标准方式来启动服务?一些注释会导致它启动并开始运行?

此外,在取消部署时中断和关闭服务的最佳标准方法是什么

【问题讨论】:

  • 你的问题有点绕。如果您在应用程序容器中运行应用程序,那么为什么要定义 main 方法?只需使用 @Schedule 方法创建一个启动单例 EJB。
  • @Perception 曲折反映了我缺乏清晰度,因此提出了这个问题。 @Schedule 需要一些时间。我应该在什么时候注释该方法?我不希望它定期运行。该方法需要运行一次。如果@Schedule 在部署后接受一个间隔,那将是完美的,但事实并非如此。我可以使用@Schedule ... myfunc (Timer timer) 并取消传入计时器并使用TimerService 设置一个间隔计时器来运行@Timeout ... mymain () 所涉及的声音。
  • 不知道您是编辑了问题还是我错过了底部。发誓它读起来不一样。无论如何,一个想法 - 使用启动单例 bean 并在其 @PostConstruct 方法中创建一个计时器。或者,嵌入像 Quartz 这样的第三方库,并安排一个非重复的作业,以便在部署应用程序时启动该作业。作业的日程安排要求是什么(应用部署、特定日期、按需运行?)。
  • @Perception 可能是您的看法 ;-) 我没有编辑,如果我编辑了,编辑将可用。在您上次发表评论后,我确实编辑了我的用户名。计划要求是“在应用程序部署上”。感谢您的建议。我不喜欢使用第三方库,但我会尝试使用@PostConstruct 计时器。
  • @Perception(续)关于关闭,是否可以让@PreDestroy 设置一个标志并等待主方法持有的锁,当主通知标志并结束时释放该锁?本质上,我想在没有任何其他手动或非标准技术的情况下停止取消部署并开始部署。

标签: jakarta-ee cdi seam3 weld java-ee-7


【解决方案1】:

当 PostConstruct 长时间运行时,与事件解耦:

@Singleton
@Startup
public class YourBean{
@Inject
private Event<XXX> started; 
@PostConstruct
private void theMainMethod(){
    started.fire(new XXX());
}
public void handleStarted(@Observes XXX started) {
    // the real main method.
}

}

【讨论】:

  • 谢谢@JanGalinski 顺便说一句,另一个选项是使用@Asynchronous public void handleStarted (),但我无法从@PostConstruct 方法中异步调用它。你认为哪个更好 - @Asynchronous@Observes?知道我需要做什么才能从同一个 bean 中的 @PostConstruct 中对同一个 bean 中的方法进行异步调用吗?同时感谢您的好建议。
  • 嗯,没有标准的方法来请求取消@Observes 方法。使用@Asynchronous,可以通过返回的Future 请求取消该方法。虽然这可以以非标准方式模拟,但在 Java EE 的未来版本中,程序员可能能够请求标准取消请求在线程处于阻塞调用时实际中断线程,这将大大提高其响应能力并清理结构。这个预期的功能不能由程序员自己实现。因此@Asynchronous 赢得了 IMO。
【解决方案2】:

如果您可以将EJB 与(或代替)CDI 一起使用,请尝试为您的 bean 使用 @Singleton + @Startup 注释,并为您的 main() 方法使用 @PostConstruct

@Singleton
@Startup
public class YourBean {

@Stateless
public static class BeanWithMainMethod{

    @Asynchronous
    public void theMainMethod(){
        System.out.println("Async invocation");
     }
}

    @EJB
    private BeanWithMainMethod beanWithMainMethod;

    @PostConstruct
    private void launchMainMethod(){
        beanWithMainMethod.theMainMethod();
    }
}

【讨论】:

  • 我认为如果@PostConstruct 没有尽快返回,容器会杀死它。您是否尝试过使用长时间运行的方法?
  • 如果MainMethod长时间不返回,部署会失败,所以,更好的做法是使用@Asyncronous或CDI事件。
  • 感谢您的澄清,赞成更正(如果您也可以编辑您的答案,那就太好了!)
  • 代码正常,但代码上方的文字与代码不匹配。它应该说:“使用@Asynchronous 注释您的主要方法,并在使用@EJB 自注入bean 后从@PostConstruct 方法调用它”
猜你喜欢
  • 2015-07-29
  • 2011-10-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-22
  • 2013-11-26
相关资源
最近更新 更多