빈스코프에는 싱글톤 스코프, 프로토타입 스코프, 그리고 웹 스코프(Requset,Session,Application) 등이 존재합니다.
싱글톤 스코프는 스프링 컨테이너가 시작할 때 생성되어, 종료될때까지 유지되는 스코프이고,
프로토타입 스코프는 호출시마다 새로 생성되고, 의존관계주입, 초기화 메소드 실행 이후 스프링 컨테이너가 관리하지 않게되는 그러한 스코프입니다.
이번에는 웹 스코프에 대해 정리해 보려고 합니다.
(조금 긴) 내용 요약 미리보기
request 스코프는 HTTP 요청이 들어온 이후 유지되기 때문에 스프링 컨테이너에서 빈을 생성하고 의존관계를 주입할 때 에러가 발생합니다.
이러한 문제를 해결하는 방법에는 1. Provider 사용,2. 프록시 사용 등이 있습니다.
@Scope 에 설정 변수로
proxymode =
TARGET_CLASS
나INTERFACES
로 프록시 지정 가능합니다.프록시 설정을 하면 CGLIB 라이브러리가 원본객체를 상속받은 가자 프록시 객체를 생성하여 빈에 주입해줍니다.
가짜 프록시 객체 내부에는 실제 빈을 요청하는 위임 로직이 들어있습니다.
가짜 프록시 객체는 원본의 request 스코프와는 관계가 없고 단순한 위임 로직만 존재하며 싱글톤 처럼 동작합니다.
Provider를 사용하거나, 프록시를 사용해도 중요한 것은 진짜 객체 조회를 실제 메소드가 호출되는 지점까지 지연 처리가 가능하다는 점 입니다
클라이언트는 프록시 인지 원본 객체인지 상관 없이 메소드를 호출할 수 있습니다. (다형성의 장점)
프록시는 웹 스코프가 아니어도 사용할 수 있습니다.
❗️ 주의
생성할 때 주입도 가능하고 마치 싱글톤을 사용하는것 같지만 다르게 동작하기에 주의해야 합니다.
이러한 여러가지 빈 스코프들은 꼭 필요한곳에서만 사용해야 이후에 유지보수 하기에 어렵지 않습니다.
웹 스코프의 종류
- request: HTTP 요청 하나가 들어오면 시작하고 나갈때까지 유지되는 스코프 각각의 HTTP마다 별도의 객체 인스턴스턴스가 생성되고 관리된다.
- session: HTTP Session과 동이한 생명주기를 가짐.
- application: 서블릿 컨텍스트와 동일한 생명주기를 가짐
- websocket: 웹 소켓과 동일한 생명주기를 가짐
웹 스코프들은 스코프의 범위만 다르고 동작 방식은 비슷합니다. 이러한 여러가지의 웹 스코프 중 request 에 대해 다뤄보려 합니다.
💡 request 스코프는 HTTP 요청이 오고 나감에 그 범위가 정해져있기 때문에
spring-boot-starter-web
라이브러리를 추가하여 웹 애플리케이션 환경에서 테스트 해 보아야 합니다.
동시에 여러 HTTP 요청이 온다면 어떤 요청이 남긴 로그인지 구분하기 어렵습니다.
이럴 경우 request 스코프를 사용하게 된다면 좋습니다.
requset 스코프의 경우 HTTP 요청 이후 유지되기 때문에 스프링 빈에 그냥 의존관계 주입을 하게 된다면 아직은 스코프 범위 밖이기에 에러가 발생합니다.
이러한 문제를 해결하기 위해서 두가지 방법이 존재합니다.
첫번째는 이전에 배웠던 Provider를 사용하는 것이고
두번째는 프록시를 사용하는 것입니다.
이번에는 프록시를 사용하는 것을 정리해 보려고 합니다.
scope에는 proxyMode 라는 설정 정보가 있어
클래스인 경우 ScopedProxyMode.TARGET_CLASS
,인터페이스인 경우 ScopedProxyMode.INTERFACES
로 설정 가능합니다.
클래스를 프록시로 만들어 둔다면 HTTP request 와 상관없이 빈에 바로 주입이 가능합니다.
이전에 @Configuration 에서 한번 언급했었던 CGLIB 라이브러리가 request스코프 클래스를 상속받은 가짜 프록시 객체를 만들어 주입하기 때문에 주입이 가능해 집니다.
System.out.println("myLogger = " + myLogger.getClass());
ac.getBean(MyLogger.class);
해당 클래스의 클래스 정보를 출력해보거나, getBean() 으로 빈을 조회해 본다면 이러한 가짜 프록시 객체가 조회됩니다.
myLogger = class hello.core.common.MyLogger$$SpringCGLIB$$0
가짜 프록시 객체는 요청이 오면 내부에서 실제 빈에게 요청하는 위임 로직이 들어있습니다.
클라이언트는 진짜 빈의 메소드를 호출한다고 생각하고 사용하겠지만 실제로는 프록시의 메소드를 호출하고 있는 것이고, 가짜 프록시 객체는 request 스코프의 진짜 메소드를 호출하게 됩니다.
클라이언트 입장에서는 진짜인지 프록시인지 상관없이 동일하게 사용 가능합니다.
proxymode =
TARGET_CLASS
나 INTERFACES
로 프록시 지정 가능합니다.참고