Spring Rest 컨트롤러 상속
유형의 모든 개체를 처리하기 위한 몇 가지 공통 로직이 포함된 추상 Rest Controller를 가지고 있습니다.처리 서비스는 생성자를 통해 제공됩니다.
하위 클래스의 빈 인스턴스화 중에 두 생성자가 null이 아닌 매개 변수로 호출되고 슈퍼 클래스 null이 아닌 어설션이 성공적으로 전달됩니다.
API 끝점(URI 경로는 하위 클래스 및 슈퍼 클래스 경로의 구성)을 호출하면 매개 변수가 올바르게 식별된 올바른 메서드가 호출됩니다.그러나 제공된 서비스(null이 아닌 어설션을 전달한 서비스)가 null이었기 때문에 엔드포인트 메서드는 null 포인터 예외를 슬로우합니다.검사 시 메서드가 호출된 빈의 하위 클래스와 상위 클래스의 모든 속성은 null로 보고됩니다.
다음은 단순화된 예입니다.
모델:
public class Cookie {
public long id;
}
public class ChocolateCookie extends Cookie {
public long chipCount;
}
서비스:
public interface CookieService<T extends Cookie> {
T findCookie(long cookieId);
void eatCookie(T cookie);
}
@Service
public class ChocolateCookieService implements CookieService<ChocolateCookie> {
@Override
public ChocolateCookie findCookie(long cookieId) {
// TODO Load a stored cookie and return it.
return new ChocolateCookie();
}
@Override
public void eatCookie(ChocolateCookie cookie) {
// TODO Eat cookie;
}
}
나머지 컨트롤러:
public abstract class CookieApi<T extends Cookie> {
private final CookieService<T> cookieService;
public CookieApi(CookieService<T> cookieService) {
this.cookieService = cookieService;
Assert.notNull(this.cookieService, "Cookie service must be set.");
}
@PostMapping("/{cookieId}")
public ResponseEntity eatCookie(@PathVariable long cookieId) {
final T cookie = cookieService.findCookie(cookieId); // Cookie service is null
cookieService.eatCookie(cookie);
return ResponseEntity.ok();
}
}
@RestController
@RequestMapping("/chocolateCookies")
public class ChocolateCookieApi extends CookieApi<ChocolateCookie> {
@Autowired
public ChocolateCookieApi(ChocolateCookieService cookieService) {
super(cookieService);
}
@PostMapping
public ResponseEntity<ChocolateCookie> create(@RequestBody ChocolateCookie dto) {
// TODO Process DTO and store the cookie
return ResponseEntity.ok(dto);
}
}
참고로, 슈퍼클래스에 서비스 개체를 제공하는 대신 서비스를 온디맨드로 제공하기 위한 추상적인 방법을 정의하고 서브클래스에 구현한다면 슈퍼클래스는 의도한 대로 작동할 것입니다.
@RestController 및 @RequestMapping이 방정식에 포함되지 않는 경우에도 동일한 원리가 적용됩니다.
제 질문은 두 가지입니다.
- 왜 이런 일이 일어나는 거지?
- 생성자를 사용하는 방법이 있습니까, 아니면 적어도 슈퍼 클래스에서 요구하는 각 하위 클래스와 각 서비스에 대해 더 나은 방법을 구현하지 않아도 됩니까?
편집 1:
저는 문제를 재현하려고 했지만, 제공된 코드는 사람들이 제안한 대로 잘 작동하고 있었습니다.단순화된 프로젝트를 조작한 후, 저는 마침내 그 문제를 재현할 수 있었습니다.문제를 재현하기 위한 실제 조건은 슈퍼클래스의 엔드포인트 메서드에 하위 클래스가 액세스할 수 없어야 한다는 것입니다(예: 클래스가 서로 다른 패키지에 있고 메서드가 패키지를 표시할 수 있음).이로 인해 spring은 필드가 0인 enhancerBySpringCGLIB 프록시 클래스를 만듭니다.
superclass 메서드를 보호/공개 가시성으로 수정하여 문제를 해결했습니다.
니콜라,
왜 당신의 코드가 당신의 시스템에서 작동하지 않는지 모르겠습니다. 저는 프로젝트에서 같은 클래스를 만들었고 잘 작동하고 있습니다. 다른 쿠키 유형, 서비스 및 api 클래스를 추가하기도 했습니다.
SpringBoot 로그(초기화된 4개의 끝점을 볼 수 있음):
2019-02-26 14:39:07.612 INFO 86060 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/chocolateCookies],methods=[POST]}" onto public org.springframework.http.ResponseEntity<cookie.ChocolateCookie> cookie.ChocolateCookieApi.create(cookie.ChocolateCookie)
2019-02-26 14:39:07.613 INFO 86060 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/chocolateCookies/{cookieId}],methods=[POST]}" onto public org.springframework.http.ResponseEntity<?> cookie.CookieApi.eatCookie(long)
2019-02-26 14:39:07.615 INFO 86060 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/oatmeal-raisin-cookie],methods=[POST]}" onto public org.springframework.http.ResponseEntity<cookie.OatmealRaisinCookie> cookie.OatmealRaisingCookieApi.create(cookie.OatmealRaisinCookie)
2019-02-26 14:39:07.615 INFO 86060 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/oatmeal-raisin-cookie/{cookieId}],methods=[POST]}" onto public org.springframework.http.ResponseEntity<?> cookie.CookieApi.eatCookie(long)
우체부에서 컨트롤러 테스트
@Domingo가 언급했듯이, OOP 및 Spring IoC 관점에서 코드가 문제 없이 실행되고 보기 때문에 애플리케이션에 구성 문제가 있을 수 있습니다.
참고: 이러한 컨트롤러는 SpringBoot 2.0.5, Java 8, Eclipse를 사용하여 실행하고 있습니다.
참고로 GitHub에 제 프로젝트를 게시했습니다.https://github.com/karl-codes/cookie-monster
건배!
추상 클래스에서 추상 메서드를 정의하고 각 구현에서 올바른 서비스를 자동 배선할 수 있습니다.
public abstract class CookieApi<T extends Cookie> {
protected abstract CookieService<T> getCookieService();
@RequestMapping("/cookieId")
public void eatCookie(@PathVariable long cookieId) {
final T cookie = cookieService.findCookie(cookieId); // Cookie service is null
this.getCookieService().eatCookie(cookie);
}
}
@RestController
@RequestMapping("/chocolateCookies")
public class ChocolateCookieApi extends CookieApi<ChocolateCookie> {
@Autowired
private ChocolateCookie chocolateCookie;
@Override
protected CookieService<T> getCookieService() {
return this.chocolateCookie;
}
@PostMapping
public ResponseEntity<ChocolateCookie> create(@RequestBody ChocolateCookie dto) {
// TODO Process DTO and store the cookie
return ResponseEntity.ok(dto);
}
}
당신의 샘플은 일반적으로 괜찮아 보이고 의존성 주입은 스프링과 함께 작동해야 합니다.
상위 추상 클래스에 있는 참조가 있는 서비스에 액세스하려면 참조가 비공개가 아니라 보호되어야 합니다.
--
Spring은 모든 RestController를 SingletonBeans로 애플리케이션 컨텍스트에 초기화하여 기존 서비스 Beans를 주입하면 애플리케이션 시작이 실패합니다.호출 중인 rest 끝점이 서비스 참조가 없는 컨트롤러에 액세스하는 경우, 해당 컨트롤러에서 서비스로 초기화된 컨트롤러와 동일하지 않거나(어떻게 발생할 수 있는지 알 수 없습니다.
그것을 깃허브에 올려놓으세요.
언급URL : https://stackoverflow.com/questions/54823765/spring-rest-controller-inheritance
'programing' 카테고리의 다른 글
SpringBoot WebClient를 사용할 때 요청을 가로채기 (0) | 2023.07.21 |
---|---|
구성에서 유형을 정의하는 것을 고려합니다. (0) | 2023.07.21 |
ASP.NET Development Server 대신 IIS에 디버거를 연결하려면 어떻게 해야 합니까? (0) | 2023.07.16 |
메모리 누수 C++ (0) | 2023.07.16 |
원산지/마스터릿 위치는 어떻게 찾고 변경은 어떻게 하나요? (0) | 2023.07.16 |