【发布时间】:2010-09-13 00:46:26
【问题描述】:
当我编写解析命令行参数的 Spring 命令行应用程序时,如何将它们传递给 Spring?我是否想让我的 main() 结构化,以便它首先解析命令行参数然后初始化 Spring?即便如此,它如何将持有已解析 args 的对象传递给 Spring?
【问题讨论】:
标签: java spring command-line
当我编写解析命令行参数的 Spring 命令行应用程序时,如何将它们传递给 Spring?我是否想让我的 main() 结构化,以便它首先解析命令行参数然后初始化 Spring?即便如此,它如何将持有已解析 args 的对象传递给 Spring?
【问题讨论】:
标签: java spring command-line
我能想到的两种可能性。
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"
};
}
解析命令行参数留给读者作为练习。
【讨论】:
查看我的 Spring-CLI 库 - http://github.com/sazzer/spring-cli - 作为执行此操作的一种方式。它为您提供了一个自动加载 spring 上下文的主类,并且能够使用 Commons-CLI 自动解析命令行参数并将它们注入到您的 bean 中。
【讨论】:
从 Spring 3.1 开始,其他答案中建议的任何自定义代码都不需要。检查CommandLinePropertySource,它提供了一种将 CL 参数注入上下文的自然方式。
如果您是一位幸运的 Spring Boot 开发人员,您可以利用 SpringApplication 为您提供以下事实的事实将代码向前简化一步:
默认情况下,类将执行以下步骤来引导您的 应用:
...
注册一个 CommandLinePropertySource 以公开命令行参数 作为 Spring 属性
如果您对 Spring Boot 属性解析顺序感兴趣,请咨询this page。
【讨论】:
您还可以将 Object 数组作为第二个参数传递给 getBean,它将用作构造函数或工厂的参数。
public static void main(String[] args) {
Mybean m = (Mybean)context.getBean("mybean", new Object[] {args});
}
【讨论】:
考虑以下类:
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"));
}
【讨论】:
这是一个为 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 支持使用双连字符从命令行接收属性(例如 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
【讨论】: