[Spring] 생성자 주입 안하면 NPE????

HwangDo·2023년 12월 10일
0

SpringBoot

목록 보기
7/14
post-thumbnail

구글에 생성자 주입이라고 검색하면 수많은 게시글이 나온다.

내용은 대부분 비슷하게,

생성자 주입 하고, 필드 주입은 하지 마세요!

정도다. 이유로는 컴파일 타임 순환 참조 방지, 객체의 불변성 등등,,, 구구절절 맞는 이야기들이 나온다

그 중에서 , 테스트 코드 작성시 NPE가 발생한다는 점에 대해 곰곰히 생각해봤다.


When?

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;
    @Autowired
    private MemberService memberService;

    public void register(String name) {
        userRepository.add(name);
    }
}
public class UserServiceTest {

    @Test
    public void addTest() {
        UserService userService = new UserService();
        userService.register("Name");
    }

}

코드 출처: https://mangkyu.tistory.com/125

위 테스트 코드를 보자. 이 코드는 실행하면 NPE가 발생한다. 왜일까?

이를 알기 위해선 생성자 주입 시점에 대해 알아야한다.

스프링에서, 객체 (빈)은 언제 만들어질까?

스프링에서 따로 설정하지 않았다면, Bean은 Singleton으로 만들어진다.
이 Bean의 생성 시점은 , Application 시작 -> 스프링 컨테이너 시작 -> 컨테이너에서 모든 빈을 싱글톤으로 생성 && 의존성 주입
과정을 거칠 때 생성된다!

즉, 우리가 @Component등으로 지정해 빈으로 설정 했을 경우 스프링 컨테이너에서 한번만 만들고, 주입까지 해준다는 뜻이다.
다시 위 코드를 바라보자.

UserService userService = new UserService(); 

테스트 클래스에서, new를 통해 서비스 클래스를 생성하고 있다.

  1. 해당 클래스는 @SpringBootTest 애노테이션이 붙지 않아, 순수 자바 코드로 돌아간다.
  2. @SpringBootTest 애노테이션을 붙여 스프링으로 실행하더라도, 컨테이너에서 만든 객체가 아닌 새로운 객체가 생성된다.
  3. 이들은 직접 생성한 클래스니까 당연히 의존성 주입이 되어있지 않다.

따라서 new로 만든 객체에서, 의존하는 클래스의 메소드가 간접적으로 호출되면 NPE가 발생한다.


Fix it!

그럼 생성자 주입으로 바꿔서 해결하는 방법은 뭘까?

@Service
public class UserService {

    private final UserRepository userRepository;
	
    @Autowired
    public UserService(UserRepository userRepository){
    	this.userRepository = userRepository;
    }
    
    public void register(String name) {
        userRepository.add(name);
    }
}
public class UserServiceTest {

    @Test
    public void addTest() {
        UserService userService = new UserService(new UserRepository());
        userService.register("Name");
    }

}

이렇게 주입 대상 객체를 같이 new를 통해 생성자로 넘겨버리면 된다.
이러면 스프링 부트 어플리케이션과 실행과 무관하게 순수 자바 코드에서도 문제없이 돌아가서, 테스트를 진행 할 수 있게 되었다.

profile
제가 배워가는 내용과, 실수한 부분을 정리합니다

0개의 댓글