[Spring] 스프링 프록시 설정을 이용하여 프로토타입 빈 업데이트하기(Spring Proxy Configuration)

| 스프링 빈 스코프 설정 (Spring Bean Scope Configuration)


스프링 빈(Spring Bean)은 생존주기를 가지고 있으며 또한 스프링 컨테이너에서 관리하는 스프링 빈이 어떤 범위로 관리될 것인지를 설정할 수 있다. 관리 형태는 싱글턴 스코프 혹은 프로토타입 스코프 둘 중 하나다. 대부분의 경우 싱글턴 형태로 빈을 관리하게 되지만 Request, Session, WebSocket 같은 하나하나의 객체를 생성해야만 할 때는 프로토타입 스코프를 쓴다.


어노테이션을 통해서 스프링 빈의 범위를 설정하는 방법은 다음과 같다. 

@Component
@Scope("singleton")
public class Single {

}
@Component
@Scope("prototype")
public class Proto {

}

참고로 @Scope를 설정하지 않을 시 default로 해당 빈을 싱글턴 스코프로 지정한다.


스프링 부트(Spring Boot)ApplicationRunner를 상속한 AppRunner 클래스를 작성하여 해당 클래스들이 컨테이너에서 어떻게 관리되는 지 확인하는 코드는 다음과 같다. 

@Component
public class AppRunner implements ApplicationRunner {

@Autowired
ApplicationContext ctx;

@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("proto");
System.out.println(ctx.getBean(Proto.class));
System.out.println(ctx.getBean(Proto.class));
System.out.println(ctx.getBean(Proto.class));

System.out.println("single");
System.out.println(ctx.getBean(Single.class));
System.out.println(ctx.getBean(Single.class));
System.out.println(ctx.getBean(Single.class));
}
}
proto
com.saelobi.springtutorial.Proto@5987e932
com.saelobi.springtutorial.Proto@1ad777f
com.saelobi.springtutorial.Proto@5bbbdd4b
single
com.saelobi.springtutorial.Single@438bad7c
com.saelobi.springtutorial.Single@438bad7c
com.saelobi.springtutorial.Single@438bad7c

프로토타입 스코프로 관리되는 스프링 빈은 컨테이너에서 해당 빈을 가져올 때마다 다른 객체가 생성된다. 싱글턴 스코프로 관리되는 빈은 오직 하나의 객체가 생성되어 쓰여진다.



| 스프링 프록시 설정을 이용하여 프로토타입 빈 업데이트 하기(Spring Proxy Configuration)


프로토타입 스코프를 가지는 빈이 싱글턴 스코프를 가지는 빈을 참조하는 경우는 문제가 될 것이 없다. 왜냐하면 단 하나의 인스턴스를 가지는 빈을 참조해서 쓰기 때문이다. 하지만 그 반대의 경우는 문제가 된다. 싱글턴 스코프를 가지는 빈이 프로토 타입 스코프를 가지는 빈을 참조할 경우 프로토 타입 스코프를 가지는 빈은 이미 싱글턴 스코프 빈이 컨테이너에 의해 생성될 시에 주입되어 같은 프로토 타입 빈 객체를 가르키게 되기 때문이다.


@Component
@Scope("singleton")
public class Single {

@Autowired
Proto proto;

public Proto getProto() {
return this.proto;
}
}
@Component
public class AppRunner implements ApplicationRunner {

@Autowired
ApplicationContext ctx;

@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("proto type by singleton");
System.out.println(ctx.getBean(Single.class).getProto());
System.out.println(ctx.getBean(Single.class).getProto());
System.out.println(ctx.getBean(Single.class).getProto());
}
}
proto type by singleton
com.saelobi.springtutorial.Proto@1556f2dd
com.saelobi.springtutorial.Proto@1556f2dd
com.saelobi.springtutorial.Proto@1556f2dd

이렇게 되면 프로토타입 스코프를 가지는 빈을 참조하는 의미가 없어지게 된다. 왜냐하면 프로토타입 스코프를 가지는 빈을 만드는 이유는 이 빈 객체를 참조할 때 새롭게 생성되는 객체를 참조하기 위해서기 때문이다. 하지만 Single 클래스를 통해 만들어진 빈은 단 하나의 Proto 인스턴스를 참조할 뿐이다.


의도한대로 동작하기 위해 쓰는 방법은 @Scope 어노테이션에 프록시 설정을 하여 해당 프로토타입 빈을 감싸는 프록시 객체를 반환하는 것이다.

@Component
@Scope(value="prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class Proto {
}

proto type by singleton
com.saelobi.springtutorial.Proto@62b3df3a
com.saelobi.springtutorial.Proto@420745d7
com.saelobi.springtutorial.Proto@7e11ab3d

proxyMode = ScopedProxyMode.TARGET_CLASS 를 명시하면 Proto 객체를 참조하는 객체들이 직접 Proto 객체를 참조하는 것이 아닌 프록시로 감싼 프록시 인스턴스를 참조하게 된다. 따라서 프로토타입 객체를 참조할 때마다 다른 프록시 객체를 만들기 때문에 다른 인스턴스를 참조하게 되는 것이다.



이 글을 공유하기

댓글(0)

Designed by JB FACTORY