[Spring] 04-1. 스프링 컨테이너와 스프링 빈

지찬우·2023년 1월 4일
0

Spring

목록 보기
15/27
post-thumbnail

이 시리즈는 인프런 강의(김영한 님의 ‘스프링 핵심 원리 - 기본편’)로 공부하며 혼자 기록하고, 사람들과도 공유할 수 있도록 작성하는 글이다. 최대한 추가적인 정보는 공식 홈페이지, 문서를 보며 얻을 예정이다.
(개인적인 생각과 이해가 들어가 있기 때문에 저의 ‘무식함’이 있을 수 있습니다😜 혹시라도 이 글을 보게 되시는 분이 계시다면 잘못된 부분 댓글로 많이 알려주시면 너무 감사하겠습니다!!)

GitHub Repository : https://github.com/jcw1031/spring-core-study


이제까지 스프링의 핵심 원리와 객체 지향에 대해 배우고, 왜 스프링이 만들어졌는지 알아봤다면 이제부터 스프링 자체에 대해 배운다.

🛠️ 스프링 컨테이너 생성

ApplicationContext를 스프링 컨테이너라고 한다. ApplicationContext는 인터페이스로 다형성이 적용되었다. 구현체들 중 하나가 AnnotationConfigApplicatioinContext이다.

ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);

위의 코드는 AppConfig 클래스의 구성 정보를 사용해 스프링 컨테이너를 만들고 스프링 빈을 등록한다는 의미이다. 스프링 컨테이너를 생성할 때 스프링 빈을 등록하는 방식은 AppConfig 클래스처럼 자바 config를 사용하는 방식 외에 XML 문서를 사용하는 등 다른 방법들도 존재한다.(XML 기반의 컨테이너 생성은 요즘에 잘 사용하지 않는다.)

더 정확히는 스프링 컨테이너를 부를 때 BeanFactoryApplicationContext로 구분해서 이야기하지만, BeanFactory를 직접 사용하는 경우는 거의 없기 때문에 일반적으로 ApplicationContext를 스프링 컨테이너라고 한다. 이 내용에 대해서는 뒤에서 배운다.

스프링 컨테이너 생성 과정

컨테이너 생성 ➡️ 빈 등록 ➡️ 스프링 빈 의존관계 설정(준비) ➡️ 스프링 빈 의존관계 설정(완료)

우리 예제처럼 자바 코드로 스프링 빈을 등록하면, 생성자를 호출하면서 의존관계 주입도 한 번에 처리된다.

스프링 컨테이너 생성

...
new AnnotationConfigApplicationContext(AppConfig.class);
...

AppConfig.class를 구성 정보로 지정하여 스프링 컨테이너를 생성한다.


스프링 컨테이너에는 구성 정보를 활용해 key에 빈 이름, value에 빈 객체가 등록되어, 빈 이름으로 빈 객체를 가져올 수 있는 저장소가 생성된다.

스프링 빈 등록

스프링 컨테이너의 스프링 빈 저장소에 스프링 빈이 등록된다.


프링 빈의 이름은 자동으로 메서드 이름으로 등록되지만, 직접 빈 이름을 설정할 수 있다.(@Bean(name=”{이름}”))
❗️ 빈 이름은 항상 다른 이름을 부여해야 한다.

스프링 빈 의존관계 설정

생성자의 매개변수 정보로 의존관계를 주입한다.DI
위에서 설명했듯이 스프링 빈을 생성할 때 생성자를 호출하면서 의존관계 주입도 한 번에 처리된다. 개념적으로 분리하여 설명한 것이다.


단순히 자바 코드를 호출하는 것과 차이가 있다. 이 차이는 싱글톤 컨테이너를 공부할 때 배운다.

🔍 등록된 빈 조회

스프링 컨테이너에 스프링 빈이 잘 등록이 되었는지 간단하게 확인해 보자.

기본 조회

test/java/Group이름.core 패키지에 beanfind 패키지를 생성하고, 그 안에 ApplicationContextBasicFindTest 클래스를 생성한다.(이름은 마음대로 해도 된다.)


테스트에서 사용할 스프링 컨테이너를 AnnotationConfigApplicationContext 구현체를 사용해 생성한다.

Test에서 ApplicationContext(AC라고 하겠다)가 아닌 AnnotationConfigApplicationContext(ACAC라고 하겠다)로 생성한 이유는, ACACAC의 상위 인터페이스로 AC는 기능이 적고 ACAC는 더 많은 기능을 제공한다. 테스트할 때 추가 기능을 사용해야 하기 때문에 ACAC로 생성했다.

개발할 때는 가급적 기능을 적게 제공하는 상위 인터페이스를 사용한다.(향후 구현 클래스가 변경되어도 클라이언트 코드를 변경하지 않아도 되기 때문이다.)


이름으로 조회

아래와 같이 테스트 메서드를 작성한다. 스프링 컨테이너의 getBean() 메서드의 매개변수로 빈 이름과 반환 타입을 전달하여 빈을 조회할 수 있다. AssertionsassertThat().isInstanceOf()를 사용해 반환받은 빈의 타입이 구현체와 같은지 확인한다.


타입을 지정하지 않고 이름만 사용하여 조회할 수도 있다. 타입을 알 수 없기 때문에 Object 타입으로 반환받아 확인한다.


타입으로 조회

getBean() 메서드의 매개변수로 이름을 전달하지 않고 타입만 전달하여 조회할 수 있다.


동일 타입 조회

동일한 타입이 둘 이상이 존재하는 경우, 타입으로 조회 시 오류가 발생한다. 따라서 빈 이름을 지정해주어야 한다.

beanfind 패키지에 ApplicationContextSameBeanFindTest 테스트 클래스를 생성하고, 기존 구성 정보인 AppConfig에는 동일한 타입의 빈이 없으므로 테스트 용도로 설정 클래스를 생성하여 테스트해 보자.

클래스 내부에 클래스를 만드는 경우 static class로 만들어야 한다.


우리가 방금 생성한 구성 정보 클래스를 사용하는 스프링 컨테이너를 생성한다.


타입으로 조회하면 동일한 타입의 빈이 둘 이상 존재하기 때문에 NoUniqueBeanDefinitionException이 발생한다. 그래서 동일한 타입이 존재하면 이름을 지정해 주어야 한다.


특정 타입의 모든 빈을 조회하려면 getBeansOfType() 메서드를 사용하면 된다. 반환 타입은 Map<이름, 객체>으로 반환된다.


📌 상속 관계 조회

상속 관계가 존재하는 경우에 조회하는 방법을 알아보자. 이 부분이 ‘중요’한 내용이다.

ApplicationContextExtendsFindTest 테스트 클래스를 생성하고, 아까와 마찬가지로 상속 관계가 포함된 구성 정보 클래스를 내부에 생성한다.


마찬가지로 이 구성 정보를 사용해 스프링 컨테이너를 생성한다.


DiscountPolicy의 자식 클래스가 두 개이기 때문에 NoUniqueBeanDefinitionException이 발생한다. 그래서 이름을 지정하거나, 자식 클래스의 타입으로 조회해야 한다.


getBeansOfType()을 사용해 부모 타입으로 조회하면 자식 클래스를 모두 조회할 수 있다.


지금까지 스프링 컨테이너의 생성 과정과 등록된 빈을 조회해 보았다. 실제로 빈을 직접 조회할 일은 거의 없지만 순수 자바 애플리케이션에서 스프링 컨테이너를 생성해 사용할 일이 있을 수 있기 때문에 조회하는 방법을 알아보았다. 또한 상속 관계에서 어떻게 조회되는지 알아야 나중에 자동 의존관계 주입 시 문제가 발생하면 잘 해결할 수 있다.

다음 시간에는 싱글톤 패턴에 대해 공부해 본다.

profile
좋은 개발자가 되자.

0개의 댓글