본문 바로가기
  • 시 쓰는 개발자
1일 1개념정리 (24년 8월~)/Spring

1일1개 (14) - ArgsConstructor

by poetDeveloper 2024. 8. 22.
반응형

1일 1개념정리 24.08.09.금 ~ 

 

큰 결정에 큰 동기가 따르지 않을 때도 있다. 하지만 큰 결심이 따라야 이뤄낼 수 있다.

무조건 무조건 1일 1개의 개념 정리하기 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!


#14. Spring @OOOArgsConstructor

스프링에서 생성자를 처리하는 방법이 여러개 있다. 보통 OOOArgsConstructor 어노테이션을(Lombok 계열) 쓰는데, 오늘은 이것과 함께 Autowired, Builder에 대해서도 알아보자.

 

@Autowired

@Autowired는 의존성 주입을 위해 사용한다. 스프링 컨테이너가 관리하는 빈 중에서 해당하는 타입의 빈을 자동으로 주입해준다. 이 어노테이션은 필드, 메서드, 생성자 모두에 사용할 수 있다. Autowired는 다음과 같은 특징이 있다.

  • 순환 참조 : 의존성 주입 시 순환 참조가 발생할 수 있는데, A클래스가 B클래스를, 다시 B가 A를 주입받으려고 하면 순환 참조가 발생하는데 생성자 주입을 사용하면 이런 문제를 파일 시점에 발견할 수 있다.
  • Optional 주입 : 필드가 반드시 필요한 것이 아니고 선택적으로 주입하고 싶다면 @Autowired(required = false)로 설정할 수 있고 이러면 해당 빈이 존재하지 않아도 에러가 발생하지 않는다.
  • @Autowired를 사용할 때 주입되는 빈이 스프링 컨텍스트에서 관리되고 있는지 확인해야 하는데, 잘못해서 의존성이 제대로 주입되지 않으면 NullPointerException이 발생한다.
public class MyService {
    private final MyRepository repository;
    
    // Optional 주입
    @Autowired(required = false)
    private MyRepository mymymyRepository;

    // 생성자 주입
    @Autowired
    public MyService(MyRepository repository) {
        this.repository = repository;
    }
}

@NoArgsConstructor

  • 파라미터가 없는 기본 생성자를 자동으로 생성하여 필드 초기화 없이 객체 생성이 가능하게 함
  • 기본 생성자가 필수인 경우에 유용. 그러나 이렇게 생성하면 필드값이 모두 기본값으로 설정돼서 0, false, null 이런 값이 들어가있어서 당황할 수 있다.
  • JPA 엔티티에서는 기본 생성자가 필요한데, JPA 엔티티에 기본 생성자를 추가할 때는 @NoArgsConstructor와 함께 protected를 사용하는 것이 권장된다.
  • 클래스에 final 필드가 있으면 @NoArgsConstructor는 컴파일 에러를 발생시킨다. 왜냐면 final 필드를 초기화할 방법이 없기 때문인데, 이럴 땐 force=true 옵션을 써서 final 필드를 0 또는 null로 초기화할 수 있긴 하다. 물론 이게 또 다른 에러 발생시킬 수도 있다.
//@NoArgsConstructor(force = true)
@NoArgsConstructor
public class MyEntity {
    private Long id;
    private String name;
}

@AllArgsConstructor

  • 클래스의 모든 필드를 파라미터로 가지는 생성자를 자동 생성해서 객체를 한 번에 초기화할 수 있다.
  • 모든 필드를 인자로 받아야 해서 불필요한 필드 초기화로 메모리사용 등 효율성 떨어뜨린다.
  • 생성자 파라미터의 순서는 클래스 필드 선언 순서에 따른다. 필드가 많아지면 생성자 호출 시 파라미터를 잘못된 순서로 전달할 위험이 있다.(잘못된 데이터 초기화 초래)
    • 뭔소리냐면, @AllArgsConstructor쓰고 User u = new User(25, kwanghwi, abc@naver.com) 이렇게 했는데 알고보니 순서가 이름, 이메일, 나이였다면??? 내 이름이 25, 이메일이 kwanghwi ... 이렇게 초기화 되는 것이다.
    • 그래서 이럴 땐 순서 신경쓰지 않아도 되는 @Builder를 쓰는 게 좋다.
  • 생성자에서 모든 필드를 초기화하므로 final 필드의 불변성을 유지할 수 있다.
@AllArgsConstructor
public class MyEntity {
    private Long id;
    private String name;
}

@RequiredArgsConstructor

  • final로 선언된 필드를 파라미터로 가지는 생성자를 생성하기 때문에 필요한 필드만을 인자로 받아 객체를 생성할 수 있음. 이를 통해 필요한 필드는 꼭 초기화하고, 반대로 불필요한 필드는 초기화 하지 않을 수 있음.
@RequiredArgsConstructor
public class MyEntity {
    private final Long id; // final 유의
    private String name;
}

@Builder

  • 복잡한 객체 생성 시에 특히 유용하고, 선택적인 필드 초기화가 가능하고, 가독성이 높아진다. (아래 코드 예시)
  • @Builder는 내부적으로 @AllArgsConstructor와 비슷하지만, 체이닝 방식으로 필드를 설정할 수 있다는 점이 다르다.
// 빌더 패턴을 사용한 객체 생성
User user = User.builder()
                .name("kwanghwi")
                .age(24)
                .email("abc@naver.com")
                .build();

 

정리

  • 단순 생성자가 필요한 경우 : @NoArgsConstructor , @AllArgsConstructor
  • 필수 필드만 초기화 : @RequiredArgsConstructor
  • 유연한 객체 생성 : @Builder
반응형