지난 시간까지 순수 자바 코드로 만든 예제 프로젝트의 문제점을 개선하면서 스프링으로 전환해봤다.
그러면서 왜 스프링이 필요한지, 스프링의 DI 개념에 대해 배웠다. 이번 시간에는 스프링 그 자체에 대해 배운다.
목표
1. 스프링 컨테이너의 생성 과정을 배운다.
2. 스프링 빈을 찾는 기본 방법을 배운다.
'스프링 컨테이너와 스프링 빈' 목차
1. 스프링 컨테이너 생성 (이번 포스팅)
2. 컨테이너에 등록된 모든 빈 조회
3. 스프링 빈 조회 - 기본
4. 스프링 빈 조회 - 동일한 타입이 둘 이상
5. 스프링 빈 조회 - 상속 관계
6. BeanFactory와 ApplicationContext
7. 다양한 설정 형식 지원 - 자바 코드, XML
8. 스프링 빈 설정 메타 정보 - BeanDefinition
1. 스프링 컨테이너 생성 과정
이전 시간에 AppConfig.class를 넘겨서 생성한 스프링 컨테이너 코드를 떠올려보자.
컨테이너라는게 '객체를 담고 있다'는 뜻이다.
ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
ApplicationContext는 스프링 컨테이너다.
ApplicationContext 는 인터페이스인데, 그것을 구현한 클래스가 AnnotationConfigApplicationContext다.
스프링 컨테이너를 생성하는 방법에는 XML 기반과 애노테이션 기반이 있다.
우리가 AppConfig.class 에 @Configuration 애노테이션을 달고, 메서드에 @Bean을 달았는데. 이 방법이 애노테이션 기반 자바 설정 클래스로 스프링 컨테이너를 생성한 것이다.
참고 : 더 정확히는 스프링 컨테이너를 부를 때 BeanFactory와 ApplicationContext를 구분한다. 뒤에서 더 자세히 배운다.
1) 스프링 컨테이너 생성 과정
스프링 컨테이너를 생성 할 때 구성 정보(설정 정보)를 정해줘야 한다. 여기서는 AppConfig.class 를 구성 정보로 지정했다.
2) 스프링 빈 등록
스프링 컨테이너는 파라미터로 넘어온 설정 클래스 정보를 사용해서 @Bean이 붙은 메서드의 반환 객체를 모두 스프링 빈으로 등록한다.
{ @Bean 이름 - @Bean 객체 } 쌍으로 컨테이너에 저장된다.
아래에 코드를 보자. memberService() 메서드에 @Bean 애노테이션이 붙어있다.
memberService 이름의 스프링빈은 아래의 쌍으로 저장된다.
{ @Bean이름: memberService - @Bean객체: new MemberServiceImpl(memberRepository()) }
빈 이름은 디폴트로 메서드 이름과 똑같이 정해지는데 직접 이름을 지을 수도 있다.
주의: 빈 이름은 중복 불가
3) 스프링 빈 의존관계 설정 - 준비
애노테이션 기반 자바 설정 클래스(AppConfig.class)를 기반으로 스프링 컨테이너를 생성한다.
@Bean 을 달아놓은 메서드를 전부 호출하여 메서드 명 그대로 이름붙여서 컨테이너에 스프링 Bean으로 등록한다.
4) 스프링 빈 의존관계 설정 - 완료
스프링 컨테이너가 설정 정보를 참고해서 의존관계를 주입(DI) 한다.
어떤 인터페이스에 어떤 구현체를 생성해서 인스턴스 레퍼런스를 넘길지 정보를 보고 의존관계를 주입한다.
단순히 자바 코드를 호출하는 것 같아보이지만, 차이가 있다. 이 차이는 뒤에서 싱글톤 컨테이너에서 설명한다.
[ 참고 ]
스프링 컨테이너는 빈을 생성하고 의존관계를 주입한다는 것이 핵심이다.
스프링 빈을 생성하고 의존관계를 주입하는 단계를 나눠서 그림으로 그렸다. 사실 스프링에서는 이것이 한 번에 처리되는 것이고 이해를 위해 나눠 그린 것이다. 이제 스프링 컨테이너에서 데이터를 조회해보자.
2. 컨테이너에 등록된 모든 빈 조회
테스트 코드를 작성해서 스프링 컨테이너에 스프링 빈이 등록되었는지 확인하자.
테스트를 실행한 결과.
파랗게 드래그한 부분은 appConfig.class를 포함해서 @Bean 을 달아놓은 스프링빈이 출력되었다.
드래그한 윗 부분은 스프링이 내부적으로 스프링 자체를 확장하기 위해 필요한 스프링빈이다.
스프링 내부적으로 필요한 것 말고, 내가 정의한 스프링 빈만 출력하자.
getRole()== ROLE_APPLICATION : 개발을 위해 등록한 (일반적으로 사용자가 등록한) 빈만 출력된다.
파랗게 드래그한 부분을 보면 appConfig.class를 포함해서 내가 정의한 빈 4개가 출력된다.
3. 스프링 빈 조회 - 기본
1) getBean() 메서드로 빈 이름을 넘기면 스프링 빈을 조회할 수 있다.
테스트 실행 결과, appConfig를 비롯한 스프링빈이 출력된다.
2) 이름 없이 타입으로만 조회할 수 있다.
memberService 빈 이름을 호출하지 않고, memberService.class 타입으로 빈을 조회할 수 있다.
3) 구체 타입 으로 조회할 수 있다.
memberService 빈을 호출하면 구체클래스 memberServiceImpl을 반환해준다.
AppConfig.class 코드를 열어 보면 memberService 스프링 빈의 반환 타입을 확인할 수 있다.
따라서 스프링 빈을 memberServiceImpl 구체 타입으로 조회 가능하다.
좋은 코드는 아니다.
왜냐하면 프로그래머는 "추상화에 의존해야지, 구현체에 의존하면 안된다." 는 SOLID원칙을 다시 떠올리자!
4) 존재하지 않는 빈을 조회해보자.
테스트 작성 시, 항상 실패 케이스도 만들어야 한다. XXX 라는 이름의 빈을 조회하면, 없는 빈이니까. 아래의 예외가 터져야 한다.
NoSuchBeanDefinitionException: No bean named 'XXX' available
XXX라는 빈 없다는 에러 내용을 확인할 수 있다.
빨간 글씨를 보긴 했지만 예쁘게 고쳐보자.
5) 실패 케이스 "@@예외가 터지면 성공이다."라는 테스트를 작성하자.
다음 시간에는 "동일한 타입의 빈이 2개 이상 있으면 어떻게 조회 하는지 " 알아보자.
다음 강의에서는 '스프링 빈 조회와 BeanFactory'를 배운다.
공부 내용 출처 : 스프링 핵심 원리 기본편
'프로그래밍 > Spring Basic' 카테고리의 다른 글
9. 스프링 컨테이너의 다양한 설정 형식 - 자바 코드, XML (0) | 2021.12.24 |
---|---|
8. 스프링 빈 조회 - 상속 관계 (0) | 2021.12.23 |
6. 객체 지향 원리 적용 - IoC, DI, 그리고 컨테이너 (0) | 2021.12.21 |
5. 객체 지향 원리 적용 - AppConfig 리팩터링 (0) | 2021.12.21 |
4. 객체 지향 원리 적용 - 관심사의 분리 (0) | 2021.12.21 |