스프링 핵심 원리 - 기본편 # Section 9

2024. 7. 6. 17:59Spring/스프링 핵심 원리 - 기본편

반응형

❓ 빈 스코프

스프링의 다양한 스코프

  • 싱글톤 : 기본 스코프, 스프링 컨테이너의 시작과 종료까지 유지되는 가장 넓은 범위의 스코프
  • 프로토타입 : 프로토타입 빈의 생성과 의존관계 주입까지만 관여하는 스코프
  • 웹 관련 스코프
    • request : 웹 요청이 들어오고 나갈때 까지 유지됨
    • session : 웹 세션이 생성되고 종료될 때 까지 유지 됨
    • application : 웹의 서블릿 컨텍스트와 같은 범위로 유지 됨

❓ 프로토타입 빈

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

프로토타입 빈 요청 1

 

프로토타입 빈 요청 2

핵심은 프로토타입 빈을 생성하고, 의존관계 주입, 초기화까지만 처리한다는 것.

이후엔 프로토타입 빈을 관리하지 않음 따라서 @PreDestroy 같은 종료 메서드를 호출 하지 않음

 


❓ 웹 스코프

  • 웹 환경에서만 동작한다
  • 웹 스코프는 프로토타입과 다르게 스프링이 해당 스코프의 종료시점까지 관리함 따라서 종료 메서드가 실행 됨

 

웹 스코프 종류

  • request : HTTP 요청 하나가 들어오고 나갈 때 가지 유지되는 스코프
  • session : HTTP Session 과 동일한 생명주기를 가짐
  • application : 서블릿 컨텍스트 (ServletContext) 와 동일한 생명주기를 가짐
  • websocket : 웹 소켓과 동일한 생명주기를 가짐

request 스코프 빈 만들기

@Component
// 스코프를 request 로 지정
@Scope(value = "request")
public class MyLogger2 {

    private String uuid;
    private String requestUrl;

    public void setRequestUrl(String requestUrl) {
        this.requestUrl = requestUrl;
    }

    public void log(String message) {
        System.out.println("[" + uuid + "]" + "[" + requestUrl + "] " + message);
    }

    @PostConstruct
    public void init() {
        uuid = UUID.randomUUID().toString();
        System.out.println("[" + uuid + "] request scope bean create:" + this);
    }

    @PreDestroy
    public void close() {
        System.out.println("[" + uuid + "] request scope bean close:" + this);
    }
}
  • @Scope(value = "request") 를 사용해서 request 스코프로 지정
  • 이 빈은 HTTP 요청 당 하나씩 생성되고, HTTP 요청이 끝나는 시점에 소멸 됨

❓ 스코프와 Provider, 프록시

위 예제 처럼 request 스코프로 지정 된 빈은 요청이 와야 생성이 된다.

요청이 오기전에 service 단에서 사용하려고 하면 오류가 발생하는데 해당 부분을 해결 할 수 있는 방법이 있다.

1. Provider 사용

@Service
@RequiredArgsConstructor
public class LogDemoService {
	private final ObjectProvider<MyLogger> myLoggerProvider;
    
	public void logic(String id) {
		MyLogger myLogger = myLoggerProvider.getObject();
		myLogger.log("service id = " + id);
	}
}
  • ObjectProvider 덕분에 호출하는 시점까지 request scope 빈의 생성을 지연 할 수 있다.

2. 프록시

@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class MyLogger {}
  • proxyMode = ScopedProxyMode.TARGET_CLASS
    • 적용 대상이 인터페이스가 아닌 클래스면 TARGET_CLASS
    • 인터페이스면 INTERFACES 를 선택
  • 이렇게 하면 MyLogger의 가짝 프록시 클래스를 만들고 다른 빈에 미리 주입해 둘 수 있다.

웹 스코프와 프록시 동작 원리

동작 정리

  • CGLIB 라는 라이브러리로 내 클래스를 상속 받은 가짜 프록시 객체를 만들어서 주입
  • 이 가짜 프록시 객체는 실제 요청이 오면 그때 내부에서 실제 빈을 요청하는 위임 로직이 있음
  • 가짜 프록시 객체는 실제 request scope 와는 관계 없다.

특징 정리

  • 프록시 객체 덕분에 클라이언트는 마치 싱글톤 빈을 사용하듯이 편리하게 requeset scope 를 사용 할 수 있음
  • 진짜 객체 조회를 꼭 필요한 시점까지 지연처리 한다는 점

 

 

 

강의 출처

김영한의 스프링 로드맵 - 스프링 핵심원리 기본편

 

반응형