티스토리 뷰

728x90
반응형

지난 글에서

 

  • 스프링은 스프링 컨테이너로 객체를 관리한다.
  • 스프링 컨테이너에서 관리되는 객체를 빈(Bean)이라고 한다.
  • BeanDefinition은 빈을 생성할 때 쓰이는 레시피이다.
  • @Content, @Configuration, @Bean 등의 애너테이션을 통해 빈을 등록할 수 있다.

는 것에 대해 언급했다.

 

https://gnidinger.tistory.com/454

 

[Spring]DI - 스프링 컨테이너(Container)와 빈(Bean)

지난번 글에서, IoC(Inversion of Control)는 DI(Dependency Injection)에 의해 구현된다고 했었다. 여기서 IoC는 제어 역전이라는 뜻을 가지며, 외부 프레임워크가 개발자의 코드를 호출해 실행된다. DI는 풀

gnidinger.tistory.com

이번 글에선 생성된 빈의 사용범위(스코프)와 그 특징에 대해 살펴본다.

 

스코프는 위에서 언급했듯이 말 그대로 빈의 사용범위를 말한다.

 

HTTP 요청마다 새로운 빈을 만들어서 사용할 것인지, 앱이 구동되는 동안 하나만 쓸 것인지 등을 결정한다.

 

특정 빈에 연결될 의존성이나 구성 값, 생성된 개체의 범위도 조절할 수 있다.

 

스프링 프레임워크는 6개의 스코프를 지원하는데, 그 각각은 아래와 같다.

 

스코프 설명
singleton (기본값) 스프링 컨테이너의 시작과 종료까지 하나의 인스턴스만 사용
prototype 스프링 컨테이너는 프로토타입 빈의 생성과 의존관계 주입까지만 관여
요청이 오면 항상 새로운 인스턴스를 생성하여 사용

request HTTP 라이프 사이클마다 하나의 빈을 사용, 호출마다 다른 인스턴스 반환
session HTTP 세션마다 하나의 빈을 사용
application 웹의 서블릿 컨텍스와 동일한 생명주기를 갖는 스코프
websocket websocket과 동일한 생명주기를 갖는 스코프

특별히 아래의 네 가지의 웹 스코프는 web-aware ApplicationContext의 컨텍스트에서만 사용할 수 있으며,

 

필요에 따라 사용자 정의 스코프를 만들어서 사용할 수도 있다.


싱글톤 패턴

 

스프링은 기본적으로 엔터프라이즈급의 웹 앱을 다루기 위해 만들어졌다.

 

엔터프라이즈급의 웹 앱이란 태생적으로 수 많은 고객이 동시에 서비스를 이용하게 되기 마련인데,

 

위 그림처럼 모든 요청마다 새로 객체를 생성해서 반환할 경우(이를 멀티톤이라 한다) 메모리에 무리가 갈 수 있다.

 

이에 대한 해결방안으로 객체를 하나만 만들고 공유하도록 설계하는 방식이 만들어졌는데, 이를 싱글톤 패턴이라고 한다.

 

계속해서 싱글톤 패턴이 적용된 코드를 살펴보자.

class Singleton {

    //1. private static 클래스명 intstance 변수로 객체생성
    private static Singleton intstance = new Singleton();

    //2. private 생성자
    private Singleton() {
    }

    //3. public static 메서드
    public static Singleton getInstance() {
        return intstance;
    }
}

1. 클래스 내에 자신 타입의 private static 변수 생성

 

private - 외부에서 접근할 수 없고, static - 한 번만 로딩되어 전체가 공유할 수 있도록 만드는 것.

 

2. private 생성자

 

외부에서 new 키워드를 통해 직접 객체를 생성할 수 없게 막음.

 

3. public static 메서드

 

public - 변수를 우회해서 빌려쓸 수 있도록, static - 객체 생성 없이 사용할 수 있도록.

 

클래스 타입의 getInstance()메서드는 private 변수(Singleton의 객체 instance)를 리턴한다.

 

객체 생성을 한 번만 하고 계속 빌려쓰는 형식을 취하고 있다고 보면 된다.

 

싱글톤 패턴을 확인하기 위해 아래와 같은 코드를 작성하자.

public class Example {
    public static void main(String[] args) {

        //외부에서 객체 생성 불가능
        //Single s = new Single();

        Singleton singleton1 = Singleton.getInstance(); // instance를 우회해서 빌려옴
        Singleton singleton2 = Singleton.getInstance();

        System.out.println("singleton1 = " + singleton1);
        System.out.println("singleton2 = " + singleton2);
    }
}

위 Example 클래스의 메인 메서드를 실행하면 아래와 같이 호출 시마다 동일한 인스턴스를 얻는 것을 확인할 수 있다.

 

하지만 오로지 싱글톤 패턴만 사용해서는 큰 단점이 존재하는데, 이는 아래와 같다.

 

  • 클라이언트가 구체 클래스에 의존한다 - 객체 지향 설계 원칙 위반
  • 싱글톤 패턴을 구성하기 위한 코드가 많아진다.
  • private 생성자를 이용하기 때문에 상속시키기가 어렵다 - 유연성 떨어짐
  • 내부 설계를 변경하기 어렵고, 테스트 하기가 어렵다.
  • 속성 공유에 따라 멀티 스레드 환경에서 속성이 스레드에 따라 바뀔 수 있다.
  • 싱글톤 빈은 앱 구동시 생성되므로 초기 구동 속도에 영향을 끼칠 수 있다.

위와 같은 문제를 해결해주는 것이 바로 싱글톤 컨테이너이다.


싱글톤 컨테이너

 

위에서 빈의 스코프에 대해 언급할 때, 스프링의 기본값은 싱글톤이라고 했었다.

 

그 말 그대로, 스프링 컨테이너는 모든 빈을 기본적으로 싱글톤으로 관리한다(이를 싱글톤 레지스트리라 한다).

 

따라서 위에 적은 것과 같은 설정 파일이 필요가 없어지며, 스프링 컨테이너 = 싱글톤 컨테이너라고 봐도 된다.

 

스프링 컨테이너의 기본 설정 덕분에 싱글톤 패턴의 모든 단점이 해결되면서도 빈을 싱글톤으로 유지할 수 있다는 뜻이다.

 

이는 단순하게 구성 설정 파일(AppConfig.java 등)에 몇 가지 애너테이션을 더하는 것으로 이룩할 수 있는데,

 

그것이 바로 앞에서 살펴봤던 @Configuration과 @Bean이다.

@Configuration
public class AppConfig {
    @Bean
    public UserService userService() {
        return new UserServiceImpl(userRepository());
    }
    @Bean
    public UserRepository userRepository() {
        return new UserRepositoryImpl();
    }
    @Bean
    public OrderService orderService() {
        return new OrderServiceImpl(userRepository(), discountInfo());
    }
    @Bean
    public DiscountInfo discountInfo() {
        return new CurrentDiscountInfo();
    }
}

위 코드에 보이는 것처럼 클래스에 @Configuration을, 메서드에 @Bean을 입력해주면 끝이다.

 

지난 글에서 알아본 것처럼 @Bean을 통해 메서드의 반환 객체가 스프링 컨테이너에 빈으로 등록된다.

 

마지막으로 싱글톤 방식을 사용할 때의 주의점을 알아보고 글을 마치자.

 

  • 앱 전역, 여러 클라이언트에서 공유되기 때문에 무상태(Stateless)로 설계해야 한다.

    • 특정 클라이언트에 의존적이거나, 특정 클라이언트가 값을 변경할 수 있어선 안 된다.
    • 읽기만 가능해야 한다.
    • 스프링 빈에 공유 값을 설정하면 큰 장애가 발생할 수 있다.
반응형
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/06   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30
글 보관함