在多应用程序环境中处理枚举
我们公司主要使用 Java 进行开发,并支持许多“实时”系统(主要是长时间运行的服务器进程),所有系统都依赖于共享参考数据和枚举。有时,枚举定义会扩展以包含新值,在这种情况下,当发生这种情况时,我们当前重新部署所有应用程序,原因是我们的每个应用程序都有一个包含所有库 jar 的私有“lib”文件夹(包括“枚举实体”库)。显然这是不可取的,所以我有兴趣听到其他人的建议或方法。
我想到的想法:
- 修改每个应用程序的启动脚本以派生最新的“枚举实体”库版本并将 jar 文件添加到类路径中。
- 某种在运行时动态类加载新枚举定义的机制。
这些方法的问题在于,应用程序通常具有以下格式的代码:
switch(enumVal) {
case A:
// Do something.
break;
case B:
// Do something.
break;
default:
throw new IllegalArgumentException("Invalid enum value: " + enumVal);
}
...,因此当它们遇到默认情况时将开始失败。也许这表明这些实体根本不应该是枚举;它们应该是枚举。在我们的例子中,这确实是一种便利的权衡。或者它可能只是表明我们的应用程序太脆弱,应该更优雅地处理默认情况。
Our firm develops primarily in Java and supports a number of "live" systems (mainly long running server processes), all reliant on shared reference data and enumerations. Occasionally an enum definition expands to include a new value and in this case we currently redeploy all our applications when this happens, the reason being that our applications each have a private "lib" folder containing all library jars (including the "enum entity" library). Obviously this is undesirable and so I'd be interested to hear other people's recommendations or approaches.
Ideas I've thought of:
- Modifying each application's start script to derive the most recent "enum entity" library version and prepend the jar file to the classpath.
- Some kind of mechanism to dynamically class load the new enum definition at runtime.
The problem with these approaches is that applications typically have code in the format:
switch(enumVal) {
case A:
// Do something.
break;
case B:
// Do something.
break;
default:
throw new IllegalArgumentException("Invalid enum value: " + enumVal);
}
... and hence will start failing when they hit the default case. Perhaps this suggests that these entities shouldn't be enums at all; it's really a convenience trade-off in our case. Or perhaps it simply suggests that our apps are too brittle and should handle the default case more gracefully.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
史密斯先生是对的:扩展枚举或老式的“枚举”int 常量很难正确完成,并且通常不是一个好方法。
正如您所暗示的,新的枚举值需要使用它们的客户端进行特殊的行为/处理。一旦修改枚举,您也必须修改客户端。这真的很糟糕,你真的应该尝试以另一种方式重新设计它。
Mr. Smith is right: Extending enums, or the old-school "enumeration" int constants for that matter, can hardly be done right and is usually not a good approach.
As you imply, the new enumeration values require a special behavior/handling by clients using them. Once you modify the enumeration, you thus must modify the clients, too. This is really bad and you should really try to re-design it in another way.
面向对象是专门为了解决这个问题而发明的:你的开关实际上只是一个显式的虚拟表,而隐式的虚拟表会更好。您应该考虑重新设计您的应用程序以使用接口/基类而不是枚举。
这将问题转移到对象创建时间,这为每个枚举提供了单个更改点的直接优势。它还为引入基于插件的架构开辟了道路,该架构很可能不需要任何重新编译,甚至可能导致无需重新启动即可扩展应用程序的可能性。鉴于您谈到的是长时间运行的服务器进程,减少停机时间可能很有吸引力。
避免重新编译的最简单方法可能是采用依赖注入。使用诸如 Spring 这样的框架,您可以有一个或多个配置文件,您可以在其中指定需要创建的对象,然后可以按名称加载它们。
Object orientation was invented specifically to solve this problem: your switch is really just an explicit virtual table when an implicit one would have been far better. You should consider redesigning your application to use interfaces/base classes instead of enums.
This moves the problem to object creation time, which gives the immediate advantage of a single change point for each enum. In also opens the way for the introduction of a plugin based architecture which may well not require any recompilation and may even lead to the possibility of extending your application without restarting it. Given that you speak of long running server processes, a reduction in downtime is likely to be appealing.
The easiest way to avoid recompilation is probably to adopt Dependency Injection. With a framework such as Spring you can have one or more configuration files where you specify the objects you need to create and then you can load them by name.