EJB与客户端构件 - 运行时依赖关系?

8
我们公司将ejb拆分成两个artifact。impl artifact包含实现代码,而client artifact则包括所有接口。这意味着impl artifact在编译时需要依赖于client artifact。
在运行时,client artifact需要impl artifact,否则容器无法注入所需的对象。这意味着ear文件需要包含所有client artifacts所需的impl artifacts。
这是否意味着client artifact应该在impl artifact上有一个"runtime"依赖呢?或者这些"循环"依赖应该被避免,即使一个方向是"compile",另一个方向是"runtime"?
2个回答

1
这是否意味着客户端构件应该在运行时依赖于实现构件?
不是的,也没有依赖关系(或者说最好没有)。查看客户端构件类和接口中的导入语句,您会发现客户端构件不依赖于实现。
如果客户端依赖于实现,它将违反依赖反转原则,这是SOLID原则的一部分。
或者说,这些“循环”依赖关系应该被避免,即使一个方向是编译时,另一个方向是运行时?
实际上,在运行时需要实现,但这是组件装配的问题。有一天,您可能想要替换实现,或者出于测试原因。因此,引入Maven依赖项以使组件装配稍微容易一些并不是一个好主意。
相反,您应该在EAR部署单元中声明实现依赖项,因为EAR是企业应用程序的组装。
我们的开发人员抱怨,确保每个客户端都有相应的 ear 实现是繁琐的手动工作。我们需要在 dependency:list 中查找所有客户端构件,添加所有对应的实现构件,再次调用 dependency:list,再次添加所有缺失的实现构件等等。
我认为他们逐字逐句地看待了 JEE development roles 描述。
软件开发人员执行以下任务以交付包含 Java EE 应用程序的 EAR 文件:
将之前阶段创建的 EJB JAR 和 WAR 文件组装成 Java EE 应用程序 (EAR) 文件
指定 Java EE 应用程序的部署描述符 (可选)
验证 EAR 文件的内容是否格式正确并符合 Java EE 规范
尽管规范也说
汇编器或部署者可以直接编辑部署描述符,也可以使用工具根据交互选择正确添加 XML 标记。
我认为一个 ear pom 是使用工具的组装说明的一个例子。

JF Meier也提到了:

一些开发人员为此编写脚本,但是当某些ejb的版本发生更改时,可能需要重复此过程,因为在依赖树的深处,ejb客户端可能被删除或添加,因此可能需要额外的实现。

对我来说,这些脚本与ear pom相同。可能更灵活,但代价是标准和约定。他们必须随着每个版本的更新而更新脚本,这表明如果这些版本也由maven更新,则会更好。

此外...由于ear pom只是一个maven构件,因此它也可以部署到存储库中。这比私有脚本更好,除了作者之外,没有人可以访问它们。

希望这些论点能帮助您与同事讨论部署策略。


我理解您的观点,但“组件装配”才是难点所在。我们的开发人员抱怨确保每个客户端都有相应的ear实现是繁琐的手动工作。首先,在dependency:list中查找所有客户端构件,然后添加所有相应的impl构件,再次调用dependency:list,再次添加所有缺失的impl构件等等。 - J Fabian Meier
一些开发人员为此编写脚本,但是如果更改了某些EJB的版本,则需要重复该过程,因为可能在依赖树的深处,EJB客户端被删除或添加,因此可能需要额外的实现。 - J Fabian Meier
感谢您的进一步讨论。我的意思是:EAR开发人员编写脚本来更新他们的POM。POM或Maven没有机制来确保每个客户端都有相应的实现。这必须由EAR的开发人员确保,否则EAR将在运行时出现故障。 - J Fabian Meier
但是 ear pom 应该列出应该用作其依赖项的实现。我的意思是,ear pom 是部署的最终工件的描述。因此,它必须声明必须包含的所有实现。它可以省略客户端依赖项,因为这些依赖项由实现(传递依赖项)引用,并且也将默认包含在内。 - René Link
我们有很多客户端对应的实现。也许我在我的依赖部分有a-impl、b-impl和c-impl。但是在更新后,c-impl使用了d-client。现在我还需要在依赖部分添加d-impl。此外,我还需要找出d-impl是否使用e-client,这意味着我还需要将e-impl添加到依赖部分。迭代这个过程... - J Fabian Meier
显示剩余4条评论

0

你不需要担心客户端对实现的隐式依赖,因为服务器会管理它。

EJB容器通过创建代理来调用实现,因此客户端从未直接引用它。

如果你有包含EJB的pom文件:

<groupId>com.stackoverflow</groupId>
<artifactId>Q43120825-server</artifactId>
<packaging>ejb</packaging>

<dependencies>
    <dependency>
        <groupId>javax</groupId>
        <artifactId>javaee-api</artifactId>
    </dependency>
    <dependency>
        <groupId>com.stackoverflow</groupId>
        <artifactId>Q43120825-api</artifactId>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <artifactId>maven-ejb-plugin</artifactId>
            <configuration>
                <ejbVersion>3.2</ejbVersion>
            </configuration>
        </plugin>
    </plugins>
</build>

以及包含 EAR 文件的 pom:

<dependencies>
    <dependency>
        <groupId>com.stackoverflow</groupId>
        <artifactId>Q43120825-server</artifactId>
        <version>1.0-SNAPSHOT</version>
        <type>ejb</type>
    </dependency>
    <dependency>
       ... other modules
    </dependency>
</dependencies>

<build>
    <finalName>${project.artifactId}</finalName>
    <plugins>
        <plugin>
            <artifactId>maven-ear-plugin</artifactId>
            <version>2.10.1</version>
            <configuration>
                <version>7</version>
                <defaultLibBundleDir>lib</defaultLibBundleDir>
                <modules>
                    <ejbModule>
                        <groupId>com.stackoverflow</groupId>
                        <artifactId>Q43120825-server</artifactId>
                        <bundleFileName>Q43120825-server.jar</bundleFileName>
                    </ejbModule>
                    ... other modules that might have the API jar as a dependency
                </modules>
            </configuration>
        </plugin>
    </plugins>
</build>

然后这将构建一个正确的EAR文件,其中API jar位于其lib目录中。


我并不真正理解<ejbModule>的目的。无论如何,我的担心是一个给定的ejb-impl-jar在运行时可能需要另一个ejb-impl-jar,但Maven只会在编译时检测到它需要ejb-api-jar。这意味着某些ejb-impl-jars可能不会被打包到ear中,尽管它们在运行时是必需的(我们有大量的ejb-jars,具有相当复杂的依赖结构)。 - J Fabian Meier
maven-ear-plugin会自动推断需要在application.xml中生成<module><ejb>...</ejb></module>元素,因为它具有<type>ejb</type>的依赖项。然而,由于现代Java EE规范要求基于模块名称生成JNDI名称,因此我们使用<bundleFileName>进行硬编码,以便我们获得<ejb>Q43120825-server.jar</ejb>而不是<ejb>Q43120825-server-1.0-SNAPSHOT.jar</ejb> - Steve C

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接