IoC 컨테이너 / BeanFactory / ApplicationContext

Crow·2021년 6월 23일
0

Spring Boot

목록 보기
3/5
post-thumbnail

용어 개념 잡기

1. IoC(Inversion of Control)란?

: 제어권 역전.

일반적인 제어권 상황IoC 상황을 코드로 예를 들어 설명하겠다.

(1) 일반적인 제어권

객체 의존성에 대한 일반적인 제어권 Example

  • 자신이 사용할 의존성 객체를 직접 초기화하여 만들어 사용한다.
    이는 의존성 객체에 대한 제어권이 자신에게 있다고 볼 수 있다.
	class OwnerController{
		private OwnerRepository owner = new OwnerRepository();
	}

(2) IoC(Inversion of Control)

IoC(Inversion of Control) Example

  • 자신이 사용할 의존성 객체를 생성자를 통해 외부로부터 주입 받는다.
    즉, 의존성 객체에 대한 제어권이 자신에게 없는 상황이고 이를 제어권이 역전되었다고 한다.
    이렇게 외부로부터 의존성 객체를 주입 받는 것을 DI(Dependency Injection) 라고 한다.
class OwnerController {
	private OwnerRepository owner;

	public OwnerController(OwnerRepository owner) {
		this.owner = owner;
	}
}



2. Bean 이란?

  • Spring 의 IoC 컨테이너가 관리하는 자바 객체를 Bean 이라고 한다.

    • 위의 '1. IoC(Inversion of Control)'에서
      • (1) 일반적인 제어권 의 example 코드 방식으로 생성된 객체는
             Bean이 아니다.
      • (2) IoC(Inversion of Control) 의 example 코드 방식으로 생성된 객체가
             Bean이다.

  • Spring 에서 의존성 주입(DI, Dependency Injection)을 받기 위해서는
    이러한 자바 객체를 IoC 컨테이너에 Spring Bean으로 등록해야 가능하다.

Bean 등록 방법

(1) Component Scanning

  • Class에 @Component와 관련된 어노테이션을 적용시켜 Bean으로 등록하는 방식
    • 종류
      • @Repository
      • @Service
      • @Controller
      • @Configuration
      • etc.

Component Scanning Example

@Controller
public class SampleBeanController {

}

(2) 직접 등록

  • 일종의 Configuration.java 파일을 생성하여
    @Configuration 과 @Bean을 사용하여 직접 등록해주는 방식

직접 등록 Example | SampleBeanConfig.java

@Configuration
public class SampleBeanConfig {

	@Bean
	public SampleBeanController sampleBeanController(){
		return new SampleBeanController();
	}
}

등록된 Bean을 어떻게 꺼내어 사용할까?

(1) @Autowired 혹은 @Inject

Example

	@Autowired
	private OwnerRepository owners;

	@Autowired
	private ApplicationContext applicationContext;

	@Autowired
	private VisitRepository visits;

	@Autowired
	private PetRepository petRepository;

(2) ApplicationContext에서 getBean()으로 직접 꺼내어 사용하기

Example

@RunWith(SpringRunner.class)
@SpringBootTest
public class SampleBeanControllerTest {

	@Autowired
	ApplicationContext applicationContext;

	// ApplicationContext에 SampleBeanController가 Bean으로 등록되어 있는지
	// 확인하는 테스트 코드
	@Test
	public void testDI() {
		SampleBeanController bean = applicationContext.getBean(SampleBeanController.class);
		assertThat(bean).isNotNull();
	}
}

의존성 주입 (Dependency Injection)

: 필요한 의존성 객체를 어떻게 주입 받을 것인가

  • 종류
    • Constructor Injection
    • Field Injection
    • Setter Injection
  • Constructor Injection의 경우,
    주입 받을 의존성 객체의 원형 필드에 보통 final 키워드를 붙인다.
  • Field InjectionSetter Injection 의 경우에는,
    필드에 final 키워드를 붙이지 않는다.
  • Spring 에서 공식적으로 권장하는 의존성 주입 방법은 Constructor Injection 이다.
  • 그럼에도 Field Injection 이나 Setter Injection 같은 방법들이 존재하는 이유는
    간혹 순환 참조(Circular Depencies or Circular Reference) 라는 문제가 발생할 수 있는데
    이 순환 참조 문제를 Field Injection 이나 Setter Injection로 해결 가능하다.

(1) Constructor Injection

Example

@Controller
class OwnerController {

	// 의존성 객체를 생성자를 통해서 주입 받는 방식 (Spring Framework 에서 권장하는 방식)
	private final OwnerRepository owners;

	private final ApplicationContext applicationContext;

	private VisitRepository visits;

	private final PetRepository petRepository;

	public OwnerController(OwnerRepository clinicService,
    				VisitRepository visits,
				ApplicationContext applicationContext,
                		PetRepository petRepository) {
                        
		this.owners = clinicService;
		this.visits =
			visits;
		this.applicationContext = applicationContext;
		this.petRepository = petRepository;
	}
}

(2) Field Injection

Example

	@Autowired
	private OwnerRepository owners;

	@Autowired
	private ApplicationContext applicationContext;

	@Autowired
	private VisitRepository visits;

	@Autowired
	private PetRepository petRepository;

(3) Setter Injection

Example

	private OwnerRepository owners;

	private ApplicationContext applicationContext;

	private VisitRepository visits;

	private PetRepository petRepository;

	@Autowired
	public void setOwners(OwnerRepository owners) {
		this.owners = owners;
	}

	@Autowired
	public void setApplicationContext(ApplicationContext applicationContext) {
		this.applicationContext = applicationContext;
	}

	@Autowired
	public void setVisits(VisitRepository visits) {
		this.visits = visits;
	}

	@Autowired
	public void setPetRepository(PetRepository petRepository) {
		this.petRepository = petRepository;
	}



IoC 컨테이너

  • Spring Bean 생성과 Bean들 사이의 관계 설정, 사용, 제거 등의 작업을 담당하는 독립된 공간
  • Spring 에서 IoC를 담당하는 컨테이너는 BeanFactory, ApplicationContext 두 가지가 있다.
  • 기본적으로 싱글톤 스코프로 Bean 을 관리.
    • 왜 싱글톤 일까?
      • 매번 클라이언트에서 요청이 들어올 때마다 각 로직을 담당하는 객체들을 새로 생성하는 것은 자원 측면에서 매우 비효율적.
      • 따라서, 클래스당 하나의 객체만 만들어두고 사용자의 요청을 담당하는 여러 스레드에서 하나의 객체를 공유해 동시에 사용.

1. BeanFactory

  • Spring IoC 컨테이너 최상위 인터페이스

2. ApplicationContext

  • BeanFactory와 그외 여러가지 인터페이스들을 추가로 상속받은 인터페이스.
  • IoC 컨테이너로서의 역할을 하는 BeanFactory에 엔터프라이즈 애플리케이션을 개발하는 데 필요한 여러가지 기능을 추가한 것이 ApplicationContext다.



※ 글 내용 추가 Log

  • 2021-06-25
    • Bean에 대한 추가 설명
    • Bean 등록 방법
    • 등록된 Bean을 어떻게 꺼내어 사용할까?
    • 의존성 주입 (Dependency Injection)
profile
올빼미를 사냥한 까마귀에서 진화한 독수리

0개의 댓글