public class ConfigurationTest {
@Test
@DisplayName("Configuration의 default 구성 특징 테스트")
public void configuration() {
}
@Configuration
static class MyConfig {
@Bean
Common common() {
return new Common();
}
@Bean
Bean1 bean1() {
return new Bean1(common());
}
@Bean
Bean2 bean2() {
return new Bean2(common());
}
}
static class Bean1 {
private final Common common;
Bean1(Common common) {
this.common = common;
}
}
static class Bean2 {
private final Common common;
Bean2(Common common) {
this.common = common;
}
}
static class Common {
}
// Bean1 <-- Common
// Bean2 <-- Common
}
@Test
@DisplayName("Configuration의 default 구성 특징 테스트")
public void configuration() {
MyConfig myConfig = new MyConfig();
Bean1 bean1 = myConfig.bean1();
Bean2 bean2 = myConfig.bean2();
Assertions.assertThat(bean1.common).isSameAs(bean2.common); // 실패. 주고값이 다르기 때문에
}
@Test
@DisplayName("Configuration의 default 구성 특징 테스트")
public void configuration() {
// MyConfig를 Spring의 구성정보로 사용하면 동작방식이 달라짐
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
ac.register(MyConfig.class);
ac.refresh();
Bean1 bean1 = ac.getBean(Bean1.class);
Bean2 bean2 = ac.getBean(Bean2.class);
Assertions.assertThat(bean1.common).isSameAs(bean2.common); // 성공.
}
@Configuration(proxyBeanMethods = true)로 설정되어진 경우(기본값) MyConfig가 빈으로 등록 될 때 직접 등록되는 것이 아닌 Proxy 오브젝트를 앞에 두고 대리인이 빈으로 등록됨 → 스프링 내부에서 자동으로 일어남
static class MyConfigProxy extends MyConfig {
private Common common;
@Override
Common common() {
if (this.common == null) this.common = super.common();
return this.common;
}
}
직접 proxy를 만들어서 스프링 컨테이너 내부에서 일어나는 빈 등록과정 테스트 진행
@Test
@DisplayName("스프링 빈 동작방식 테스트")
public void proxyCommonMethod() {
MyConfigProxy myConfigProxy = new MyConfigProxy();// 확장해서 대체하는 방식으로 동작
Bean1 bean1 = myConfigProxy.bean1();
Bean2 bean2 = myConfigProxy.bean2();
Assertions.assertThat(bean1.common).isSameAs(bean2.common); // 성공
}
확장한 MyConfigProxy 오브젝트를 통해서 common 메서드가 생성하는 오브젝트의 개수를 하나로 제한하고 재사용 할 수 있도록 캐싱하는 방식으로 동작하게 만든 것