Reputation: 681
I'm building a Spring Boot application that will be called from command line. I will pass to application some parameters but I'm having problems to call a service from this class:
@SpringBootApplication
public class App{
public static void main(String[] args) {
SpringApplication.run(App.class, args);
App app = new App();
app.myMethod();
}
@Autowired
private MyService myService;
private void myMethod(){
myService.save();
}
}
I'm trying to call a method from inside the main but I'm getting the error:
Exception in thread "main" java.lang.NullPointerException
at com.ef.Parser.App.myMethod(Application.java:26)
at com.ef.Parser.App.main(Application.java:18)
Upvotes: 39
Views: 86233
Reputation: 4382
In SpringBoot 2.x you can simply run the application by SpringApplication.run
method and operate on the returned ApplicationContext. Working example below:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import java.util.Arrays;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
ApplicationContext applicationContext = SpringApplication.run(DemoApplication.class, args);
SomeService service = applicationContext.getBean(SomeService.class);
service.doSth(args);
}
}
@Service
class SomeService {
public void doSth(String[] args){
System.out.println(Arrays.toString(args));
}
}
Upvotes: 55
Reputation: 39
The issue with your code is you didn't look up the applicationContext bean for the service Which you are using. I had a similar use case, to call a feature service on the startup of the application. Initializing multiple applicationContext beans for the services and then making the method called works just fine! Code below :
public static void main(String[] args) {
ApplicationContext applicationContext = SpringApplication.run(UamRbacApplication.class, args);
AccessChangeSchedulerService accessChangeSchedulerService = applicationContext.getBean(AccessChangeSchedulerService.class);
AppContext appContext = applicationContext.getBean(AppContext.class);
try {
accessChangeSchedulerService.fetchAccessLevelChanges("EP", appContext.getSplunkToken());
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
Cheers.
Upvotes: 2
Reputation: 513
By using the new
keyword yourself to create an instance of the App
class, Spring cannot know about it.
It's also redundant, as Spring automatically creates a bean instance of this class by a mechanism called component scan.
I like the solution of the CommandLineRunner
.
What you also can do, is retrieve the ApplicationContext
, lookup the bean and then call the method.
You can inject the ApplicationContext
by letting your App
class implement ApplicationContextAware
, override the setter method and save the context in a static variable which you can access from your main method.
Then, you can use it to retrieve the correct App
instance.
App myApp = (App) applicationContext.getBean(App.class);
myApp.myMethod()
Please note that accessing the ApplicationContext
directly does kind of violate the whole dependency injection principle, but sometimes you haven't got much choice.
Upvotes: 6
Reputation: 4983
you can create a class that implements CommandLineRunner and this will be invoked after the app will start
@Component
public class CommandLineAppStartupRunner implements CommandLineRunner {
@Autowired
private MyService myService;
@Override
public void run(String...args) throws Exception {
myService.save();
}
}
you can get farther information on this here
Upvotes: 45