본문 바로가기

Framework/Spring

[Spring] 롬복 어노테이션(@NoArgsConstructor, @RequiredConstructor, @AllArgsConstruct)에 대해서 - 컴도리돌이

728x90

 

생성자 주입(Constructor Injection)은 의존성 주입의 한 종류로, 객체를 생성할 때 해당 객체가 필요로 하는 의존성을 생성자를 통해 주입하는 방식이에요. 스프링 프레임워크에서는 Autowired 어노테이션을 사용합니다. 반면에 필드 주입(Field Injection)은 의존성을 클래스의 필드에 직접 주입하는 방식이며, Autowired 어노테이션을 필드에 적용합니다. 

@Service
public clas ExampleService {

    private final ExampleRepository exampleRepository;
    
    @Autowired
    public ExampleService(ExampleRepository exampleRepository) {
       this.exampleRepository = exampleRepository;
    }
}

 

위아래의 두 코드는 Autowired 어노테이션이 적용 유/무이 차이가 있는데, 놀랍게도 두 코드는 동일한 동작을 수행해요 🤔🤔

첫 번째 코드에서는 스프링 프레임워크에게 해당 생성자를 사용하여 ExampleRepository 의존성을 주입하라는 것을 알려줍니다. 반면에 두 번째 코드에서는 Autowired 어노테이션이 없습니다. 그러나 스프링 프레임워크는 여전히 생성자 주입을 사용하여 ExampleRepository 의존성을 주입할 것입니다.

 

스프링 프레임워크에서는 생성자 주입을 적극 지원하고 있기 때문에, 생성자가 1개만 있을 경우에 @Autowired를 생략해도 주입이 가능하도록 편의성을 제공하고 있습니다. 그렇기 때문에 위아래 코드는 아래와 동일한 코드가 돼요 🙄🙄

@Service
public clas ExampleService {

    private final ExampleRepository exampleRepository;
    
    public ExampleService(ExampleRepository exampleRepository) {
       this.exampleRepository = exampleRepository;
    }
}

 

그런데 저는 보통 위 와 같이 필드 주입이나 Autowired 어노테이션을 사용해서 생성자를 생성하지 않고, 롬복(Lombok) 라이브러리를 사용하여 더욱 편리하게 생성자를 주입을 합니다. 😊😊

@NoArgsConstructor

@NoArgsConstructor 어노테이션은 파라미터가 없는 디폴트 생성자를 자동으로 생성해 줘요. 이 어노테이션을 사용하면, 클래스에 명시적으로 선언된 생성자가 없더라도 인스턴스를 생성할 수 있습니다.

1-1) 상속 클래스와 함께 사용 시, 올바르지 않은 코드

import lombok.NoArgsConstructor;

public class ParentClass {
    public ParentClass(String name) {
        // 생성자 로직
    }
}

@NoArgsConstructor
public class ChildClass extends ParentClass {
    // 생성자가 없음
}

 

하지만 위와 같이 ChildClass가 ParentClass를 상속받고 있지만, NoArgsConstructor 어노테이션을 사용하여 자동으로 생성된 기본 생성자가 부모 클래스의 생성자를 호출하지 않으므로 컴파일 오류가 발생합니다. 위와 같은 상황에서는 아래와 같이 코드 수정이 필요해요.

1-2) 상속 클래스와 함께 사용 시, 올바른 코드 

import lombok.NoArgsConstructor;

@NoArgsConstructor
public class ParentClass {
    public ParentClass(String name) {
        // 생성자 로직
    }
}

@NoArgsConstructor
public class ChildClass extends ParentClass {
    
}

 

부모 클래스에도 동일하게 기본 생성자를 생성하고 있으므로 상속 관계에서도 문제가 발생하지 않습니다 😊

2-1)  의존성 주입을 할 때, 올바르지 않은 코드

그리고 의존성 주입과 함께 사용할 때도 주의해줘야 해요. 아래 예시 코드를 한번 볼까요? 🤨

import lombok.NoArgsConstructor;
import org.springframework.stereotype.Service;

@Service
@NoArgsConstructor
public class ExampleService {

    private final ExampleRepository exampleRepository;

    // 생성자가 없음

    // 서비스 메서드들...
}

 

위에 예시 코드에서 ExampleService 클래스는 스프링의 서비스로 사용되지만 NoArgsConstructor 어노테이션을 사용하여 자동 생성된 기본 생성자가 없습니다. 이 경우 스프링이 해당 클래스의 의존성 주입할 수가 없습니다. 이럴 때는 NoArgsConstructor 어노테이션을 사용하지 않고 RequiredArgsConstructor 어노테이션 또는 AllArgsConstructor 어노테이션을 사용해줘야 합니다. 🤔

 

물론 아래 코드처럼 force=true 옵션을 사용하면 모든 final 필드는 0 / false / null로 초기화할 수 있어요. 

@NoArgsConstructor(force = true)

 

그런데 filed에 final이 아닌 @NonNull 같은 제약이 있는 어노테이션이 붙어 있다면, 해당 옵션을 주어도 생성자에 들어가지 않기 때문에 이점 주의해줘야 합니다 🙄🙄

 

2-2) 의존성 주입할 때, 올바른 코드

RequiredArgsConstructor 어노테이션 또는 AllArgsConstructor 어노테이션을 사용하여 필드 주입을 허용하고, 스프링이 해당 클래스의 의존성을 주입할 수 있게 됩니다. 🧑‍💻

import lombok.NoArgsConstructor;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class ExampleService {

    private final ExampleRepository exampleRepository;

    // 생성자가 없어도 Spring이 의존성을 주입함

    // 서비스 메서드들...
}

@RequiredArgsConstructor

RequiredArgsConstructor 어노테이션은 final이나 @NonNull으로 선언된 필드만을 파라미터로 받는 생성자를 자동으로 생성해 줍니다. 이 어노테이션을 사용하면, 클래스가 의존하는 필드를 간단하게 초기화할 수 있어요. 

 

RequiredArgsConstructor 어노테이션을 사용할 때는 제일 중요한 게 초기화되지 않은 final이나 @NonNull이 선언된 필드만 생성자가 생긴다는 점이에요!! 다음과 같이 사용하면 생성자가 없으므로 컴파일 오류가 발생합니다.

 

1) 의존성 주입을 할 때, 올바르지 않은 코드

간혹 아래 코드처럼 final을 생략한 채로 필드를 생성할 때가 있어요. 이런 경우 생성자가 없으므로 컴파일 오류가 발생하게 됩니다.

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class ExampleService {

    private ExampleRepository exampleRepository;

    // 생성자가 없음

    // 서비스 메서드들...
}

 

2) 의존성 주입할 때, 올바른 코드

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class ExampleService {

    private final ExampleRepository exampleRepository;

    // 생성자가 없어도 Lombok이 생성해줌

    // 서비스 메서드들...
}

 


@AllArgsConstructor

AllArgsConstructor 어노테이션을 사용하면 클래스의 모든 필드를 매개변수로 받는 생성자를 자동으로 생성해 줍니다. 이를 통해 객체를 초기화할 때 모든 필드에 대한 값을 직접 설정하는 생성자를 명시적으로 작성하지 않아도 됩니다. 

import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;

@Service
@AllArgsConstructor
public class ExampleService {

    private ExampleRepository exampleRepository;

    // 생성자가 없어도 Lombok이 생성해줌

    // 서비스 메서드들...
}

 

[Lombok] @RequiredArgsConstructor / @NoArgsConstructor / @AllArgsConstructor

@RequiredArgsConstructor 초기화되지 않은 final필드나, @NonNull이 붙은 필드에 대해 생성자를 생성해준다. 주로 의존성 주입 편의성을 위해 사용된다. 해당 어노테이션으로 의존성주입이 가능한이유는

esoongan.tistory.com

 

[Lombok] 생성자를 만드는데 사용되는 Lombok 어노테이션

@NoArgsConstructor No Argument Constructor, 파라미터가 없는 생성자를 만든다.('인수'라고 해야할지, '파라미터'라고 해야할지..) 만약 필드가 final로 설정되어 있는 경우 컴파일러 에러가 발생한다. 필드가

charliecharlie.tistory.com

 

롬복 @All/NoArgsConstructor 제대로 알고 사용해보자.

문득 전 회사 레거시 코드를 생각하다가 @AllArgsConstructor, @NoArgsConstructor 등 여러 어노테이션이 한클래스에 같이 작성되어있는 것을 본적이있다.Lombok은 불필요한 코드와 작업을 줄여주는 좋은 라

velog.io