[Spring] Bean Scope, Proxy

[verify$y]·2025년 6월 6일

Spring

목록 보기
14/16

💡 Spring 핵심 개념 인터뷰 Q&A



핵심개념

  • 스프링 빈 : 스프링 컨테이너에서 관리하는 자바 객체
  • 스코프 : 스프링빈이 존재할 수 있는 범위

이 스프링빈도 싱글톤이냐, 프로토타입이냐에 따라 다르다.

  • 싱글톤에서 스프링빈은 기본적으로 스프링컨테이너에서 알아서 생성했기때문에 스프링빈의 스코프와 스프링 컨테이너의 생명주기가 같다.

  • 하지만 빈 스코프는 클라이언트 요구에 적절하게 설정할 필요가 있다.


스코프

  • request : 웹 요청이 들어오고 나갈때까지의 스코프로, 각 요청마다 빈 인스턴스가 생성되고 관뢰된다.
  • session: 웹 세션이 생성되고 종료될 떄까지 유지되는 스코프, Http Session과 동일한 생명주기를 가진다.
  • application : 웹의 서블릿 컨텍스트와 같은 범위를 유지되는 스코프
  • webSocket : 웹 소켓과 동일한 생명주기를 갖는다.



빈 스코드 사용방법

  • 일반적으로 스프링이 컴포넌트를 자동스캔하여 등록한다.
  • 아래는 프로토 타입의 스코프
@Scope("protype")
@Component
public class protoTypeBean() 

싱글톤 빈 스코프경우

  • 싱글톤 빈 스코프에서는 스프링 컨테이너는 항상 같은 빈을 반환한다.
  • 싱글톤 스코프 빈을 요청하면 동일한 스프링빈을 반환한다.

프로토타입 스코프의 스프링 빈

작동 순서

  1. 클라이언트에서 프로토타입 스코프의 스프링빈을 스프링 컨테이너에 요청
  2. 스프링 컨테이너는 이 시점에서 프로토타입 빈을 생성하고, Di
  3. 생성한 프로토타입 빈을 클라이언트에 반환
  • 프로토타입 빈은 빈 생성, 의존관계 주입, 초기화까지만 진행한다.
  • 스프링 빈을 클라이언트에 반환한 후 관리하지 않기 때문에 모두 클리이언트에서 관리해야한다.



주소값

싱글콘 스코프

  • 싱글통스포프의 스프링 빈은 여러번 호출해도 모두 동일한 인스턴스 주소값을 가진다.
  • 스프링 컨테이너 종료할 때 소멸 메서드도 자동으로 실행된다

프로토타입 스코드

  • 프로토타입 빈 2개가 참조하는 인스턴스 참조 주소값이 다르다.
  • 스프링 컨테이너 종료시 소멸 메서드가 실행되지 않는다.


정리

  • 싱글톤은 스프링 컨테이너와 생명주기를 같이하지만, 프로토타입 스프링빈은 생명주기를 달리한다.
  • 싱글톤 스프링 빈은 매번 스프링 컨테이너에서 동일한 인스턴스를 반환하지만, 프로토타입빈은 소명 메서드가 호출되지 않는다.
  • 클라이언트가 프로토타입 스프링빈을 직접 관리해야한다.



문제상황 : 프로토타입 스코프가 싱글톤 빈과 함께 사용될떄

케이스 : 싱글톤 스프링 빈 내부에 의존관계로 주입되는 스프링 빈이 프로토타입일떄
설명 :

  • 싱글톤 빈의 스코프는 스프링 컨테이너와 같은데, 프로토 타입 스코프의 스프링빈이 새로 생성되기는 하지만 싱글톤 빈과 함께 사용되기 때문에 계속 유지된다
  • 해당 빈을 2번 요청하지만 동일한 프토토타입 빈을 사용하게 되어 count는 2
  • 프로토타입 빈만 클라이언트가 직접 사용하는 경우라면 상관없지만 싱글톤 빈과 함께 사용하면서 프로토타입 빈이 자기의 스코프를 지키고 매번 새롭게 생성하려면?

해결 : 프로토타입 스코프를 싱글톤 빈과 함께 사용할때

  • 싱글톤 빈 내부에서 주입된 빈이 프로토타입이면 계속 동일한 인스턴스를 참조하게 되어 프로토타입 스코프를 갖지 못하게 되었다.
  • 싱글톤 빈과 프로토타입을 혼용하면서 프로토타입을 매번 생성하려면?
  • 의존관계를 외부에서 주입받지 않고 직접 의존관계를 찾는것을 해야한다.
  • 이것은 DL(dependency lookup) 의존관계 조회를 말한다.
  • .getBean()으로 직접조회해서 주입


이 해결방식의 문제점

  • 스프링 애플리케이션 컨텍스트 전체를 주입받게된면 스프링 컨테이너와 종속성이 생기고 테스트가 어렵다.
static class ClientBean{
		@Autowired
    private ApplicationContext ac;

    public int logic() {
				PrototypeBean prototypeBean = ac.getBean(PrototypeBean.class);
        prototypeBean.addCount();
        int count = prototypeBean.getCount();
        return count;
    }

}



해결방식 : ObjectrFactory, ObjectProvider

  • ObjectrFactory: 지정한 빈을 컨테이너에서 대신 찾아준다.
  • ObjectProvider : ObjectrFactory에 편의기능을 추가해서 만들어진 객체
static class ClientBean{
    @Autowired
    private ObjectProvider<PrototypeBean> prototypeBeanProvider;

    public int logic() {
        PrototypeBean prototypeBean = prototypeBeanProvider.getObject();
        prototypeBean.addCount();
        int count = prototypeBean.getCount();
        return count;
    }
}
  • ObjectProvider 을 사용하였고, 매번 새로운 프로토타입 빈이 생성되는 것을 확인할 수 있다.
  • ObjectProvider의 getObject()를 호출하면 내부에서는 스프링 컨테이너를 통해 해당 빈을 찾아서 반환(DL)

프로토타입빈 사용목적

  • 스프링은 기본세팅이 싱글톤이므로 DL을 해야한다.
  • DL해야하는 경우
  • 여러 인스턴스검색
  • 인스턴스 지연
  • 순환 종속성 깨야할때
  • 스코프에 포함된 인스턴스로부터 더 작은 범위의 인스턴스를 찾아 추상화하기 위해서 사용한다.



스코프와 Provider, 스코프와 프록시의 동작 원리

  • @Scope 의 proxyMode를 사용하면 스프링 컨테이너는 CGLIB이라는 바이트코드 조작 라이브러리를 사용해 가짜 프록시 객체를 생성
  • 스프링컨테이너에는 이프록시 객체가 들록된다.
  • getbean()을 통해 해당 클래스 타입을 조회해도 가짜 프록시 객체가 조회되는 것을 볼 수 있다.
    • 심지어 의존관계에서 프록시 객체가 주입된다.
  • CGLIB 이라는 바이트코드 조작 라이브러리로 클래스를 상속받은 가짜 프록시 객체를 만들어 의존관계를 주입하며
  • lazyLoading
  • 애노테이션 추가속성으로 원본객체레 프록시 객체로 대체가 가능하다.




profile
welcome

0개의 댓글