<TIL> 135. 생성자 주입 선택의 이유, @PostMapping 사용 이유

YUJIN LEE·2023년 7월 19일
0

개발log

목록 보기
127/149

@Autowired 필드 주입 방식의 문제점.

순환 참조 발생 가능성

순환 참조가 발생 시, 컴파일 타임 시 에러가 잡히지 않다가 로직이 실행되는 런타임 시에 에러가 잡힘.
컴파일 때 에러가 잡히지 않아, 애플리케이션이 정상적으로 작동하는 것으로 보이나,
setter 주입이나 생성자 주입의 경우 컴파일 타임 때 에러가 잡혀, 문제가 되는 부분을 즉각 파악 가능

순환참조?

순환참조 문제는 A 클래스가 B 클래스의 Bean을 주입받고, B 클래스가 A 클래스의 Bean을 주입 받는 상황처럼 서로 순환되어 참조 시 발생하는 문제 의미

왜 발생?
특정 클래스에서 IoC컨테이너에 있는 Bean을 주입받기 위해 세 가지 방법 사용 가능.
필드 주입방식, Setter 주입방식, 생성자 주입방식이 이에 해당.

필드 주입방식과 Setter 주입방식에서 발생하는 순환참조문제는
A클래스가 B클래스를 의존, B클래스가 A클래스를 의존하는 상황이더라도 애플리케이션의 실행과정에서 예외가 발생하지 않는다.
실제로 두 개의 클래스가 순환참조하고 있더라도 당장에 문제는 생기지 않지만,
A 클래스의 메소드와 B 클래스의 메소드가 서로 순환참조하고 있는 상황에서 해당 메소드가 호출되면 발생.

정리
1. 스프링 애플리케이션 로딩 시 예외 발생 X
2. 단순히 클래스 끼리 순환참조하는 것이 아니라 실제로 메소드가 순환호출되어야 하고, 해당 메소드가 호출되는 시점에 예외 발생.

-> 서로 다른 메소드가 서로 호출할 때 발생하는 순환호출문제.

생성자 주입방식에서의 순환참조 문제

생성자 주입방식의 동작방식?
스프링 애플리케이션이 로딩되는 시점에 A 클래스가 B 클래스를 의존하고, B 클래스가 C 클래스를 의존한다면 Spring Boot 는 A 클래스에 대한 Bean을 만들기 위해 B 클래스의 Bean을 주입하는데 없으니까, B클래스의 Bean을 먼저 생성. 하지만 그 과정에서 C 클래스의 Bean을 주입하는데 없어 C 클래스의 Bean을 먼저 만듬.
-> 결과적으로 Spring Boot는 C - B - A 순서로 Bean 생성

그렇다면 A 클래스가 B 클래스를 의존, B 클래스가 A 클래스를 의존하는 상황은?
-> A 클래스의 Bean을 만드는 과정에서 B 클래스의 Bean을 주입하고, 없으니 B 클래스의 Bean 먼저 생성.
이때 A클래스의 Bean을 주입하려는데 없으니 A클래스의 Bean을 먼저 생성......
이러면서 무한반복에 빠짐.

-> 이렇게 순환하는 과정에서 결과적으로 어떠한 Bean 도 생성하지 못하는 문제 = 순환참조 문제.

정리
1. 클래스가 서로 의존성 주입을 통해 순환참조하고 있을 때 발생하는 문제.(메소드까지 가지도못함)
2. 스프링 애플리케이션 로딩 시점에서 예외발생.

-> 이러한 문제를 해결하기 위해서는 @Lazy 사용할 수 있고 필드주입이나 setter주입방식 사용가능..
하지만 스프링에서 권장하지 않아서
순환참조되는 설계를 지양하는 것이 좋다.

생성자 주입방식의 장점 중 하나로
이러한 순환참조 여부를 애플리케이션 로딩 시점에서 알 수 있어
아주 불가피한 상황이 아니라면 설계를 개선하는게 좋다.

생성자 주입 방식 선택의 이유?

불변

생성자 주입은 객체를 생성할 시 딱 한번 호출되어, 이후 의존 관계를 변경할 일이 없으며 변경의 여지를 만들지 않음.

누락

순수 자바 테스트에서 의존 관계를 누락 시, 생성자 주입은 컴파일 오류 발생.
setter 주입의 경우 런타임 시 에러.
필드 주입의 경우 아예 불가(외부 라이브러리에 테스트를 의존해야함)

final 키워드 사용 유무

생성자 주입의 경우 final 키워드 사용 가능.
그래서 혹시라도 값이 설정되지 않는 경우 즉각적으로 컴파일 오류 뱉음.

요약

생성자 주입 방식 장점

  • 의존관계 설정이 되지 않으면 객체 생성 불가 -> 컴파일 타임에 인지 가능, NPE 방지
  • 의존성 주입이 필요한 필드를 final로 선언 가능 -> Immutable
  • (스프링에서) 순환참조 감지가능 -> 순환참조시 앱구동 실패
  • 테스트 코드 작성 용이

필드 주입 장점

  • 편함 끝.

@GetMapping, @PostMapping 어노테이션사용 이유.

@RequestMapping(value="경로", method=RequestMethod.GET)
이렇게 긴 코드가
@GetMapping("경로")
이렇게 짧아질 수 있는 장점.

하지만
@RequestMapping("경로")
이렇게 처리도 가능한데 왜 굳이 @GetMapping을 사용해야하나?

@RequestMapping은 method를 생략 시 GET방식과 POST 방식 모두 처리.
-> 어떻게 보면 이렇게 쓰는 게 더 편하다 생각할 수 있음.

@GetMapping...등을 사용 이유는 @RequestMapping에 굳이 method를 명시하는 이유와 같다고 본다.

url 중복 사용 가능

url 요청을 통해 메서드를 요청 시 전송 방식을 명시하면 하나의 url로도 두 개 이상의 매핑 처리 가능

@GetMapping("/insert")
@PostMapping("/insert")

이렇게 두 개의 매핑 가능.

만약, @RequestMapping("/insert")로 GET 방식의 요청을 받았다면 POST 방식의 요청은 다른 url을 써야함.
이렇게 되면 보기에도 코드를 관리하기 좋지 못함
-> 전송 방식을 명시 시 url을 경제적으로 사용 가능

코드에 의미 명시

코드만 봐도 어떤 전송 방식을 처리하는지 확인할 수 있는 장점

profile
인정받는 개발자가 되고싶습니다.

0개의 댓글