我有10多个Spring Boot应用程序,可以将它们构建为war文件并部署在应用程序服务器中或单独运行。每个应用程序都包含业务操作所需的唯一代码,功能和RESTful服务。
我的包裹结构如下:
WebServices (Gradle project)
|---A (Gradle project)
|---B (Gradle project)
|---C (Gradle project)
服务A,B和C都打包并可以作为战争运行。
但是,我还希望提供一个选项来启动包含所有服务的“大型”服务器,而不必分别启动每个应用程序或因大型Spring Boot大战而停滞主应用程序服务器。
理想情况下,这将通过另一个Spring Boot应用程序进行,该应用程序使用ComponentScan包括所有其他服务的功能。我要使用Spring Boot应用程序 X ,该应用程序引用了服务 A , B 和 C 中的功能。 / p>
问题在于上下文。通过应用程序服务器启动时,我的每项服务都会根据war文件的名称自动分配一个上下文。例如,如果我在应用程序 A 中具有安全功能,因为它包含敏感信息,我可以使用以下方式登录:
/ 安全性 /登录
其中 security 是War文件(security.war)的名称。
为弥补这一点,在独立运行时,我为上下文设置了一个应用程序属性,以匹配war文件名server.servlet.context-path: /security
。这使我可以保持使用两种部署方法部署的相同端点天气。
现在,当我启动服务器 X 时,该服务器引用带有组件的项目 A , B 和 C 扫描@ComponentScan(basePackages = {"com.package.a.*", "com.package.b.*", "com.package.c.*"})
我在应用程序 A 中释放了安全性的上下文,现在可以通过以下方式访问我的端点:
/登录
应用程序 A , B 或 C 之间没有区别。
所以,我的问题是如何基于被扫描的组件来维护单个上下文,甚至基于上下文进行路由?
答案 0 :(得分:1)
由于Spring Boot并非真正针对您的要求而设计,因此您必须具有很大的创造力。以下是一些指示:
选项1
只要在同一台服务器上部署了许多战争,contextPaths就会不同,您可以根据实际服务器使用它们,但是它们必须不同,以便Web服务器可以以某种方式区分它们。 考虑到这一点,您可以运行您要尝试执行的操作,然后定义一个代理(Zuul,ha-proxy或其他任何代理),该代理将仔细地将每个可能的URL映射到适当的服务器。
选项2
与1几乎相同,但是您可以使用docker-compose(甚至kubernetes)并将spring boot应用程序作为不同的容器运行。如果您想在CI或开发环境中运行,则可以说这可能是一个更好的解决方案(docker compose会在给定已创建war文件的位置的情况下为您构建所有内容,而无需移动到Web服务器,部署服务器等)。只是说这是一个选择。
选项3
如果您真的希望它们全部位于同一内容路径中。创建一个gradle插件,将wars / jars合并为一个。胖子风格。请注意,Spring Boot应用程序可能具有不同的布局(在Jars中肯定是这样),因此该实现可能应执行以下操作:
第1步
该插件假定已构建模块A,B,C。现在我没有Gradle的经验,但是在Maven中,您可以转到目标目录(我相信gradle中有一个用于相同目的的构建目录)并提取war / jar的内容(类,资源,依赖项)放入另一个文件夹,例如对于项目A,然后对项目B执行相同操作,依此类推。依赖项可能会发生冲突(不同版本,因此您必须确保所有应用程序都使用相同版本的依赖项来消除问题),这些类不应发生冲突,因为它们应驻留在不同的包中(com.package.a
与com.package.b
相对)。
第2步
在步骤“ a”之后,您必须将所有内容打包到您选择的工件中,该工件仍应是spring boot项目。如果您选择使用JAR,则必须了解JAR的构建方式。我无法评论WAR,还没有在Spring Boot中与之合作。
选项4
与选项3几乎相同,但第1步是在其构建的真实项目之一(如项目A,B等)下完成的。该插件会将生产类,依赖项或其他内容复制到某个预定义的文件夹中。该插件将安装在每个模块中,以便它在运行时将“贡献”到一天结束时将包含所有必需资源的文件夹。步骤2与方法3相同。
更新
根据您的评论,考虑使用Jars和选项1 /2。Jars是在春季启动应用程序中推荐的工作方式,对于那些维护Web服务器并且不想执行“操作”的老式组织,应该使用wars ”更改。
现在,如果端口是一个问题,如果您使用容器/ kubernetes编排,则还可以为每个服务分配一个虚拟主机名,以便可以在同一端口上使用虚拟主机名访问所有虚拟主机名。代理服务器选项将为所有端口提供相同的端口和主机
答案 1 :(得分:0)
我以另一种方式解决了这个问题。
我在每个控制器上都设置了一个默认RequestMapping("${serviceContext}")
。每个控制器的服务在何处更改。即 aContext , bContext 和 cContext 。
在我已被上下文绑定的环境中,在应用程序服务器内并通过application.yml独立运行,此属性未设置,并导致已经存在的绑定。
在捆绑软件应用程序中,我能够对@ComponentScan(basePackages = {"com.package.a.*", "com.package.b.*", "com.package.c.*"})
进行组件扫描。然后,该更改将在应用程序启动期间添加其他属性。
用于绑定上下文的属性
Properties properties = new Properties(); properties.put("aContext", "/security"); properties.put("bContext", "/b"); properties.put("cContext", "/c");
我在运行应用程序之前将其添加到Spring的setDefaultProperties
中。然后,当我将每个捆绑包启动时,我将获得预期的上下文绑定。