如何判断系统属性是否来自人类操作员,而不是默认值?
我有一个 JAR 打包的独立应用程序,在执行时,它会将自身解压到临时目录中,并在该目录中生成一个子进程。原因是一些第三方代码和配置假设数据文件是相对于当前工作目录找到的,而java没有 chdir() 方法,因此唯一的方法是切换子进程的工作目录。
除了系统属性之外,一切正常。操作员可能决定在命令行中指定一些系统属性,包括标准属性和与第三方配置相关的属性:
java -Djava.io.tmpdir=/temp -Dsomething=else -jar foo.jar (parameters)
默认情况下,父 java 进程可用的系统属性不会传播到子进程。我应该自己做。在这里我遇到了一个障碍:我无法分辨哪些属性是由操作符设置的,哪些属性是由 JVM 默认初始化的。
以 java.io.tmpdir 为例。如果操作员提供了它,他就有充分的理由这样做(也许默认位置是“磁盘已满”)。我必须将其设置为子进程,否则会失败。但我怎么知道它是否来自运营商呢?它可能只是默认值。
我可以尝试将所有可用的系统属性设置为子进程。但它需要一个很长的列表,更糟糕的是,在某些命令行长度有限的环境中会失败。
到目前为止,我发现的唯一解决方法(相当邪恶的方法)是首先生成另一个子进程,根本不带任何参数,然后让它将其拥有的所有系统属性通过管道传回父进程。与父级匹配的值是默认值。其余的应该传递给工作子进程。
有人有更好的选择吗?
I have a JAR-packaged standalone application that, when executed, unpacks itself into a temporal directory and spawns a child process within that directory. The reason being some third-party code and configuration assumes data files are found relative to current working directory, and java has no chdir() method, so the only way is to switch the working dir for a child process.
All works fine, except for the system properties. An operator may decide to specify some system properties in the command line, both standard ones and ones related to the third-party configuration:
java -Djava.io.tmpdir=/temp -Dsomething=else -jar foo.jar (parameters)
The system properties available to the parent java process are not by default propagated to child. I should do it myself. And here I get into a roadblock: I have no way to tell which properties are set by operator and which are initialized by default by JVM.
Take that java.io.tmpdir one. If operator has provided it, he has a good reason to do so (perhaps the default location is "disk full"). I have to set it to child process, or it will fail. But how do I know if it came from operator? It may be just the default value.
I may try and set all available system properties to the child process. It takes a long list though and, worse, fails in some environments where the command line length is limited.
The only workaround I've found so far (quite a wicked one) is to spawn another child process first, with no arguments at all, and let it pipe back to the parent all the system properties it has. The values that match those that parent has are defaults. The rest should be passed down to the worker child process.
Does anyone have a better alternative?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
在我工作的地方,我们有一个缓慢增长的用户可以应用的系统属性列表,虽然我们没有需要担心的子进程,但我们确实遇到了一个不同的问题:太多了。
我们没有让用户通过命令行提供系统属性(或者在我们的例子中,使启动应用程序的脚本中的行更长),而是默认添加了对加载 .properties 文件的支持。
如果您可以说服用户将永久属性放在那里,然后开始启动子进程,然后从文件中加载,则可以完全避免令人头痛的问题。
尽管如此,您可能会遇到需要临时或一次性属性而不修改文件的调试场景(这并不是什么大问题)。您在这里有几个选择:
Where I work, we had a slowly growing list of system properties that users could apply, and while we did not have the child process to worry about, we did have a different issue: there were simply too many.
Rather than making the user supply system properties via the command line (or, in our case, making the line in the script that launches the application yet another property longer), we added support for loading a .properties file by default.
If you can convince users to put permanent properties there, then start the process of launching the child process, and then loading from the file, you could avoid the headache altogether.
Still, you would likely be presented with debug scenarios where temporary, or one-time properties are desired without modifying the file (not that it's really a big deal). You have a few choices here:
我认为这个问题没有一个好的答案。但幸运的是,大多数标准系统属性要么无法被覆盖,要么任何头脑清醒的人都不会覆盖。
因此,以下方法可能是您最好的选择:
I don't think there is a good answer to this. But fortunately, most of the standard system properties either can't be overridden, or nobody in their right mind would override.
So the following approaches are probably your best bets:
选择的解决方案:
我仍然必须使用一个子进程,它什么也不做,只是将它要比较的所有系统属性传递给父进程。我偶然发现的唯一小问题是 line.separator 属性,它导致我的行读取代码偶然发现额外的空行。这很容易解决。
为什么我没有接受任何答案:
以下答案中建议的方法是合理的,但没有一个是完全令人满意的。
我没有太多权力告诉用户 Java 系统属性应该通过属性文件或特殊的命令行参数传递。这很尴尬并且违背了操作实践(特殊情况总是不好的)。
我也无法选择系统属性的子集传递给子进程。系统类文档并没有告诉哪些可以覆盖(并且常识不能取代任何文档)。还有一个供最终用户定义自己的属性的工具,而我无法通过名称或数字来预测这些属性。
Chosen solution:
I still had to go with a child process that does nothing but passes the parent all the system properties it gets to compare. The only minor issue I stumbled upon was line.separator property which caused my line reading code stumble on extra empty line. That was easy to fix.
Why I accepted none of answers:
Approaches suggested in the answers below are reasonable, but none of them is completely satisfying.
I do not have much power over the users to tell them that Java system properties should be passed via a property file or a special command-line argument. This is awkward and goes against operational practices (special cases are always bad).
I cannot also select a subset of system properties to pass to the child process. System class documentation doesn't tell which ones are OK to overwrite (and common sense replaces no documentation). There is also a facility for end-user to define their own properties, and those I cannot predict neither by name no number.