Framework/Spring Framework

[Spring] Spring Framework - 핵심 원리 (19) - 스프링 빈 조회 (상속 관계)

JB1104 2022. 1. 28. 00:24
728x90
반응형
SMALL

스프링 빈 조회 (상속관계)


 

스프링 빈 조회 - 상속 관계

  • 부모 타입으로 조회하면, 자식 타입도 함께 조회한다.
  • 그래서 모든 자바 객체의 최고 부모인 'Object'타입으로 조회하면, 모든 스프링 빈을 조회한다.

 

이 내용을 코드로 알아보자. 먼저 'ApplicationContextExtendsFindTest' 클래스를 만들자.

 

그리고 아래처럼 '@Configuration'을 하나 작성하자.

	public class ApplicationContextExtendsFindTest {
	AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(TestConfig.class);
    
    	@Configuration
	static class TestConfig{
		//빈의 이름이 다르지만, 객체 인스턴스 타입은 같을 수 있다.
		@Bean
		public DiscountPolicy rateDiscountPolicy() {
			return new RateDiscountPolicy();
		}
		@Bean
		public DiscountPolicy fixDiscountPolicy() {
			return new FixDiscountPolicy();
		}
	}
타입을 'DiscountPolicy'로 하는 이유
개발하거나 설계를 할 때, 역할구현을 항상 분리하자고 했었다. 'DiscountPolicy'을 보고 역할이 무엇인지 쉽게
알아내고, 다른 곳에서'DI'를 할 때도 더 편리하게 사용할 수 있기 때문이다. 

1. 부모 타입으로 조회 시, 자식이 둘 이상 있으면, 중복 오류가 발생하는 경우

'getBean()'으로 모든 클래스를 조회하면, 사용하려는 'DiscountPolicy'가 중복이 되기 때문에

'NoUniqueBeanDefinitionException'가 발생한다. 'assertThrows()'를 이용해서 테스트를 작성하자.

    	@Test
	@DisplayName("부모 타입으로 조회시, 자식이 둘 이상 있으면, 중복 오류가 발생한다.")
	void findBeanByParentTypeDuplicate() {
		//DiscountPolicy bean = ac.getBean(DiscountPolicy.class);
		org.junit.jupiter.api.Assertions.assertThrows(NoUniqueBeanDefinitionException.class, 
				()-> ac.getBean(DiscountPolicy.class));
	}

2. 부모 타입으로 조회 시, 자식이 둘 이상 있으면, 빈 이름을 지정하여 조회하는 방법

'getBean()' 안에 'Bean'의 이름을 지정해줘서 특정 타입을 조회할 수 있다.

	@Test
	@DisplayName("부모 타입으로 조회시, 자식이 둘 이상 있으면, 빈 이름을 지정하면 된다..")
	void findBeanByParentTypeBeanName() {
		DiscountPolicy rateDiscountPolicy = ac.getBean("rateDiscountPolicy" ,DiscountPolicy.class);
		Assertions.assertThat(rateDiscountPolicy).isInstanceOf(RateDiscountPolicy.class);
	}

3. 특정 하위 타입으로 조회하는 방법

좋지 않은 방법이지만, 이런 방법도 있다고 생각하고 알아보자.

'DiscountPolicy' 대신에 특정 'RateDiscountPolicy'를 지정해서 조회하는 방법이 있다. 

	@Test
	@DisplayName("특정 하위 타입으로 조회") // 물론 좋지 않은 방법
	void findBeanBySubType() {
		RateDiscountPolicy bean = ac.getBean(RateDiscountPolicy.class);
		Assertions.assertThat(bean).isInstanceOf(RateDiscountPolicy.class);
	}

4. 부모 타입으로 모두 조회하기

'getBeansOfType'를 사용해서 'Key : Value'로 조회하는 방법이다.

	@Test
	@DisplayName("부모 타입으로 모두 조회하기")
	void findAllBeanByParentType() {
		Map<String, DiscountPolicy> beansOfType = ac.getBeansOfType(DiscountPolicy.class);
		Assertions.assertThat(beansOfType.size()).isEqualTo(2);
		for(String key : beansOfType.keySet()) {
			System.out.println("key = " + key + "value = " + beansOfType.get(key));
		}
	}

5. 부모 타입으로 모두 조회하기 - Object

모든 객체가 'Object'타입의 자식이기 때문에 결과를 확인해보면 스프링이 내부적으로 쓰는 빈까지 조회된다.

 

조회의 기능을 거의 다 알아보았다. 사실, 'AppliContext'에서 'getBean'을 쓸 일이 거의 없다고 한다.

왜냐하면, ''스프링 컨테이너'가 자동으로 'DI'를 사용하는 방법을 사용하기 때문이다.


하지만, 가끔 '순수 Java Application'에서 컨테이너를 생성해서 쓸 일이 있기 때문에 알아두면 좋다고 한다.

	@Test
	@DisplayName("부모 타입으로 모두 조회하기 - Object")
	void findAllBeanObjectType() {
		Map<String,Object> beansOfType = ac.getBeansOfType(Object.class);
		for(String key : beansOfType.keySet()) {
			System.out.println("key = "+ key + "Value = " + beansOfType.keySet());
		}
	}
더보기

key = org.springframework.context.annotation.internalConfigurationAnnotationProcessorValue = [org.springframework.context.annotation.internalConfigurationAnnotationProcessor, org.springframework.context.annotation.internalAutowiredAnnotationProcessor, org.springframework.context.annotation.internalCommonAnnotationProcessor, org.springframework.context.event.internalEventListenerProcessor, org.springframework.context.event.internalEventListenerFactory, applicationContextExtendsFindTest.TestConfig, rateDiscountPolicy, fixDiscountPolicy, environment, systemProperties, systemEnvironment, applicationStartup, org.springframework.context.annotation.ConfigurationClassPostProcessor.importRegistry, messageSource, applicationEventMulticaster, lifecycleProcessor]
key = org.springframework.context.annotation.internalAutowiredAnnotationProcessorValue = [org.springframework.context.annotation.internalConfigurationAnnotationProcessor, org.springframework.context.annotation.internalAutowiredAnnotationProcessor, org.springframework.context.annotation.internalCommonAnnotationProcessor, org.springframework.context.event.internalEventListenerProcessor, org.springframework.context.event.internalEventListenerFactory, applicationContextExtendsFindTest.TestConfig, rateDiscountPolicy, fixDiscountPolicy, environment, systemProperties, systemEnvironment, applicationStartup, org.springframework.context.annotation.ConfigurationClassPostProcessor.importRegistry, messageSource, applicationEventMulticaster, lifecycleProcessor]
key = org.springframework.context.annotation.internalCommonAnnotationProcessorValue = [org.springframework.context.annotation.internalConfigurationAnnotationProcessor, org.springframework.context.annotation.internalAutowiredAnnotationProcessor, org.springframework.context.annotation.internalCommonAnnotationProcessor, org.springframework.context.event.internalEventListenerProcessor, org.springframework.context.event.internalEventListenerFactory, applicationContextExtendsFindTest.TestConfig, rateDiscountPolicy, fixDiscountPolicy, environment, systemProperties, systemEnvironment, applicationStartup, org.springframework.context.annotation.ConfigurationClassPostProcessor.importRegistry, messageSource, applicationEventMulticaster, lifecycleProcessor]
key = org.springframework.context.event.internalEventListenerProcessorValue = [org.springframework.context.annotation.internalConfigurationAnnotationProcessor, org.springframework.context.annotation.internalAutowiredAnnotationProcessor, org.springframework.context.annotation.internalCommonAnnotationProcessor, org.springframework.context.event.internalEventListenerProcessor, org.springframework.context.event.internalEventListenerFactory, applicationContextExtendsFindTest.TestConfig, rateDiscountPolicy, fixDiscountPolicy, environment, systemProperties, systemEnvironment, applicationStartup, org.springframework.context.annotation.ConfigurationClassPostProcessor.importRegistry, messageSource, applicationEventMulticaster, lifecycleProcessor]
key = org.springframework.context.event.internalEventListenerFactoryValue = [org.springframework.context.annotation.internalConfigurationAnnotationProcessor, org.springframework.context.annotation.internalAutowiredAnnotationProcessor, org.springframework.context.annotation.internalCommonAnnotationProcessor, org.springframework.context.event.internalEventListenerProcessor, org.springframework.context.event.internalEventListenerFactory, applicationContextExtendsFindTest.TestConfig, rateDiscountPolicy, fixDiscountPolicy, environment, systemProperties, systemEnvironment, applicationStartup, org.springframework.context.annotation.ConfigurationClassPostProcessor.importRegistry, messageSource, applicationEventMulticaster, lifecycleProcessor]
key = applicationContextExtendsFindTest.TestConfigValue = [org.springframework.context.annotation.internalConfigurationAnnotationProcessor, org.springframework.context.annotation.internalAutowiredAnnotationProcessor, org.springframework.context.annotation.internalCommonAnnotationProcessor, org.springframework.context.event.internalEventListenerProcessor, org.springframework.context.event.internalEventListenerFactory, applicationContextExtendsFindTest.TestConfig, rateDiscountPolicy, fixDiscountPolicy, environment, systemProperties, systemEnvironment, applicationStartup, org.springframework.context.annotation.ConfigurationClassPostProcessor.importRegistry, messageSource, applicationEventMulticaster, lifecycleProcessor]
key = rateDiscountPolicyValue = [org.springframework.context.annotation.internalConfigurationAnnotationProcessor, org.springframework.context.annotation.internalAutowiredAnnotationProcessor, org.springframework.context.annotation.internalCommonAnnotationProcessor, org.springframework.context.event.internalEventListenerProcessor, org.springframework.context.event.internalEventListenerFactory, applicationContextExtendsFindTest.TestConfig, rateDiscountPolicy, fixDiscountPolicy, environment, systemProperties, systemEnvironment, applicationStartup, org.springframework.context.annotation.ConfigurationClassPostProcessor.importRegistry, messageSource, applicationEventMulticaster, lifecycleProcessor]
key = fixDiscountPolicyValue = [org.springframework.context.annotation.internalConfigurationAnnotationProcessor, org.springframework.context.annotation.internalAutowiredAnnotationProcessor, org.springframework.context.annotation.internalCommonAnnotationProcessor, org.springframework.context.event.internalEventListenerProcessor, org.springframework.context.event.internalEventListenerFactory, applicationContextExtendsFindTest.TestConfig, rateDiscountPolicy, fixDiscountPolicy, environment, systemProperties, systemEnvironment, applicationStartup, org.springframework.context.annotation.ConfigurationClassPostProcessor.importRegistry, messageSource, applicationEventMulticaster, lifecycleProcessor]
key = environmentValue = [org.springframework.context.annotation.internalConfigurationAnnotationProcessor, org.springframework.context.annotation.internalAutowiredAnnotationProcessor, org.springframework.context.annotation.internalCommonAnnotationProcessor, org.springframework.context.event.internalEventListenerProcessor, org.springframework.context.event.internalEventListenerFactory, applicationContextExtendsFindTest.TestConfig, rateDiscountPolicy, fixDiscountPolicy, environment, systemProperties, systemEnvironment, applicationStartup, org.springframework.context.annotation.ConfigurationClassPostProcessor.importRegistry, messageSource, applicationEventMulticaster, lifecycleProcessor]
key = systemPropertiesValue = [org.springframework.context.annotation.internalConfigurationAnnotationProcessor, org.springframework.context.annotation.internalAutowiredAnnotationProcessor, org.springframework.context.annotation.internalCommonAnnotationProcessor, org.springframework.context.event.internalEventListenerProcessor, org.springframework.context.event.internalEventListenerFactory, applicationContextExtendsFindTest.TestConfig, rateDiscountPolicy, fixDiscountPolicy, environment, systemProperties, systemEnvironment, applicationStartup, org.springframework.context.annotation.ConfigurationClassPostProcessor.importRegistry, messageSource, applicationEventMulticaster, lifecycleProcessor]
key = systemEnvironmentValue = [org.springframework.context.annotation.internalConfigurationAnnotationProcessor, org.springframework.context.annotation.internalAutowiredAnnotationProcessor, org.springframework.context.annotation.internalCommonAnnotationProcessor, org.springframework.context.event.internalEventListenerProcessor, org.springframework.context.event.internalEventListenerFactory, applicationContextExtendsFindTest.TestConfig, rateDiscountPolicy, fixDiscountPolicy, environment, systemProperties, systemEnvironment, applicationStartup, org.springframework.context.annotation.ConfigurationClassPostProcessor.importRegistry, messageSource, applicationEventMulticaster, lifecycleProcessor]
key = applicationStartupValue = [org.springframework.context.annotation.internalConfigurationAnnotationProcessor, org.springframework.context.annotation.internalAutowiredAnnotationProcessor, org.springframework.context.annotation.internalCommonAnnotationProcessor, org.springframework.context.event.internalEventListenerProcessor, org.springframework.context.event.internalEventListenerFactory, applicationContextExtendsFindTest.TestConfig, rateDiscountPolicy, fixDiscountPolicy, environment, systemProperties, systemEnvironment, applicationStartup, org.springframework.context.annotation.ConfigurationClassPostProcessor.importRegistry, messageSource, applicationEventMulticaster, lifecycleProcessor]
key = org.springframework.context.annotation.ConfigurationClassPostProcessor.importRegistryValue = [org.springframework.context.annotation.internalConfigurationAnnotationProcessor, org.springframework.context.annotation.internalAutowiredAnnotationProcessor, org.springframework.context.annotation.internalCommonAnnotationProcessor, org.springframework.context.event.internalEventListenerProcessor, org.springframework.context.event.internalEventListenerFactory, applicationContextExtendsFindTest.TestConfig, rateDiscountPolicy, fixDiscountPolicy, environment, systemProperties, systemEnvironment, applicationStartup, org.springframework.context.annotation.ConfigurationClassPostProcessor.importRegistry, messageSource, applicationEventMulticaster, lifecycleProcessor]
key = messageSourceValue = [org.springframework.context.annotation.internalConfigurationAnnotationProcessor, org.springframework.context.annotation.internalAutowiredAnnotationProcessor, org.springframework.context.annotation.internalCommonAnnotationProcessor, org.springframework.context.event.internalEventListenerProcessor, org.springframework.context.event.internalEventListenerFactory, applicationContextExtendsFindTest.TestConfig, rateDiscountPolicy, fixDiscountPolicy, environment, systemProperties, systemEnvironment, applicationStartup, org.springframework.context.annotation.ConfigurationClassPostProcessor.importRegistry, messageSource, applicationEventMulticaster, lifecycleProcessor]
key = applicationEventMulticasterValue = [org.springframework.context.annotation.internalConfigurationAnnotationProcessor, org.springframework.context.annotation.internalAutowiredAnnotationProcessor, org.springframework.context.annotation.internalCommonAnnotationProcessor, org.springframework.context.event.internalEventListenerProcessor, org.springframework.context.event.internalEventListenerFactory, applicationContextExtendsFindTest.TestConfig, rateDiscountPolicy, fixDiscountPolicy, environment, systemProperties, systemEnvironment, applicationStartup, org.springframework.context.annotation.ConfigurationClassPostProcessor.importRegistry, messageSource, applicationEventMulticaster, lifecycleProcessor]
key = lifecycleProcessorValue = [org.springframework.context.annotation.internalConfigurationAnnotationProcessor, org.springframework.context.annotation.internalAutowiredAnnotationProcessor, org.springframework.context.annotation.internalCommonAnnotationProcessor, org.springframework.context.event.internalEventListenerProcessor, org.springframework.context.event.internalEventListenerFactory, applicationContextExtendsFindTest.TestConfig, rateDiscountPolicy, fixDiscountPolicy, environment, systemProperties, systemEnvironment, applicationStartup, org.springframework.context.annotation.ConfigurationClassPostProcessor.importRegistry, messageSource, applicationEventMulticaster, lifecycleProcessor]

 

결과

 

 

참고로 출력하는 것은, 테스트를 위해서 '출력(println)'을 하는 것이다.
실제로 '테스트 코드'를 짤 때는 출력물을 남기면 안 된다.
왜냐면, 시스템이 자동 통과를 시스템이 결정하게 해야 한다. 즉, 눈으로 다 보고 있을 수 없기 때문이다.
실무에서는 테스트를 통과한다 안 한다로만, 평가할 수 있게끔만 코드를 짜야한다고 한다.
728x90
반응형
LIST