코딩못하는사람

스프링 Bean,Singleton,Bean Scope 본문

스프링(Spring)/개념

스프링 Bean,Singleton,Bean Scope

공부절대안함 2021. 3. 6. 03:58

스프링 빈(Spring Bean)이란?

스프링 IoC(Inversion of Control) 컨테이너에 의해서 관리되고 애플리케이션의 핵심을 이루는 객체들을

스프링 빈(Beans)이라고 한다. 빈은 스프링 컨테이너에 의해서 인스턴스화 되어 조립되고 관리됩니다.

스프링 컨테이너가 관리해준다는 점을 제외하면 자바 객체이다.

 

Singleton

클래스의 인스턴스가 딱 1개만 생성되는 것을 보장하는 디자인 패턴이다.

그래서 객체 인스턴스를 2개 이상 생성하지 못하도록 막아야 한다.

코드에서 private 생성자를 사용해서 외부에서 임의로 new 키워드를 사용하지 못하도록 막아야 한다.

하지만 스프링 컨테이너를 사용하면 컨테이너에 등록되는 빈들을 알아서 싱글톤으로 관리해준다.

 

스프링 핵심기본원리/김영한

(클라이언트들이 스프링 빈을 요구할 때 같은 참조값을 가진 빈 객체를 반환해준다.)

 싱글톤 패턴에서 주의점

  • 하나의 인스턴스를 생성해서 공유하는 형식이므로 객체의 상태를 유지하게(stateful) 설계하면 안된다.

  • 특정 클라이언트에 의존적이거나 값을 변경할 수 있는 필드가 있으면 안된다.

  • 가급적 읽기만 가능해야 한다.

  • 필드 대신 공유되지 않는 지역변수,파라미터,ThreadLocal을 쓰자.(예를 들어 필드를 반환하는게 아닌 파라미터를 반환하자)

 

빈 스코프란?

Scope의 뜻대로 빈이 존재할 수 있는 범위를 말한다. 스프링 빈은 기본적으로 싱글톤 스코프가 적용된다.

스프링은 다양한 종류의 스코프를 지원하는데 각 스코프를 분석해보자.

 

1.싱글톤: 기본 스코프, 스프링 컨테이너의 시작과 종료까지 유지되는 가장 넓은 범위의 스코프

 

2.프로토타입: 스프링 컨테이너는 프로토타입 빈의 생성과 의존관계 주입까지만 관여하고

더는 관리하지 않는 매우 짧은 범위의 스코프. @Scope("prototype")로 선언한다.

(의존관계 까지만 주입하고 보내주기 때문에 @PreDestroy를 볼 수 없음)

스프링 핵심기본원리/김영한

 

싱글톤과 프로토타입 빈을 같이 사용할 때 주의할 점.

우리는 보통 싱글톤과 프로토타입 빈을 같이 사용하게 되는데 여기서 문제가 생긴다.

clientBean은 싱글톤이고 prototypeBean은 프로토타입이고 호출할 때 마다 값이 1씩 증가한다고 가정.

싱글톤 빈은 스프링 컨테이너에 등록할 때 의존관계 주입을 위해 PrototypeBean을 요청해서 주입 받는다.

이런 방식이면 클라이언트들이 싱글톤인 clientBean을 사용할 때 마다 다른 객체가 생성되길 바라는 프로토타입의 효과를 보지 못한다.(이미 주입이 완료된 상태인 싱글톤 빈을 공유해서 사용하기 때문에)

 

PrototypeBean이 공유되어서 count가 공유되어 사용되는 문제가 발생한다.

해결방법

싱글톤 빈과 함께 사용시 Provider로 문제 해결한다.

ObjectProvider <prototypeBean>Provider를 선언하면

getObject()메서드를 실행할 때 마다 빈을 만들어준다.

(Provider가 직접 의존관계를 찾고있으므로 Dependency Lookup(DL)이라고 한다.)

 

프로토타입 스코프를 주입받을 때 매번 새로운 스코프를 받기위해 ObjectProvider를 사용하는 코드로 바꾼 것(오른쪽)

스프링에서 제공하는 ObjectFactory, ObjectProvider를 사용하는 방식도 있고

자바표준에서 제공하는 JSR-330 Provider를 사용하는 방식도 있다.

 

 

3.웹 관련 스코프

 

웹 스코프는 웹 환경에서만 동작한다. @Scope("request")로 선언가능

웹 스코프는 프로토타입과 다르게 스프링이 해당 스코프의 종료시점까지 관리한다.

따라서 종료 메서드가 호출된다(@PreDestroy,@PostConstruct 둘다 가능)

 

 

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

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

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

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

request 스코프에서 생각해야할 점.

request스코프 빈은 HTTP request가 들어와야 생성할 수 있다.

따라서 미리 의존관계를 주입시켜주기 위해 프로토타입에서 활용했던 Provider을 사용하거나

프록시 방식을 써야 한다.

다음과 같이 프록시를 설정해주면 HTTP request의 여부와 상관없이  프록시 클래스를 빈에 미리 주입해 두고 필요할 때마다 사용 가능하게 해준다.(CGLIB이라는 라이브러리로 바이트코드를 조작해서 가짜 프록시 객체를 넣어놓는다)

 

사실 Provider를 사용하든, 프록시를 사용하든 핵심 아이디어는 진짜 객체 조회를 꼭 필요한 시점까지 지연 처리 한다는 점이다.

 

 

스코프 사용시 주의점

  • 스코프마다 동작 방법이 다르므로 주의해서 사용해야 한다.

  • 특별한 scope는 꼭 필요한 곳에만 최소화해서 사용하자, 무분별하게 사용하면 유지보수하기 어려워 진다

'스프링(Spring) > 개념' 카테고리의 다른 글

@AuthenticationPrincipal 어노테이션  (0) 2022.01.02
Filter와 Interceptor  (0) 2021.12.30
스프링과 스프링부트  (0) 2021.09.17
스프링이 무엇이고 왜 나왔을까?  (1) 2021.09.17
객체지향 설계 5원칙-SOLID  (0) 2021.09.17
Comments