【问题标题】:Dealing with command line arguments and Spring处理命令行参数和 Spring
【发布时间】:2010-09-13 00:46:26
【问题描述】:

当我编写解析命令行参数的 Spring 命令行应用程序时,如何将它们传递给 Spring?我是否想让我的 main() 结构化,以便它首先解析命令行参数然后初始化 Spring?即便如此,它如何将持有已解析 args 的对象传递给 Spring?

【问题讨论】:

    标签: java spring command-line


    【解决方案1】:

    我能想到的两种可能性。

    1) 设置静态引用。 (静态变量,虽然通常不受欢迎,但在这种情况下是可以的,因为只能有 1 个命令行调用)。

    public class MyApp {
      public static String[] ARGS; 
      public static void main(String[] args) {
        ARGS = args;
          // create context
      }
    }
    

    然后您可以通过以下方式在 Spring 中引用命令行参数:

    <util:constant static-field="MyApp.ARGS"/>
    

    或者(如果您完全反对静态变量),您可以:

    2) 以编程方式将参数添加到应用程序上下文中:

     public class MyApp2 {
       public static void main(String[] args) {
         DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
    
            // Define a bean and register it
         BeanDefinition beanDefinition = BeanDefinitionBuilder.
           rootBeanDefinition(Arrays.class, "asList")
           .addConstructorArgValue(args).getBeanDefinition();
         beanFactory.registerBeanDefinition("args", beanDefinition);
         GenericApplicationContext cmdArgCxt = new GenericApplicationContext(beanFactory);
         // Must call refresh to initialize context 
         cmdArgCxt.refresh();
    
         // Create application context, passing command line context as parent
         ApplicationContext mainContext = new ClassPathXmlApplicationContext(CONFIG_LOCATIONS, cmdArgCxt);
    
         // See if it's in the context
         System.out.println("Args: " + mainContext.getBean("args"));
       }
    
       private static String[] CONFIG_LOCATIONS = new String[] {
         "applicationContext.xml"
       };
    
     }
    

    解析命令行参数留给读者作为练习。

    【讨论】:

    • +1 用于静态参考。 6行代码优于20行。
    • 我非常喜欢这个解决方案,并找到了解决练习的这种古怪方法:System.out.println("Args: " + mainContext.getBean("args")); String[] arg1 = (String[]) ((Collection)mainContext.getBean("args")).toArray(new String[0]);字符串 o = arg1[0]; System.out.println(o);
    【解决方案2】:

    查看我的 Spring-CLI 库 - http://github.com/sazzer/spring-cli - 作为执行此操作的一种方式。它为您提供了一个自动加载 spring 上下文的主类,并且能够使用 Commons-CLI 自动解析命令行参数并将它们注入到您的 bean 中。

    【讨论】:

      【解决方案3】:

      从 Spring 3.1 开始,其他答案中建议的任何自定义代码都不需要。检查CommandLinePropertySource,它提供了一种将 CL 参数注入上下文的自然方式。

      如果您是一位幸运的 Spring Boot 开发人员,您可以利用 SpringApplication 为您提供以下事实的事实将代码向前简化一步:

      默认情况下,类将执行以下步骤来引导您的 应用:

      ...

      注册一个 CommandLinePropertySource 以公开命令行参数 作为 Spring 属性

      如果您对 Spring Boot 属性解析顺序感兴趣,请咨询this page

      【讨论】:

      • 这应该是正确的做法。它非常适合我。
      【解决方案4】:

      您还可以将 Object 数组作为第二个参数传递给 getBean,它将用作构造函数或工厂的参数。

      public static void main(String[] args) {
         Mybean m = (Mybean)context.getBean("mybean", new Object[] {args});
      }
      

      【讨论】:

        【解决方案5】:

        考虑以下类:

        public class ExternalBeanReferneceFactoryBean 
            extends AbstractFactoryBean
            implements BeanNameAware {
        
            private static Map<String, Object> instances = new HashMap<String, Object>();
            private String beanName;
        
            /**
             * @param instance the instance to set
             */
            public static void setInstance(String beanName, Object instance) {
                instances.put(beanName, instance);
            }
        
            @Override
            protected Object createInstance() 
                throws Exception {
                return instances.get(beanName);
            }
        
            @Override
            public Class<?> getObjectType() {
                return instances.get(beanName).getClass();
            }
        
            @Override
            public void setBeanName(String name) {
                this.beanName = name;
            }
        
        }
        

        还有:

        /**
         * Starts the job server.
         * @param args command line arguments
         */
        public static void main(String[] args) {
        
            // parse the command line
            CommandLineParser parser = new GnuParser();
            CommandLine cmdLine = null;
            try {
                cmdLine = parser.parse(OPTIONS, args);
            } catch(ParseException pe) {
                System.err.println("Error parsing command line: "+pe.getMessage());
                new HelpFormatter().printHelp("command", OPTIONS);
                return;
            }
        
            // create root beanFactory
            DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        
            // register bean definition for the command line
            ExternalBeanReferneceFactoryBean.setInstance("commandLine", cmdLine);
            beanFactory.registerBeanDefinition("commandLine", BeanDefinitionBuilder
                .rootBeanDefinition(ExternalBeanReferneceFactoryBean.class)
                .getBeanDefinition());
        
            // create application context
            GenericApplicationContext rootAppContext = new GenericApplicationContext(beanFactory);
            rootAppContext.refresh();
        
            // create the application context
            ApplicationContext appContext = new ClassPathXmlApplicationContext(new String[] { 
                "/commandlineapp/applicationContext.xml"
            }, rootAppContext);
        
            System.out.println(appContext.getBean("commandLine"));
        
        }
        

        【讨论】:

          【解决方案6】:

          这是一个为 Main 方法引导 spring 的示例,只需像往常一样获取传递的参数,然后使您在 bean 上调用的函数(在这种情况下为 deployer.execute())将它们作为字符串或通过任何格式你觉得合适。

          public static void main(String[] args) throws IOException, ConfigurationException {
              Deployer deployer = bootstrapSpring();
          
              deployer.execute();
          }
          
          private static Deployer bootstrapSpring()
          {
              FileSystemXmlApplicationContext appContext = new FileSystemXmlApplicationContext("spring/deployerContext.xml");
          
              Deployer deployer = (Deployer)appContext.getBean("deployer");
              return deployer;
          }
          

          【讨论】:

          • 啊,我应该提到我的 spring 初始化必须在命令行被解析之后进行,因为它取决于命令行中的值
          【解决方案7】:

          我不确定您到底想达到什么目的,也许您可​​以添加一些关于命令和参数的外观以及您期望从应用程序中获得什么结果的详细信息。

          我认为这不是您需要的,但它可能对其他读者有所帮助:Spring 支持使用双连字符从命令行接收属性(例如 java -jar app.jar --my.property="Property Value" 查看此文档以获取更多信息: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-command-line-args

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2015-05-01
            • 1970-01-01
            • 2013-05-08
            • 1970-01-01
            • 2014-12-19
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多