Home

Published

- 13 min read

[ Spring ] Spring IOC

img of [ Spring ] Spring IOC

IOC에 대한 개념이 이해가 갔다면 이제 스프링의 IOC에 대해 알아보자. 스프링은 앞서 말했던 코드들중에서 AppConfig 와 같은 역할을 한다고 보면 된다.

   class AppConfig {
    public UserDao userDao() {
        return new MySqlUserDao();
    }

    public UserService userService() {
        return new UserService(userDao());
    }
}

AppConfigUserService의 생성과 생명주기를 관리한다. 그렇다면 스프링은 어떤 객체의 생성과 생명주기를 담당할까?

Bean, Bean Factory

스프링에서는 스프링이 제어권을 가지고 직접 만들고 관계를 부여하는 오브젝트를 빈(Bean)이라고 부른다. 스프링 빈은 스프링 컨테이너가 생성과 관계설정, 사용 등을 제어해주는 제어의 역전이 적용된 오브젝트를 가리키는 말이다.

이런 스프링 빈의 생성과 관계설정같은 제어를 담당하는 IoC 오브젝트를 빈 팩토리(bean factory)라고 부른다.

Application Context

Application Context는 IoC 방식을 따라 만들어진 일종의 빈 팩토리이다. Application Context는 별도의 정보를 참고해서 빈(오브젝트)의 생성, 관계설정 등의 제어 작업을 총괄한다. 스프링에서는 이 애플리케이션 컨텍스트를 IoC 컨테이너라 하기도 하고, 간단히 스프링 컨테이너라고 부르기도 한다. 또는 빈 팩토리라고 부를 수도 있다.

스프링의 애플리케이션 컨텍스트는 ApplicationContext 인터페이스로 정의되는데, ApplicationContext는 빈 팩토리의 기능을 정의한 BeanFactory 인터페이스를 상속했으므로 애플리케이션 컨텍스트는 빈 팩토리의 확장된 버전이라고 할 수 있다. ApplicationContext 인터페이스를 구현한 클래스들이 스프링의 가장 대표적인 컨테이너 오브젝트이므로, 이를 간단히 스프링이라고 부르는 개발자도 있다.

Application Context의 동작방식

image

애플리케이션 컨텍스트는 DaoFactory 클래스를 설정정보로 등록해두고 @Bean이 붙은 메소드의 이름을 가져와 빈 목록을 만들어둔다. 클라이언트가 애플리케이션 컨텍스트의 getBean() 메소드를 호출하면 자신의 빈 목록에서 요청한 이름이 있는지 찾고, 있다면 빈을 생성하는 메소드를 호출해서 오브젝트를 생성시킨 후 클라이언트에 돌려준다.

토비의 스프링 vol1

여기서 말하는 클라이언트는 애플리케이션 컨텍스트를 사용하여 빈(bean)을 요청하는 코드를 의미한다. 구체적으로는 애플리케이션의 메인 로직을 담당하는 클래스들, 다른 빈을 사용해야 하는 빈 클래스들, 테스트 코드를이 있다.

싱글톤 레지스트리와 오브젝트 스코프

싱글턴의 필요성

일반적으로 자바에서 같은 객체를 두개 생성해서 비교해보면 둘이 다른 값이 나온다. 각 객체는 유일한 hashcode 값을 가지기 때문이다. 예를 들어 다음 코드를 보자.

   DaoFactory factory = new DaoFactory();
UserDao dao1 = factory.userDao();
UserDao dao2 = factory.userDao();

System.out.println(dao1.equals(dao2));

실행결과는 false 이다. dao1과 dao2의 hashcode 값이 다르기 때문이다. 만약 스프링이 이런 방식으로 설정되어 있다면 곤란할 것이다. 매번 새로운 객체 생성으로 메모리 낭비가 될 수도 있고, 이는 성능저하로 이어질 수 있다. 또한, 매번 새로운 인스턴스가 생성된다면 그에 맞게 의존성 주입도 매번 새롭게 설정되어야 하므로 의존성 관리가 복잡해진다.

그래서 객체를 불러올 때, 새로운 객체를 생성해주는 것이 아닌 같은 객체를 보내주기 위해 스프링은 “싱글턴같은” 객체를 유지한다. 싱글턴 패턴이 아닌 “싱글턴같은” 방식이라고 말하는 이유는 자바에서 싱글턴을 구현했을 때 여러 문제가 있기 때문이다.

자바에서 싱글턴을 구현하는 방법은 보통 이렇다.(from 토비의 스프링 vol1)

  • 클래스 밖에서는 오브젝트를 생성하지 못하도록 생성자를 private으로 만든다.
  • 생성된 싱글톤 오브젝트를 저장할 수 있는 자신과 같은 타입의 스태틱 필드를 정의한다.
  • 스태틱 팩토리 메소드인 getInstance()를 만들고 이 메소드가 최초로 호출되는 시점에서 한 번만 오브젝트가 만들어지게 한다. 생성된 오브젝트는 스태틱 필드에 저장된다. 또는 스태틱 필드의 초기값으로 오브젝트를 미리 만들어둘 수도 있다.
  • 한번 오브젝트(싱글톤)가 만들어지고 난 후에는 getInstance() 메소드를 통해 이미 만들어져 스태틱 필드에 저장해둔 오브젝트를 넘겨준다.

자바 스프링에서 싱글턴의 문제

이런 이유로 싱글턴은 여러 문제가 생긴다. (from 토비의 스프링 vol1)

  • 상속이 불가능하다. 싱글턴으로 구현시 private 생성자를 가지고 있기 때문이다. 객체지향적으로 코드를 작성해야 하는 경우에 큰 문제가 생긴다.
  • 테스트하기 어렵다. 싱글턴은 만들어지는 방식이 제한적이기 때문에 테스트에서 사용될 때 Mock 오브젝트 등으로 대체하기가 힘들다.
  • 서버환경에서는 싱글톤이 하나만 만들어지는 것을 보장하지 못한다. 서버에서 클래스로더를 어떻게 구성하느냐에 따라 달라질 수 있다.(하나 이상의 오브젝트가 만들어질 수도 있다.) 여러 개의 JVM에 분산돼서 설치가 되는 경우에도 각각 독립적으로 오브젝트가 생기기 때문에 싱글톤으로서의 가치가 떨어진다.
  • 싱글턴의 사용은 전역 상태를 만들 수 있기 때문에 바람직하지 못하다. 싱글턴의 스태틱 메소드를 이용해 언제든지 싱글톤에 쉽게 접근할 수 있기 때문에 애플리케이션 어디서든지 사용될 수 있고,그러다 보면 자연스럽게 전역 상태로 사용되기 쉽다. 이는 객체지향적이지 못하다.

싱글턴 레지스트리(singleton registry)

그래서 자바에서 싱글턴을 사용하는 것은 한계가 있기 때문에 스프링에서는 “싱글턴같은” 방식을 사용한다. 그게 싱글턴 레지스트리이다. 스프링은 직접 싱글턴 형태의 객체를 만들고 관리하는 기능을 제공한다. 싱글턴 레지스트리의 장점은 기존의 싱글턴과 같이 static 메소드와 private 생성자를 사용한 클래스가 아니라 평범한 자바 클래스를 싱글턴으로 활용하게 해 준다.

기존 자바에서의 싱글턴은 객체지향적인 접근이 불가능하다는 점이 가장 큰 문제였다. 하지만 스프링에서 싱글턴 레지스트리로 인해 스프링이 지지하는 객체지향적인 설계 방식과 디자인 패턴 등을 적용하는 데 아무 문제가 없게 되었다.

싱글턴 레지스트리와 오브젝트 상태

싱글턴 레지스트리는 멀티 스레드 환경이라면 여러 스레드가 동시에 접근하여 사용할 수 있다. 이 말은 즉, R/W를 여러 곳에서 동시에 할 수 있다는 점인데 이건 운영체제에서의 동기화 문제와 비슷한 문제가 발생할 수 있다. 따라서 상태관리에 주의를 기울여야 한다.

기본적으로 싱글턴 레지스트리는 멀티스레드 환경에서 서비스 형태의 객체로 사용될 경우에 상태정보를 담고 있지 않은 stateless로 만들어져야 한다. 만약 그렇지 않다면 여러 사용자가 읽고 쓰는 과정에서 상태정보가 꼬여버릴 가능성이 매우 매우 높다. 하지만 읽기만 한다면 정보가 꼬일 일은 없으므로 상관없다. 읽기 속성만을 가지고 있는 정보라면 싱글턴 레지스트리에서 인스턴스 변수로 사용해도 된다.(예: 서버 정보, jwt값 등)

빈의 스코프

스프링이 관리하는 객체, 빈은 싱글턴 스코프이다. 싱글턴 스코프는 컨테이너 내에서 한 개의 오브젝트만 만들어져서 강제로 제거되지 않는 한, 스프링 컨테이너가 존재하는 한 계속 유지된다. 스프링에서 만들어지는 대부분의 빈은 싱글턴 스코프를 가진다.

경우에 따라서는 싱글톤 외의 스코프를 가질 수 있다. 대표적으로 프로토타입 prototype 스코프가 있다. 프로토타입은 싱글톤과 달리 컨테이너에 빈을 요청할 때마다 매번 새로운 오브젝트를 만들어준다. 그 외에도 웹을 통해 새로운 HTTP 요청이 생길 때마다 생성되는 요청(request) 스코프가 있고, 웹의 세션과 스코프가 유사한 세션(session) 스코프도 있다. 스프링에서 만들어지는 빈의 스코프는 싱글톤 외에도 다양한 스코프를 사용할 수 있다.토비의 스프링 vol1

출처

  • 토비의 스프링 vol1