Spring - 스프링 빈과 의존관계

백승우·2024년 11월 14일

Spring(입문)

목록 보기
4/5

컴포넌트 스캔과 자동 의존관계 설정

기존에 만들었던 회원서비스와 회원 리포리토지를 새로 만들 회원 컨트롤러가 사용할 수 있게 의존관계를 설정할 것이다.

우선 어노테이션을 사용하여 해당 클래스가 컨트롤러임을 선언한다.

이는 스프링 컨테이너가 컨테이너에서 먼저 스캔하여 클래스를 찾을 수 있게 해주는 기능이다.
그리고 생성자에 @Autowired를 선언해 주어서 관련된 객체를 스프링 컨테이너에서 찾아서 자동으로 연결시켜 준다. 이렇게 객체 의존관계를 외부에서 넣어주는 것을 DI (Dependency Injection), 의존성 주입이라 한다.

이렇게 작업을 하고 실행을 시키면 다음과 같은 오류가 발생한다.

이는 스프링 컨테이너가 관련 클래스들을 찾아서 연결시켜주지 못했기 때문이다. 이 이유는 컨트롤러 클래스에서 어노테이션으로 선언을 해준것처럼 다른 클래스도 선언을 해주어야 스프링이 찾을 수 있기 때문이다. 따라서 회원 서비스 클래스에도 스프링 빈을 등록시켜준다.(@Service 선언)

그리고 서비스 클래스에서도 회원 리포지토리의 객체를 활용하기 때문에 리포지토리 클래스에서도 마찬가지로 스프링 빈 등록을 해준다.

이렇게 작업을 끝내고 실행을 시키면 오류없이 정상적으로 실행이 되는 것을 알수 있다.
해당 작업 결과로서 스프링 빈 등록 이미지를 시각적으로 구성해 본다면 아래의 그림과 같이 표현할 수 있다.

추가로 컴포넌트의 스캔 원리를 정리해 보자면 다음과 같다.

  • @Component 애노테이션이 있으면 스프링 빈으로 자동 등록된다.
  • @Controller 컨트롤러가 스프링 빈으로 자동 등록된 이유도 컴포넌트 스캔 때문이다.
  • @Component 를 포함하는 다음 애노테이션도 스프링 빈으로 자동 등록된다.
    - @Controller
    - @Service
    - @Repository

자바코드로 직접 스프링 빈 등록하기

이제 그럼 어노테이션을 사용하지 않고 직접 코드 작업을 통해서 스프링 빈 등록을 해보자.

앞에서 선언했던 어노테이션들을 지워준다. 컨트롤러 어노테이션만 남겨두고 서비스와 리포지토리에 선언했던 어노테이션들을 지운다.(@Autowired 포함)
그리고 실행을 시키면 다음과 같이 당연하게도 오류가 뜨는것을 알 수 있다.

그리고 최상위 패키지 아래에 SpringConfig라는 클래스를 하나 생성해 준다. 해당 클래스에 @Configuration 어노테이션을 선언해 주어서 config를 다루는 클래스임을 명시한다.

그리고 Service 생성자를 만들어 주고 그 위에 @Bean 어노테이션을 선언하여 스프링 빈 등록을 해준다.

작업을 마치면 위에 사진과 같이 되는데 보면 알 수 있듯이 생성자의 return 코드에 오류가 뜬다. 이는 Service 클래스는 리포지토리의 객체를 받아서 그 데이터를 이용해 작업하기 때문에 그렇다.

따라서 아래에 리포지토리도 위에서 했던것과 동일하게 스프링 빈에 등록을 해주고 Service 객체 선언 안에 해당 리포지토리 객체를 입력해주면 된다.

이렇게 작업이 끝났다면 처음에 각 클래스에 어노테이션으로 선언해 준것과 같이 스프링 빈 등록이 완료된다.

@Autowired를 사용한 것과 같이 해당 작업이 실행될때 스프링 빈에 등록된 객체를 찾아내어서 넣어준다고 이해하면 된다.

그리고 컨트롤러는 어쩔 수 없이 스프링이 통제해야 하기 때문에 어노테이션을 사용하지 않는 것은 어렵다. 그리고 해당 컨트롤러에서 스프링 빈에 등록된 Service와 Repository 객체들을 사용해야 하기 때문에 @Autowired또한 남겨둔다.

마지막으로 작업을 완료한 후 실행을 시키면 처음에 했던 실행결과와 같이 오류없이 아래와 같이 잘 실행되는 것을 알 수 있다.

참고로 과거에는 XML을 사용하여 이러한 작업을 하기도 하였지만 잘 쓰지 않으니 생략하자.

참고로 DI에는 필드 주입, setter 주입, 생성자 주입 이렇게 3가지 방법이 있다. 의존관계가 실행중에 동적으로 변하는 경우는 거의 없으므로 생성자 주입을 권장한다.
앞서 작업한 방식이 생성자 주입이며, 필드 주입은 잘 사용하지 않으며 setter 주입도 public 으로 선언을 해주어애 하기 때문에 잘 사용하지 않는다.

또한, 실무에서는 주로 정형화된 컨트롤러, 서비스, 리포지토리 같은 코드는 컴포넌트 스캔을 사용한다. 그리고 정형화 되지 않거나, 상황에 따라 구현 클래스를 변경해야 하면 설정을 통해 스프링 빈으로 등록한다

마지막으로 주의할 점은 @Autowired를 통한 DI는 helloController , memberService 등과 같이 스프링이 관리하는 객체에서만 동작한다. 스프링 빈으로 등록하지 않고 내가 직접 생성한 객체에서는 동작하지 않는다.

profile
나는 부자가 될래!😼🐰❤️

0개의 댓글