생성자 주입을 사용해야 되는 이유

반응형
반응형

스프링에서는 빈이라는 객체를 만들어서 관리할 수 있습니다.
이것을 IOC라고 부릅니다.
빈을 만드는 방법은 어노테이션 방법과 XML방법이 존재합니다.
하지만 여기에서는 빈 생성 방법에 대해 설명하지는 않겠습니다.
이러한 방법이 발전을 해서

@ComponentScan

을 이용해서 빈 등록이 가능해집니다.
정확히 말하면 이게 빈을 등록하는 직접적인 방법은 아니지만,
이 글에서 중요한 부분이 아니기 때문에 넘어가도록 하죠.
이렇게 빈을 생성하게 되면 (어떠한 방법이든 상관없습니다.)
@Autowrite라는 어노테이션을 활용해서 빈을 사용할 수 있습니다.
이것을 의존성 주입이라고 부릅니다.
의존성 주입에는 총 3가지가 존재합니다.

필드 주입

필드 주입 방법은 말 그대로
필드 위에 @Autowrite같은 의존성 주입 어노테이션을 붙여주면 사용할 수 있습니다.

@Autowired private TestService testService;

이런식으로 작성하면 간편하게 작성할 수 있습니다.
하지만 이 방법의 치명적인 단점은 수정이 불가능하다는 점입니다.
물론 private를 풀어주면 수정이 가능하지만 그렇게 되면 객체지향 원칙과 맞지 않습니다.
그렇다고 방법이 없는 것이 아닙니다.
수정 전용 메서드를 만들면 됩니다.

메서드 주입(수정자 주입)

여기에서 메서드는 set, 커스텀 메서드 모두 해당됩니다.

private TestService testService; @Autowired public void setTestService(TestService testService) { this.testService = testService; }

이렇게 만들어도 의존성 주입을 사용할 수 있습니다.
코드의 양이 필드 주입보다 많이 만들어져서 사용하기가 조금 꺼려지는 것은 사실입니다.

생성자 주입

거의 모든 DI프레임워크가 권장하는 방법입니다.
다른건 모르겠고 스프링은 확실합니다.
근데 왜 생성자 주입을 권장하는 걸까요?

private TestService testService; @Autowired public ConfigurationcomponentApplication(TestService testService) { this.testService = testService; }

솔직히 이것 쓸빠에 필드나 수정자를 쓰는게 낫다고 생각할지도 모릅니다.
왜냐하면 코드의 양이 비약적으로 증가했기 때문입니다.
하지만 생성자의 장점은 final을 붙일 수 있다는 것에 있습니다.
final을 붙이게 되면 불변이라는것을 의미합니다.
즉 TestService를 어떤 방식으로 수정이 불가하다는 뜻입니다.
이렇게 생각할 수 있을 것 같습니다.
생성자도 수정하는 건데 어떻게 가능한거지?
당연한 이야기지만 생성자는 객체가 생성할때 가장 먼저 호출이 되어집니다.
또, final을 붙여주게 되면 이 객체의 값을 어떻게든 지정을 해줘야 합니다.
필드로도 해결 할 수 있지만, 생성자로도 가능하다는 사실을 말하고 싶었습니다.
제가 생각할때 이 방법의 최고의 장점은 @Autowrite생략이 가능하다는 점입니다.
생성자가 하나일때만 가능합니다. 두개 이상일 경우에는 생략이 불가합니다.
일반적으로는 생성자가 하나일것입니다. 아마도. 아마도..

private final TestService testService; public ConfigurationcomponentApplication( TestService testService) { this.testService = testService; }

그래도 코드가 필드 주입보다 길어서 필드 주입에 손이 가는건 사실입니다.
이것은 롬복을 이용하면 어느정도 해결할 수 있습니다.


+ 추가)

final + 생성자가 하나일때 @Autowirte생략 가능하다는 점을 활용해서 코드를 간결하게 만들 수 있습니다.
롬복에는 여러 어노테이션을 제공하고 있습니다.
그중 여기에서 주목해야 되는 어노테이션 그룹은 생성자 어노테이션 그룹입니다.
생성자 어노테이션에는
@NoArgsConstructor
@AllArgsConstructor
@RequiredArgsConstructor 등이 존재합니다.
(등이라고 말한 이유는 이 다음은 잘 모르기 때문이고 더 있을 것 같다는 느낌적인 느낌때문입니다.)
하나하나 보자면 빈 생성자 생성, 전체 ?? 생성자 생성, 필수 ?? 생성자 생성
final을 붙는 이유를 생성해봅시다.
final이 붙여지는 순간 이 값은 반드시 필드 또는 생성자에 필수적으로 들어가야 됩니다.
그러면 이렇게 변경되어집니다.

@RequiredArgsConstructor public class XXXX { private final TestService testService; }

이 정도면 필드 주입을 사용할때 처럼은 아니지만, 그래도 짧은 코드를 사용할 수 있을 것 같습니다.
이제 정리해봅시다.
생성자 주입을 사용해야 되는 이유는 제가 생각할때 2가지로 생각할 수 있습니다.
1. final을 사용해서 보다 견고한 코드를 작성할 수 있습니다.
2. 생성자가 하나일때는 @Autowired 생략이 가능하다.
영한님의 말씀을 빌리자면 필드 주입과 수정자 주입은 테스트가 조금 어렵다고 합니다.
반면에 생성자 주입은 POJO한 방법으로 테스트가 가능하다고 합니다.
실제로 이렇게 말씀했는지는 기억은 나지 않고, 이런식으로 말씀하신 것 같습니다.

반응형

'SPRING START!' 카테고리의 다른 글

API GATE WAY (1)  (0) 2021.10.04
AOP  (0) 2021.08.25
DI 와 IOC  (0) 2021.08.14
이벤트 발생시키기!!  (0) 2021.01.12
스프링은 환경을 어떻게 조성할 수 있을까?(프로파일, 프로퍼티, 국제화)  (0) 2021.01.10

댓글

Designed by JB FACTORY