스프링 컨테이너
AppConfig를 생성하고 main 메서드에서 아래 코드를 작성하였다. 코드의 역할은 스프링 컨테이너 생성이다.
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
컨테이너 안에는 AppConfig에서 @Bean으로 설정해둔 빈 들이 있다. ApplicationContext는 인터페이스이다. AnnotationConfigApplicationcontext는 자바 코드로 작성한 config를 사용하기 위한 구체 클래스이다. (config는 xml로도 작성될 수 도 있고 본인이 작성한 파일을 등록할 수도 있다.) AppConfig.class는 우리가 작성한 파일을 명시해준다. 위의 코드가 실행되면 스프링 컨테이너가 생성되고 AppConfig에 작성한 메서드 명이 빈의 이름, return에 작성한 구체화 클래스가 빈의 객체로 등록된다. 빈의 이름은 중복되면 오류가 발생하거나 기존 빈이 무시된다. 빈 이름은 따로 변경할 수 있으며 기억해야 할 것은 빈 이름은 중복되면 안.된.다.
ApplicationContext는 BeanFactory 인터페이스를 상속한 인터페이스이다. getBean 등 빈을 조회하고 관리하는 기능은 BeanFactory에 모두 포함되어 있다. 그럼에도 ApplicationContext를 사용하는 이유는 애플리케이션을 개발할 때 필요한 부가 기능이 추가되어 있기 때문이다. BeanFactory를 직접 사용할 상황은 거의 없다. 그래서 우리가 부르는 스프링 컨테이너는 일반적으로 ApplicationContext라 생각하면 된다.
스프링 빈 조회
컨테이너에 등록한 빈들을 조회하는 코드를 보면서 유의 사항을 알아보겠다. (getBean을 사용해서 조회는 실무에서 잘 쓰이지 않는다고 한다. 이런 기능이 있다는 정도로 알아두자.)
모든 컨테이너 생성 후 진행하였다. ac는 컨테이너를 호출한 변수이다.
MemberService memberService = ac.getBean("memberService", MemberService.class);
assertThat(memberService).isInstanceOf((MemberServiceImpl.class));
getbean의 매개 변수로는 위의 코드처럼 빈의 이름, 타입으로 작성한다. 타입으로만 조회할 수도 있다. 이름으로만 조회할 시 해당 빈의 타입이 명시되어있지 않으므로 타입을 Object로 받아야 한다.
타입을 MemberServiceImpl로 작성해도 테스트는 정상 작동한다. 하지만 우리는 구체화가 아닌 추상화에 의존해야 한다. (이유는? 구체 클래스가 바뀌면 코드 수정을 테스트 케이스도 해주어야 한다.)
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
getBeanDefinitionNames()는 컨테이너에 등록된 모든 빈의 이름을 반환한다. 컨테이너에는 우리가 등록한 빈 말고도 스프링이 스스로 등록해둔 빈이 다수 존재한다. 출력할 때 그것들을 분리해서 출력하는 기능이 있다. 아래 코드를 참고 하자.
(.getBeanDefinition()은 빈 설정 메타 정보를 보여준다. 메타 정보에는 빈의 설정 값이 포함되어 있다고 생각하자. )
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
BeanDefinition beanDefinition = ac.getBeanDefinition(beanDefinitionName);
//Role ROLE_APPLICATION : 직접 등록한 애플리케이션 빈
//Role ROLE_INFRASTRUCTURE : 스프링이 내부에서 사용하는 빈
if (beanDefinition.getRole() == BeanDefinition.ROLE_APPLICATION) {
Object bean = ac.getBean(beanDefinitionName);
System.out.println("name = " + beanDefinitionName + " object = " + bean);
}
.getBean()을 타입으로만 조회할 때 자식이 둘 이상 있거나(상속 관계), 해당 타입이 두 개 이상 있을 경우 오류가 발생한다. 그럴 경우 빈 이름을 지정해서 호출하거나 . getBeansOfType('타입')을 사용하여 특정 타입을 모두 조회하는 방법이 있다. 이 경우 Map 형태로 반환된다.
Map<String, MemberRepository> beansOfType = ac.getBeansOfType(MemberRepository.class);
상속 관계에서도 이와 같은 경우가 발생하는 이유는 부모 타입으로 조회하면 모든 자식 타입도 같이 조회되기 때문이다. (모든 자바 객체의 부모 클래스인 Object 타입으로 조회하면 모든 스프링 빈을 조회할 수 있다.)
'Spring' 카테고리의 다른 글
[Spring] @ComponentScan & @Autowired (의존관계 자동 주입) (1) | 2022.07.26 |
---|---|
[Spring] 싱글톤 컨테이너 (1) | 2022.07.23 |
[Spring] AppConfig (0) | 2022.07.16 |
[Spring] Test (0) | 2022.07.16 |
[Spring] 객체지향 기본 개념 (0) | 2022.07.12 |