나의 브을로오그으

#4. [스프링 입문] - 스프링 빈과 의존관계 본문

Spring

#4. [스프링 입문] - 스프링 빈과 의존관계

__jhp_+ 2022. 7. 10. 14:32

스프링 빈은 한마디로 쉽게 말하면 스프링이 가지고 있는(등록되어 있는) 객체 이다.

 

[스프링 빈과 의존관계]

스프링 애플리케이션 실행 시 @Controller 에노테이션이 붙은 클래스 객체를 생성해서

스프링 컨테이너가 가지고 있다. 이를 스프링 빈과 의존관계를 형성했다고 표현한다.

 

 

@Controller, @Service, @Repository 애노테이션을 각 클래스 위에 붙여주자. (정형화된 형식임)

이렇게 붙여주면, 스프링 컨테이너가 해당 객체를 생성 할 때 공통으로 사용하는 객체들(Service, Repository)일 경우 1회 생성하여 공유해서 사용한다.

 

컨트롤러와 서비스가 연결되어 있다. 연결 시 @AutoWired를 컨트롤 생성자에 붙이면,

인자로 받은 memberService객체는 스프링 컨테이너가 앱 실행 시 생성해서 가지고 있는 객체를 인자로 주어 MemberController객체를 생성하게 된다.

MemberService도 마찬가지이다. Repository객체를 스프링 컨테이너가 가지고 있기 때문에 MemberService 객체를 생성 할 때 스프링 컨테이너가 가지고 있는 MemberRepository 객체를 인자로 넣어서 생성하게 된다.

 

[스프링 빈을 등록하는 2가지 방법]

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

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

 

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

- @Component 애노테이션이 있으면 스프링 빈으로 자동 등록된다.

- @Controller 컨트롤러가 스프링 빈으로 자동 등록된 이유도 컴포넌트 스캔 때문이다.

 

- @Component를 포함하는 다음 애노테이션도 스프링 빈으로 자동 등록된다.

  * @Controller

  * @Service

  * @Repository 

 

사실 Repository, Service, Controller 에노테이션 모두 Component 애노테이션이다. 실제로 스프링 애플리케이션 실행 시 스프링 빈과 관련 동작은 다음과 같다.

1. 스프링 앱 실행

2. Component에 해당하는 객체를 생성

3. 스프링 컨테이너에 등록 (AutoWired는 자동으로 기존에 생성된 Component들을 연결해준다.(주입))

 

 

그렇다면 스프링 빈에 등록하기 위해서 아무곳에서 생성한 자바클래스에 @애노테이션만 붙여주면 될까? X

 

※ 스프링 빈에 등록될 수 있는 조건은 SprintApplication실행 파일이 있는 hellospring패키지을 포함한 하위 패키지에서만 적용된다. (특정 설정 시 다른 패키지도 되긴 하는데 기본적으로 이러함)

※ 스프링은 스프링 컨테이너에 스프링 빈을 등록할 때 기본으로 싱글톤으로 등록한다. (유일하게 하나만 등록해서 공유한다.) 따라서 같은 스프링 빈이면 모두 같은 인스턴스이다. 설정으로 싱글톤이 아니게 설정할 수 있지만, 특별한 경우를 제외하면 대부분 싱글톤을 사용한다.

 

 

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

이렇게 MemberService에 해당하는 스프링 빈으로 등록해주면,

 

MemberController의 생성자에 MemberService를 스프링 컨테이너에서 자동으로 등록된 스프링 빈을 주입해준다.

 

[컴포넌트 스캔 방식과 자바 코드 스프링 빈 설정 방식의 장/단점]

- DI(Dependency Injection 의존성 주입)에는 필드, Setter, 생성자 주입 이렇게 3가지 방법이 있다. 의존관계가 실행중에 동적으로 변하는 경우는 거의 없으므로 생성자 주입을 권장한다.

필드, Setter, 생성자 주입

대개 생성자 주입을 통해 의존성 주입을 받는다. 이유는 한번 의존성 주입을 받으면 크게 바뀌는 경우가 없고, 필드 주입이나 Setter 주입은 MemberService를 다른 클래스에서 Setter 호출 가능하기 때문에 서비스가 외부에서 변경가능 하도록 노출된다.

 

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

 

- `@Autowired`를 통한 DI는 `helloController`, `MemberService`등과 같이 스프링이 관리하는 객체에서만 동작한다. 스프링 빈으로 등록하지 않고 내가 직접 생성한 객체에서는 동작하지 않는다.