#java #spring #spring-boot #spring-mvc #spring-aop
#java #весна #весенняя загрузка #spring-mvc #spring-aop
Вопрос:
У меня есть простой сервис, в котором я хочу вести журнал через Spring AOP. Я получаю компонент при его запуске, у меня есть компонент для RestTemplate в контроллере, который уже определен, пожалуйста, предложите, если здесь что-то отсутствует.
Трассировка стека :
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'demo1Controller': Unsatisfied dependency expressed through field 'restTemplate'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'restTemplate' defined in class path resource [com/test/demo1/controller/Demo1Controller.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.web.client.RestTemplate]: Circular reference involving containing bean 'demo1Controller' - consider declaring the factory method as static for independence from its containing instance. Factory method 'restTemplate' threw exception; nested exception is java.lang.NullPointerException
Мой класс аспектов DemoHttpAspect.java
@Aspect
@Component
@Order(1)
public class DemoHttpAspect {
private final static Logger logger = LoggerFactory.getLogger(DemoHttpAspect.class);
@After("execution(public * com.test.demo1.controller.*.*(..))")
public void logAfter() throws Throwable {
System.out.println(SplunkLogImpl.of("Performance Logging via AspectJ, Into DemoAspect"));
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
HttpAspectCore.controllerEvents(request);
System.out.println(SplunkLogImpl.of("Performance Logging via AspectJ, Out of CoreAspect"));
}
}
Мой класс контроллера
package com.test.demo1.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpHeaders;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
public class Demo1Controller {
@Autowired
RestTemplate restTemplate;
@Bean
public RestTemplate restTemplate()
{
return new RestTemplate();
}
@RequestMapping("/demo1/name")
public String getMicroserviceName()
{
String micro2Response = restTemplate.postForObject("http://localhost:8084/service/sleuth", null, String.class);
System.out.println("getMicroserviceName");
return "Demo" " : " micro2Response ;
}
@GetMapping("/demo1/sleuth")
public String helloSleuth(@RequestHeader HttpHeaders headers) {
System.out.println("helloSleuth");
System.out.println("headers.getClass()" headers.getClass());
return "success demo1";
}
}
Комментарии:
1. Вы не должны помещать
Bean
методы в компоненты. Удалите его (и это также решит вашу проблему).2. @M.Deinum, если я удалю аннотацию, это даст: Описание: для поля RestTemplate в com.test.demo1.controller.Demo1Controller требуется компонент типа org.springframework.web.client. RestTemplate’ который не удалось найти. Точка внедрения имеет следующие аннотации: — @org.springframework.beans.factory.annotation. Действие с автоматической настройкой (обязательно = true): Рассмотрите возможность определения компонента типа ‘org.springframework.web.client. RestTemplate’ в вашей конфигурации.
3. сэр, если прокомментировал «//@Component» в aspect, и он начал работать, но ведение журнала аспектов не работает, не уверен, нужно ли это для Aspect.
Ответ №1:
Ваш Demo1Controller зависит от RestTemplate, но он также определяет его как облегченный компонент. Итак, у вас есть циклическая зависимость, вам нужен Demo1Controller для создания RestTemplate, но Demo1Controller нуждается в RestTemplate.
У вас есть два решения:
- переместите определение @Bean в класс @Configuration
- сделайте метод статическим.
В данном случае рекомендуется первое решение.
@Configuration
public class DepsConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
@RestController
public class Demo1Controller {
@Autowired
RestTemplate restTemplate;
@RequestMapping("/demo1/name")
public String getMicroserviceName()
{
String micro2Response = restTemplate.postForObject("http://localhost:8084/service/sleuth", null, String.class);
System.out.println("getMicroserviceName");
return "Demo" " : " micro2Response ;
}
@GetMapping("/demo1/sleuth")
public String helloSleuth(@RequestHeader HttpHeaders headers) {
System.out.println("helloSleuth");
System.out.println("headers.getClass()" headers.getClass());
return "success demo1";
}
}
Поскольку вы используете spring boot, я полагаю, вы используете ComponantScanning по умолчанию, что означает, что DepsConfig должен находиться в пакете (или подпакете), в котором определено приложение.
Я предлагаю вам ознакомиться с документацией о том, как IoC работает с spring и как определять компоненты. И как работает автоконфигурация spring boot.
Комментарии:
1. Использование «@Configuration» приводит к появлению нескольких маркеров в этой строке — Конфигурация не может быть преобразована в тип — аннотация @Configuration запрещена для этого местоположения
2. это должно использоваться в классе
3. извините, что не понял вас, я использую его в классе контроллера, не могли бы вы пояснить, что вы имели в виду.
4. Я обновил свой ответ, но это действительно базовая весна.
5. На самом деле, даже сообщение об ошибке, опубликованное Вики, уже предлагает то, что ДЖЕЙ более подробно объяснил здесь в качестве одного из возможных решений: «Циклическая ссылка, включающая содержащий компонент’demo1Controller’ — рассмотрите возможность объявления фабричного метода как статического для независимости от содержащего его экземпляра». Иногда это помогает просто прочитать сообщение об ошибке. Что касается «Конфигурация не может быть преобразована в тип» , возможно, просто импортируйте правильный класс. Ваша среда разработки должна помочь вам и предложить ее автоматически.