23

我们使用 Tomcat 来托管基于 WAR 的应用程序。我们是 servlet 容器兼容的 J2EE 应用程序,但 org.apache.catalina.authenticator.SingleSignOn 除外。

我们被要求迁移到商业 Java EE 应用程序服务器。

  1. 我看到的改变的第一个缺点是成本。无论应用服务器收费多少,Tomcat都是免费的。
  2. 其次是复杂性。我们既不使用 EJB 也不使用 EAR 特性(当然不,我们不能),并且没有错过它们。

那么我没有看到的好处是什么?

我没有提到的缺点是什么?


提到的是...

  1. JTA - Java Transaction API - 我们通过数据库存储过程控制事务。
  2. JPA - Java Persistence API - 我们使用 JDBC 和存储过程来持久化。
  3. JMS - Java 消息服务 - 我们使用 XML over HTTP 进行消息传递。

这个不错,请多多指教!

4

5 回答 5

59

当我们以 Java EE 6 将 Apache Tomcat 认证为Apache TomEE为目标时,这里有一些我们必须填补的空白才能最终通过 Java EE 6 TCK。

不是一个完整的列表,而是一些即使有现有答案也可能不明显的亮点。

没有事务管理器

任何经过认证的服务器都绝对需要事务管理。在任何 Web 组件(servlet、过滤器、侦听器、jsf 托管 bean)中,您应该能够UserTransaction像这样获得注入:

  • @Resource UserTransaction transaction;

您应该能够使用javax.transaction.UserTransaction来创建事务。您在该事务范围内触及的所有资源都应在该事务中注册。这包括但不限于以下对象:

  • javax.sql.DataSource
  • javax.persistence.EntityManager
  • javax.jms.ConnectionFactory
  • javax.jms.QueueConnectionFactory
  • javax.jms.TopicConnectionFactory
  • javax.ejb.TimerService

例如,如果在 servlet 中启动事务,则:

  • 更新数据库
  • 向主题或队列触发 JMS 消息
  • 创建一个计时器以在稍后的某个时间进行工作

.. 然后其中一件事情失败了,或者您只是选择调用rollback()UserTransaction那么所有这些事情都被撤消了。

无连接池

很清楚有两种连接池:

  • 事务感知连接池
  • 非事务感知连接池

Java EE 规范并不严格要求连接池,但是如果你有连接池,它应该是事务感知的,否则你将失去事务管理。

这基本上意味着:

  • 同一事务中的每个人都应具有来自池的相同连接
  • 在事务完成(提交或回滚)之前,不应将连接返回到池中,无论是否有人调用close()DataSource.

Tomcat 中用于连接池的通用库是 commons-dbcp。我们也想在 TomEE 中使用它,但是它不支持事务感知连接池,因此我们实际上将该功能添加到 commons-dbcp(是的,Apache)中,并且从 commons-dbc 版本 1.4 开始。

请注意,将 commons-dbcp 添加到 Tomcat 仍然不足以获得事务连接池。您仍然需要事务管理器,并且您仍然需要容器来完成注册与TransactionManagerviaSynchronization对象的连接的管道。

在 Java EE 7 中,有人谈论添加一种标准方法来加密 DB 密码并将它们与应用程序一起打包到安全文件或外部存储中。这将是 Tomcat 不支持的另一项功能。

没有安全集成

WebServices 安全性、JAX-RS SecurityContext、EJB 安全性、JAAS 登录和 JAAC 都是默认情况下不会在 Tomcat 中“挂钩”的安全概念,即使您单独添加 CXF、OpenEJB 等库也是如此。

当然,这些 API 都假设在 Java EE 服务器中协同工作。我们必须做很多工作才能让所有这些协作并在 Tomcat RealmAPI 之上完成,以便人们可以使用所有现有的 TomcatRealm实现来驱动他们的“Java EE”安全性。它实际上仍然是 Tomcat 安全性,它只是很好地集成。

JPA 集成

是的,您可以将 JPA 提供程序放入 .war 文件中,并在没有 Tomcat 帮助的情况下使用它。使用这种方法,您不会得到:

  • @PersistenceUnit EntityManagerFactory注入/查找
  • @PersistenceContext EntityManager注入/查找
  • 连接EntityManager到事务感知连接池
  • JTA 托管EntityManager支持
  • 扩展的持久性上下文

JTA-ManagedEntityManager基本上意味着同一事务中希望使用 an 的两个对象EntityManager都将看到相同的EntityManager内容,并且无需显式传递EntityManager。所有这些“传递”都是由容器为你完成的。

这是如何实现的?很简单,EntityManager你从容器中得到的是假货。这是一个包装。当您使用它时,它会在当前事务中查找 realEntityManager并将调用委托给EntityManager. 这就是神秘EntityManager.getDelegate()方法的原因,因此用户可以根据需要获取真正的EntityManager 并使用任何非标准 API。这样做当然要非常小心,永远不要保留对委托的引用,EntityManager否则您将遇到严重的内存泄漏。当事务完成时,委托EntityManager通常会被刷新、关闭、清理和丢弃。如果您仍然持有一个引用,您将阻止对该引用EntityManager以及它所持有的所有数据进行垃圾收集。

  • EntityManager保存对从容器中获得的a 的引用总是安全的
  • 引用它是不安全的EntityManager.getDelegate()
  • 要非常小心地引用EntityManager您通过 an 创建的自己的引用EntityManagerFactory——您对它的管理负有 100% 的责任。

CDI 集成

我不想过度简化 CDI,但我发现它有点太大了,而且很多人没有认真看 - 它在很多人的“总有一天”列表上:) 所以这里只是几个亮点我想一个“网络人”会想知道。

你知道在一个典型的 web 应用程序中的所有投入和获取吗?HttpSession整天把东西拉进拉出?使用String你从HttpSession. 您可能已经使用实用程序代码为您执行此操作。

CDI 也有这个实用程序代码,它被称为@SessionScoped. 任何带有注释的对象@SessionScoped都会被放入并跟踪HttpSession。您只需通过请求将对象注入到您的 Servlet 中@Inject FooObject,CDI 容器就会以与我描述的事务跟踪相同的方式跟踪“真实”FooObject 实例EntitityManager。Abracadabra,现在你可以删除一堆代码了 :)

做任何getAttributesetAttributeHttpServletRequest?好吧,你也可以用@RequestScoped同样的方法删除它。

当然还有@ApplicationScoped消除你可能正在做的getAttribute电话setAttributeServletContext

为了让事情变得更酷,任何像这样跟踪的对象都可以实现一个@PostConstruct在创建 bean 时调用的@PreDestroy方法,以及在所述“范围”完成时通知的方法(会话完成,请求结束,应用程序正在关闭)向下)。

CDI 可以做得更多,但这足以让任何人想要重写旧的 web 应用程序。

一些挑剔的东西

Java EE 6 中添加了一些在 Tomcat 驾驶室中没有添加的东西。它们不需要大的解释,但确实占了“填补空白”的很大一部分。

  • 支持@DataSourceDefinition
  • 支持全球 JNDI ( java:global, java:app, java:module)
  • @Resource MyEnum myEnum通过和枚举注入
  • @Resource Class myPluggableClass通过and进行类注入
  • 支持@Resource(lookup="foo")

小问题,但以可DataSource移植的方式在应用程序中定义、在 web 应用程序之间共享 JNDI 条目以及简单地说“查找并注入它”的能力非常有用

结论

如前所述,不是完整的列表。没有提到 EJB、JMS、JAX-RS、JAX-WS、JSF、Bean Validation 和其他有用的东西。但是,当人们谈论 Tomcat 是什么和不是什么时,至少有一些经常被忽视的东西。

另请注意,您可能认为的“Java EE”可能与实际定义不符。有了 Web Profile,Java EE 就缩小了。这是故意解决“Java EE 太重,我不需要所有这些”的问题。

如果您将 EJB 从 Web 配置文件中删除,则剩下的内容如下:

  • Java 小服务程序
  • Java 服务器页面 (JSP)
  • Java ServerFaces (JSF)
  • Java 事务 API (JTA)
  • Java 持久性 API (JPA)
  • Java 上下文和依赖注入 (CDI)
  • Bean 验证

这是一个非常有用的堆栈。

于 2012-02-08T19:14:46.573 回答
8

除非您想要正确的 EJB,否则您不需要全栈 J2EE 服务器(商业或非商业)。

您可以拥有大多数 J2EE 功能(例如 JTA、JPA、JMS、JSF)而无需全栈 J2EE 服务器。全栈 j2ee 的唯一好处是容器将以声明方式代表您管理所有这些。随着 EJB3 的出现,如果您需要容器管理的服务,使用一个是一件好事。

您还可以拥有免费的全栈服务器,例如 Glasfish、Geronimo 或 JBoss。

您还可以使用嵌入式 Glasfish 运行嵌入式 j2ee 容器管理服务,例如,就在 Tomcat 中。

如果您想使用为您很好地管理的会话 bean、消息 bean、计时器 bean,即使使用集群和故障转移,您可能需要一个 EJB 容器。

我建议管理层根据功能需求考虑升级。其中一些 EJB 容器可能只是使用嵌入式 Tomcat 作为他们的网络服务器,所以有什么好处!

有些经理只是喜欢为事情买单。让他们考虑捐赠城市庇护所,或者直接选择 BEA。

于 2008-11-06T16:11:09.763 回答
3

如果您被要求迁移到商业 J2EE 服务器,原因可能与 J2EE 堆栈无关,而是出于非技术考虑。

使用 Tomcat 无法获得的商业 J2EE 产品提供的一件事是技术支持。

这可能不是您的考虑因素,具体取决于您的 Web 应用程序应该满足的服务级别。当您尝试找出 Tomcat 的问题时,您的应用程序是否会停止运行,或者这会是一个主要问题吗?

于 2008-11-06T16:31:13.340 回答
2

成本不一定是不利因素,因为有一些免费的 J2EE 服务器,例如 JBoss 和 Glassfish。

您的问题假定 (J2EE = Servlet + EJB + EAR),因此,如果您不使用 EJB 或 EAR,那么除了使用 Servlet 容器之外没有任何意义。事实并非如此,J2EE 包含的远不止这些。示例包括:

  • JTA - Java 事务 API
  • JPA - Java 持久性 API
  • JMS - Java 消息传递规范
  • JSF - 用组件构建用户界面的技术

干杯,多纳尔

于 2008-11-06T15:52:40.987 回答
2

事实上,由于有大量可用的包和库,几乎没有 EJB 容器提供不能添加到现代 servlet 容器(ala Tomcat)中。因此,如果您想要这些功能中的任何一个,您可以“点菜”获得它们,也就是说,成本是将这些功能集成到您的应用程序的过程。

如果您现在没有“缺少”这些功能中的任何一个,那么从实际的角度来看,您可能不需要它们。

总而言之,现代 EJB 容器非常好,并且预集成了所有这些服务,使它们在某种程度上更易于使用,如果您需要它们的话。有时,将功能放在附近且方便使用就足以让人们探索其在应用程序中的潜力,而不是将功能的集成过程视为采用的障碍。

凭借免费 EJB 容器的质量,真的很难想象购买一个会有多大用处,尤其是考虑到您目前没有真正的需求。

但是,我确实鼓励您实际购买并使用它并探索该平台。Glassfish 非常容易上手并且非常好,并且应该可以轻松地按原样(或进行非常小的调整)处理您的 WAR。

作为一项规则,当涉及到运行 Tomcat 与 EJB 容器之间时,问题真的是为什么不使用一个?专门针对 Glassfish 来说,我发现它比 Tomcat 更易于使用,主要区别在于它可以比 Tomcat 具有更大的内存占用(特别是对于小型应用程序),但在大型应用程序上你甚至不会注意到. 对我来说,内存命中没什么大不了的,对其他人来说可能是个问题。

它为我提供了所有这些优秀功能的单一来源,而无需为第 3 方选项爬网。

于 2008-11-06T16:32:38.300 回答