繁体   English   中英

通过工件版本向后兼容

[英]backwards compatible by artifact version

我正在使用三个Maven项目开发RESTful Webapp。 这是我的Maven设置(从一些详细信息中剥离)

客户端(第二版):

<project>
    <groupId>com.mycompany.app</groupId>
    <artifactId>app-client</artifactId>
    <version>2.0</version>
    ...
    <dependency>
        <groupId>com.mycompany.app</groupId>
        <artifactId>app-model</artifactId>
        <version>2.0</version>
    </dependency>
</project>

模型(第二个版本):

<project>
    <groupId>com.mycompany.app</groupId>
    <artifactId>app-model</artifactId>
    <version>2.0</version>
</project>
...
<plugin>
    <groupId>org.jvnet.jaxb2.maven2</groupId>
    <artifactId>maven-jaxb2-plugin</artifactId>
    <configuration>
        <generatePackage>com.mycompany.app.model.v2</generatePackage>
    </configuration>
</plugin>

Webapp(第二版):

<project>
    <groupId>com.mycompany.app</groupId>
    <artifactId>app-webapp</artifactId>
    <version>2.0</version>
    ...
    <dependency>
        <groupId>com.mycompany.app</groupId>
        <artifactId>app-model</artifactId>
        <version>1.0</version>
    </dependency>
    <dependency>
        <groupId>com.mycompany.app</groupId>
        <artifactId>app-model</artifactId>
        <version>2.0</version>
    </dependency>
</project>

对于每个发行版,我都会更新模型的软件包名称,以确保唯一的类名称。

com.mycompany.app:app-model:1.0中的Foo类

package com.mycompany.app.model.v1;

public class Foo {
    private String name;
}

com.mycompany.app:app-model:2.0中的Foo类

package com.mycompany.app.model.v2;

public class Foo {
    private String name;
    private int age;
}

在第一个版本中,一切正常,因为Webapp仅依赖com.mycompany.app:app-model:1.0。 在第二个版本中,maven决定仅依赖com.mycompany.app:app-model:2.0。 这是正常行为,我了解在正常情况下为什么这是一件好事。 尽管如此。 我的Backwords兼容性代码(在服务器中)希望使用com.mycompany.app:app-model:1.0中的类,因为该版本中发布的客户端使用了这些类。 而且,较新的客户端(2.0版)的代码希望使用com.mycompany.app:app-model:2.0类。

我敢肯定,有一种诱使Maven依赖于两者的方法,但是如何? 通常,当我最终遇到这种情况时,我的脑海里就会响起警报,而我解决问题的方式通常出问题了。 但是我似乎在这里找不到其他方法,它不包括其他“更大”的缺点:(想知道有人吗?

因此,回答我自己的问题,这就是我的想法。 我认为这是相当困难的,而不是很多现成的。

最初我有3个人工制品:

  • com.mycompany.app:app-client
  • com.mycompany.app:app-model
  • com.mycompany.app:app-webapp

最后,我又介绍了一种人工制品:

  • com.mycompany.app:应用依赖

该工件的唯一工作是将所有已发布的模型工件捆绑到一个可靠的工件中。 为此,我遵循Esko的建议并使用了maven插件:

  • org.apache.maven.plugins:maven依赖插件

目标是打开包装 这会将所有.class文件放在目标目录下的一个目录中,并且由于我确保每个模型版本都在唯一的程序包中生成了类,因此可以正常工作而不会被覆盖。 我只包含.class文件,而忽略了所有其他文件(MANIFEST.MF,pom.xml和pom.properties)

之后,trix很简单。 我要做的就是向工件添加资源,并且由于它不包含任何其他来源,因此成为了一个新的可靠工件。 真好!

现在,为了使所有这些都能按照我想要的方式工作,我在Webapp工件中声明了新工件作为依赖项,从而使我可以访问模型所有版本中的所有类。 另一方面,客户端仍然只需要依赖模型,因为客户端只对最新的模型版本(发行时)感兴趣。

我还设法设计了webapp,以便如果版本1的客户端调用了webapp,他会在模型版本1中得到响应,他理解。 同时,当第2版中的客户端调用webbap时,他会收到模型版本2的响应,他理解。 这一直是我们的目标,我认为这将促进我的api的版本控制。

我应该提到,Web应用程序具有自己的域模型(独立但类似于表示模型),因此对于所有请求,都需要完成从域到表示的转换。 对于版本1,这两个模型几乎相同,但是在版本2中,域已更改,(最新)表示也已更改。 Webapp最好将域转换为演示模型1和2,但是模型1可能没有所有信息。 现在,如果域模型发生了很大的变化,以至于试图将其转换为表示模型1毫无意义,我认为是时候停止支持该模型了。

依赖maven pom最终看起来像这样(对于版本2)

<project>

  <groupId>com.mycompany.app</groupId>
  <artifactId>app-depend</artifactId>
  <version>2.0</version>
  <packaging>jar</packaging>

  <build>
    <resources>
      <resource>
        <!-- this is where 'unpack' puts the files -->
        <directory>${project.build.directory}/dependency</directory>
        <filtering>false</filtering>
      </resource>
    </resources>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-dependency-plugin</artifactId>
        <version>2.5.1</version>
        <executions>
          <execution>
            <id>unpack</id>
            <!-- we must do the 'unpack' before the building the jar -->
            <phase>generate-sources</phase>
            <goals>
              <goal>unpack</goal>
            </goals>
            <configuration>
              <artifactItems>
                <artifactItem>
                  <groupId>com.mycompany.app</groupId>
                  <artifactId>app-model</artifactId>
                  <version>1.0</version>
                  <type>jar</type>
                  <includes>com/mycompany/app/model/v1/**</includes>
                </artifactItem>
                <artifactItem>
                  <groupId>com.mycompany.app</groupId>
                  <artifactId>app-model</artifactId>
                  <version>2.0</version>
                  <type>jar</type>
                  <includes>com/mycompany/app/model/v2/**</includes>
                </artifactItem>
                <!-- future releases will go here -->
              </artifactItems>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

</project>

那是IT人员!

这个问题比Maven更深。 默认情况下,JVM将仅加载类的一个版本。 如果程序的类路径上有两个版本的com.mycompany.app.model.ModelObject (例如),则当您的一个类请求ModelObject ,类加载器将退出并加载它找到的第一个。

我看到在公共Web服务中处理此问题的一种方法是根据所有类的版本对它们进行命名空间。 因此,例如,版本1模型类可以放在包com.mycompany.app.model_1 ,版本2模型类可以放在com.mycompany.app.model_2 在这种情况下,您(和客户)可能最终要编写大量的额外代码。

可能更简单的方法是为要支持的模型的每个版本托管一个单独的webapp,并根据模型版本指定webapp路径。 因此,在这种情况下,版本1的Webapp可能托管在http://app.mycompany.com/webapp_1/... ,版本2的托管在http://app.mycompany.com/webapp_2/... (Web服务器为每个webapp使用单独的类加载器,因此webapp_1和webapp_2可以使用同一类的不同版本。)

(如果您喜欢冒险,也可以尝试在单个Web应用程序中为每个模型版本设置自己的单独的类加载器。我不知道是否建议这样做。)

您可以使用Maven Dependency插件的复制目标将这些工件复制到项目中的目录中。 复制同一工件的多个版本应该可以。 尽管仍然无法帮助针对这些不同版本编译代码(您可能需要将其他类路径配置为手写编译器参数 )。

或者只是更改每个版本的工件ID。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM