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

标签 java spring osgi modularization

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

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

  • 类(class);
  • 静态资源(图片、CSS、脚本);
  • Facelet 模板;
  • 托管 bean - Spring 应用程序上下文,具有请求、 session 和应用程序范围的 bean(另一种选择是 JSF 托管 bean);
  • Servlet API 的东西 - servlet、过滤器、监听器(这是可选的)。

  • 我想避免(几乎不惜一切代价)需要将模块资源(如 Facelets 模板)复制或提取到 WAR 或扩展 web.xml用于模块的 servlet、过滤器等。将模块(JAR、包、工件等)添加到 Web 应用程序( WEB-INF/libbundlesplugins 、...)必须足以扩展带有此模块的 Web 应用程序。

    目前,我使用自定义模块化解决方案解决了这个任务,该解决方案很大程度上基于使用类路径资源:
  • 特殊资源 servlet 为来自类路径资源 (JAR) 的静态资源提供服务。
  • 特殊的 Facelets 资源解析器允许从类路径资源加载 Facelet 模板。
  • Spring 通过模式 classpath*:com/acme/foo/module/applicationContext.xml 加载应用程序上下文- 这会加载模块 JAR 中定义的应用程序上下文。
  • 最后,一对委托(delegate) servlet 和过滤器将请求处理委托(delegate)给 Spring 应用程序上下文中配置的来自模块的 servlet 和过滤器。

  • 前几天我阅读了很多关于 OSGi 的文章,我正在考虑如何(以及是否)将 OSGi 用作标准化的模块化方法。我在考虑如何使用 OSGi 解决单个任务:
  • 静态资源 - 想要导出静态资源的 OSGi 包注册 ResourceLoader具有捆绑上下文的实例。一个中央ResourceServlet使用这些资源加载器从包中加载资源。
  • Facelet 模板 - 与上面类似,中央 ResourceResolver使用由包注册的服务。
  • 托管 bean - 我不知道 如何使用类似 #{myBean.property} 的表达式如果 myBean在其中一个包中定义。
  • Servlet API 的东西 - 使用 WebExtender/Pax Web 之类的东西来注册 servlet、过滤器等等。


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

  • 我会非常感谢您的评论。

    最佳答案

    你的目标听起来是可行的,但有一些警告:

    View 层:首先,你的 View 层听起来有点过头了。还有其他方法可以通过使用自定义组件来模块化 JSF 组件,这些方法将避免尝试创建像后期绑定(bind)托管 bean 这样引人注目的东西所涉及的麻烦。

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

    依赖项:我有点担心您将模块描述为“可能相互依赖”。您可能(我希望)已经知道这一点,但是您的依赖项应该形成一个有向无环图。一旦您引入了循环依赖,就应用程序的最终可维护性而言,您会受到伤害。 OSGi 最大的弱点之一是它不能防止循环依赖,因此由您来强制执行。否则你的依赖会像葛根一样增长,并逐渐扼杀系统生态系统的其余部分。

    小服务程序: Fuhgeddaboudit。您不能将 servlet 后期绑定(bind)到 Web 应用程序中,直到 Servlet 3.0 规范投入生产(正如 Pascal 指出的那样)。要启动一个单独的实用程序 servlet,您需要将它放入它自己的应用程序中。

    好的,注意事项就到这里。让我们考虑一下这可能是如何工作的:

    您已经定义了自己的 JSF 模块来执行...究竟是什么?让我们给它一个明确的、相当简单的目的:一个登录屏幕。因此,您创建了登录屏幕,使用 OSGi 将其延迟绑定(bind)到您的应用程序中,然后……然后呢?如果您尚未在 .jspx 页面中定义它,应用程序如何知道登录功能是否存在?应用程序如何知道导航到它不知道的地方?

    有一些方法可以使用条件包含等(例如, <c:if #{loginBean.notEmpty}> )来解决这个问题,但是,就像你说的,当你的托管 loginBean 存在于另一个模块中时,事情会变得有点麻烦,这个模块甚至可能没有被引入到应用程序中然而。事实上,除非 loginBean 存在,否则您将得到一个 servlet 异常。所以你会怎么做?

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

    我需要花点时间指出这不是我处理这个问题的方式。一点也不。鉴于像登录页面一样简单,甚至像股票图表一样复杂,我个人更喜欢创建自定义 JSF 组件。但是,如果要求是“我希望我的托管 bean 是模块化的(即,可热插拔等)”,这是我知道的使其工作的唯一方法。我什至不完全确定 工作。 This email exchange表明这是一个 JSF 开发人员才刚刚开始研究的问题。

    我通常认为托管 bean 是 View 层的一部分,因此我仅将它们用于 View 逻辑,并将其他所有内容委托(delegate)给服务层。在我看来,使托管 bean 后期绑定(bind)是将它们从 View 层提升到业务逻辑中。所有这些教程都如此专注于服务是有原因的:因为大多数时候你想考虑你的应用程序“ headless ”运行需要什么,以及“皮肤”你的 View 是多么容易,如果,例如,您希望它能够在 Android 手机上运行并发挥其所有功能。

    但听起来您正在处理的很多事情本身就是 View 逻辑——例如,需要交换不同的 View 模板。 OSGi/Spring 应该能够提供帮助,但您需要在您的应用程序中选择可用的实现:几乎是 OSGi 的服务注册表的构建目的。

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

    至于你剩下的问题:

    Am I inventing a bicycle here? Are there standard solutions for that?



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

    Do you think OSGi is the right technology for the described task?



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

    Is my sketch of OSGI application more or less correct?



    如果不了解您的组件边界在哪里,我真的无法判断。目前,听起来您可能正在插入 OSGi 做超出其能力范围的事情。

    但不要相信我的话。 I found other这些地方的阅读 Material 。

    既然您询问了 Spring Slices,this should be enough to get you started .您将需要一个 Git 客户端,而且看起来您将通过查看源代码来训练自己使用该应用程序。这是非常早期的原型(prototype)代码。

    关于java - 如何使用 OSGi 模块化 JSF/Facelets/Spring 应用程序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2575669/

    相关文章:

    java - Spring启动Jdbc模板

    java - 运行多个 Spring Boot 测试时,@MockBean 在 JMS 监听器中使用不同的实例

    java支持的网页根本不显示

    java - 将外部库集成到 OSGI 中

    java - 'mvn clean' 与 .'mvn clean install' (当插件执行附加到 'clean' 时)

    java - 在 Spring MVC 3.2.4 中将资源映射到 jsp

    java - 按下按钮后获取图像对应的文件名

    java - 我们可以在osgi服务中添加@postconstruct注解吗?

    java - 不根据 java 系统属性激活 OSGI 声明性服务

    java - 在 Mac 上正确运行基于 SWT 的跨平台 jar