2011-01-24 17 views
31

Deseo crear una aplicación de consola de primavera (ejecutándose desde la línea de comandos con maven, por ejemplo: mvn exec: java -Dexec.mainClass = "package.MainClass").Aplicación de consola de primavera configurada con anotaciones

Es esta aplicación que quiero tener algún tipo de servicios y capas de datos. Sé cómo hacerlo para una aplicación web, pero no he encontrado ninguna información sobre cómo hacerlo en el caso de una aplicación de consola (tal vez con Swing).

estoy tratando de crear algo como:

public interface SampleService { 
public String getHelloWorld(); 
} 


@Service 
public class SampleServiceImpl implements SampleService { 
public String getHelloWorld() { 
    return "HelloWorld from Service!"; 
} 
} 

public class Main { 
@Autowired 
SampleService sampleService; 
public static void main(String [] args) { 
    Main main = new Main(); 
    main.sampleService.getHelloWorld(); 
} 
} 

¿Es posible? ¿Puedo encontrar en algún lugar un ejemplo de cómo hacerlo?

Respuesta

31

Eche un vistazo a la referencia de primavera, 3.2.2 Instantiating a container.

Para utilizar Spring en la aplicación de consola, debe crear una instancia de ApplicationContext y obtener beans gestionados por Spring desde ella.

La creación de un contexto usando la configuración XML se describe en la Referencia. Para la aproximación completamente basado en la anotación, se puede hacer calle detrás de esta manera:

@Component // Main is a Spring-managed bean too, since it have @Autowired property 
public class Main { 
    @Autowired SampleService sampleService; 
    public static void main(String [] args) { 
     ApplicationContext ctx = 
      new AnnotationConfigApplicationContext("package"); // Use annotated beans from the specified package 

     Main main = ctx.getBean(Main.class); 
     main.sampleService.getHelloWorld(); 
    } 
} 
+2

También si, como yo, ha anotado su configuración: ctx = new AnnotationConfigApplicationContext (MyConfig.class); –

+0

¿Cómo se pueden suministrar los argumentos de la línea de comando al contexto de la aplicación para que el contexto a su vez pueda inyectar estos argumentos en un bean? –

20

El muelle de referencia sugiere el uso de ClassPathXmlApplicationContext en el método main para crear el contexto de aplicación, a continuación, llamar al método getBean para tener una referencia inicial a un bean desde el contexto de la aplicación. Después de escribir este mismo código varias veces, terminas refactorización el repetitivo en esta clase de utilidad:

/** 
* Bootstraps Spring-managed beans into an application. How to use: 
* <ul> 
* <li>Create application context XML configuration files and put them where 
* they can be loaded as class path resources. The configuration must include 
* the {@code <context:annotation-config/>} element to enable annotation-based 
* configuration, or the {@code <context:component-scan base-package="..."/>} 
* element to also detect bean definitions from annotated classes. 
* <li>Create a "main" class that will receive references to Spring-managed 
* beans. Add the {@code @Autowired} annotation to any properties you want to be 
* injected with beans from the application context. 
* <li>In your application {@code main} method, create an 
* {@link ApplicationContextLoader} instance, and call the {@link #load} method 
* with the "main" object and the configuration file locations as parameters. 
* </ul> 
*/ 
public class ApplicationContextLoader { 

    protected ConfigurableApplicationContext applicationContext; 

    public ConfigurableApplicationContext getApplicationContext() { 
     return applicationContext; 
    } 

    /** 
    * Loads application context. Override this method to change how the 
    * application context is loaded. 
    * 
    * @param configLocations 
    *   configuration file locations 
    */ 
    protected void loadApplicationContext(String... configLocations) { 
     applicationContext = new ClassPathXmlApplicationContext(
       configLocations); 
     applicationContext.registerShutdownHook(); 
    } 

    /** 
    * Injects dependencies into the object. Override this method if you need 
    * full control over how dependencies are injected. 
    * 
    * @param main 
    *   object to inject dependencies into 
    */ 
    protected void injectDependencies(Object main) { 
     getApplicationContext().getBeanFactory().autowireBeanProperties(
       main, AutowireCapableBeanFactory.AUTOWIRE_NO, false); 
    } 

    /** 
    * Loads application context, then injects dependencies into the object. 
    * 
    * @param main 
    *   object to inject dependencies into 
    * @param configLocations 
    *   configuration file locations 
    */ 
    public void load(Object main, String... configLocations) { 
     loadApplicationContext(configLocations); 
     injectDependencies(main); 
    } 
} 

Llame al método load en su método principal de la aplicación. Tenga en cuenta que la clase Main no es un bean creado por Spring y, sin embargo, puede inyectar una de sus propiedades con un bean desde el contexto de la aplicación.

public class Main { 
    @Autowired 
    private SampleService sampleService; 

    public static void main(String[] args) { 
     Main main = new Main(); 
     new ApplicationContextLoader().load(main, "applicationContext.xml"); 
     main.sampleService.getHelloWorld(); 
    } 
} 
3

En cuanto a la respuesta de la barbilla por encima de Huang ...

Su ejemplo no funcione de verdad, o al menos no está funcionando para mí a nivel local. Esto se debe a que está inicializando el objeto SampleService utilizando @Autowired, pero especifica AutowireCapableBeanFactory.AUTOWIRE_NO en las propiedades. En su lugar, configúrelo en AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE o AutowireCapableBeanFactory.AUTOWIRE_BY_NAME.

Además, esto es extraño, así que puedo estar haciendo algo mal. Pero parece que con AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, tengo que tener un setProp() con @Autowired para que funcione. Así que en lugar de esto:

public class Main { 
    @Autowired 
    private SampleService sampleService; 

    public static void main(String[] args) { 
     Main main = new Main(); 
     ApplicationContextLoader loader = new ApplicationContextLoader(); 
     loader.load(main, "applicationContext.xml"); 
     main.sampleService.getHelloWorld(); 
    } 
} 

que tengo que hacer esto:

public class Main { 
    private SampleService sampleService; 

    public static void main(String[] args) { 
     Main main = new Main(); 
     ApplicationContextLoader loader = new ApplicationContextLoader(); 
     loader.load(main, "applicationContext.xml"); 
     main.sampleService.getHelloWorld(); 
    } 

    @Autowired 
    public void setSampleService(SampleService sampleService) { 
     this.sampleService = sampleService; 
    } 
} 

Si tengo, como en el ejemplo original de la barbilla, los datos privados con @Autowired, el DI falla. Estoy usando 3.1.1.RELEASE y creo que algunas de las cosas del auto-cableado han cambiado en 3.1.x, por lo que puede deberse a eso. Pero tengo curiosidad de por qué esto no funcionaría, ya que eso es consistente con versiones anteriores de Spring.

2

Puede hacerlo de esta manera:

  • hacer la inicialización en su principal método
  • continuación, puede utilizar el método de inicio como su controlador sudo
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.context.ApplicationContext; 
import org.springframework.context.support.ClassPathXmlApplicationContext; 
import org.springframework.stereotype.Component; 

import com.org.service.YourService; 

@Component 
public class YourApp{ 

    public static void main(String[] args) { 
     ApplicationContext context = new ClassPathXmlApplicationContext(
       "ApplicationContext.xml"); 

     YourApp p = context.getBean(App.class); 
     p.start(args); 
    } 

    @Autowired 
    YourService yourService; 
    private void start(String[] args) { 

     yourService.yourMethod(); 

    } 

} 
3

Tendría que resolver esto recientemente para un proyecto. Estaba construyendo una CLI para una utilidad que se ejecutaría desde un trabajo programado y una parte reutilizada del código de la aplicación web para el proyecto. Tuve un problema al inicializar todas las dependencias @Autowired, y realmente no las necesitaba todas, así que arranqué las dependencias específicas en la clase principal usando el método AnnotationConfigApplicationContext register (java.lang.Class ...) de la siguiente manera:

@Component 
public class SpringAppCLI 
{ 

    /** 
    * Service to be autowired! 
    */ 
    @Autowired 
    private SampleService sampleService; 

    /** 
    * 
    */ 
    public static void main(String[] args) throws Exception { 

     final AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); 

     // setup configuration 
     applicationContext.register(SampleServiceConfig.class); 
     applicationContext.register(SampleServiceRepository.class); 
     applicationContext.register(JpaConfig.class); 
     applicationContext.register(CommandLineConfig.class); 
     applicationContext.register(SampleService.class); 
     applicationContext.register(SpringAppCLI.class); 
     // add CLI property source 
     applicationContext.getEnvironment().getPropertySources() 
       .addLast(new SimpleCommandLinePropertySource(args)); 

     // setup all the dependencies (refresh) and make them run (start) 
     applicationContext.refresh(); 
     applicationContext.start(); 

     try { 
      SpringAppCLI springAppCLI = applicationContext.getBean(SpringAppCLI.class); 
      springAppCLI.doWhatever(); 
     } catch (Exception e) { 
      //some handling 

     } finally { 
      applicationContext.close(); 
     } 
    } 
} 

y aquí está la clase de configuración:

@Configuration 
@ComponentScan(basePackageClasses = SolrLoadCLI.class, includeFilters = @Filter(Controller.class), useDefaultFilters = false) 
class CommandLineConfig implements ApplicationContextAware { 

    /** 
    * 
    */ 
    private ApplicationContext applicationContext; 

    /** 
    * 
    */ 
    @Override 
    public void setApplicationContext(ApplicationContext applicationContext) 
      throws BeansException { 
     this.applicationContext = applicationContext; 
    } 

    /** 
    * 
    * @return 
    */ 
    @Bean 
    public static PropertyPlaceholderConfigurer propertyPlaceholderConfigurer() { 
     PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer(); 
     Resource[] resourceArray = new Resource[2]; 
     resourceArray[0] = new ClassPathResource("/SampleService.properties"); 
     resourceArray[1] = new ClassPathResource("/Database.properties"); 
     ppc.setLocations(resourceArray); 
     return ppc; 
    } 
} 
+0

Esto es limpio ... –

0

Esta fue mi solución para ejecutar una salida. Lo uso en un módulo que funciona como terreno común para todos los demás específicos: un sitio web y un API. Cuando especifico los argumentos correctos en el módulo correcto, ejecutaré la tarea correcta.

import org.springframework.boot.SpringApplication; 
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 
import org.springframework.boot.builder.SpringApplicationBuilder; 
import org.springframework.context.ConfigurableApplicationContext; 
import org.springframework.context.annotation.ComponentScan; 

@ComponentScan 
@EnableAutoConfiguration 
public class CLIApp { 

    public static void main(String[] args) { 
     ConfigurableApplicationContext ctx = 
       new SpringApplicationBuilder(CLIApp.class) 
         .web(false) 
         .properties("spring.jmx.enabled=false") 
         .run(args); 

     final int exitCode = SpringApplication.exit(ctx); 

     System.out.println("************************************"); 
     System.out.println("* Console App sucessfully executed *"); 
     System.out.println("************************************"); 

     System.exit(exitCode); 
    } 
} 

Como ve, también desactivé el entorno web no utilizado y JMX. Me centraré en escanear el classpath del paquete de la clase y usar las habilidades de autoconfiguración de Spring Boot. Después de que la aplicación termine de hacer lo que necesita, se cierra como una aplicación de consola.

Cuestiones relacionadas