Access java arguments in spring standalone application [duplicate] - java

Here is my code:
public class Main {
public static void main(String[] args) {
Main p = new Main();
p.start(args);
}
#Autowired
private MyBean myBean;
private void start(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("META-INF/config.xml");
System.out.println("my beans method: " + myBean.getStr());
}
}
#Service
public class MyBean {
public String getStr() {
return "string";
}
}
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config />
<context:component-scan base-package="mypackage"/>
</beans>
Why doesn't this work? I get NullPointerException. Is it possible to use autowiring in a standalone application?

Spring works in standalone application. You are using the wrong way to create a spring bean. The correct way to do it like this:
#Component
public class Main {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("META-INF/config.xml");
Main p = context.getBean(Main.class);
p.start(args);
}
#Autowired
private MyBean myBean;
private void start(String[] args) {
System.out.println("my beans method: " + myBean.getStr());
}
}
#Service
public class MyBean {
public String getStr() {
return "string";
}
}
In the first case (the one in the question), you are creating the object by yourself, rather than getting it from the Spring context. So Spring does not get a chance to Autowire the dependencies (which causes the NullPointerException).
In the second case (the one in this answer), you get the bean from the Spring context and hence it is Spring managed and Spring takes care of autowiring.

Spring is moving away from XML files and uses annotations heavily. The following example is a simple standalone Spring application which uses annotation instead of XML files.
package com.zetcode.bean;
import org.springframework.stereotype.Component;
#Component
public class Message {
private String message = "Hello there!";
public void setMessage(String message){
this.message = message;
}
public String getMessage(){
return message;
}
}
This is a simple bean. It is decorated with the #Component annotation for auto-detection by Spring container.
package com.zetcode.main;
import com.zetcode.bean.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
#ComponentScan(basePackages = "com.zetcode")
public class Application {
public static void main(String[] args) {
ApplicationContext context
= new AnnotationConfigApplicationContext(Application.class);
Application p = context.getBean(Application.class);
p.start();
}
#Autowired
private Message message;
private void start() {
System.out.println("Message: " + message.getMessage());
}
}
This is the main Application class. The #ComponentScan annotation searches for components. The #Autowired annotation injects the bean into the message variable. The AnnotationConfigApplicationContext is used to create the Spring application context.
My Standalone Spring tutorial shows how to create a standalone Spring application with both XML and annotations.

For Spring 4, using Spring Boot we can have the following example without using the anti-pattern of getting the Bean from the ApplicationContext directly:
package com.yourproject;
#SpringBootApplication
public class TestBed implements CommandLineRunner {
private MyService myService;
#Autowired
public TestBed(MyService myService){
this.myService = myService;
}
public static void main(String... args) {
SpringApplication.run(TestBed.class, args);
}
#Override
public void run(String... strings) throws Exception {
System.out.println("myService: " + MyService );
}
}
#Service
public class MyService{
public String getSomething() {
return "something";
}
}
Make sure that all your injected services are under com.yourproject or its subpackages.

I case you are running SpringBoot:
I just had the same problem, that I could not Autowire one of my services from the static main method.
See below an approach in case you are relying on SpringApplication.run:
#SpringBootApplication
public class PricingOnlineApplication {
#Autowired
OrchestratorService orchestratorService;
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(PricingOnlineApplication.class, args);
PricingOnlineApplication application = context.getBean(PricingOnlineApplication.class);
application.start();
}
private void start() {
orchestratorService.performPricingRequest(null);
}
}
I noticed that SpringApplication.run returns a context which can be used similar to the above described approaches. From there, it is exactly the same as above ;-)

A nice solution would be to do following,
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
#Component
public class SpringContext implements ApplicationContextAware {
private static ApplicationContext context;
/**
* Returns the Spring managed bean instance of the given class type if it exists.
* Returns null otherwise.
* #param beanClass
* #return
*/
public static <T extends Object> T getBean(Class<T> beanClass) {
return context.getBean(beanClass);
}
#Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
// store ApplicationContext reference to access required beans later on
SpringContext.context = context;
}
}
Then you can use it like:
YourClass yourClass = SpringContext.getBean(YourClass.class);
I found this very nice solution in the following website: https://confluence.jaytaala.com/pages/viewpage.action?pageId=18579463

Related

Spring : Cannot get value from application.properties

I created Spring project via Spring Initializr with project following struct:
I defined property in application.properties file :
my.prop=testvalue
I inject this value into MyClass as following :
#Component
class MyClass {
#Value("${my.prop}")
private String myProp;
public String getMyProp() {
return myProp;
}
}
ConfigBeans defined as following:
package com.example.propertiesdemo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class ConfigBeans {
#Bean
public MyClass myLitoBean() {
return new MyClass();
}
}
PropertiesdemoApplication.java :
package com.example.propertiesdemo;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
#SpringBootApplication
public class PropertiesdemoApplication {
public static void main(String[] args) {
ApplicationContext context
= new AnnotationConfigApplicationContext(
ConfigBeans.class);
MyClass myClass = context.getBean(MyClass.class);
System.out.println(myClass.getMyProp());
}
}
I am expecting that after executing line
System.out.println(myClass.getMyProp());
will be printed value of myprop defined in application.properties (i.e testvalue), but after running (via Netbeans IDE) I get output :
${my.prop}
What was missed / wromg in this code ? Thanks in advance
You are creating MyClass bean twice.
Using #component annotation
using #bean annotation in the config class (use method name lowerCamelCase i.e. in your case myClass())
Create bean only once using any one of the above.
You dont need to create an application context in the main method like this. The presented code is a kind of mixture of "traditional" spring and spring boot. So you're kind of bypassing all the goodies that spring boot offers, among which is automatic application.properties loading.
If you're using spring boot (there is a #SpringBootApplication annotation) then it will create everything by itself.
Usually it should be something like this
public static void main(String[] args) {
SpringApplication.run(PropertiesdemoApplication.class, args);
}
Right, as Navnath Adsul said, you need the bean to be created once, and also, since you are using Spring Boot, you need to raise the context using a special method
#SpringBootApplication
public class PropertiesdemoApplication implements CommandLineRunner {
// Inject Bean
#Autowired
private MyClass myClass;
public static void main(String[] args) {
new SpringApplicationBuilder()
.sources(PropertiesdemoApplication.class)
.run(args);
// or SpringApplication.run(PropertiesdemoApplication.class, args);
}
#Override
public void run(String[] args) throws Exception {
System.out.println(myClass.getMyProp());
}
}
#SpringBootApplication
public class PropertiesdemoApplication {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(PropertiesdemoApplication.class, args);
MyClass myClass = context.getBean(MyClass.class);
System.out.println(myClass.getMyProp());
}
}

How to autowire a bean annoted with #service in other class

In a SPRING BOOT application i have a class as below
#Service
public class XYZ{
}
I want to use above in other class ABC
public class ABC{
#Autowired
private XYZ xyx;
}
It throws error that XYZ could not be found. I already have #SpringBootApplication in the class where the main method is written. Hence, this will automatically enable #ComponentScan on the package.My understanding is , since XYZ has been annoted with #service, spring scans and creates and registers that bean. How can i access that bean in other class without using xml configuration ?
Well your ABC class also need to have the #Service or #Component annotation. Otherwise, you will get a warning with the following message.
Autowired memebers must be defined in valid Spring bean (#Component|#Service|...).
#Service
public class ABC {
#Autowired
private XYZ xyx;
}
Your class ABC is not in spring boot context, that is reason you can't get a bean. you might get it the following way:
Create an ApplicationContextProvider
#Component
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext context;
public static ApplicationContext getApplicationContext() {
return context;
}
#Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
context = applicationContext;
}
}
After you need to call the following way:
public class ABC {
public void method() {
XYZ xyz = ApplicationContextProvider.getApplicationContext().getBean(XYZ.class);
}
}
If you don't want to configurate #ComponentScan. you need to put the Class XYZ and ABC in the same level directory with Spring boot application runner class
your class ABC should also be a spring-managed
you can do this by making it a Component
#Component
public class ABC{
#Autowired
private XYZ xyx;
}
or provide it as a Bean
#Configuration
public SomeConfig{
#Bean
public ABC abc(){
return new ABC();
}
}
Use #ComponentScan("<your root package>") in you Spring boot application runner class so that it inspects all the components and create the bean which can be autowired. Also Calling class should be a component annotated with #Componenent. If you create object of ABC as new ABC() then
ABC abc = new ABC();
ContextProvider.getApplicationContext().getAutowireCapableBeanFactory().autowireBean(abc); //Autowiring dependencies
//Then use the abc object which will have instance of XYZ populated.
ContextProvider implementation
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
* #author dpoddar
*
*/
#Component("ContextProvider")
#Order(Ordered.HIGHEST_PRECEDENCE)
public class ContextProvider implements ApplicationContextAware {
#Autowired
private static ApplicationContext CONTEXT;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
CONTEXT = applicationContext;
}
/**
* #return the cONTEXT
*/
public static ApplicationContext getApplicationContext() {
return CONTEXT;
}
/**
* Get a Spring bean by type.
**/
public static <T> T getBean(Class<T> beanClass) {
return CONTEXT.getBean(beanClass);
}
/**
* Get a Spring bean by type.
**/
public static <T> T getBean(String beanName,Class<T> beanClass) {
return CONTEXT.getBean(beanName, beanClass);
}
/**
* Get a Spring bean by name.
**/
public static Object getBean(String beanName) {
return CONTEXT.getBean(beanName);
}
}

Spring service bean is null

I have a simple Spring boot application that initialize a CLI game.
import com.rpg.game.rpggame.client.RpgGameClient;
#SpringBootApplication
public class RpgGameApplication {
public static void main(String[] args) {
SpringApplication.run(RpgGameApplication.class, args);
RpgGameClient.runGame();
}
}
The runGame() uses some of my services (spring beans).
public class RpgGameClient {
#Autowired
private static GameService gameService;
public static void runGame() {
gameService.createNewGame();
}
}
But I have a NullPointerException when using my service, since Spring can not successfully inject it on my RpgGameClient class.
How can I solve it?
1) RpgGameClient is not declared as a bean candidate. So Spring ignores it.
You can do it by annotating the class with #Component for example (the simplest way) or by declaring a #Bean method that returns the instance of the class.
2) Even with that, it will not work still as #Autowired doesn't work for static fields. Spring injects dependencies into a bean and a bean is an instance of a class.
I think that runGame() should also be non static. Make all static for a bean spring makes no sense. It is the same thing for the Spring boot application class.
3) Constructor injection should be favored to field injection.
So it should be better :
#Component
public class RpgGameClient {
private GameService gameService;
public RpgGameClient(GameService gameService){
this.gameService = gameService;
}
public void runGame() {
gameService.createNewGame();
}
}
And change the Spring Boot app class to use injection dependency such as :
#SpringBootApplication
public class RpgGameApplication {
#Autowired
RpgGameClient rpgGameClient;
#PostConstruct
public void postConstruct(){
rpgGameClient.runGame();
}
public static void main(String[] args) {
SpringApplication.run(RpgGameApplication.class, args);
}
}

Spring - NullPointerException when autowiring [duplicate]

This question already has answers here:
Using Spring 3 autowire in a standalone Java application
(5 answers)
Closed 9 years ago.
Is there a way to run Spring application configured by annotation, directly from main method?
I'm still getting NullPointerException runing code below. Note that I'm not using SpringMVC and when I'm using beans defined inside context.xml, injected inside main method by context.getBean method, all code works perfect (without error) - but I just wondering if it is a way to manage runing this only with annotations?
//IElem.java
package com.pack.elem;
public interface IElem {
public abstract String sayHello();
}
//Elem.java
package com.pack.elem;
import org.springframework.stereotype.Component;
#Component
public class Elem implements IElem{
#Override
public String sayHello() {
return ("Hello from Elem class object");
}
}
//RunElem.java
package com.pack.elem;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Component
public class RunElem {
#Autowired
private IElem elem;
public void runHello(){
System.out.println(elem.sayHello());
}
}
//Main.java
package com.pack.main;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.pack.elem.RunElem;
public class Main {
#Autowired
private RunElem runelem;
public static void main(String[] args) {
ApplicationContext context= new ClassPathXmlApplicationContext("/META-INF/application-context.xml");
new Main().runRun();
}
private void runRun(){
runelem.runHello();
}
}
<!--/META-INF/application-context.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<context:annotation-config/>
<context:component-scan base-package="com.pack"/>
</beans>
Put simply, Spring is autowiring if it is the one instantiating the bean. So you have to use getBean(). If you want to use annotations only, something like this should work:
#Component
public class Main {
#Autowired
private RunElem runelem;
public static void main(String[] args) {
ApplicationContext context= new ClassPathXmlApplicationContext("/META-INF/application-context.xml");
Main mainBean = context.getBean(Main.class);
mainBean.runRun();
}
private void runRun(){
runelem.runHello();
}
}
Alternatively you can autowire an existing bean as shown below, but this is not a recommended Spring usage:
public class Main {
#Autowired
private RunElem runelem;
public static void main(String[] args) {
ApplicationContext context= new ClassPathXmlApplicationContext("/META-INF/application-context.xml");
Main mainBean = new Main();
context.getAutowireCapableBeanFactory().autowireBean(mainBean);
mainBean.runRun();
}
private void runRun(){
runelem.runHello();
}
}

Spring console application configured using annotations

I want to create spring console application (running from command line with maven for example: mvn exec:java -Dexec.mainClass="package.MainClass").
Is this application I want to have some kind of services and dao layers. I know how to do it for a web application but I have not found any information on how to do in case of a console application (leter maybe with Swing).
I'm trying to create something like:
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();
}
}
Is it possible?
Can I find somewhere an example of how to do it?
Take a look at the Spring Reference, 3.2.2 Instantiating a container.
In order to use Spring in console application you need to create an instance of ApplicationContext and obtain Spring-managed beans from it.
Creating a context using XML config is described in the Reference. For completely annotation-based approach, you can do someting like this:
#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();
}
}
The Spring Reference suggests using ClassPathXmlApplicationContext in the main method to create the application context, then calling the getBean method to get an initial reference to a bean from the application context. After writing this same code a few times, you wind up refactoring the boilerplate into this utility class:
/**
* 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);
}
}
Call the load method in your application main method. Notice that the Main class is not a Spring-created bean, and yet you can inject one of its properties with a bean from the application context.
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();
}
}
I'd to figure this out for a project recently. I was building a CLI for a utility that would be run from a scheduled job and reused part of the web application code for the project. I had a problem bootstrapping all of the #Autowired dependencies, and I didn't actually need them all, so I bootstrapped the specific dependencies in the main class using the AnnotationConfigApplicationContext register(java.lang.Class...) method as follows:
#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();
}
}
}
and here's the configuration class:
#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;
}
}
Regarding Chin Huang's answer above...
Your example won't actually work, or at least isn't working for me locally. That's because you're initializing the SampleService object using #Autowired, but you specify AutowireCapableBeanFactory.AUTOWIRE_NO on the properties. Instead set it to AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE or AutowireCapableBeanFactory.AUTOWIRE_BY_NAME.
Also, this is odd, so I may be doing something wrong. But it seems that with AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, I have to have a setProp() with #Autowired for it to work. So instead of this:
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();
}
}
I have to do this:
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;
}
}
If I have, as in Chin's original example, private data with #Autowired, the DI fails. I'm using 3.1.1.RELEASE and I think some of the auto-wiring stuff has changed in 3.1.x, so it may be due to that. But I'm curious as to why this wouldn't work, since that's consistent with earlier releases of Spring.
You can do it this way :
Do the initialization in your main method
You can then use the start method as your sudo controller
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();
}
}
This was my solution to run an exit. I use it in a module which works as common ground to all other specific ones: a website and an API one. When I specify the right arguments on the right module it will run the right task.
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);
}
}
As you see, I also disabled the unused web environment and JMX. I will focus on scanning the classpath from the package of the class and use the autoconfiguration skills of Spring Boot.
After the application finishes doing what it needs it closes like a console app.
I used EliuX's approach with other findings from around the web and came up with this one-class command line application.
It also demonstrates how you can take advantage of the annotation scanning and spring context to pull in, say, spring services from other parts of your application to use in the CLI.
Also note that the API has changed for .web since #EliuX's answer above.
// spring boot imports
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.Banner;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
// spring imports
import org.springframework.context.annotation.ComponentScan;
// my import from another package that has spring annotations like
// #Service, #Component, #Autowired, to demonstrate how I can wrap those
// in a command line application
import my.packages.having.annotations.services.MyOtherService;
// This starts the spring container
#SpringBootApplication
// I deliberately scan packages in MY namespace that I know to have
// Spring annotations
#ComponentScan(value = "my.packages.having.annotations.*")
public class MyCliWithSpringAnnotations implements ApplicationRunner
{
// I can autowire other services in since spring instantiates
// this CLI class - as long as these are component-scanned (above)
private MyOtherService _otherService;
#Autowired
public MyCliWithSpringAnnotations(MyOtherService otherService)
{
_otherService = otherService;
}
// This implements the ApplicationRunner interface which Spring is going
// to find, then instantiate, then autowire, and then _run_ when I call
// run() below in the main method.
// This can be be implemented in any other scanned class (or classes)
// on the classpath and will be run, but I'm sticking it all in one
// class for simplicity.
#Override
public void run(ApplicationArguments args) throws Exception
{
// getSourceArgs() returns the original String[] of command
// line args to the main() method
_otherService.toSomethingWithThese(args.getSourceArgs());
}
public static void main(String... args)
{
new SpringApplicationBuilder(MyCliWithSpringAnnotations.class)
.web(WebApplicationType.NONE)
.bannerMode(Banner.Mode.OFF)
.logStartupInfo(false)
.build()
.run(args);
}
}

Categories