如何使用OSGi模块化JSF / Facelets / Spring应用程序?

我正在使用非常大的JSF / Facelets应用程序,它们使用Spring进行DI / bean管理。 我的应用程序具有模块化结构,我目前正在寻找标准化模块化的方法。

我的目标是从许多模块(可能相互依赖)组成Web应用程序。 每个模块可能包含以下内容:

  • 类;
  • 静态资源(图像,CSS,脚本);
  • Facelet模板;
  • 托管bean – Spring应用程序上下文,包含请求,会话和应用程序范围的bean(替代方法是JSF托管bean);
  • Servlet API的东西 – servlet,filter,监听器(这是可选的)。

我想避免(几乎不惜一切代价)需要将模块资源(如Facelets模板)复制或提取到WAR或扩展web.xml以获取模块的servlet,filter等。它必须足够将模块(JAR,bundle,artifact,…)添加到Web应用程序( WEB-INF/libbundlesplugins ,…)以使用此模块扩展Web应用程序。

目前,我使用自定义模块化解决方案来解决此任务,该解决方案主要基于使用类路径资源:

  • 特殊资源servlet从类路径资源(JAR)提供静态资源。
  • Special Facelets资源解析器允许从类路径资源加载Facelet模板。
  • Spring通过模式classpath*:com/acme/foo/module/applicationContext.xml加载应用程序上下文classpath*:com/acme/foo/module/applicationContext.xml – 这将加载模块JAR中定义的应用程序上下文。
  • 最后,一对委托servlet和filter将请求处理委托给模块中Spring应用程序上下文中配置的servlet和filter。

最后几天我读了很多关于OSGi的内容,我正在考虑,如何(以及如果)我可以将OSGi用作标准化的模块化方法。 我在考虑如何使用OSGi解决单个任务:

  • 静态资源 – 想要导出静态资源的OSGi包用bundle上下文注册ResourceLoader实例。 中央ResourceServlet使用这些资源加载器从bundle加载资源。
  • Facelet模板 – 与上面类似,中央ResourceResolver使用bundle注册的服务。
  • 托管bean – 如果myBean在其中一个bundle中定义, 我不知道如何使用像#{myBean.property}这样的表达式。
  • Servlet API的东西 – 使用像WebExtender / Pax Web这样的东西来注册servlet,filter等等。

我的问题是:

  • 我在这里发明了一辆自行车吗? 那有标准的解决方案吗? 我发现提到Spring Slices但是找不到很多关于它的文档。
  • 您认为OSGi是所述任务的正确技术吗?
  • 我的OSGI应用草图或多或少是正确的吗?
  • 应如何处理托管bean(尤其是请求/会话范围)?

我非常感谢你的评论。

你想要做的事情听起来可行,但有几点需要注意:

视图层:首先,您的视图层听起来有点过度填充。 还有其他方法可以通过使用自定义组件来模块化JSF组件,这样可以避免尝试创建与后期绑定托管bean一样引人注目的事情。

模块本身:其次,您的模块似乎并不特别模块化。 您的第一个子弹列表听起来好像您正在尝试创建可互操作的Web应用程序,而不是模块本身。 我对模块的想法是每个组件都有一个明确定义的,或多或少离散的目的。 就像以前的 vi一样 。 如果您要沿着OSGi路线走下去,那么我们应该像这样定义模块化: 为了这个讨论,模块化意味着组件是可热插拔的 – 也就是说,可以在不破坏应用程序的情况下添加和删除它们。

依赖关系:我对你对模块的描述有点担心“可能依赖于彼此”。 您可能(我希望)已经知道这一点,但您的依赖关系应该形成一个有向无环图。 一旦你引入循环依赖,你就会要求在应用程序的最终可维护性方面受到伤害。 OSGi最大的弱点之一是它不会阻止循环依赖,所以由你来强制执行。 否则,您的依赖关系会像kudzu一样增长,并逐渐扼杀系统的其余部分。

Servlets: Fuhgeddaboudit。 你不能将servlet延迟绑定到Web应用程序中,直到Servlet 3.0规范正在生产中(如Pascal指出的那样)。 要启动单独的实用程序servlet,您需要将其放入自己的应用程序中。


好的,这么多的警告。 让我们考虑一下这可能如何工作:

你已经定义了自己的JSF模块……究竟是什么? 让我们给它一个明确的,相当微不足道的目的:一个登录屏幕。 因此,您创建了登录屏幕,使用OSGi将其后期绑定到您的应用程序中……然后是什么? 如果您没有在.jspx页面中定义登录function,应用程序如何知道登录function? 应用程序如何知道导航到它不知道的东西?

有一些方法可以使用条件包含等来解决这个问题(例如, ),但是,就像你说的那样,当你的托管loginBean存在于另一个模块中时,事情会变得有些毛茸茸甚至还没有被介绍到应用程序。 实际上,除非存在loginBean,否则您将获得servletexception。 所以你会怎么做?

您可以在其中一个模块中定义API。 您打算在模块之间共享的所有托管bean必须在此API层中指定为接口。 并且所有模块必须具有他们打算使用的任何这些接口的默认实现。 此API必须在所有可互操作的模块之间共享。 然后,您可以使用OSGi和Spring将指定的bean与其实现连接在一起。

我需要花一点时间指出,这不是我将如何处理这个问题。 一点也不。 鉴于像登录页面一样简单,或者甚至像股票图表那样复杂,我个人更喜欢创建自定义JSF组件。 但如果要求是“我希望我的托管bean是模块化的(即热插拔等),”这是我知道使其工作的唯一方法。 而且我甚至都不确定它起作用。 这个电子邮件交换表明,这是JSF开发人员刚刚开始研究的问题。

我通常认为托管bean是视图层的一部分,因此我只将它们用于视图逻辑,并将其他所有内容委托给服务层。 在我看来,使托管bean延迟绑定是将它们从视图层推广到业务逻辑中。 这就是为什么所有这些教程都如此专注于服务的原因:因为大多数时候你想要考虑你的应用程序运行“无头”需要什么,以及如果,为了“皮肤”你的视图是多么容易例如,您希望它在Android手机上运行,​​具有所有function。

但听起来你正在使用的很多东西本身就是视图逻辑 – 例如,需要交换不同的视图模板。 OSGi / Spring应该能够提供帮助,但是您需要在应用程序中选择可用的实现:几乎是OSGi的Service Registry构建的。

这留下了静态资源。 您可以模块化这些,但请记住,您需要定义一个接口来检索这些资源,并且您需要提供默认实现,以便您的应用程序在不存在时不会阻塞。 如果考虑i18n,这可能是一个很好的方法。 如果您想要真正冒险,那么您可以将静态资源推送到JNDI。 这将使它们完全热插拔,并且省去了尝试解决以编程方式使用哪个实现的痛苦,但是有一些缺点:任何失败的查找都会导致您的应用抛出NamingException。 这太过分了。 JNDI通常用于应用程序配置的Web应用程序。

至于你剩下的问题:

我在这里发明了一辆自行车吗? 那有标准的解决方案吗?

你是,有点。 我见过应用程序做这种事情,但你似乎偶然发现了一组相当独特的要求。

您认为OSGi是所述任务的正确技术吗?

如果您需要热插拔模块,那么您可以选择OSGi和轻量级ServiceLocator接口。

我的OSGI应用草图或多或少是正确的吗?

如果不了解组件边界的位置,我真的无法分辨。 目前,听起来你可能正在推动OSGi做的比它能做的更多。

但是不要相信我的话。 我在这些地方找到了 其他阅读材料。

既然你问起Spring Slices, 这应该足以让你开始 。 你需要一个Git客户端,看起来你将通过查看源代码来训练你自己。 它是非常早期的原型代码。

我在当前的项目中遇到了同样的问题。 在我看来,OSGi是标准和未来支持方面最好,最干净的解决方案,但是如果您尝试在Web应用程序中使用它,目前可能遇到一些问题:

  1. Web容器和OSGi平台之间还没有很好的集成解决方案。
  2. 对于只搜索简单模块化架构的自定义构建Web应用程序,OSGi可能太多了。 如果我的项目需要支持不受我们控制的第三方扩展,如果项目需要热重新部署,插件之间的严格访问规则等,我会考虑OSGi。

基于类加载器和资源filter的自定义解决方案似乎非常适合我。 作为示例,您可以学习Hudson源代码或Java Plug-in Framework(JPF)项目(http://jpf.sourceforge.net/)。

至于扩展web.xml,我们可能很幸运使用Servlet 3.0规范(http://today.java.net/pub/a/today/2008/10/14/introduction-to-servlet-3.html#可插拔-和可扩展性)。

Servlet 3.0规范引入的“Web模块部署描述符片段”(又名web-fragment.xml)在这里很不错。 规范将其定义为:

Web片段是Web应用程序的逻辑分区,使得Web应用程序中使用的框架可以定义所有工件,而无需让devlopers在web.xml中编辑或添加信息。

Java EE 6现在可能不适合您。 它仍然是标准化的解决方案。

企业OSGi是一个相当新的领域,所以不要认为你会得到一个直接满足你需求的解决方案。 这就是说我从Equinox中发现的东西之一(eclipse背后的osgi引擎,因此拥有最大用户群!)是一致的配置/ DI服务。 在我的项目中,我们最近有一些类似的需求,并结束了构建一个简单的配置osgi服务。

模块化应用程序固有的问题之一是DI,因为在某些情况下模块可见性可能会阻止类访问。 我们使用注册好友政策解决了这个问题,这个政策并不太理想但有效。

除了配置之外,您还可以查看最近发布的Equinox书籍,获取有关使用OSGi作为创建模块化应用程序基础的指导。 这些示例可能特定于Equinox,但这些原则适用于任何OSGi框架。 链接 – http://equinoxosgi.org/

您应该查看Spring DM Server(它正在转换到Eclipse Virgo,但尚未发布)。 最近发布的OSGi企业规范中有很多好东西。

我想,有些Spring DM教程会有所帮助。 但是,是的,可以使用标准模块化从Web包外部加载资源和类。 在那,它是一个很好的选择。

至于会话上下文 – 它会按照您在会话中的预期进行处理。 但是,您可能会遇到在Web捆绑包之间共享该会话的问题,以至于不确定它是否可能。

您还可以查看单个Web捆绑包,然后使用Eclipse扩展注册表来扩展Web应用程序的function。