Reputation:
How to run code from class with @SpringBootApplication annotation. I want to run my code without calling to controller and get info from terminal not web browser. I tried to call weatherService in @SpringBootApplication but I've got a application failed start with description
The dependencies of some of the beans in the application context form a cycle:
┌─────┐
| weatherClientApplication
↑ ↓
| weatherService defined in file [C:\Users\xxx\IdeaProjects\weatherclient\target\classes\com\xxx\restapiclient\service\WeatherService.class]
└─────┘
@SpringBootApplication
public class WeatherClientApplication {
private WeatherService weatherService;
public WeatherClientApplication(WeatherService weatherService) {
this.weatherService = weatherService;
}
private static final Logger log = LoggerFactory.getLogger(WeatherClientApplication.class);
public static void main(String[] args) {
SpringApplication.run(WeatherClientApplication.class, args);
}
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder){
return builder.build();
}
@Bean
public CommandLineRunner run(RestTemplate restTemplate) throws Exception {
return args -> {
log.info(weatherService.getTemperatureByCityName("Krakow"));
};
}
}
@Service
public class WeatherService {
private RestTemplate restTemplate;
public WeatherService(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
public String getTemperatureByCityName(String cityName) {
String url = "http://api.openweathermap.org/data/2.5/weather?q=" + cityName + "&APPID=" + API_KEY + "&units=metric";
Quote quote = restTemplate.getForObject(url, Quote.class);
return String.valueOf(quote.getMain().getTemp());
}
}
Upvotes: 1
Views: 6464
Reputation: 33091
You are creating a cycle as you are injecting a service in the @SpringBootApplication
itself. Constructor injection means that nothing can really happen until the class is built but that service is going to be created later on.
Don't use field injection on your @SpringBootApplication
as it represents the root context. Your CommandLineRunner
injects a RestTemplate
but you are not using it. If you replace that by the WeatherService
and remove the constructor injection, things should work just fine.
I am glad you find the weather application useful by the way :)
Upvotes: 0
Reputation: 131346
1) What you want is implementing CommandLineRunner
and define the entry point of your application in the public void run(String... args)
method defined in this interface.
2) As said by Spring you have a cycle : break it with a injection outside the constructor.
Such as :
@SpringBootApplication
public class WeatherClientApplication implements CommandLineRunner{
@Autowired
private WeatherService weatherService;
//...
@Override
public void run(String... args) {
log.info(weatherService.getTemperatureByCityName("Krakow"));
}
//...
}
Generally constructor injection should be favored over field or setter injection but in your case, that is acceptable.
Upvotes: 0
Reputation: 40048
You can do this by using main method and by using ApplicationContext
, In this approach you don't need any CommandLineRunner
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(WeatherClientApplication.class, args);
WeatherService service = (WeatherService)context.getBean("weatherService");
service. getTemperatureByCityName("cityname");
}
Upvotes: 2