IoC(Inversion of Control) - 제어의 역전
IoC
- 메소드나 객체의 호출작업을 개발자가 아닌 외부에서 결정(외부는 Spring Framework)
- 기존에는 객체를 클래스 내부에서 생성하고 사용했지만 IoC를 적용하면 미리 생성해놓은 객체를 주입받아 사용하기만 하면 됨
장점
- 객체 간 결합도를 낮춤, 유연한 코드 작성, 가독성 증진, 코드 중복 방지, 유지 보수 용이
컨테이너
- 객체의 생명주기를 관리, 생성된 인스턴스들에 추가적 기능을 제공하도록 함
IoC컨테이너
- 객체의 생성을 책임지고, 의존성을 관리
- Pojo의 생성,초기화,서비스,소멸에 대한 권한을 가짐, 따라서 개발자는 비지니스 로직에 집중 가능.
D.I(Dependency Injection) - 의존성 주입
- 객체 사이의 의존 관계를 스프링 설정 파일에 등록된 정보를 바탕으로 컨테이너가 자동으로 처리해주는 것
- 컨테이너가 직접 객체들 사이의 의존관계를 처리하는 것
- 스프링 설정 파일에 등록된 정보를 바탕으로 하기 때문에, 직접 코드를 바꾸지 않고 스프링 설정 파일을 변경하는 것만으로 유지보수가 가능하기 때문에
의존성이 줄어들고, 재사용성과 가독성이 높아지며 보다 객체지향에 부합하는 방식의 코드를 작성가능
방법
1. 생성자 주입
@Autowired
public void MemberController(MemberService memberService){
this. memberService = memberService;
}
@Autowried
필요한 의존객체의 ‘타입’에 해당하는 빈을 찾아서 주입해주는 어노테이션
Ioc컨테이너가 빈으로 등록해주기 때문에, 빈으로 등록 되어 있는 것들은 autowired로 꺼낼 수 있다.
- 생성자에 의존성을 주입받고자하는 field를 나열하는 방법.
- 필수적으로 사용해야하는 레퍼런스 없이는 인스턴스를 만들지 못하도록 강제함 - 스프링 컨테이너가 올라오고 어플리케이션이 setting되는 시점에 생성자 주입을 통해 한번만 호출하는 것이 보장되어
불변, 필수
의존관계에 사용
2. Setter 주입
@Autowired
public void setMemberService(MemberService memberService){
this.memberService = memberService;
}
- set이 public하게 노출될 경우 setter가 실행되어 변경될 수 있는 문제점을 가짐
- 변경가능성이 존재하는 의존관계에서 사용할 필요가 있으나 권장되지 않음
3. 필드 주입
@Autowired
private final MemberService memberService;
- 필드에 @Autowired 어노테이션을 붙임. 중간에 외부에서 변경이 불가능하기 때문에 테스트가 힘듦
Bean
- 일반적으로 생성한 객체와 다를 바가 없어 보이지만 일반 객체와 빈의 차이점은 관리하는 주체
- Spring IoC 컨테이너가 관리하는 자바 객체를 Bean(빈)이라고 함
즉 new 연산자로 생성해서 개발자가 관리하는 객체가 아닌 등록만 해주면 스프링 컨테이너가 관리하는 객체
(스프링 컨테이너는 코드 상에서는 ApplicationContext라는 인터페이스)
--Spring Container = ApplicationContext---
| --------스프링 빈 저장소-------- |
| | | |
| | Bean : name :: object | |
| |__________________________| |
|________________________________________|
<Cycle>
스프링 컨테이너 생성 → 스프링 빈 생성 → 의존관계 주입 → 초기화 콜백 → 사용 →
소멸전 콜백 → 스프링 종료
- Spring Container 안에는 Bean 저장소가 있고 등록을 요청하면 Bean 저장소에 저장이 되고 이를 사용
Bean 저장 형식
-
Bean 이름 + Bean 객체
-
Bean 이름은 어노테이션으로 등록하는 방식 기준으로 @Bean 어노테이션이 붙은 메서드 이름을 사용
-
@Bean(name = "...") 방식으로 커스텀 가능
-
Bean 객체는 Singleton scope(Default), Prototype scope로 정의되고 사용됨
scope : 빈이 존재할 수 있는 범위
싱 글 톤 : 기본 스코프, 스프링 컨테이너의 시작과 종료까지 유지되는 가장 넓은 범위의 스코프
프로토타입: 프로토타입 빈의 생성과 의존관계 주입까지만 스프링 컨테이너가 관여하고
그 이후로는 관여하지 않는 매우 짧은 범위의 스코프이다.
Bean의 의존관계 주입
-
스프링 컨테이너는 Bean 생성 후에 의존관계를 주입
-
설정해놓은 의존관계들을 스프링 컨테이너가 인식하고 필요할 때 주입시켜줘야 함.(추가. 이는 XML로 Bean과 의존관계를 설정해주는 방식을 사용하면 명확히 보입니다)
-
스프링 컨테이너는 파라미터로 넘어온 클래스 정보에 따라 의존관계를 주입
동적인 객체 인스턴스 관계를 컨테이너가 연결
BeanFactory
- Bean을 조회하고 관리하는 기능은 ApplicationContext도 BeanFactory라는 최상위 인터페이스를 상속받아서 제공하고 있는 기능
- BeanFactory 개요
- 스프링 컨테이너의 최상위 인터페이스
- Bean을 조회하고 관리하는 기능 제공
- ApplicationContext는 BeanFactory의 기능에 부가 기능이 조금 더 더해진 것
싱글톤
- 객체의 인스턴스가 오직 1개만 생성되는 패턴을 의미한다.
- 한 번의 new 연산자를 통해 고정된 메모리 영역을 사용하기 때문에 메모리 낭비를 방지하고, 싱글톤 인스턴스가 전역으로 사용되는 인스턴스이기 때문에 다른 클래스 간에 데이터 공유가 쉽다는 장점이 있음(동기화)
- 객체간의 결합이 강해진다는 단점이 있음(강한 결합)
- IoC, DI로 느슨한 결합 생성 가능
stateless가 필요한 이유
- stateless : 상태를 공유하는 필드 변수가 없는 것을 의미
- 싱글톤 방식은 객체 인스턴스를 하나만 생성하고 공유하여 사용한다. 따라서 여러 클라이언트가 하나의 객체를 공유하게 되는데 이때 무상태(stateless)가 아니라면, 하나의 객체가 갖는 상태를 여러 클라이언트가 공유하는 결과가 생김
- 특정 클라이언트가 의존할 수 있는 필드 변수가 존재하면 안됨. 당연히 값을 변경할 수 없어야 하고 가능한 메서드를 이용해 값을 읽기만 가능하게 해야 함
- 하나의 객체를 공유하는 싱글톤 패턴의 특성상 상태가 공유되는 문제가 발생할 수 있음
- 클라이언트마다 고유한 값이 뒤섞이는 문제가 발생할 수 있기 때문에 싱글톤 패턴을 사용한다면 반드시 무상태로 설계해야 힘
- 스프링 컨테이너는 싱글톤 패턴을 사용하므로, 스프링 빈은 항상 무상태(stateless) 설계가 필요
Spring의 싱글톤
- 스프링 컨테이너는 싱글턴 패턴을 적용하지 않아도 객체 인스턴스를 싱글톤으로 관리한다. 이러한 기능 덕분에 싱글톤 패턴의 모든 단점을 해결하고 객체를 싱글톤으로 유지할 수 있다.
결론
싱글톤을 사용하는 이유
IoC가 필요한 이유
- 강한 결합으로 인한 의존성을 풀어내기 위하여
- 개발자가 아닌 프레임워크 단에서 인스턴스를 관리함
DI가 필요한 이유
- 관리를 하려면 기존의 인스턴스에 대한 정보를 주입해줘야함. 안하면 뭔지 모르니까
그래서 IoC 컨테이너에 DI를 하는 것으로 다른 파일에서 사용할 수 있게 됨
생성자로 가져오는 것을 대부분 사용함.
전체
- 의존 중인 객체를 외부로부터 주입받는 방식이 DI이다.
- DI를 통해 IoC를 이루고 이는 결합도를 줄이고 가독성을 높이고 유지 보수를 편하게 해 준다.
- DI를 수행하는 것은 스프링 컨테이너(= ApplicationContext)이다.
- Bean 객체는 스프링 컨테이너가 관리하는 객체를 의미한다.
- 스프링 컨테이너 내부에 Bean 저장소에 Bean 객체의 정보를 저장한다.
- Bean은 기본적으로는 싱글톤 스코프로 생성, 관리되고 프로토타입 스코프도 사용 가능하다.
도서관 DI
싱글톤에 stateless가 필요한 이유
싱글톤 패턴
DI 사용예시
DI와 Bean
각 어노테이션 내부 - https://velog.io/@jkijki12/Spring-%EC%8A%A4%ED%94%84%EB%A7%81-Bean-IoC-Container-DI%EA%B0%80-%EB%AD%94%EB%8D%B0