[스프링 프레임워크 핵심기술] 스프링 IoC 컨테이너와 빈

Dayeon myeong·2021년 2월 18일
0

이 글은 인프런 스프링 프레임워크 핵심 기술을 보고 정리한 글입니다.

IoC

  • Inversion of Control: 의존 관계 주입(Dependency Injection)이라고도 하며, 어떤 객체가 사용하는 의존 객체를 직접 만들어 사용하는게 아니라, 어떤 장치를 사용해서 (생성자, setter,필드 인젝션 등)주입 받아 사용하는 방법을 말 함.
//의존 객체를 직접 만들어 사용하는 방법
BookRepository bookRepository = new BookRepository();
BookService bookService = new BookService(bookRepository);
//의존 객체를 직접 만들어 사용하는 방법
@Service
public class BookService {
	private BookRepository bookRepository = new BookRepository();
}
//의존성 주입 방법 (생성자 주입 방식)
@Service 
public class BookService {
	
	private BookRepository bookRepository;//bookRepository는 빈으로 설정되있어야 함.
    
    //생성자 주입 방식
    //누군가 밖에서 주입해준다.
    public BookService(BookRepository bookRepository) {
    	this.bookRepository = bookRepository;
    }
    ...
}

혹은

@Service
public class BookService {

	//주입
    @Autowired
    private BookRepository bookRepository;

    public void doSomething() {
        // ....
    }
}

등 여러 주입 방식이 있다.

스프링 IoC 컨테이너

IOC (Inversion of Control) 를 구현하는 프레임워크로 빈 설정 소스로부터 빈 정의를 읽어 빈을 구성하고 제공한다.

  • Ioc컨테이너를 사용하는 이유 : 여러 개발자들이 스프링 커뮤니티에서 논의해서 만들어진 여러가지 디펜던시 인젝션 방법과 여러 노하우,방법이 쌓여있는 프레임워크이기때문
  • 컨테이너라고 부르는 이유 : 컨테이너 안 객체들을 빈이라 함. 컨테이너라 부르는 이유는 이 안에 ioc 기능을 제공하는 빈들이 담겨져있기 때문에 컨테이너(빈들을 담고있음), 이 빈들이 들어있기 때문에 컨테이너를 가져와서 사용이 가능
  • BeanFactory : 스프링 ioc 컨테이너의 가장 최상위 인터페이스, Ioc 컨테이너의 핵심
  • ioc컨테이너에 있는 2가지 중요한 인터페이스 beanfactory와 applicationcontext
  • 애플리케이션 컴포넌트의 중앙 저장소.

BeanFactory

스프링 ioc 컨테이너의 가장 최상위 인터페이스, Ioc 컨테이너의 핵심
Bean의 생성과 설정, 관리를 맡고 있다.

ApplicationContext

  • ioc컨테이너에 있는 중요한 인터페이스
  • BeanFactory를 상속받으면서도 추가적인 기능(EventPublisher,EnvironmentCapable,,,)을 제공해줌
  • 메시지 소스 처리 기능 (i18n) , 이벤트 발행 기능, 리소스 로딩 기능 등이 있음

BeanFactory를 상속받고 있기 때문에, BeanFactory와 같은 일을 한다고 볼 수 있다.

스프링 IoC 컨테이너가 관리 하는 객체.

  • ex) Repository, Service 등의 어노테이션이 붙은 클래스
  • 위 예시같은 어노테이션을 사용해서 객체를 빈으로 등록할 수 있다. (의존성 주입을 받으려면 빈이 되어야함, 의존성 주입은 빈끼리만 가능하다. 즉, IoC 컨테이너 안에 들어있는 객체들끼리만 의존성 주입을 해준다.)

빈의 장점

  • 장점
    • 의존성관리
    • 라이프사이클 인터페이스를 지원해줌 : 빈이 만들어졌을 때 추가적인 작업을 할 수 있고, 그 외에도 스프링 자체의 라이프사이클 콜백을 이용해서 부가적인 작업도 가능하다.
      • @PostConstruct ,,,
    • 빈의 스코프
      • 싱글톤: 하나의 객체, 스프링 IoC 컨테이너는 기본적으로 싱글톤 스코프로 등록됨
        • 싱글톤이란 생성자가 여러 차례 호출되더라도 실제로 생성되는 객체는 하나이고 최초 생성 이후에 호출된 생성자는 최초의 생성자가 생성한 객체를 리턴한다. = 객체 하나만 만들어서 공유
          • 만약 우리가 만들었던 DI 컨테이너인 요청을 할 때마다 새로운 객체를 생성한다면, 요청이 엄청나게 많은 트래픽 사이트에서는 계속 객체를 생성하게 되면 메모리 낭비가 심하기 때문에 사용.
      • 프로포토타입: 매번 다른 객체를 사용하는 것
//라이프사이클 인터페이스 예제
@Service 
class BookService {
	@PostConstruct
	public void postConstruct() {
    	...
    }
}

BookService는 bookRepository의 save가 null을 리턴하기 때문에 테스트를 할 수가 없다.
BookRepository를 구현해야지만 BookService를 테스트할 수 있다.

의존성의 문제 : 의존성을 가진 클래스들을 단위테스트 하기 힘들다(이 상황보다 BookService 클래스에서 BookRepository를 직접 생성하는 경우에는 더 힘들다.)

@Repository
public class BookRepository{
	public Book save(Book book) {
    	return null;
    }
}

@Service
public class BookService {
	
    @Autowired
	private BookRepository bookRepository;
    
    public Book save(Book book) {
    	...
    	return bookRepository.save(book);
    }


}

//테스트코드
public class BookServiceTest {

	@Test
    public void save() {
    Book book = new Book();
    BookRepository bookRepository = new BookRepository();
    BookService bookService = new BookService(bookRepository);
    
    Book result = bookService.save(book);
    
    assertThat(book.getCreated()).isNotNull();
    ...
    

}

의존성 주입 방식 코드로 구현한 경우 얼마든지 가짜 객체를 만들어서 의존성 주입을 해주면 된다.

@RunWith(SpringRunner.class)
public class BookServiceTest {

	@Mock
    BookRepository bookRepository; // 가짜 객체
    
	@Test
    public void save() {
    Book book = new Book();
    when(bookRepository.save(book)).thenReturn(book); //save 메서드 호출시 book이 인자로 들어오면 book을 리턴하라 
    
    BookRepository bookRepository = new BookRepository();
    BookService bookService = new BookService(bookRepository);
    
    Book result = bookService.save(book);
    
    assertThat(book.getCreated()).isNotNull();//book이라는 인스턴스가 들어왔기 때문에 테스트 동작됨
    ...
    

}
profile
부족함을 당당히 마주하는 용기

0개의 댓글