purplely88's home

시작에 앞서

6장을 완료해주세요.

DI 

오래 기다리셨습니다.

5장과 6장에서 의존성과 주입에 대해 알아보았습니다만, DI는 이 두 가지를 동시에 한다고 생각하시면 될 거 같습니다.

 

DI 내부 처리

일단 DI 내부 처리가 어떻게 일어나는지 한번 알아보겠습니다.

 

1. DI의 관리 대상 클래스를 찾는다. (컨포넌트 스캔)

알아보실 수 있으시겠죠..?

스프링을 기동 하면, 컨포넌트 스캔이라고 불리는 처리가 이루어집니다.

이것은 DI에서 관리하는 대상의 어노테이션이 붙은 클래스를 찾는 처리입니다.

 

컨포넌트 스캔 대상의 어노테이션은 다음과 같습니다.

@Component

@Controller

@Service

@Repository

@Configuration

@RestController

@ControllerAdvice

@ManagedBean

@Named

 

위에 어노테이션이 붙은 클래스가 DI의 대상이 됩니다.

또한 어노테이션이 붙은 클래스를 빈(Bean)이라고 합니다.

 

빈 (Bean)

물론, 어노테이션을 붙이지 않아도 DI 컨테이너에 클래스를 등록하는 것도 가능합니다

이로 인해, 정확히는 DI 컨테이너상에서 관리하는 클래스를 빈(Bean)이라고 합니다.

 

2. 인스턴스 생성과 주입

다음으로는 DI 컨테이너에 등록된 Bean의 인스턴스 생성과 주입을 한다고 생각하시면 됩니다.

어디까지나 간단한 입니다. 실제로는 다르니 이해로써만 참고해주세요.

DI 대상 클래스 (Bean)을 모은 후에는, 그것들의 인스턴스를 DI가 생성합니다.

그리고 생성한 인스턴스를 @Autowired 어노테이션이 붙은 필드 곳곳에 주입합니다.

 

위 이미지의 DI 컨테이너를 보시면, 안에 각 클래스의 인스턴스를 생성해 두고, 그 인스턴스를 getter로 취득하는 이미지입니다. 그리고 @Autowired가 붙어있는 필드들에는 DI 컨테이너의 getter를 호출하는 이미지입니다.

 

이것은 6장에서 만든 Factory 클래스와 상당히 비슷합니다.

하지만 Factory 클래스와 달리 매회 new 처리는 하지 않습니다만, 매회 new 처리하게 할 수도 있습니다.

 

즉, @Component 등의 어노테이션을 붙이는 것만으로도 하나하나 Factory 클래스를 만들 필요가 없다는 이야기가 됩니다.

 

@Autowired를 쓰는 곳

@Autowired를 쓰는 곳은 아래의 3곳입니다.

1. 필드 변수

2. 생성자 파라미터

3. setter 파라미터

이 외에는 @Autowired를 붙일 수 없습니다. 예를 들어 메서드 내부 로컬 변수에는 붙일 수 없습니다.

 

@Autowired를 쓰는 곳(2. 생성자 파라미터)

생성자 앞에 @Autowired를 붙임으로써, 파라미터에 인스턴스가 반환됩니다.

@Autowired

public class TestClass(xxxComponent component) {

  super();

  this.component = component;

}

 

@Autowired를 쓰는 곳(3. setter 파라미터)

setter 앞에 @Autowired를 붙임으로써, 파라미터에 인스턴스가 반환됩니다.

@Autowired

public class void setxxxComponent(xxxComponent component) {

  this.component = component;

}

 

이와 같이 클래스의 인스턴스를 생성하여 주입하는 것이 DI 컨테이너의 기능입니다.

 

DI 코딩 방법

 

DI를 코딩하는 방법은 총 5가지가 있습니다.

1. 어노테이션 베이스

2. JavaConfig

3. xml

4. JavaConfig + 어노테이션

5. xml + 어노테이션

 

지금까지 보여드린 방식은 1. 어노테이션 베이스입니다.

즉, @Controller, @Service만 사용한 코딩 방법입니다.

 

이번 코딩 방식에는 2번과 4번에 대해서 설명드리겠습니다.

 

JavaConfig

1. DI의 관리대상 클래스를 찾는다. (컨포넌트 스캔)

처음으로 DI 컨테이너에 등록하는 Bean을 정의합니다.

 

@Bean을 붙인 getter의 반환 값이 DI 컨테이너에 Bean으로 등록됩니다.

먼저 @Configuration 어노테이션을 붙인 클래스를 준비합니다.

그 클래스 안에는 @Bean 어노테이션이 붙은 getter 메서드를 준비하면, getter 반환 값이 Bean으로써 DI 컨테이너에 등록됩니다.

 

2. 인스턴스 생성과 주입

다음으로는 DI 컨테이너에 등록한 Bean의 인스턴스 생성과 주입을 한다고 생각하시면 됩니다.

이전 이미지를 그대로 가져왔습니다만, 꼭 집어서 추가될 부분은 DI 컨테이너 안에 private JavaConfig config = new JavaConfig(); 가 있겠네요.

DI 컨테이너 안에 JavaConfig 클래스와 Bean 인스턴스를 준비한 후, 각 인스턴스를 getter로 취득하는 이미지입니다.

그리고 @Autowired가 붙은 부분에 getter로 호출하는 이미지입니다.

이건 DI 코딩 방법 1. 어노테이션 베이스와 같습니다.

 

1. 어노테이션 베이스에서는 @Component 혹은 @Controller가 붙은 클래스를 스프링에서 자동으로 DI 컨테이너에 등록해줍니다. 한편, 2. JavaConfig에서는 @Bean 어노테이션이 붙은 getter의 반환 값을 DI 컨테이너에서 관리해줍니다.

즉, 2. JavaConfig에서는 DI 컨테이너에서 관리하는 인스턴스 분(개수)의 메서드를 준비하지 않으면 안 됩니다.

 

그럼 JavaConfig 방식은 굳이 안 써도 되지 않나?라고 생각하실 수 있습니다만, JavaConfig 방식은 상세한 설정이나 교체가 가능합니다. 예를 들어, 인스턴스를 생성할 때에 생성자에 전달하는 값을 설정할 수 있습니다.

혹은 JavaConfig 클래스 교체하여 개발환경용/본 환경용과 같이 교체하면서 사용이 가능합니다.

 

그래도 역시 개발규모가 크면 클수록 JavaConfig 안에 정의해야만 하는 메서드가 늘어갑니다.

이것을 회피하기 위해 통상은 1. 어노테이션 베이스 방식과 2. JavaConfig 방식을 같이 사용합니다. 

이 두 가지 방식을 사용하는 것이 4. JavaConfig + 어노테이션 방식입니다.

 

4. JavaConfig + 어노테이션

이 방식은 DI에서 관리하고 싶은 클래스에 @Controller와 같은 어노테이션을 붙이고, 상세한 설정을 하고 싶은 인스턴스만 JavaConfig에 설정하는 방식입니다.

보통 소규모 애플리케이션이라고 하면 1. 어노테이션 베이스 방식으로 개발합니다. 그리고 규모가 크거나 설정 교체와 같은 작업을 하고 싶을 때에는 4. JavaConfig + 어노테이션 방식으로 개발합니다.

 

추후에 4. JavaConfig + 어노테이션 방식으로 Bean정의로 코딩하는 것을 보여드리겠습니다.

 

엥!? xml 방식은...?

xml 은 JavaConfig에서 설정하는 내용을 단지 xml로 옮긴 거뿐입니다.

 

 

다음 포스트에서는 DI 라이프 사이클에 대해서 알아보겠습니다.

'프로그래밍 > 스프링 부트' 카테고리의 다른 글

9. 데이터 바인딩 & 밸리데이션 (1/4)  (0) 2020.06.20
8. DI (4/4)  (0) 2020.06.18
6. DI (2/4)  (0) 2020.06.16
5. DI (1/4)  (0) 2020.06.14
4. 웹 애플리케이션 작성 (데이터 베이스로부터 값 취득)  (0) 2020.06.14