Как запустить код из класса с аннотацией @SpringBootApplication. Я хочу запустить свой код без обращения к контроллеру и получить информацию с терминала, а не с веб-браузера. Я пытался вызвать WeatherService в @SpringBootApplication, но у меня не получилось запустить приложение с описанием
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());
}
}




Вы можете сделать это, используя основной метод и используя ApplicationContext. В этом подходе вам не нужен CommandLineRunner.
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(WeatherClientApplication.class, args);
WeatherService service = (WeatherService)context.getBean("weatherService");
service. getTemperatureByCityName("cityname");
}
почему бы и нет, у вас есть ApplicationContext, зачем вам что-то запускать? @Стефан Николл
Потому что есть другие способы избежать ручной игры с контекстом?
1) Вам нужно внедрить CommandLineRunner и определить точку входа вашего приложения в методе public void run(String... args), определенном в этом интерфейсе.
2) Как сказал Spring, у вас есть цикл: разорвите его инъекцией вне конструктора.
Такие как :
@SpringBootApplication
public class WeatherClientApplication implements CommandLineRunner{
@Autowired
private WeatherService weatherService;
//...
@Override
public void run(String... args) {
log.info(weatherService.getTemperatureByCityName("Krakow"));
}
//...
}
Как правило, внедрение конструктора должно быть предпочтительнее внедрения поля или сеттера, но в вашем случае это приемлемо.
Я бы тоже не рекомендовал этого делать. Внедрение поля происходит сразу после создания экземпляра класса, и для WeatherService требуется bean-компонент, который фактически предоставляет тот же класс. Это, вероятно, также создаст цикл.
Думаете, это случайно? Spring не предназначен для проверки зависимости, необходимой перед внедрением поля, и создания экземпляров bean-компонентов, необходимых до ?
Да, он предназначен для проверки таких вещей, и я на самом деле немного удивлен, что он работает. Тот факт, что это работает, не является причиной плохого дизайна: если бы вы сами подключали что-то, вы бы не проектировали свой код таким образом, так зачем вам это, потому что «вы можете»? В конце дня этот код пытается инициализировать поле чем-то, что требуется для вызова метода.
Вы создаете цикл, вводя службу в сам @SpringBootApplication. Внедрение конструктора означает, что ничего не может произойти, пока класс не будет построен, но эта служба будет создана позже.
Не используйте внедрение полей на вашем @SpringBootApplication, так как оно представляет собой корневой контекст. Ваш CommandLineRunner вводит RestTemplate, но вы его не используете. Если вы замените его на WeatherService и удалите инъекцию конструктора, все должно работать нормально.
Кстати, я рад, что вы нашли приложение погоды полезным :)
Работает отлично. Спасибо
WeatherClientApplication требует запуска Bean WeatherService. Для запуска Bean WeatherService требуется Bean RestTemplate в WeatherClientApplication. Вы должны автоматически подключить службу и позволить Spring обрабатывать внедрение зависимостей, а не объявлять требования bean-компонента в конструкторе, чтобы обойти эту проблему.