학습테스트를 해보겠습니다.
남이 만들 코드의 동작방식을 이해하기 위해 테스트를 작성하는것을 말합니다.
기술을 정확하게 익히기 위해 사용합니다
Configuration클래스는 Bean메소드를 많이 가지고 있다는 것입니다.
팩토리 메서드의 기능을 생각하면 됩니다.
하지만 이것이 생각보다 간단하지 않습니다.
팩토리 메서드는 싱글톤을 보장해주지 못하기 때문입니다.
스프링 Bean
은 싱글톤
을 보장해 줍니다.
하지만 자바 코드
로 팩토리 메서드를 만들면, 싱글톤이 보장되지 않습니다.
public class ConfigurationTest {
@Test
void configuration() {
MyConfig myConfig = new MyConfig();
Bean1 bean1 = myConfig.bean1();
Bean2 bean2 = myConfig.bean2();
Assertions.assertThat(bean1).isSameAs(bean2);
}
@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;
public Bean1(Common common) {
this.common = common;
}
}
static class Bean2 {
private final Common common;
public Bean2(Common common) {
this.common = common;
}
}
static class Common {
}
}
스프링의 도움이 없이 팩토리 메서드의 흉내를 낸다면 싱글톤을 보장하지 않습니다.
스프링 컨테이너를 사용하면 자바코드와는 달리 싱글톤을 보장합니다.
내부적으로는프록시 오브제트
가 하나 등록이 되고 그것이 Bean으로 등록됩니다.
public class ConfigurationTest {
@Test
void configuration() {
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
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;
public Bean1(Common common) {
this.common = common;
}
}
static class Bean2 {
private final Common common;
public Bean2(Common common) {
this.common = common;
}
}
static class Common {
}
}
스프링이 어떻게 싱글톤을 보장할 수 있을까요??
바로 프록시 패턴의 역할을 하는 @Configuration의 proxyBeanMethods 때문입니다.
클래스를 확장하는 방식으로 만들어, 클래스 앞에서 객체를 필드값으로 저장하여 반환하기때문에
싱글톤
을 흉내낼 수 있습니다.
스프링은 내부적으로proxyBeanMethods
를 True로 설정하고 있습니다.
@Test
void proxyCommonMethod() {
MyConfigProxy myConfigProxy = new MyConfigProxy();
Bean1 bean1 = myConfigProxy.bean1();
Bean2 bean2 = myConfigProxy.bean2();
Assertions.assertThat(bean1.common).isSameAs(bean2.common);
}
static class MyConfigProxy extends MyConfig {
private Common common;
@Override
Common common() {
if (this.common == null) this.common = super.common();
return this.common;
}
}
프록시 오브젝트가 Common메서드가 생성하는 오브젝트의 개수를 제한함으로써 싱글톤을 흉내내었습니다.
Configuration가 기본
proxyBeanMethods=True
인것은
스프링 컨테이너가싱글톤
으로 객체를 띄우기 위해 프록시 패턴을 사용한다는 뜻입니다.
proxyBeanMethods=False
라면, Bean들은 더이상 싱글톤이 아닙니다!
자바로 팩토리 메서드를 구현할때와,
스프링 컨테이너로 등록한 팩토리 메서드는 다르게 작동한다는 것입니다!!
내부적으로 프록시 패턴이 적용되기 떄문입니다!