김영한님의 Spring 핵심원리 강의를 듣고 정리하는 글입니다
1. DI, IoC 탄생배경
DI, IoC가 없었더라면, 객체지향의 원칙 중 DIP, OCP 등을 완벽하게 지킬 수 없다.
코드를 보자.
public class MemberServiceImpl implements MemberService {
private MemberRepository memberRepository = new MemoryMemberRepository();
}
- MemberServiceImpl은 MemoryMemberRepository와 의존관계를 가진다.
- MemberReposiory는 인터페이스로 구현체(클래스)가 바뀔 경우 MemberServiceImpl에서도 코드를 변경해줘야 한다. ⇒ 객체지향 설계원칙(DIP, OCP)를 위반한다.
- 스프링에서 이야기하는 제어의 역전(IoC), 의존관계 주입(DI)은 다형성을 활용해서 역할과 구현을 편리하게 다룰 수 있도록 지원한다.
2. IoC / DI / DL / 스프링 컨테이너
IoC(Inversion of Control)
- 제어의 역전이라 한다.
- 스프링 애플리케이션에서는 오브젝트(빈)의 생성과 의존관계 설정, 사용, 제거 등의 작업을 애플리케이션 코드 대신 스프링 컨테이너가 담당한다.
- 프로그램의 제어 흐름을 직접 제어하는 것이 아니라 외부에서 관리하는 것을 IoC 라고 한다.
DI(Dependency Injection)
- 의존관계 주입이라는 의미이다.
- 의존관계를 자신이 아닌 외부(스프링 컨테이너)에서 주입하는 것이다.
DL(Dependency Lookup)
- 의존관계 검색이라는 의미이다.
- 의존관계가 있는 객체를 외부에서 주입 받는 것이 아닌, 의존관계가 필요한 객체에서 직접 검색하는 방식이다.
스프링 컨테이너
- 스프링에서 IoC를 담당하는 컨테이너를 어셈블러, IoC 컨테이너라, DI 컨테이너 라고도 한다.
- 빈을 생성하고 의존관계를 설정하는 기능을 담당하는 가장 기본적인 IoC 컨테이너는 BeanFactory라고 한다.
- 스프링에서는 컨테이너가 단순한 DI 작업 이외에 다른 작업을 하는데, BeanFactory에 여러가지 기능을 추가한 것을 Application Context라 한다.
3. Application Context와 BeanFactory의 관계
[Spring Framwork 6.0.12 문서]
ApplicationContext와 BenFactory
BeanFactory
- BeanFactory는 스프링 컨테이너에서 최상위 인터페이스다.
- 스프링 빈을 관리하고 조회하는 역할을 한다.
- getBean()과 같은 대부분의 기능은 BeanFactory에서 제공한다.
ApplicationContext
- 위에서 말했듯이 BeanFactory에서 제공하는 Bean을 관리하고 조회하는 기능 외에 많은 부가기능이 존재한다.
- 대표적으로 BeanFactory 이외에도 4가지 인터페이스를 상속 받아 부가기능을 제공한다.(다른 인터페이스도 존재)
- MessageSource를 활용한 국제화 가능
- EnvironmentCapable(환경변수)
- ApplicationEventPublisher(애플리케이션 이벤트)
- ResourceLoader(편리한 리소스 조회)
4. DI, IoC 설정과 ApplicationContext 등록하는 코드 예시
1.의존관계 주입이 필요한 MemberServiceImpl, MemberRepository
public class MemberServiceImpl implements MemberService {
private final MemberRepository memberRepository;
public MemberServiceImpl(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
}
2.IoC와 의존관계 설정
컨테이너가 의존 관계를 맺어주기 위해서는 빈(bean)으로 등록해줘야 한다.
ApplicationContext 설정 정보를 등록하는 방법은 대표적으로 두 가지 방법이 존재한다.(xml, java)
< Java 코드로 빈 등록 >
@Configuration
public class AppConfig {
@Bean
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}
@Bean
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
}
< xml 파일로 빈 등록(appConfig.xml) >
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="memberService" class="hello.core.member.MemberServiceImpl">
<constructor-arg name="memberRepository" ref="memberRepository"/>
</bean>
<bean id="memberRepository" class="hello.core.member.MemoryMemberRepository"/>
<bean/>
3.Application Context 생성과 설정 파일 등록
// Java 코드로 등록한 설정 파일(AppConfig.java) ApplicationContext에 등록
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
// XML로 등록한 설장 파일(AppCong.xml) ApplicationContext에 등록
ApplicationContext ac = new GenericXmlApplicationContext("appConfig.xml");
- DI, IoC 설정과 ApplicationContext 설정 정보를 등록하는 방법에 대해서 알아보았다.
- XML 파일이나, Java코드(@Bean)의 설정 정보를 ApplicationContext에 파라미터 넘겨주면 스프링 컨테이너는 설정 정보를 사용해서 스프링 빈에 등록한다.
또한 각 빈 이름은 하나만 존재해야 하며, 그렇지 않을 경우에 NoUniqueBeanDefinitionException 예외가 발생한다.
기본적으로 빈 이름은 메서드 이름을 사용한다. @Bean(name ="빈이름") 이런식으로 빈이름을 직접 지정할 수 있다.
5. ApplicationContext에서 관리하는 Bean 조회
// ApplicationContext에 AppConfig를 설정 정보로 등록
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
@Test
@DisplayName("이름으로 조회")
void findBeanName() {
MemberService memberService = ac.getBean("memberService", MemberService.class);
assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
}
- AnnotationConfigApplicationContext 설정 정보를 등록하면 설정 정보에 맞게 빈을 생성하고 의존 관계를 맺어주게 된다.
- 빈이 제대로 등록 되었는지 확인하고 싶을 경우에 getBean(”빈 이름”, 타입)을 통해 확인할 수 있다.(타입만으로 조회할 수 있다)
6. BeanDefinition이란?
- 스프링 빈 설정 메타정보라고 한다.
- 스프링에서 다양한 설정 형식(java, xml)을 지원할 수 있는 이유는 추상화가 잘 되어 있기 때문이다.
- 하나의 Bean 당 가각 하나씩 메타 정보가 생성된다.
스프링 컨테이너는 메타 정보를 가지고 스프링 빈을 생성한다.
7. 마무리
- 객체지향 설계원칙을 지키며 의존관계를 클라이언트 코드에서 설정하지 않고, 외부에서 설정하며, 애플리케이션을 빠르고 편리하게 개발하기 위해 Spring 컨테이너와 DI, IoC 개념이 나오게 되었다.
- 스프링 컨테이너는 다양한 설정 형식을 지원하며, XML, Java 코드로 의존 관계와 빈 등록과 같은 정보를 설정하는 방법에 대해서 다뤄보았다.
'Programming > Spring' 카테고리의 다른 글
[Spring Boot] Spring Boot + Redis CRUD 예제 (0) | 2023.09.24 |
---|---|
[Spring Boot] Spring Integration MQTT 예제 (0) | 2023.09.24 |
[Spring] Bean 생명주기 콜백 (0) | 2023.09.16 |
[Spring] 의존관계 자동으로 주입하는 방법 (0) | 2023.09.07 |
[Spring] 컴포넌트 스캔(Component Scan) (0) | 2023.09.07 |