Spring 에 interface 의존성 주입에 대해 알아보자!
당연하지만 실제로 테스트를 해보고 싶었다.
나는 간단하게 Controller 를 Test 로 만들고 TestInterface 와 구현체인 Test1 를 만들었다.
아래의 코드다.
@RestController
@RequiredArgsConstructor
public class Test {
private final TestInterface testInterface;
@GetMapping("/t")
public String test(){
return testInterface.getMsg();
}
}
public interface TestInterface {
String getMsg();
}
@Component
public class Test1 implements TestInterface{
@Override
public String getMsg() {
return "1번째 test입니다~";
}
}
당연하게도 1번째 test 라는 메세지가 반환하게 된다.
그런데 만약 TestInterface 를 implements 하는게 2개의 클래스라면? 당연히 에러가 나올거다. 실제로 해보니 아래의 에러가 나온다.
Parameter 0 of constructor in com.test.spring.spring_test.domain.Test required a single bean, but 2 were found:
- test1: defined in file [C:\Users\ty_ty\OneDrive\바탕 화면\코딩자료\Spring\spring_test\out\production\classes\com\test\spring\spring_test\domain\Test1.class]
- test2: defined in file [C:\Users\ty_ty\OneDrive\바탕 화면\코딩자료\Spring\spring_test\out\production\classes\com\test\spring\spring_test\domain\Test2.class]
하지만 해결할수 있는 방법이 있다.
이 어노테이션을 쓰게 되면 그 해당 클래스를 제일 먼저 의존성 주입을 시키기 때문에 에러가 뜨지 않고 정상적으로 할수 있다.
또한
@Qualifier 를 이름 지정하고 @Autowired 로 원하는것을 받을수 있다.
하지만, Spring 4.3 버전부터는 변수명으로 지정할수 있기 때문에 해당 변수명 -> 클래스명 으로 지을시 자동적으로 해당 클래스가 의존성 주입을 받을수 있다..아래 테스트 코드 이다.
와우... 이렇게 되면 너무 편리하게 쓸수 있다.
private final TestInterface test1;
@Component
public class Test1 implements TestInterface{
@Override
public String getMsg() {
return "1번째 test입니다~";
}
}
@Component
public class Test2 implements TestInterface {
@Override
public String getMsg() {
return "2번째 test 입니다~";
}
}
@Component
public class Test2 implements TestInterface {
@Override
public String getMsg() {
return "2번째 test 입니다~";
}
}
Util 파일들을 전부 interface 로 만들어 놓는다면?
그렇다면 이제 Util 파일들을 전부 Interface 만들고 implements 받는다면? 예를 들자면 JpaRepository 같은 인터페이스를 따로 만든다는 이야기다. 왜 이 생각을 하게 되었냐면 Util 이라고 해도 CRUD 인데 이렇게 되면 Interface 로 관리 할수 있지 않을까? JpaRepository 처럼! 그런생각이 들게 된다. ( 대단히 객체지향적 생각인것 같다 후후 )
실제로 써야 되는 상황이 왔다!!!
항해99 클론코딩주차때 프론트 인원이 부족하여 msg 를 우리가 정해주고 보내주면 좋을것 같다고 프론트쪽에서 요청하여 수락하여 만들었다.
여기서 나는 생각을 하게 되었다. 음 그러면 성공 실패 를 나눠서 관리하면 좀더 좋지 않을까? 즉, 미리 매서드를 만들어 놓고 쓰면 좋지 않을까? 라고 생각하였다. 그렇게 나온것이 아래의 코드들이다.
해당 enum class 를 통해 HttpStatus 와 메세지를 한눈에 보고 관리할수 있다. 먼저 이런식으로 구성을 하였다. 이 중 코드 하나만 가져오겠다.
public interface CustomException {
HttpStatus getHttpStatus();
String getErrorMsg();
}
@RequiredArgsConstructor
@Getter
public enum FollowingErrorCode {
NO_FOLLOWING(HttpStatus.BAD_REQUEST, "팔로워가 없습니다."),
SELF_FOLLOWING_NOT_ALLOWED(HttpStatus.BAD_REQUEST, "팔로잉을 자신한테 걸 수 없습니다."),
NOT_FOLLOWING_USER(HttpStatus.BAD_REQUEST, "팔로잉할 유저가 없습니다.")
;
private final HttpStatus status;
private final String msg;
}
@RequiredArgsConstructor
@Getter
public class FollowingExceptionImpl extends RuntimeException implements CustomException{
private final FollowingErrorCode followingErrorCode;
@Override
public HttpStatus getHttpStatus() {
return followingErrorCode.getStatus();
}
@Override
public String getErrorMsg() {
return followingErrorCode.getMsg();
}
}
이런식으로 구성하였다. 이제 RestControllerAdvice 코드를 보자.
@RestControllerAdvice
@RequiredArgsConstructor
public class GlobalExceptionAdvice {
@ExceptionHandler(FileExceptionImpl.class)
public ResponseEntity<?> fileErrorHandler(FileExceptionImpl e) {
return CustomResponse.error(e);
}
}
여기서 + CustomResponse 의 코드도 같이 첨부하겠다.
@Getter
@RequiredArgsConstructor
public class CustomResponse<T> {
private final String msg;
private final T result;
public static ResponseEntity error(CustomException errorCode) {
return ResponseEntity.status(errorCode.getHttpStatus())
.body(new CustomResponse<>(errorCode.getErrorMsg(), null));
}
public static <T> CustomResponse<T> success(String msg, T result) {
return new CustomResponse<>(msg, result);
}
public static ResponseEntity vaildationError(String msg) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(new CustomResponse<>(msg, null));
}
}
이런식으로 코드를 작성하였다. error 와 success 를 나눴고 error 일때는 인터페이스를 통해 가져오게 된다.
왜냐하면, 여러 Exceptiom 들이 있고 그걸 하나하나 받기에는 CustomResponse 가 반복하는 매서드가 많아 질것 같았다.
그래서 Interface 하나로 관리 하고 매개변수로 받아서 처리를 하자! 생각이 들어 이런식으로 처리 하였다.
'Spring' 카테고리의 다른 글
HikariCP (0) | 2023.08.17 |
---|---|
테스트 도구 Apache JMeter (0) | 2023.08.11 |
QueryDSL (1) (2) | 2023.07.10 |
Filter (0) | 2023.06.26 |
Spring Security (3) (0) | 2023.06.26 |