假设有一个包含多个客户端的REST服务。每个客户端必须大致相同才能调用REST服务:构造URL,发送请求,反序列化响应,将HTTP返回代码映射到异常等等。
这似乎是重复的代码,所以将REST网关代码放入可重用的库中可能是个好主意。在Java中,这可能如下所示:
因此,没有客户担心REST,只能调用方法。
这是个好主意吗?
(此问题来自this other question)
答案 0 :(得分:2)
这可能会让您遇到依赖项问题。这是一个非常典型的依赖关系问题,并没有绑定到REST或Jersey。但是,让我们来看看以下情况:
假设有两个服务器(S1和S2),两个客户端(C1和C2)和两个包含用于访问服务器(L1和L2)的其余客户端代码的库。两个客户端都需要查询两个服务器,因此调用结构如下所示:
C1 ---> L1 ---> S1
\ ^
\ /
X
/ \
/ v
C2 ---> L2 ---> S2
此外,L1和L2都依赖泽西岛。此外,容器(可能是在Glassfish或Wildfly应用程序服务器上运行您的应用程序)依赖于Jersey(或至少在jax-rs API [1]上)。
C1的简化依赖结构如下所示:
C1
/ | \
/ | \
< v >
Container L1 L2
| | |
v v v
Jersey Jersey Jersey
只要Jersey的三个版本都相同,一切都很好。什么都没有问题。但如果版本不同,您可能会遇到讨厌的NoClassDefFoundError
s,MethodNotFoundError
等等[2]。
如果版本足够相似,您将不会直接遇到这些错误。也许它会工作很长一段时间。但随后可能发生以下情况:
请记住,错误可能会也可能不会发生。无法保证您遇到麻烦,并且无法保证它会起作用。这是一个风险,一个定时炸弹。
另一方面,这只是一个简单的例子,只有两个服务和两个客户端。当有更多时,风险正在增加。
依赖关系应遵循Stable Dependencies Principle(SDP),其中&#34;取决于稳定性。&#34;鲍勃叔叔使用数字传入和传出依赖来定义它,但SDP可以从更广泛的意义上理解。
当我们查看给定的依赖结构并用zeava替换Jersey时,与SDP的连接变得很明显。这个问题在番石榴中很常见。问题是番石榴通常不向下兼容。它是一个相当不稳定的库,可以在应用程序中使用(不稳定),但是你永远不应该在可重用的库中使用它(它应该是稳定的)。
对于泽西来说,这并不是那么明显,因为你可能会认为泽西岛很稳定。事实上,就Bob Martin的定义而言,它非常稳定。但L2也可能非常稳定。也许它是由另一个团队开发的,一些人离开了公司,没有人敢去触摸它,因为去年有人试图这样做,导致C2团队有依赖性问题。也许L2也是稳定的,因为在开发C1和L2的团队的管理者之间存在一些持续的争吵,所以L2经理声称没有资源,没有预算或其他什么,所以更新L2只能在明年年底完成。 / p>
因此,根据您的代码库,您的组织结构等库可以比您的库更稳定。
optional
,在C1和C2中标记provided
。然后它不包含在你的war文件中,因此只有一个版本的Jersey(容器中的那个)。只要此版本与接口兼容,它就可以正常工作[3]。我建议将您的表示类(即您的DTO)放入客户端jar中,让每个客户端决定使用哪个库来进行REST调用。通常那些REST gateways非常简单,在应用程序之间共享它们通常不值得冒这个风险。至少在没有了解的情况下考虑这里提到的问题,然后再进入这些问题。
[1]为了简化说明,我们忽略了Jersey和jax-rs API之间的区别。论点是一样的。
[2]实际上它有点复杂。通常,您的构建工具(maven等)将选择一个版本的Jersey并将其放入war文件中。泽西岛的另一个版本是&#34;因冲突而被省略&#34;与其他版本。只要版本兼容,这就没问题。因此,您最终会在容器中使用两个版本,并在war文件中使用一个版本。虽然前一种情况下的接口兼容性应该足够,但对于剩下的两个版本来说,它还不够。
[3]因为只有一个版本,所以[2]中提到的问题不会发生。接口兼容性问题当然存在。