GWT和SpringBoot - 有一种智能的方法来处理冲突的依赖关系吗?

时间:2016-05-17 21:24:16

标签: gwt spring-boot gwt-super-dev-mode

在一个理想的世界中,您将GWT应用程序编译为javascript,将其作为静态资源提供,并在幕后运行JVM上的后端代码,并且生活顺利。 但是这个理想世界在运行时被称为生产。

但是,在开发期间,当您想使用gwt代码服务器时......

您需要在运行时(源代码+类)中使用GWT编译时依赖项,以便调试和重新编译GWT模块。

与此同时,您可能希望通过spring-boot 1.3.5.RELEASE等支持后端。

在这种情况下,遭受多次频繁发布的spring boot现在想要添加为托管依赖项,例如:

<hibernate-validator.version>5.2.4.Final</hibernate-validator.version>

当然,这是一件非常好的事情。事实上,它是春天的众多优点之一。

另一方面,Gwt,见下面的链接, http://www.gwtproject.org/doc/latest/DevGuideValidation.html

仍然要求您使用:

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>4.1.0.Final</version>
            <scope>runtime</scope>              
        </dependency>

现在,如果你要说:我不关心生产性发展,只需编译一些在生产中正常运作的东西。

然后,您可以通过以这种方式构建项目来轻松解决上述问题:

ROOT
--- Backend-api
--- Backend-Impl
--- Gwt-Front-end
---- War or stand alone Spring jar module to glue it all together

对于某些RPC服务和DTO,使Gwt-Front端依赖于后端API的位置。您可以在大多数情况下仅在前端模块中管理pom.xml依赖项,而与后端中的哪些依赖项无关。 最后,你制作一个战争,或一个弹簧启动可运行的jar,它将你的gwt代码作为静态资源,并带有你的所有依赖项的后端代码,即Hirbernate验证器最新版本。

然而,当你试图获得一个可用于开发目的的pom时,据我所知,你不得不全局地管理后端和前端层之间常见的依赖关系在ROOT pom.xml中,将依赖项降级为gwt所需的版本。

也就是说,在理想的世界场景中。 你有你的ROOT pom.xml只是声明你的模块和它们构建的顺序。并且你得到了你的后端impl,有权声明它想要从spring-boot-starter pom.xml等继承依赖关系......

与理想情况相反,在开发时实际帮助您的pom.xml配置中... 好吧,你必须重新访问Root pom.xml。 并且您必须在此根pom.xml中添加托管依赖项,以便对于GWT前端和Spring引导后端之间的所有常见冲突依赖项,您始终必须锤击GWT的版本并进行降级到位。

这将确保当你执行gwt:run,dev模式重新编译等...你最终没有让gwt编译器尝试javascript编译你的Hibernate版本5,而是确实支持GWT的版本4.1决赛。当然,你最终可能会对后端代码感到惊讶,其中一天就是通过实施这样的黑客攻击......

是否有人知道如何正确组织多模块项目,其中允许基于后端和gwt的前端具有冲突的依赖性要求?

最终,如果答案是否定的,我相信我会更喜欢网络浪费并增加通信延迟,通过一个纯粹的独立弹簧引导后端与纯gwt独立码头集成,后端在这个码头上做的只不过是愚蠢地将请求发送到实际的弹簧启动后端。让gwt jetty后端被UI调用1 + 1并将计算转发到第二个后端运行的sprin引导,实际上知道如何做1 + 1 ......这有点可悲。但如果这是最有效的工作方式,那么确保开发是有效的,生产将毫无意外地运行,所以就这样吧。

感谢您的反馈,理想情况下,我希望看到一个多pom项目,您可以将其作为现有的maven项目导入到eclipse中,并演示如何实现这一目标。

3 个答案:

答案 0 :(得分:2)

找出编译GWT代码时要排除的传递依赖项。

    <dependency>
        <groupId>spring-dependency-with-hibernate</groupId>
        <artifactId>some-spring-boot-starter</artifactId>
        <exclusions>
            <exclusion>
               <groupId>org.hibernate</groupId>
               <artifactId>hibernate-validator</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

这样,只有GWT提供的hibernate版本才会在运行时提供。

答案 1 :(得分:2)

是的,我想做的事情其实可以做到,虽然不是微不足道的......根本不是。

要设置maven多模块pom,可以高效地使用,因为您可以为后端代码和前端代码交换代码,而无需选择gwt验证器依赖项或springboot验证器依赖项,基本上我按如下方式组织我的项目。

你有:

LEVEL 1: myproject-root
----- LEVEL 2: myproject-backend
---------- LEVEL 3: myproject-backend-api
---------- LEVEL 3: myproject-backend-impl
------ LEVEL 2: myproject-frontend
------ LEVEL 2: myproject-runner
-----------LEVEL 3: myproject-runner-jar
-----------LEVEL 3: myproject-runner-war

在myproject-root中,您自然会声明子模块。 您对一些无用的插件(例如surefire插件)进行依赖关系管理。您可以控制java源代码和目标编译语言。你做的不多。如果您有一些可以交叉配置的插件,那么您可以将它们放在插件管理中。

在myproject-backend中,通过添加到依赖关系管理,你基本上让它继承到依赖关系管理springboot依赖项:

<dependencyManagement>
        <dependencies>
            <!-- Inherit dependencies from spring boot dependency management pom -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-parent</artifactId>
                <version>${version.spring.boot}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

你声明了两个子模块,然后你就出局了。 您没有在此声明任何交叉切割依赖项。您只使用依赖关系管理。前端组件将隐藏api子模块,并且您不希望在后端pom中创建依赖磁体,所以在这里您尽可能保守。

在myproject-backend-api中,首先让这个子模块成为一个jar子模块。在线下,您将希望通过按入口点性质细分api-s来进一步分支api组件。 首先,-api组件将具有服务器和前端之间通信所需的api,类似于通常看到的&#34; shared&#34;在文档中。 在这里,您要尽可能小地了解依赖项元素中的元素。前端将使用这些api,你不希望你的api包取决于任何spring boot apis。

在后端impl中,您可以编写实际的业务逻辑,并且可以自由地依赖完整的Spring引导堆栈。规则是,确保没有人指向这种依赖磁铁,特别是,永远不要让gwt组件闻到springboot库的存在。不要提及它。

在myproject-frontend中,您不会将其分支到不同的子模块中,就像您对api组件所做的那样。 在这里,您为gwt代码创建一个monolitic组件,以便您可以更轻松地使用gwt maven插件为您进行热代码重新编译。 在这个组件中,你依赖于myproject-api,以及任何相关的gwt库,例如gwt-user,hibernate验证器以及gwt所需的旧版本等等...... myproject-frontend的规则是将组件中的每个依赖项声明为可选。您不希望对组件采用任何传递依赖性。 在生产中你需要的是myproject-frontend.jar / META-INF / resources / MyProjectModule.html ...... 而springboot必须检测和服务的所有这些静态资源。 但是,当您处于开发模式时,您希望在此前端组件中执行的操作是: (a)调整你的gwt-plugin以不运行jetty服务器

<noServer>true</noServer>

关键是,如果运行这个jetty服务器,它在类路径中唯一的东西就是前端代码和api,绝对不是impl代码。 第二,你不想使用gwt jetty,你要么想使用springboot tomcat,要么使用springboot jetty。更好的方法是使用springboot的嵌入式容器和相应的websocket库等。

(b)使用springboot,您希望从META-INF / resources /或公共文件夹中为静态资源提供服务。我更喜欢资源,因为它通常也会放置JSF组件。 在任何情况下,因为静态资源的来源很特殊,所以你想调整你的gwt插件来将你的java源代码编译成write文件夹。

<webappDirectory>${project.build.directory}/classes/META-INF/resources</webappDirectory>

如上所述。

最后,这是我的主要错误,您不会从编写前端代码的位置运行代码。 这是错误的,因为这会迫使您的前端代码需要springboot依赖项,这会因为库的冲突而导致极度痛苦。

因此,为了避免这个问题,你创建了myproject-runner组件,如果你想非常详细,你可以将它作为一个pom父组件,这样你就可以将你的包装分成jar或war。 我个人更喜欢可执行jar,而不是war选项。我永远不会想要像一个重量级的weblogic那样部署sprinboot应用程序......但不管你的船是什么晃动。

无论如何,弹簧靴跑步者是你最终的依赖性magenet。 该组件将取决于您拥有的每个模块及其传递依赖性。但是因为你将你的跑步者组件与前端代码分开,并且你在前端代码中做出所有依赖关系...... 好吧,你基本上只捆绑了springboot和你的gwt静态资源。

在你开发的过程中,你所做的就是......一旦你知道它......简单。 (A)通过触发主文件启动spring boot jar应用程序。如果你真的想要部署一个war文件,你可以选择构建war文件并将其部署到tomcat或者其他任何东西......

(b)你去你的前端组件,直接点击它,选择以Maven Build运行,然后运行gwt:run。 gwt运行将启动gwt代码服务器,它将完全对你的后端代码视而不见,它面前唯一能看到的就是你在前端组件中的代码以及你所有的gwt依赖关系# 39; ve加入了optinal。

如果您使用springboot dev,最后可以在后端热交换代码。 一旦你启动了teh gwt插件,你最终可以在该monolitic前端组件中热交换代码。

结论,这是可能的,但它是一团糟。 很高兴这个问题不在考虑范围内。

答案 2 :(得分:0)

我相信我也有类似的问题,并且在使用Eclipse IDE,GWT Google插件,SpringBoot和Maven时发现了以下问题。 食谱并不简单,但是对我的团队有用。

GWT-dev和Jetty服务器不适用于SpringBoot。 由于Jetty和gwt-dev硬编码的依赖关系,您必须修复类路径,只有针对gwt-dev和Jetty的依赖关系才有效。

我不得不将GWT UI项目分成两个Maven工件。 一个工件是一个WebApp,它只能在Eclipse中运行,而所有SpringBoot库都从类路径中排除。 另一个工件是具有“ war” maven打包类型的可部署SpringBoot JAR,并且Eclipse专用工件的WAR覆盖图仅包括GWT特定内容。

我希望这会有所帮助