포스트

스프링 핵심 원리 (11) - 롬복과 최신 트렌드

스프링 핵심 원리 (11) - 롬복과 최신 트렌드

1. 개요

앞 글에서 생성자 주입을 기본으로 써야 하는 이유를 정리했다. 그런데 막상 실무 코드를 짜보면 대부분의 의존관계가 final 필드이고, 그 필드들을 그대로 받아 대입해주는 생성자를 매번 손으로 채워 넣어야 한다. 필드가 늘어나면 생성자 파라미터도, 대입 코드도 같이 늘어나는 반복 작업이다. 이번 글에서는 이 반복을 롬복(Lombok)으로 줄이는 방법과, 그 결과 최근 스프링 코드가 어떤 모습으로 수렴하고 있는지를 정리한다.


2. 반복되는 생성자 코드

생성자가 하나뿐이면 @Autowired는 생략할 수 있다는 것을 앞 글에서 확인했다. 그래도 아래처럼 필드 선언, 생성자 시그니처, 대입문을 다 손으로 써야 하는 건 여전하다.

1
2
3
4
5
6
7
8
9
10
11
@Component
public class OrderServiceImpl implements OrderService {

    private final MemberRepository memberRepository;
    private final DiscountPolicy discountPolicy;

    public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
        this.memberRepository = memberRepository;
        this.discountPolicy = discountPolicy;
    }
}

필드가 3개, 4개로 늘어나도 패턴은 동일하다. 필드 목록과 생성자 내용이 사실상 같은 정보를 두 번 적는 셈이라, 필드를 하나 추가하거나 지울 때마다 생성자도 같이 고쳐야 하는 번거로움이 생긴다.


3. 롬복으로 생성자 생략하기

롬복은 자바의 애노테이션 프로세서 확장 지점을 이용하는 라이브러리다. 소스 코드에는 없던 내용을 컴파일 과정 중간에 끼워 넣어, 결과물인 class 파일에는 코드가 실제로 존재하게 만드는 방식으로 동작한다. @RequiredArgsConstructor는 이 원리를 이용해 클래스 안의 final 필드를 스캔한 뒤, 그 필드들을 파라미터로 받는 생성자를 대신 만들어 넣어주는 애노테이션이다. 클래스에 아래처럼 한 줄만 붙이면 된다.

1
2
3
4
5
6
7
@Component
@RequiredArgsConstructor
public class OrderServiceImpl implements OrderService {

    private final MemberRepository memberRepository;
    private final DiscountPolicy discountPolicy;
}

눈에 보이는 소스에는 생성자가 없지만, IDE에서 .class 파일을 디컴파일해보면 2장에서 손으로 작성했던 것과 사실상 같은 생성자가 들어 있는 것을 확인할 수 있다. 코드에 적혀 있지 않을 뿐 실제로 존재하고 정상적으로 호출되는 것이다. 필드를 추가하거나 삭제해도 다음 컴파일 때 생성자가 다시 만들어지므로, 개발자는 필드 선언만 관리하면 된다.


4. 롬복 적용 방법

build.gradle에 라이브러리와 컴파일 설정을 추가한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter'

    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
    testCompileOnly 'org.projectlombok:lombok'
    testAnnotationProcessor 'org.projectlombok:lombok'

    testImplementation('org.springframework.boot:spring-boot-starter-test') {
        exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
    }
}

IntelliJ에서는 다음 두 가지를 추가로 설정해야 한다.

  1. Preferences → Plugins에서 lombok을 검색해 설치하고 재시작한다.
  2. Preferences → Annotation Processors에서 Enable annotation processing을 체크하고 재시작한다.

설정이 끝났다면 임의의 클래스에 @Getter, @Setter 등을 붙여보고 정상적으로 인식되는지 확인하면 된다.


5. 최근 스프링 코드의 모습

지금까지의 내용을 정리하면, 최근 스프링 프로젝트에서 자주 보이는 패턴은 다음과 같다.

  • 의존관계 필드는 final로 선언해 불변을 보장한다.
  • 클래스에 @RequiredArgsConstructor를 붙여 생성자 코드를 직접 작성하지 않는다.
  • 생성자가 하나뿐이므로 @Autowired는 자연스럽게 없어도 된다.

이렇게 하면 필드 주입만큼 코드는 짧아지면서도, 생성자 주입이 주는 불변성과 컴파일 시점 검증은 그대로 유지된다. 실무에서 서비스나 리포지토리 클래스를 작성할 때 기본값처럼 자리 잡은 조합이라고 볼 수 있다.


6. 정리

이번 글에서 다룬 내용을 한 줄로 요약하면, 롬복은 생성자 코드를 없앤 게 아니라 그 코드를 개발자 대신 써주는 도구라는 것이다. 생성자 주입이 가진 불변성과 컴파일 시점 검증이라는 장점은 그대로 남아 있고, 겉으로 보이는 코드만 필드 주입만큼 짧아진다.

@Component@RequiredArgsConstructor를 함께 쓰고 생성자에서 @Autowired를 생략하는 조합이 현재 스프링에서 가장 널리 쓰이는 패턴이다. 새로운 의존관계 주입 방법이라기보다는, 이미 검증된 생성자 주입을 더 편하게 작성하기 위한 도구라는 점을 기억해두면 된다.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.