본문 바로가기
웹 개발/Java Spring

빈 스코프(Bean Scope), 프록시(Proxy)

by 동배_ 2021. 8. 11.

빈 스코프란 무엇일까?

 스프링 빈은 기본적으로 스프링 컨테이너가 생성될때 같이 생성되면서 컨테이너가 종료될때까지 유지되는 구조이다. 하지만 이는 스프링 빈의 기본이 싱글톤(Singleton)스코프로 생성되기 때문이다. 이때 스코프란 말 그대로 빈이 존재할 수 있는 범위를 뜻한다.

 

스프링은 다양한 스코프를 지원한다. 

싱글톤, 프로토타입, 웹관련스코프(request, session, application.,websocket) 정도의 스코프가 있다. 그 중 싱글톤은 스프링을 접하면서 가장 많이 써보고 스프링입문자라면 어떤 방식인지 알 수 있다.

 

// 모른다면 https://donghs1541.tistory.com/9  or https://ko.wikipedia.org/wiki/%EC%8B%B1%EA%B8%80%ED%84%B4_%ED%8C%A8%ED%84%B4

를 참고하자.

 

이 중에서 그나마 가끔 이용하는 프로토타입, 웹관련 request를 알아보자.

스코프는 @Scope라는 어노테이션을 bean이나 component에 등록하여 이용할 수 있다.

 

@Component가 없는 이유는 구현을 할 때 이 클래스를 불러오면 자동으로 컴포넌트로 인식됨 

이렇게 등록 할 수 있고 프로토타입의 특징은 싱글톤과 다르게 프로토타입 스코프를 스프링 컨테이너에서 조회할 때마다 항상 새로운 인스턴스를 생성해서 반환한다.(즉 객체가 일회용, 싱글톤은 계속 사용 가능)

 

예를 들어 3명의 클라이언트가 있고 count가 0이고 +1하여 반환하는 기능이 스프링 Di컨테이너에 존재한다고 가정해보자.

싱글톤은 3명의 클라이언트가 count를 요청하면 count가 3으로 반환 된다.

하지만 프로토타입은 count가 1로 반환이 된다. 왜냐하면 싱글톤은 스프링컨테이너가 소멸하기 전까지 객체가 소실되지 않지만 프로토타입은 클라이언트가 요청할때마다 새로운 객체를 만들고 기능이 다하면 사라지기 때문이다.

 

이때 주의할점은 프로토타입은 빈을 생성하고, DI, 초기화 까지만 처리한다. 즉 스프링컨테이너가 클라이언트에게 프로토타입 빈을 반환하고 그 후 더이상 손대지 않는다 (@PreDestroy 같은 종료메서드가 호출이 안됨)

 

@PreDestroy(빈 소멸시 실행되는 메소드를 정하는 어노테이션)

이러한 프로토타입 스코프가 존재하고 빈을 생성하고 끝나는 메소드를 실행시켜보았다.

이런 출력문이 뜬다. 앞서 말했듯이 초기화 init는 출력되지만 destroy에 있는 출력문은 안나오는 것을 볼 수 있다.(싱글톤은 나온다) 그래서 만약 사용하고 싶으면 직접 손으로 메소드를 호출해주어야 한다.

 

이번에는 웹 스코프에 대해서 알아보자

 

웹 스코프

일단 웹스코프는 웹 환경에서만 동작하는 것을 알아야한다.

또 앞서 소개한 프로토타입과는 다르게 종료시점까지 관리한다.

 

 

웹스코프의 종류

request: HTTP 요청 하나가 들어오고 나갈 때 까지 유지되는 스코프, 각각의 HTTP 요청마다 별도의 빈 인스턴스가 생성되고, 관리된다.

session: HTTP Session과 동일한 생명주기를 가지는 스코프

application: 서블릿 컨텍스트( ServletContext )와 동일한 생명주기를 가지는 스코프 

websocket: 웹 소켓과 동일한 생명주기를 가지는 스코프

 

* ServletContext : 서블릿 컨테이너와 통신하기 위해서 사용되는 메소드를 지원하는 인터페이스

 

웹스코프의 종류가 있다. 여기서는 request 스코프를 설명하겠다. 왜냐하면 다른 스코프들과 범위만 다르지 동작 방식은 거의 유사하기 때문이다.

request 스코프는 요청 마다 빈 인스턴스가 생성된다. 

 

이렇게 어노테이션을 선언하면 request스코프가 완성이 된다.

 

이 코드는 앞서 설정한 request 스코프에 등록 돼 있는 고유아이디와 url을 출력하는 코드이다. 이 코드를 실행시키면 작동이 될까?

 

아마 작동이 되지 않을 것이다. 그 이유는 request 빈은 실제 고객의 요청이 와야 생성이 되는데 그 전에 호출을 하기 때문에 오류가 작동을 한다.

 

이를 해결하기 위한 것이 프록시이다. 

 

프록시는 더미라는 정도의 느낌으로 생각하면된다. 그래서 이야기하자면 실제로 http request가 오기전에 프록시를 통해 미리 더미값을 생성하는 방법으로 오류를 제거 할 수 있다. 다음 코드를 보자.

 

 

스코프 어노테이션에 proxyMode = ScopedProxyMode.TARGET_CLASS를 추가히주자(inteface이면 TARGE_INTERFACE)

이 명령어는 현재 등록하려는 클래스에 가짜 프록시 클래스를 만들어두는 것이다. 

 

다시 말하면 CGLIB라는 라이브러리로 내 클래스를 상속 받은 가짜 프록시 객체를 만들어 주입한다.

*CGLIB: 코드 생성 라이브러리로서 런타임에 동적으로 자바 클래스의 프록시를 생성해주는 기능을 제공한다.

 

그래서 다시 저 코드를 실행하면

 

이런 식으로 가짜 프록시 객체가 만들어진 것을 볼 수 있다. 이로서 request 스코프를 사용할 수 있게 됐다.

 


마지막으로 정리하자면 

 

프로토타입 스코프

  • 스프링 컨테이너에 요청할 때 마다 새로 생성된다.(일회성)
  • 스프링 컨테이너는 프로토타입 빈의 생성과 의존관계 주입 그리고 초기화까지만 관여하고 종료는 관여하지 않는다.
  • 그래서 프로토타입 빈은 프로토타입 빈을 조회한 클라이언트가 관리해야 한다.(종료도 직접)

웹 관련 스코프

  • request, session, application ,websocket 방식의 웹스코프가 있고 이는 각 이름에 맞는 범위만큼 유지되는 스코프들이다.
  • 요청시 빈이 생성되며 의존관계 주입, 초기화, 소멸까지 함께한다

프록시 

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

이상 빈스코프와 프록시에 대해 정리해보았다.

 

 

 

 

댓글