[Java] bean을 찾지 못하는 또다른 이유 2 - 빈생성/등록/생성자 주입(*빈 등록과정)

Hyo Kyun Lee·2025년 1월 24일
0

Java

목록 보기
84/87

1. 개요

지금까지 primitive, reference 변수의 유형 상관없이 모두 일괄적으로 멤버변수에 선언해놓은 상태에서 활용하는 것이 가독성, 확장성 측면에서 유리하다 생각하여 그렇게 진행하고 있었다.

하지만 그럴때마다 bean을 찾을 수 없다, 혹은 서버를 실행하는 것까지는 정상적으로 동작하였으나 서비스 실행시 Servlet에서 전역 exception을 발생하는 등의 문제가 발생하였다.

이 문제들을 해결하면서 어노테이션, di 등에 대한 개념이 다듬어지고 있다는 생각이 들었고, 또다른 성장의 순간을 남기기 위해 글을 남긴다.

이 글이랑 함께 보자1

이 글이랑 함께 보자2

2. 빈 생성 주기와 빈을 못찾는 오류가 발생하는 시점

스프링 빈은 생성 후 Spring Container 중 하나인 IoC Container의 저장소에 등록, 이 등록된 빈의 의존관계를 주입하여 최종적으로 활용할 준비를 마친다.

우리가 흔히 알고있는 어노테이션, 즉 di는 컴파일과 런타임 관점에서 모두 살펴봐야하는 개념인다.

구체적으로 말하면, 빈의 주입방법에 따라 주입순서가 다르며 이에 따라 의존관계를 생성할때 빈 저장소에 빈이 없다면 그 시점에서 오류가 발생할 것이다.

이 오류는 컴파일 시점에서 발생할 수 있고, 컴파일에서는 발생하지 않다가 런타임 시점에서 발생할 수 있다.

3. 컴파일 시점 - 어노테이션을 적절하게 사용하지 않거나 누락하였다.

@RestController
public class Controller {
    private ControllerClass controllerClass;
    @GetMapping("/controll")
    public String controll() {
        return controllerClass.getMesaage();
    }
}

위와 같이 controllerClass 객체에서 getMessage 메소드를 호출하여 메시지를 받아오는 컨트롤러가 있다고 하자.

  • 이 컨트롤러가 있는 프로젝트를 실행할때 controllerClass의 getMessage 메소드를 찾을 수 없다는 오류가 발생하였다.

controllerClass 객체를 생성하지 않은 상태인데도 메소드를 사용하기 때문에 컴파일 오류가 발생할 수 있다.

이 경우 필드멤버변수에 대해 생성자와 getter, setter를 자동 생성해주는 @AllArgsConstructor 어노테이션을 사용해주거나 함수 내 지역변수를 통해 객체생성 및 메소드 사용을 하도록 한다.

4. 런타임 시점 - 빈을 등록하지 않았다.

@RestController
@AllArgsConstructor
public class Controller {

    private ControllerClass controllerClass;

    @GetMapping("/controll")
    public String controll() {
        return controllerClass.getMesaage();
    }
}

위와 같이 controllerClass 객체에서 getMessage 메소드를 호출하여 메시지를 받아오는 컨트롤러가 있다고 하자.

  • 이 컨트롤러가 있는 프로젝트를 실행할때 controllerClass에 대한 빈을 찾을 수 없다는 오류 메시지가 나타났다.

controllerClass의 빈을 주입해야 하는데, 컨테이너에 빈이 등록되지 않은 것이다.

이 경우 열에 아홉은 해당 클래스의 @component를 구성해주어 컴포넌트 스캔 대상에 포함해주거나, 그래도 안된다면 컴포넌트 스캔 대상 범위를 잘 입력해주도록 한다.

또 하나의 방법은 멤버변수가 아닌, 클래스 내부에서 직접 객체를 생성하여 메소드를 호출할 수도 있다.

이래도 안된다면 프로젝트 구조 문제이다. 최상위 main 프로젝트에서 하위 경로로 스캔대상을 찾아 들어가는데, 스캔 대상이 하위에 포함되어있지 않으면 역시 빈을 찾을 수 없다는 오류가 발생한다.

@RestController
public class Controller {

    private ControllerClass controllerClass;

    @GetMapping("/controll")
    public String controll() {
        return controllerClass.getMesaage();
    }
}
  • 이번엔 AllArgsConstructor 어노테이션을 제거하였다. 컴파일 시점에서는 오류가 발생하지 않았지만, 해당 서비스를 실행할때 Servlet Exception이 발생하였다.

보통 필드멤버변수에 의존성을 주입할때는 @Autowired를 사용하는데, 이 경우 필드 객체를 생성하는 시점에(생성자가 생성되는 시점에) 의존성이 주입된다.

@AllArgsConstructor도 마찬가지로 생성자 생성 시점에 의존성을 주입하는데, 이에 따라 해당 어노테이션이 없다면 저 컨트롤러를 실제 호출해야 저 생성자주입 방식을 사용하면 객체를 생성하는 시점에 주입이 발생하지 않기에(먼저 빈 생성이 이루어지지 않으므로), 이때 컨테이너에서 exception을 발생하여 서블릿 에러가 발생한다.

이 경우에는 AllArgsConstructor, Autowired의 어노테이션을 사용하여 의존관계 주입을 도와주도록 한다.

있음에도 오류가 났다면 위의 경우처럼 스캔을 했는데 빈이 컨테이너에 없는것이다.

5. factorypath

이클립스는 어노테이션 처리를 진행하면서 factorypath 파일을 생성한다.

주입을 관리하는 컨테이너에 대한 정보가 들어있으므로 inject 등 의존성 라이브러리가 제대로 포함되어있는지 확인하도록 한다.

6. 참고자료

빈 생성주기 - https://bsssss.tistory.com/m/1484,
https://developshrimp.com/entry/Spring-%EC%8A%A4%ED%94%84%EB%A7%81-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88%EC%99%80-%EC%9E%90%EB%8F%99%EC%88%98%EB%8F%99-%EB%B9%88-%EB%93%B1%EB%A1%9D-%EA%B0%9C%EB%85%90-%EC%A0%95%EB%A6%AC

servlet 오류와 생성시점 다름으로 인한 주입 오류 - https://delightpip.tistory.com/m/24

의존관계(일반적인 개념) - https://toongri.tistory.com/m/10

factorypath - https://stackoverflow.com/questions/42949198/automatically-generate-factorypath-on-project-import-when-using-maven-project-i

0개의 댓글

관련 채용 정보