빈의 스코프
싱글턴
애플리케이션 전반에 걸쳐 빈의 인스턴스가 오직 하나 뿐인 것을 말한다.
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}@Component
public class AppRunner implements ApplicationRunner {
@Autowired
Single single;
@Autowired
Proto proto;
@Override
public void run(ApplicationArguments args) throws Exception {
// AppRunner가 불러오는 proto
System.out.println(proto);
// Single이 불러오는 proto
System.out.println(single.getProto());
}
}주입 받은 proto와 single 객체에서 불러온 proto의 주소가 같은 것을 확인할 수 있다.
프로토타입
매번 새로운 인스턴스를 생성하는 것이다.
Request
Session
WebSocket
Proto에 Scope을 prototype으로 정의해놓으면
이렇게 서로 다른 주소값이 나오게 된다.
여러 번을 시도해도 역시 같은 결과를 가져온다.
프로토타입 빈이 싱글턴 빈을 참조하는 경우
프로토타입 빈은 항상 새롭지만 안에서 참조하는 싱글턴 빈은 항상 동일하므로 아무 문제가 없다.
싱글턴 빈이 프로토타입 빈을 참조하는 경우
싱글턴 빈은 한 번만 만들어지므로 이미 프로토타입의 빈이 이미 세팅된 상태다.
따라서 프로토타입 빈이 변경되지 않는다.
코드로 테스트 해보니 역시 프로토타입임에도 같은 주소값을 출력한다.
해결법
프록시 모드를 설정하면 된다. 기본은 DEFAULT(프록시 모드 사용 안 함)으로 되어있다.
매번 새로운 인스턴스가 만들어짐을 확인할 수 있다.
TARGET_CLASS클래스 기반의 프록시로 빈(
Proto)를 감싸라고 설정하는 것프록시를 쓰지 않으면 직접 참조하므로 프로토타입을 생성할 때마다 새로 바꿔 줄 여지가 없다.
프록시를 거쳐서 참조하도록 하면 매번 바꿔서 참조할 수 있다.
원래 자바 안에 있는 다이내믹 프록시는 인터페이스의 프록시만 만들 수 있다.
CG LIB(Code Generator Library라는 서드 파티 라이브러가TARGET_CLASS설정을 보고 클래스도 만들 수 있도록 한다.만약 인터페이스였다면
INTERFACES로 설정해서 인터페이스 기반의 프록시를 썼을 것이다.
프록시 빈도 프로토타입의 빈을 상속해서 만들었기 때문에 해당 빈과 타입(여기서는
Proto타입)은 같다.따라서 의존성 주입이 가능한 것이다.
Reference
싱글턴 객체 사용 시 주의할 점
프로퍼티에 담긴 값이 안정적일 것이라고, thread-safe 할 것이라고 생각해서는 안 된다.
싱글턴 객체는 ApplicationContext를 만들 때 인스턴스를 생성하게 되어 있다.
따라서 애플리케이션 구동에 시간이 걸릴 수 있다.
Last updated
Was this helpful?