Roland
Roland

Reputation: 681

How to call a service from Main application calls Spring Boot?

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

Answers (4)

Wojciech Wirzbicki
Wojciech Wirzbicki

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

Ranjan Singh
Ranjan Singh

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

KenCoenen
KenCoenen

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

shahaf
shahaf

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

Related Questions