Trattare con argomenti da riga di comando e Spring
-
02-07-2019 - |
Domanda
Quando scrivo un'applicazione della riga di comando di Spring che analizza gli argomenti della riga di comando, come posso passare a Spring? Vorrei che il mio main () fosse strutturato in modo che prima analizzasse gli argomenti della riga di comando e poi in Spring? Anche così, come passerebbe l'oggetto che tiene gli arg analizzati a Spring?
Soluzione
Due possibilità che mi vengono in mente.
1) Imposta un riferimento statico. (In questo caso una variabile statica, sebbene generalmente disapprovata, è OK, perché può esserci solo 1 invocazione della riga di comando).
public class MyApp {
public static String[] ARGS;
public static void main(String[] args) {
ARGS = args;
// create context
}
}
È quindi possibile fare riferimento agli argomenti della riga di comando in Spring tramite:
<util:constant static-field="MyApp.ARGS"/>
In alternativa (se sei completamente contrario alle variabili statiche), puoi:
2) Aggiungi a livello di codice gli arg al contesto dell'applicazione:
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"
};
}
L'analisi degli argomenti della riga di comando viene lasciata come esercizio al lettore.
Altri suggerimenti
Dai un'occhiata alla mia libreria Spring-CLI - su http://github.com/sazzer/spring -cli - come un modo per farlo. Ti dà una classe principale che carica automaticamente i contesti di primavera e ha la capacità di usare Commons-CLI per analizzare automaticamente gli argomenti della riga di comando e iniettarli nei tuoi bean.
Puoi anche passare un array di oggetti come secondo parametro a getBean
che sarà usato come argomento per il costruttore o la fabbrica.
public static void main(String[] args) {
Mybean m = (Mybean)context.getBean("mybean", new Object[] {args});
}
A partire dalla primavera 3.1 non è necessario alcun codice personalizzato suggerito in altre risposte. Controlla CommandLinePropertySource , fornisce un modo naturale per inserire argomenti CL nel tuo contesto.
E se sei un fortunato sviluppatore di Spring Boot potresti semplificare il tuo codice un passo avanti sfruttando il fatto che SpringApplication ti offre quanto segue:
Per impostazione predefinita, la classe eseguirà i seguenti passaggi per avviare il tuo applicazione:
...
Registra un oggetto CommandLinePropertySource per esporre gli argomenti della riga di comando come proprietà della primavera
E se sei interessato all'ordine di risoluzione delle proprietà di Spring Boot, consulta questa pagina .
Considera la seguente classe:
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;
}
}
insieme a:
/**
* 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"));
}
Ecco un esempio per avviare la molla del cinturino per un metodo Main, semplicemente prendi i parametri passati normalmente, quindi fai in modo che la funzione che chiami sul tuo bean (nel caso deployer.execute ()) li prenda come stringhe o tramite qualsiasi formato ti senti adatto.
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;
}