Inversion Of Control (IOC)
- 의존성 관리를 내 클래스 밖에서 누군가 알아서 해준다 -> 제어권의 역전
- 클래스 안에서 필요한 인스턴스를 생성하지 않는다 -> 주입받음
- Dependency Injection -> @Autowired / Constructor / Setter
- 따라서, DI는 IOC를 구현하는 방법이라 할 수 있다.
- 이 때, 의존성의 타입(또는 인터페이스)만 맞으면 어떤 것이든 상관없다.
- 또한, 코드 테스트도 편해진다.
IOC Container
- Bean 객체를 관리하는 컨테이너
- 기능 = Bean생성 + Bean사이의 의존성 엮기 + Bean제공
- ApplicationContext 또는 BeanFactory (주로 전자를 의미)
- ApplicationContext는 BeanFactory를 상속받고 더 다양한 기능
- 그러나, 직접 사용할 일은 거의 없음
직접 ApplicationContext를 사용하고 싶다면?
- @Autowired를 통해 ApplicationContext 타입 인스턴스를 생성
- 이 객체 안에는 모든 Bean객체가 포함되어 있다.
- getBean( )으로 특정이름 / 특정타입의 Bean을 가져올 수 있다.
Bean 등록 방법 = 특정 인스턴스를 IOC Container에 넣는 방법
- Component Scan
- @Configuration 클래스 안에 직접 등록
방법1 - Component Scan
설명 | |
작동방식 |
- Bean의 생명주기 = Bean Lifecycle - Bean의 특정 작업에 대한 Lifecycle Callback 존재 - Lifcycle Callback는 스프링 IOC컨테이너가 사용하는 인터페이스 존재 - 이런 인터페이스들 중, @Component가 붙은 클래스를 모두 찾아서 인스턴스를 만들고, Bean으로 등록하는 Annotation Processor 존재 |
이해1 |
- @SpringBootApplication을 선언하면, 이 위치에서부터 하위 패키지의 모든 클래스를 스캔한다. - 왜냐하면 @SpringBootApplication 안의 @ComponentScan이 어디부터 컴포넌트를 찾아보라고 알려주기 때문 |
이해2 |
- @Controller / @Repository / @Service / @Configuration은 모두 메타 어노테이션 @Component를 사용하기 때문에 스캔되는 것 |
이해3 |
- 그렇지만 Repository는 보통 JPA 이용 - JPA는 Repository인터페이스를 상속하고 있는 인터페이스의 구현체를 만들고 Bean으로 등록해준다. |
이해4 |
- 클래스에 직접 @Component를 붙이는 경우도 있다. |
방법2 - 직접 등록
설명 | |
어떻게? |
- java source code || xml - 대세는 전자이므로, 이 방식만 설명 |
자세히 |
- @Configuration이 붙은 클래스 생성 - @Bean이 붙은 메소드 선언 - 해당 메소드에서 인스턴스를 생성하여 반환 |
이해 |
- @Component 스캐닝이 되지 않아도 Bean으로 등록 - 왜냐하면 @Configuration도 @Component를 사용하기 때문에 이를 스캔하는 과정에서 Annotation Processor가 @Bean을 보고 등록한다. |
모든 객체가 Bean으로 등록되진 않는다
- Bean이 아닌 객체는 기본적으로 주입하지 않는다.
- ex) @Entity는 Bean으로 등록되지 않는다.
★ Bean = Singleton Scope Object
- 특정 타입의 Bean = 컨테이너 안에 단 1개만 존재
- 1개 인스턴스를 어플리케이션 전반에서 재사용
싱글톤 스코프 객체 확인
- 생성자 인자로 받은 Bean객체의 Hash값
- ApplicationContext.getBean(객체타입)으로 가져온 객체의 Hash값
- 서로 동일함!
싱글톤 객체 in 멀티스레드
- 사실 스프링의 싱글톤은 멀티스레드에서의 동기화를 보장하지 않는다 (Not Thread-Safe)
- 그러나 스프링에서 관습적으로 사용하는 설계는 싱글톤 객체가 가변적인 상태를 가지고 있게끔 하지 않는다.
- 예컨대 빈으로 등록되는 @Controller, @Service와 같은 클래스들이 상태 변수를 가지고 있게끔 만들지 않는다.
- 따라서 빈의 동기화를 신경쓰지 않는 것이다.
Dependency Injection (DI)
- IOC Container가 타입에 맞는 Bean을 꺼내서 알아서 넣어준다.
- 의존성 관리 = 필요한 의존성을 주입
- 스프링이 아니어도 DI라는 개념은 적용가능
@Autowired를 통해 의존성을 주입받기
- Constructor Injection
- Field Injection
- Setter Injection
레퍼런스 권장 DI = 생성자
- 스프링 4.3부터 생성자가 받는 인자가 Bean이라면, @Autowired를 생략할 수 있음
- 필수적으로 요구되는 객체 없이는 인스턴스를 만들지 못하도록 강제
Field Injection / Setter Injection의 원리
- 스프링 IOC컨테이너가 인스턴스를 생성하고 나서, Field할당 / Setter를 통해서 알맞은 Bean을 찾아 주입한다.
- 일단 인스턴스는 생성된다는 단점!
- Circular Dependency 해결 가능하나, 순환참조가 일어나지 않도록 의존성을 조율하는 게 더 좋다.
참고
인프런-예제로 배우는 스프링 입문 (백기선)
5~8강 (스프링 IOC, 스프링 IOC 컨테이너)를 들으며 정리한 내용입니다.
'학습 > Spring' 카테고리의 다른 글
[spring] 핵심3_Portable Service Abstraction (0) | 2020.03.22 |
---|---|
[spring] 핵심2_Aspect Oriented Programming (0) | 2020.03.21 |
[spring] @RequestParam과 @PathVariable (0) | 2020.02.15 |
[spring] DAO와 Repository / DTO / VO (0) | 2020.02.02 |
[java] Gradle(그레이들)이란? (0) | 2020.01.05 |
댓글