【问题标题】:Handling multi-war setup with shared parent spring context in tomcat with maven使用 maven 在 tomcat 中使用共享父 spring 上下文处理多战争设置
【发布时间】:2012-12-28 10:07:01
【问题描述】:

这可能是一个非常初级的问题,但如果这是众所周知的并且已在其他地方解决,请帮助我。

我有一个多战争设置(所有 maven 模块)说 kilo-webapp1kilo-webapp2 作为我需要在 Tomcat 实例上部署的两个 WAR。这两个 web 应用程序都使用来自公共服务 jar 的服务,例如 kilo-common-services.jarkilo-common-services.jar 有自己的 spring 上下文,由 jar 即用户加载。在这种情况下,kilo-webapp1kilo-webapp2。碰巧kilo-common-services中的服务初始化需要很长时间,因此我希望它只发生一次(以确保启动实例所需的时间不是很高),这也对我有帮助将其用作在 JVM 实例中保持最新的二级缓存。为此,我们采取了以下步骤:

  1. 修改tomcat中CATALINA_BASE的catalina.properties,将shared.loader改为${catalina.base}/shared/lib
  2. kilo-common-services.jar 及其所有依赖的jar 复制到CATALINA_BASE/shared/lib。 [手动步骤]
  3. 将 spring 相关的 jar 复制到 CATALINA_BASE/shared/lib 位置 [手动步骤]
  4. kilo-common-services.jar 中创建了一个beanRefContext.xml 文件。在此处定义一个新的ClassPathXmlApplicationContext,其中为构造函数提供了公共服务的 spring 上下文文件的位置。
  5. kilo-webapp1kilo-webapp2 pom 文件中将kilo-common-services.jar 和所有其他依赖项(如Spring 相关的jar)的依赖范围标记为provided。对于 Spring,这需要确保不会触发两次类路径扫描操作。如果没有通过provided 范围排除,这也会导致不同的ClassCastExceptions(比如说log4j)。
  6. kilo-webapp1kilo-webapp2 的web.xml 表明它们的父上下文是kilo-common-services.jar 中定义的servicesContext

我能够验证只有一个kilo-common-services 服务实例存在,但是您可能想象的设置很痛苦。如果有人在 Eclipse 之类的 IDE 中进行此类设置的最佳实践,将不胜感激。我的问题如下:

  • #2 正在成为一个挑战。我目前在kilo-common-services 上运行mvn dependency:copy-dependencies 将依赖的jar 从target/dependency 复制到shared/lib,这是一个非常糟糕的手动步骤。一次又一次,我忘记重新生成依赖项,不得不重新部署。
  • #3 也不是直截了当的,因为经常有更新的常见依赖项,我们总是必须记住将其复制到共享库以避免 ClassCastExceptions
  • #5 再次成为维护的噩梦。

此外,随着时间的推移,将有更多这样不同的普通罐子需要共享,并且每个罐子都会带来痛苦。随意批评设置并提出一个更好的设置,它可能易于使用(也来自 IDE)。很乐意提供任何其他详细信息。

提前致谢!

【问题讨论】:

  • kilo-common-services.jar 中的这些服务是什么类型的?网页服务 ?或者只是一种将用作通用代码的库功能?
  • 常规图书馆进程内服务。
  • 如果它只是一个通用代码库,我建议将其与两个 war 文件一起打包,并且您摆脱了在现实生活中通常会导致问题的单独部署步骤(共享库)。跨度>
  • 我认为他想在应用程序上保留一个缓存,这就是为什么他只想要一个kilo-common实例。您可以使用分布式缓存,但这会增加很多复杂性:S.
  • @khmarbaise 我很想知道这些现实生活中的问题是什么,因为我认为这正是 maven、单元测试和持续集成旨在解决的问题......

标签: java eclipse spring tomcat maven


【解决方案1】:

问题在于您的架构已损坏(这就是您为解决方案苦苦挣扎的原因)。您有两种解决方案:

1) 如果您想在两个战争应用程序之间共享一个需要很长时间(初始化)的服务,请将其完全设为一个单独的服务,并通过休息或任何类型的远程处理来访问它。

2) 将两个 webapp 合并为一个。

拥有公共库是共享库文件夹会给你带来很多麻烦,你最终会回滚它。

我的(个人)方法是合并两个应用程序,但保持包足够分离并具有单独的弹簧配置。这样,至少你仍然保持了两个 webapp 的逻辑分离。 此外,由于两者都在同一个容器上运行,因此进行 2 次单独的战争几乎没有什么好处(除非您计划很快将它们移动到不同的容器中)。


关于 IDE,您可以使用 maven-cargo-plugin 来启动一个带有多个 Web 应用程序的 tomcat,并具有(几乎)任何您想要的配置。

【讨论】:

  • “拥有公用库是共享库文件夹会给你带来很多麻烦” 为什么?您在共享位置有一个版本的所需文件/类,有什么问题......?如果您转换为 REST 调用,那是您必须管理的第三个 Web 应用程序(并首先为其开发 RESTful 界面)
  • 答案在原问题中:他只想初始化一次公共服务。问题很简单(但不明显),很容易创建类加载器的噩梦。这种方法适用于标准资源(例如 jdbc 连接),但在共享库中拥有完整的业务逻辑堆栈则不行。它还存在如何将共享对象注入两个 Web 应用程序的问题(但这可以通过一些 jndi 黑客来完成)
  • "如何将共享对象注入两个 Web 应用程序" 为什么会有问题?您只需照常执行(在我的情况下,将 jar 包含为依赖项并注入注释。我仍然不明白为什么它是“类加载器的噩梦”。我刚刚将所有 jar 移动到共享文件夹中,我不得不增加 MaxPermspace ...但我的可部署战争文件的大小已从 20mb 缩小到 400kb。
  • “这种方法适用于标准资源(例如 jdbc 连接)”您显然是指 JDBC 数据源(不是连接)。嗯,这是共享业务服务的一个很好的例子——池化的 JDBC 数据源总是共享的,而且运行良好。而且它们绝不是“标准资源”,它们很常见但不是标准的。所以不清楚为什么其他业务服务不能以与 JDBC 数据源相同的方式使用。至于 RESTifying 他们 - 这是一个巨大的性能影响。现在不调用 JVM 中的方法,您必须在 JSON 中序列化您的参数,响应也是如此。
【解决方案2】:

我们正在开发 restful soa,使用 spring 和 tomcat 并利用域驱动设计(无论如何,这就是计划)。有 migrationProject 和初始的基本搜索服务。两个独立的 WAR 文件,带有两个独立的 POM。两者都使用相同的域对象。

所以我将有一个单独的项目,它只是 DomainObjects 我会将它们包装到一个 jar 中,然后使用 maven 和/或 jenkins 它会自动部署(每当我配置时(例如,当推送到特定存储库时) .

拥有同一个罐子的两个副本,对我来说听起来是一个更糟糕的主意。不是您的架构被破坏,而是您的部署和开发过程需要改进,恕我直言。

(my kind of related question).

我们的长期计划是让一个项目作为 restful 接口,由多个控制器从它们的依赖项中注入服务类和存储库。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-29
    • 1970-01-01
    • 2015-06-19
    • 2013-03-23
    • 1970-01-01
    • 2010-11-14
    相关资源
    最近更新 更多