ApplicationContext란
서론
스프링은 객체지향의 장점
을 살리기 위해 EJB시절 로드 존슨이 취미로 만들기 시작하나 3만 줄의 예제 코드부터 시작 되었다.
객체 지향의 장점이란 변화에 대응하기 쉬운 코드
를 말한다. 하지만 EJB는 객체지향과는 거리가 멀고 너무 변경에 어려웠다고 하며,
이때 나온 말이 POJO라고 한다. 순수 자바로 돌아가서 객체지향적 개발을 하자는 취지의 용어이다.
본론
- ApplicationContext는
스프링의 DI 컨테이너이다
. 변경에 용이하기 위해 DI 컨테이너에서 의존 객체를 주입 해주기 위해
여러 객체들을 관리하는 상자라고 생각하면 된다. - 인터페이스이다.
순수 자바로 DI 컨테이너와 스프링의 DI 컨테이너
아래는 순수 자바로 DI 컨테이너를 만든 코드이다.
간단한 코드이므로 설명을 생략한다.
public class AppConfig {
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
public OrderService orderService() {
return new OrderServiceImpl(memberRepository(), discountPolicy());
}
public DiscountPolicy discountPolicy() {
return new RateDiscountPolicy();
}
}
// 아래는 AppConfig를 직접 관리하고 사용하는 코드이다.
public class MemberApp {
public static void main(String[] args) {
AppConfig appConfig = new AppConfig();
MemberService memberService = appConfig.memberService();
Member member = new Member(1L, "memberA", Grade.VIP);
memberService.join(member);
Member findMember = memberService.findMember(1L);
System.out.println("member = " + member.getName());
System.out.println("findMember = " + findMember.getName());
}
}
아래는 스프링의 DI 컨테이너를 사용하는 코드이다.
@Configuration
public class AppConfig {
@Bean
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}
@Bean
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
@Bean
public OrderService orderService() {
return new OrderServiceImpl(memberRepository(), discountPolicy());
}
@Bean
public DiscountPolicy discountPolicy() {
// return new FixDiscountPolicy();
return new RateDiscountPolicy();
}
}
// 아래는 스프링 컨테이너에 등록된 객체를 사용하는 코드이다.
public class MemberApp {
public static void main(String[] args) {
ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
MemberService memberService = ac.getBean("memberService", MemberService.class);
Member member = new Member(1L, "memberA", Grade.VIP);
memberService.join(member);
Member findMember = memberService.findMember(1L);
System.out.println("member = " + member.getName());
System.out.println("findMember = " + findMember.getName());
}
}
차이를 보자면 @Configuration, @Bean
이라는 키워드가 있다는 것이다.
스프링에서는 두 키워드가 바로 스프링의 DI 컨테이너에 등록할 수 있도록 해주는 키워드이다.
@Configuration이 있는 클래스에 @Bean이라는 키워드가 붙은 메서드를 모두 DI 컨테이너에 등록하게 된다.
즉, 개발자가 직접 객체를 관리하는 것이 아닌 스프링 컨테이너가 관리하는 것의 차이이다.
- 엄밀히 말하면 @Bean이 달린 것을 컨테이너에 등록하는 것이고 @Configuration은 싱글톤으로 생성할지 말지를 결정하는 요소가 된다.
즉, 반드시 @Configuration이 있어야만하는 것은 아니다.
AnnotationConfigApplicationContext
- ApplicationContext의 구현체이다.
new AnnotationConfigApplicationContext(AppConfig.class)
의 코드로 위에서 사용되고 있는데
AppConfig클래스에 있는 @Bean이 달린 메서드를 스프링 컨테이너에 등록하는 코드이다. 이 코드를 작성하면
모두 등록이 되어ac.getBean("memberService", MemberService.class)
을 사용하여 사용할 수 있게 된다.- 이름에서 보이듯 어노테이션 기반의 설정 정보를 읽어 스프링 컨테이너에 등록하게 된다.
스프링 컨테이너에 등록했을 때 로그
스프링 컨테이너에 등록 했을 때와 등록하지 않았을 때의 차이가 있다. 등록하지 않았을 때는 아무런 로그도 없지만,
등록하게 되면 스프링 컨테이너에 싱글톤 빈으로 등록 되었다는 로그를 볼 수 있다. 이 빈들은 AppConfig클래스의@Bean이 붙었던 메서드들의 빈 이름을 보여준다.
스프링의 빈 의존관계 설정 단계
의존관계에 필요한 객체들을 생성해서 등록하는 단계와 생성된 객체들을 참조시키는 의존관계 설정 단계로 크게 2단계로 구분할 수 있다.
빈을 등록하는 단계
- AppConfig에 있던 @Bean이 달린 메서드들을 컨테이너에 메서드명으로 빈의 이름을 생성하고, 인스턴스는 구현체를 등록하게 된다.
- 아직 의존관계는 설정되지 않은 상태이다.
의존관계 설정 단계
- 컨테이너에 등록된 빈들을 의존 관계를 맺는 단계이다.
예로 아래 코드를 보자. memberService라는 빈은 memberRepository에 의존하고 있다. 이렇게 의존관계를 설정하는 단계이다.
@Bean
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}
@Bean
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
하지만 반전은 이렇게 자바 설정
으로 스프링 빈을 등록을 하게 되면 실제로는 2단계가 한번에 이루어지게 된다.
즉, 현재 이 코드들은 2단계가 한 번에 이루어지게 되는 코드이지만, 스프링 자체에서는 단계가 나누어져 있다고 한다.
이 부분은 나중에 더 살펴보도록 하겠다.
해당 코드들에서 2단계가 통합되는 것은 당연한데 왜냐하면, memberService를 빈으로 등록하려면 당연히 memberRepository도 필요하기 때문에
빈 등록과 의존관계 설정이 같이 이루어질 수 밖에 없다.
'Spring' 카테고리의 다른 글
스프링의 자바 코드와 XML 설정 방식 (0) | 2022.01.10 |
---|---|
스프링의 BeanFactory와 ApplicationContext의 차이 (0) | 2022.01.10 |
org.springframework.dao.InvalidDataAccessApiUsageException: No enum constant (0) | 2021.10.03 |
Spring Data Jpa로 DB에 생성일, 수정일 자동화 하기 (0) | 2021.10.02 |
스프링부트 캐시 정책 적용하기 (0) | 2021.09.30 |