15

好的。这又是一个行业实践的问题。

  • Tomcat = Web 容器
  • JBoss、WebLogic 等 = 具有 Web 容器的应用程序服务器(对于 JBoss,它的分叉 Tomcat)

Spring 不需要 JBoss 之类的 Application Server。如果我们使用 JMS 等企业服务,我们可以使用 RabbitMQ、ApacheMQ 等独立系统。

  1. 问题是为什么人们仍然将 JBoss 和其他应用程序服务用于纯基于 Spring 的应用程序?
  2. 通过使用应用程序服务器,Spring 可以利用哪些优势?像对象池一样?Application Server 提供了哪些具体优势?那些是如何配置的?
  3. 如果不是用于 Spring,那么应用程序服务器用于 Spring/Hibernate 等堆栈的其他用途是什么?(用例)
4

3 回答 3

7

实际上我会说监听 JMS 可能是应用服务器的最佳理由。独立的消息代理不能解决问题,因为您仍然需要一个正在侦听消息的组件。最好的方法是使用 MDB。理论上你可以使用 Springs MessageListenerContainer。然而,这有几个缺点,例如 JMS 仅支持阻塞读取,因此 Spring 需要启动它自己的线程,这完全不受支持(即使在 Tomcat 中),并且可能会破坏事务、安全性、命名(JNDI)和类加载(这反过来会破坏远程)。JCA 资源适配器可以随意做任何事情,包括通过 WorkManager 启动线程。除了 JMS(或其他目的地)之外,可能还使用了一个数据库,此时您需要 XA 事务和 JTA,换句话说,一个应用程序服务器。

恕我直言,反对应用服务器的最大原因是规范发布后需要数年时间(这反过来也需要数年时间),直到服务器实施规范并消除最严重的错误。直到现在,就在 EE 7 即将发布之前,我们是否有 EE 6 服务器开始出现,它们并没有完全充满错误。一些供应商不再修复其 EE 6 产品线中的错误,因为他们已经忙于即将推出的 EE 7 产品线,这变得可笑了。

编辑

最后一段的详细解释:

Java EE 在很多地方都依赖于所谓的上下文信息。未作为参数从服务器/容器显式传递给应用程序但隐式“存在”的信息。例如当前用户进行安全检查。当前事务或连接。当前用于查找类以延迟加载代码或反序列化对象的应用程序。或者用于进行 JNDI 查找的当前组件(servlet、EJB、...)。所有这些信息都在服务器/容器在调用组件(servlet、EJB、...)之前设置的线程局部变量中。如果您创建自己的线程,则服务器/容器不知道它们,并且依赖此信息的所有功能都不再起作用。您可能会通过不使用您生成的线程中的任何这些功能来解决这个问题。

一些链接

http://www.oracle.com/technetwork/java/restrictions-142267.html#threads http://www.ibm.com/developerworks/websphere/techjournal/0609_alcott/0609_alcott.html#spring-4

如果我们检查 Servlet 3.0 规范,我们会发现:

2.3.3.3 异步处理

Java Enterprise Edition 功能(例如第 15-174 页的第 15.2.2 节“Web 应用程序环境”和第 15-176 页的第 15.3.1 节“在 EJBTM 调用中传播安全身份”)仅适用于执行初始请求的线程或者当请求通过 AsyncContext.dispatch 方法分派到容器时。通过 AsyncContext.start(Runnable) 方法直接在响应对象上运行的其他线程可以使用 Java 企业版功能。

这是关于异步处理的,但同样的限制也适用于自定义线程。

public void start(Runnable r) - 此方法使容器调度一个线程,可能来自托管线程池,以运行指定的 Runnable。容器可以将适当的上下文信息传播到 Runnable。

同样,异步处理,但同样的限制适用于自定义线程。

15.2.2 Web应用环境

这种类型的 servlet 容器在开发人员创建的线程上执行时应该支持这种行为,但目前不需要这样做。这样的要求将在本规范的下一个版本中添加。开发人员需要注意的是,不建议依赖于应用程序创建的线程的此功能,因为它是不可移植的。

不可移植意味着它可以在一台服务器上但不能在另一台服务器上。

当您想在 MDB 之外使用 JMS 接收消息时,您可以使用以下四种方法javax.jms.MessageConsumer

  • #receiveNoWait()您可以在容器线程中执行此操作,它不会阻塞,但就像偷看一样。如果没有消息,它只会返回null。这不太适合收听消息。
  • #receive(long)您可以在容器线程中对此进行处理,它确实会阻塞。您通常不希望在容器线程中进行阻塞等待。再次不太适合收听消息。
  • #receive(),这可能会无限期地阻塞。再次不太适合收听消息。
  • #setMessageListener()这就是你想要的,当消息到达时你会得到一个回调。但是,除非库可以连接到应用程序服务器,否则它不会是容器线程。应用程序服务器的挂钩只能通过 JCA 提供给资源适配器。

所以是的,它可能会起作用,但不能保证,并且有很多事情可能会破坏。

于 2013-03-07T18:24:27.867 回答
2

您说得对,您并不需要真正的应用程序服务器(实现所有 Java EE 规范)来使用 Spring。人们不使用像 JBoss 这样的真正的 Java EE 应用程序的最大原因是,在冷启动时速度很慢,因为 #$@#% 使开发变得痛苦(热部署仍然不能很好地工作)。

你看有两个阵营:

  • Java EE
  • 春天框架。

一个阵营相信规范/委员会过程,另一个阵营相信仁慈的独裁者/有机 OSS 过程。两者都有自己的“议程”。

您可能不会得到一个非常好的公正答案,因为这两个阵营很像 Emacs 与 VIM 之战

用 Spring 偏见回答您的问题

  1. 因为它从理论上购买了您较少的供应商锁定(尽管我发现这是相反的)。
  2. Spring 最大的优势是 AspectJ AOP。到目前为止。
  3. 我想看到菲利普的回答。

(开始吐槽)

自从@PhilippeMarschall 为 Java EE 辩护以来,我会说我已经完成了 Tomcat+RabbitMQ+Spring 路线,而且效果很好。@PhilippeMarschall 讨论是有效的,如果您想要正确的 JTA + JMS,但使用 Sprig AMQP 和像 Postgresql 这样的良好事务数据库进行正确设置,这不是一个问题。此外,他对消息队列事务未绑定/同步到平台事务的说法也不正确,因为 Spring 支持这一点(恕我直言,@Transactional AOP 更优雅)。AMQP也明显优于 JMS。

(吐槽结束)

于 2013-03-08T15:53:19.700 回答
0

我们在 tomcat 上使用 JBoss 用于 JNDI 数据源和池。它使程序员不必了解数据库的任何信息,只需了解其 JNDI 名称

于 2013-03-08T00:54:24.307 回答