代码之家  ›  专栏  ›  技术社区  ›  Uri

在爪哇中,即使主()没有保存命令行参数,也有办法获得吗?

  •  5
  • Uri  · 技术社区  · 16 年前

    我们有一个带有main()的程序,它解析某些CLP,但不在任何地方保存它们。 然后我有自己的插件代码,需要访问原始CLP(以便我可以为它传输更多参数)。但是,我不能更改main()。

    I saw that there is apparently a way to do this in C# 我在Linux上寻找一个等价的Java解决方案。

    更新:显然,我知道main()是如何工作的。不幸的是,我无法更改现有应用程序或调用它的方式(CLP除外)。我只能通过沙盒插件代码访问。我的问题是,是否有一种方法来获取用-d调用JVM的命令行(而不是环境变量)。

    5 回复  |  直到 9 年前
        1
  •  4
  •   Community CDub    8 年前

    除了以某种方式进行主要操作之外,我认为唯一的其他选择是转到操作系统级别并执行一些命令来获取参数。

    在Linux上,正在运行的进程的命令行参数存储在 /PRO/ PID /CMDLIN

    因此,要获得它们,您必须找到进程ID。请参见以下内容:

    How can a Java program get its own process ID?

    然后用这个打开 /PRO/ PID /CMDLIN 然后分析一下。此文件的格式和C中的一个示例如下:

    http://www.unix.com/unix-advanced-expert-users/86740-retrieving-command-line-arguments-particular-pid.html

    最好将这两个调用封装在一个shell脚本中,从Java调用。

    请注意,这将是非常不便携,有点黑客。但如果需要的话…

        2
  •  4
  •   nd.    16 年前

    一旦您意识到Java的主要方法只是以字符串数组作为参数的另一个静态方法,那么解决方案很简单。

    创建一个存储CLP的新类,然后调用旧类。稍后,您可以使用新类访问CLP:

    import NotToBeChangedMainClass;
    
    public MyMainClass {
      public static final String[] ARGUMENTS;
      public static void main(String ... args) {
        ARGUMENTS = args;
        NotToBeChangedMainClass.main(args);
      }
    

    }

    最后,更改任何外部调用程序(例如任何批处理文件)以使用MyMainclass而不是NotToBechChangedMainclass。如果您使用的是不可运行的JAR或类似文件,则需要更改相应的配置文件。

        3
  •  1
  •   Tom Hawtin - tackline    16 年前

    创建自己的主类。保存参数。叫老 main .

    可能更容易使用 System.getProperty -Dkey=value 在命令行上(在主类名或 -jar )

        4
  •  1
  •   Community CDub    8 年前

    如果您没有选择,那么您必须保留所有现有类名及其确切名称。( as stated in your comment 我之前的回答),那么你必须和Aspectj一起去。

    我们来考虑一下这门课:

    public class UnmodifyableClassWithMain {
      public static void main(String[] args) {
        System.out.println("In main");
        new ClassUsingArgumentRegistry();
      }
    }
    

    首先,您需要保存命令行参数。为了简单起见,我将使用带有静态字段的简单类:

    public class ArgumentRegistry {
      public static String[] ARGS;
    }
    

    然后,您需要定义一个方面来拦截对main的调用并存储参数。

    public aspect StoreArgumentsOfMain {
    
      /**
       * This pointcut intercepts all calls to methods called main with a string array as
       * argument.
       */
      pointcut mainMethod(String[] arguments): execution(void main(String[])) && args(arguments);
    
      /**
       * Before the original main method gets called, store the arguments in the registry.
       */
      before(String[] arguments): mainMethod(arguments) {
        System.out.println("Storing arguments");
        ArgumentRegistry.ARGS = arguments;
      }
    
    }
    

    为了尝试,我还创建了一个ClassusingargumEntreRegistry:

    public class ClassUsingArgumentRegistry {
    
      public ClassUsingArgumentRegistry() {
        System.out.println("Arguments: " + java.util.Arrays.toString(ArgumentRegistry.ARGS));
      }
    
    }
    

    就这样。如果我启用AspectJ的编译时间编织,并使用“Java unMuffyabLabsAccess主FooBar BAZ”运行结果,我得到了如下的输出:

    Storing arguments
    In main
    Arguments: [foo, bar, baz]
    
        5
  •  0
  •   mab    9 年前

    注意,这个解决方案非常有限,因为Linux会截断它保存的命令行。由于Java命令行通常有很长的分支,这是一个非常现实的问题。

    下面是Java代码实现Pablojim给出的答案。

    package test;
    
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    
    public class Test {
      public static List<String> getLinuxCmdline(int maxBytesToRead) throws IOException {
        List<String> result = new ArrayList<>();
        String pid = new File("/proc/self").getCanonicalFile().getName();
        File cmdlineFile = new File("/proc/" + pid + "/cmdline");
        final int growBy = 1024;
        try (FileInputStream is = new FileInputStream(cmdlineFile);) {
          byte[] data = new byte[Math.min(growBy, maxBytesToRead)];
          int totalRead = 0; 
          while (totalRead < maxBytesToRead) {
            int read = is.read(data, totalRead, data.length - totalRead);
            if (read > 0) {
              totalRead += read;
              if (data.length == totalRead) {
                data = Arrays.copyOf(data, Math.min(data.length + growBy, maxBytesToRead));
              }
            } else {
              break;
            }
          }
          int start = 0;
          int scan = 0;
          while (scan < totalRead) {
            if (data[scan] == 0) {
              result.add(new String(Arrays.copyOfRange(data, start, scan)));
              start = scan + 1;
            }
            scan++;
          }
          if (scan - start > 0) result.add(new String(Arrays.copyOfRange(data, start, scan)));        }
        return result;
      }
    
      public static void main(String[] args) throws IOException {
        System.out.println(getLinuxCmdline(Integer.MAX_VALUE));
      }
    }
    

    在Eclipse中用参数“foo bar”运行这个程序,我可以得到:

    [/usr/lib/jvm/java-8-oracle/bin/java, -Dfile.encoding=UTF-8, -classpath, /home/mab/workspace/test/bin, test.Test, foo, bar]