Spring Framework - @RequiredArgsConstructor와 final 변수

h.Im·2024년 8월 29일

Springboot 기초

목록 보기
7/17
post-thumbnail

final 키워드

final 키워드는 특정 변수, 메서드, 또는 클래스가 변경되지 않도록 제한하는 역할을 합니다.

  • 변수에 사용될 때:
    final로 선언한 변수는 초기화 후에 다시 값을 변경할 수 없습니다. 지역 변수에 붙는다면 초기화 후 값을 변경하지 못하도록 하고, 멤버 변수에 붙는다면 생성자에서 초기화한 후 다시는 값을 변경하지 못하게 됩니다.

  • 메서드에 사용될 때:
    final 메서드는 서브클래스에서 오버라이드(상속받은 메소드의 내용을 자식 클래스에서 변경하는 것)할 수 없습니다.

  • 클래스에 사용될 때:
    final 클래스는 다른 클래스가 상속할 수 없습니다.

@RequiredArgsConstructor와 final 변수

@RequiredArgsConstructor는 Lombok 라이브러리에서 제공하는 어노테이션으로, 클래스 내의 final로 선언된 모든 필드와 @NonNull로 지정된 필드들을 초기화하는 생성자를 자동으로 생성해 줍니다. 그렇다면 왜 final로 선언된 모든 필드와 @NonNull로 지정된 필드들을 초기화하는 것일까요?
그 이유는 위에서 final에 대해 살펴 보았듯, 생성자 내부에서 초기화 후 다시는 변경할 수 없는 특징을 가졌기 때문에 생성자에 초기화 코드가 자동으로 들어가게 되기 때문입니다.

import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
public class Service {
    private final String name;
    private final int level;

    // @RequiredArgsConstructor을 DeLombok하면 나타날 코드
    // public Service(String name, int level) {
    //     this.name = name;
    //     this.level = level;
    // }
}

Spring Framework에서의 사용 예시

@RestController
@RequiredArgsConstructor
public class MyController {
    private final MyService myService;

    @GetMapping("/create-one")
    public List<String> createOne() {
    	...
        myService.createOne();
        ...
    }
}

final 키워드와 @RequiredArgsConstructor 어노테이션이 Spring Framework 내에서 쓰이는 예제를 한 가지 살펴보겠습니다. 위 Controller 코드에서 Service Bean을 final로 선언 후, @RequiredArgsConstructor을 붙여 자동으로 의존성을 주입받고 있습니다.
Controller도 Bean이기 때문에 생성 단계가 Spring Application Context에 이루어질 텐데, 생성 단계에서 myService가 주입되는 것 마저도 Spring Application Context에 의해 이루어 지겠네요. 정말 어마어마하게 편리한 기능인 것 같습니다.

편리함 이외에 이런 코드 작성 방식이 어떤 장점을 갖는지 자세히 살펴보겠습니다.

불변성 (Immutability) 보장

final 키워드를 사용해서 객체의 불변성이 보장되기 때문에 멀티스레드 환경에서 동시성 문제를 줄일 수 있습니다.

의존성 누락 방지

@RequiredArgsConstructor를 사용하면, 필요한 서비스 객체를 주입받지 않은 채로 컨트롤러를 생성할 수 없게 됩니다. 이로 인해 의존성 주입 누락을 방지할 수 있으며, 컴파일 타임에 문제를 잡을 수 있습니다.

주입 순서와 순환 의존성 문제 해결

모든 의존성이 객체가 생성될 때 명확하게 초기화되므로, 주입 순서로 인한 문제를 방지할 수 있습니다. 또한 생성자 주입은 순환 의존성(circular dependency) 문제를 쉽게 발견할 수 있게 도와줍니다. 만약 A가 B를, B가 다시 A를 주입받으려고 할 경우, 생성자 주입에서는 순환 의존성을 컴파일 타임에 발견할 수 있습니다.

0개의 댓글