울음참고 개발공부
728x90

 

 

 

@RequiredArgsConstructor 

 

개념

- final 필드나 @Nonnull 애노테이션이 붙은 필드만을 파라미터로 받는 생성자를 자동으로 생성해줌(기본생성자 생성 X) 

- Lombok 라이브러리에서 제공하는 애노테이션 중 Java 클래스에서 필수 필드를 초기화하는 생성자를 자동으로 생성해주는 기능

 

 

# 사용예시

@RequiredArgsConstructor
public class MemberService {
    private final MemberRepository memberRepository;
    private final PasswordEncoder passwordEncoder;
    
    private String optionField;
}

 

 

위 코드에서 @RequiredArgsConstructor 는 생성자를 다음과 같이 자동으로 만들어준다.

 

public MemberService(MemberRepository memberRepository, PasswordEncoder passwordEncoder) {
    this.memberRpository = memberRepository;
    this.passwordEncoder = passwordEncoder;
}

 

 

# final & @NonNull 에 대해서 만 생성되는 이유

 

1. final 필드는 생성시 반드시 초기화 되어야함 

 

 

2. @NonNull  은 'null 이면 안된다'는 의미

 

- final 이 아니면 필드 선언만으로 초기화를 강제할 수 없기 때문에 @RequiredArgsConstructor 가 객체 생성 시점에 반드시 값을 넘기도록 강제시킴 

 

예시) 

@RequiredArgsConstructor
public class User {
    @NonNull
    private String name; // final 아님!
}

 

 

@RequiredArgsConstructor 사용시 생성자 자동 생성하여 아래와 같이 직접 작성하지 않아도 됨

public User(String name) {
    if (name == null) {
        throw new NullPointerException("name is marked non-null but is null");
    }
    this.name = name;
}

 

 

보일러플레이트 코드 제거 효과

@RequiredArgsConstructor 사용시 생성자 직접 작성 없이 자동 생성할 수 있기 때문에 불필요한 코드 작성을 피할 수 있다 ! 

*보일러플레이트 코드(Boilderplate Code)
자주 반복되는 작업이나 패턴을 미리 구현해놓은 코드를 일컫는 말 

 

 

 

 

필드 주입 vs 생성자 주입

 

 

# 필드 주입(Field Injection) 방식

@Autowired
private JwtUtil jwtUtil;

 

- Spring이 리플렉션(Reflection)을 이용해서 객체를 강제로 주입

 

* 리플렉션 = 자바가 내부적으로 필드에 접근해서 값 넣는 것

 

 

 

# 필드 주입의 문제 


문제 설명
테스트 어려움 필드가 private이라 Mock 주입이 어렵고 setter가 없으면 더 어려움
불변성 깨짐 객체 생성 후에도 값을 변경할 수 있음 (final 못 씀)
순환참조 숨김 생성자에 드러나지 않아서 IDE나 컴파일러가 의존성 문제를 못 잡음
명시성이 부족 어떤 의존성을 사용하는지 클래스만 봐선 한눈에 안 들어옴

 

 

@Autowired를 필드에 붙이면 주입 시점, 방식이 불명확함 

 

 

필드 주입 방식 

@RequiredArgsConstructor
@Slf4j
@Tag(name = "Account", description = "계정 관련 API")
@RestController
public class AccountController {
    
    @Autowired
    private AccountService accountService; // <- 필드 주입
}

 

  • final이 아니기 때문에
    누군가 코드 중간에 바꿔치기 할 수 있음 (accountService = new Something() 같은 거)
  • 생성자에 없어서 IDE나 컴파일러가 의존성을 체크 못 함
    → 빠뜨려도 오류 안 나고 런타임 에러 발생 (NullPointerException)
  • 테스트 불편
    • private이라서 Mockito 같은 걸로 바꿔끼우려면 리플렉션 필요함
    • 주입 시점도 불명확해서 테스트에 복잡성 추가

 

 

 

생성자 주입 방식 

@RequiredArgsConstructor
@RestController
public class AccountController {

    private final AccountService accountService; // 생성자로 주입됨!
}

 

  • final이라 바꿀 수 없음 (불변)
  • @RequiredArgsConstructor가 생성자 만들어줌
  • 스프링이 생성자 보고 자동으로 주입해줌
  • IDE가 의존성 빠졌는지 바로 감지 가능!

 

 

 

 

# 요약 

 

항목  @Autowired 필드 주입 생성자 주입 (@RequiredArgsConstructor)
선언 방식 필드에 @Autowired 붙임 생성자에서 받음 (final + 생성자 자동 생성)
장점 코드 간결 불변성, 테스트 용이, 명확한 의존성
단점 테스트 어려움, 프록시 오류 가능성 약간의 boilerplate 있음 (Lombok으로 해결 가능)
추천 여부 ❌ 비추천 (Spring 공식에서도 지양) 강력 추천
주입 시점 객체 생성 후 주입 (따로) 객체 생성 시점에 주입 (한번에)
Null 가능성 있음 (초기화 전에 쓰면 null 가능) 없음 (생성자에서 반드시 초기화)
불변성 보장 없음(final 아님) 있음(final 필드)
테스트 편의성 어려움(리플렉션 등 필요) 쉬움 (생성자 통해 바로 주입 가능)

 

 

 

- final, @NonNull 필드는 반드시 생성자로 초기화해야 하므로 @RequiredArgsConstructor를 사용하면 편함

- @Autowired 필드 주입은 테스트, 유지보수에서 불리하고 요즘은 거의 안 씀

 

 

 

Spring에서 지원하는 의존성 주입 방식 3가지

1. 필드 주입
@Autowired private A a; 

2. 생성자 주입 - 가장 많이 쓰임
public A(A a) { this.a = a; }

3. 세터 주입
@Autowired public void setA(A a) { this.a = a; } 

 

 

 

 


 

 

 

`@RequiredArgsConstructor` 에 대해서 완전하게 이해지못하고 그냥 있어야한다는 사실만 알고 공식처럼 쓰며 `@Autowired` 와 같이 사용하고 있었다

 

이번 학습을 통해 명확하게 이해하고 기존 코드를 리펙터링 할 수 있는 기회가 되었다 !! 

 

 

 

 

728x90
profile

울음참고 개발공부

@메각이

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!