java - springboot - Tratando con argumentos de línea de comando y primavera
spring boot standalone java application (6)
Cuando estoy escribiendo una aplicación de línea de comandos de Spring que analiza argumentos de línea de comandos, ¿cómo los paso a Spring? ¿Me gustaría tener mi main () estructurado para que primero analice los argumentos de línea de comando y luego ingrese Spring? Aun así, ¿cómo pasaría el objeto que contiene los args analizados a Spring?
A partir de Spring 3.1 no es necesario ningún código personalizado sugerido en otras respuestas. Compruebe CommandLinePropertySource , proporciona una forma natural de insertar argumentos CL en su contexto.
Y si usted es un desarrollador afortunado de Spring Boot, podría simplificar su código un paso adelante aprovechando el hecho de que SpringApplication le ofrece lo siguiente:
De forma predeterminada, la clase realizará los siguientes pasos para iniciar su aplicación:
...
Registre CommandLinePropertySource para exponer los argumentos de la línea de comando como propiedades de Spring
Y si está interesado en el orden de resolución de propiedad de Spring Boot, consulte esta página .
Aquí hay un ejemplo para arrancar el resorte de correa para un método Principal, simplemente agarre los parámetros pasados de manera normal y luego haga que la función que llame en su bean (en el caso deployer.execute ()) los tome como Cuerdas o mediante cualquier formato que considere adecuado .
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;
}
Considera la siguiente clase:
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;
}
}
junto con:
/**
* 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"));
}
Dos posibilidades que puedo pensar
1) Establecer una referencia estática. (Una variable estática, aunque normalmente desaprobada, está bien en este caso, porque solo puede haber 1 invocación de línea de comando).
public class MyApp {
public static String[] ARGS;
public static void main2(String[] args) {
ARGS = args;
// create context
}
}
A continuación, puede hacer referencia a los argumentos de línea de comando en Spring a través de:
<util:constant static-field="MyApp.ARGS"/>
Alternativamente (si se opone completamente a las variables estáticas), puede:
2) Agregue programáticamente los argumentos al contexto de la aplicación:
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"
};
}
El análisis de los argumentos de la línea de comando se deja como un ejercicio para el lector.
Eche un vistazo a mi biblioteca Spring-CLI, en http://github.com/sazzer/spring-cli , como una forma de hacerlo. Le proporciona una clase principal que carga automáticamente contextos de primavera y tiene la capacidad de usar Commons-CLI para analizar argumentos de línea de comando automáticamente e inyectarlos en sus beans.
También puede pasar una matriz de Objetos como un segundo parámetro para getBean
que se usará como argumentos para el constructor o la fábrica.
public static void main(String[] args) {
Mybean m = (Mybean)context.getBean("mybean", new Object[] {args});
}