스프링 부트에서 제공하는 주요한 빈의 범위(scope)
Published: 2023-11-08 02:05:43

1. Singleton: 이는 기본적으로 스프링 빈의 범위입니다. 스프링 컨테이너에서 해당 빈의 인스턴스를 오직 하나만 생성하며, 이 인스턴스를 여러 곳에서 공유하여 사용합니다.
예제
```java
import org.springframework.stereotype.Component;

@Component
public class SingletonScopeBean {
    private final long instanceId;

    public SingletonScopeBean() {
        this.instanceId = System.nanoTime(); // Unique ID for each instance
    }

    public long getInstanceId() {
        return instanceId;
    }
}

```

다음은 이 Singleton 빈을 사용하는 서비스 클래스의 예제입니다:

```java
javaCopy code
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class MyService {
    private final SingletonScopeBean singletonScopeBean;

    @Autowired
    public MyService(SingletonScopeBean singletonScopeBean) {
        this.singletonScopeBean = singletonScopeBean;
    }

    public long getSingletonScopeBeanId() {
        return singletonScopeBean.getInstanceId();
    }
}

```

이제 이 두 클래스를 사용하여 스레드 아이디를 통해 Singleton 범위의 동작을 확인할 수 있습니다:

```java
javaCopy code
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class SingletonScopeExampleApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SingletonScopeExampleApplication.class, args);

        MyService myService1 = context.getBean(MyService.class);
        MyService myService2 = context.getBean(MyService.class);

        // 스레드 아이디를 통해 Singleton 빈이 동일한 인스턴스인지 확인
        System.out.println("Singleton Bean 1 ID: " + myService1.getSingletonScopeBeanId());
        System.out.println("Singleton Bean 2 ID: " + myService2.getSingletonScopeBeanId());

        // 두 서비스 인스턴스가 같은 Singleton 빈을 공유하므로 동일한 ID가 출력됩니다.

        context.close();
    }
}

```

위의 코드는 스레드 아이디를 사용하여 Singleton 범위에서 동일한 인스턴스가 공유되는 것을 보여주는 예제입니다. 이 코드를 실행하면 **`myService1`**과 **`myService2`**가 같은 **`SingletonScopeBean`** 인스턴스를 사용함을 확인할 수 있습니다.

2. Prototype: 이 범위를 가지는 빈은 매번 요청할 때마다 새로운 인스턴스가 생성됩니다. 즉, 요청할 때마다 독립적인 빈 인스턴스가 제공됩니다.

```java
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
@Scope("request")
public class RequestScopedBean {
    private final long instanceId;

    public RequestScopedBean() {
        this.instanceId = System.nanoTime(); // Unique ID for each instance
    }

    public long getInstanceId() {
        return instanceId;
    }
}

```

다음, 웹 컨트롤러를 만듭니다. 이 컨트롤러는 HTTP 요청을 처리하고 Request 범위 빈을 사용하여 인스턴스 아이디를 출력합니다:

```java

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class MyController {
    private final RequestScopedBean requestScopedBean;

    @Autowired
    public MyController(RequestScopedBean requestScopedBean) {
        this.requestScopedBean = requestScopedBean;
    }

    @GetMapping("/example")
    public String example(Model model) {
        // Request 범위 빈의 인스턴스 아이디를 가져와서 모델에 추가
        long instanceId = requestScopedBean.getInstanceId();
        model.addAttribute("instanceId", instanceId);

        return "example";
    }
}

```

마지막으로, 템플릿 엔진을 사용하여 결과를 렌더링할 "example.html" 템플릿을 만듭니다:

```html
htmlCopy code
<!DOCTYPE html>
<html>
<head>
    <title>Request Scope Example</title>
</head>
<body>
    <h1>Request Scope Example</h1>
    <p>Instance ID: <span th:text="${instanceId}"></span></p>
</body>
</html>

```

이제 스프링 부트 애플리케이션을 실행하고 "/example" 경로로 HTTP 요청을 보내면, 매 요청마다 Request 범위 빈의 새로운 인스턴스 아이디가 출력됩니다. 이를 통해 Request 범위 빈이 각 HTTP 요청에 대해 새로운 인스턴스를 생성함을 확인할 수 있습니다.

3. Request: 웹 애플리케이션에서 사용되는 범위로, 각각의 HTTP 요청마다 새로운 빈 인스턴스가 생성됩니다. 주로 웹 요청의 처리 과정에서 사용되며, 해당 요청의 범위 내에서만 빈 인스턴스가 유지됩니다.

```java

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
@Scope("request")
public class RequestScopedBean {
    private final String requestIdentifier;

    public RequestScopedBean(HttpServletRequest request) {
        this.requestIdentifier = "Request ID: " + System.identityHashCode(request);
    }

    public String getRequestIdentifier() {
        return requestIdentifier;
    }
}

```

다음으로, 웹 컨트롤러를 만듭니다. 이 컨트롤러는 HTTP 요청을 처리하고 Request 범위 빈을 사용하여 요청 식별자를 출력합니다:

```java

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

import javax.servlet.http.HttpServletRequest;

@Controller
public class MyController {
    private final RequestScopedBean requestScopedBean;

    @Autowired
    public MyController(RequestScopedBean requestScopedBean) {
        this.requestScopedBean = requestScopedBean;
    }

    @GetMapping("/example")
    public String example(Model model) {
        // Request 범위 빈의 요청 식별자를 가져와서 모델에 추가
        String requestIdentifier = requestScopedBean.getRequestIdentifier();
        model.addAttribute("requestIdentifier", requestIdentifier);

        return "example";
    }
}

```

마지막으로, 템플릿 엔진을 사용하여 결과를 렌더링할 "example.html" 템플릿을 만듭니다 (이전 예제와 동일):

```html

<!DOCTYPE html>
<html>
<head>
    <title>Request Scope Example</title>
</head>
<body>
    <h1>Request Scope Example</h1>
    <p th:text="${requestIdentifier}"></p>
</body>
</html>

```

이제 스프링 부트 애플리케이션을 실행하고 "/example" 경로로 HTTP 요청을 보내면, 매 요청마다 Request 범위 빈의 새로운 요청 식별자가 출력됩니다. 이를 통해 Request 범위 빈이 각 HTTP 요청에 대해 새로운 인스턴스를 생성함을 확인할 수 있습니다.

4. Session: 이 역시 웹 애플리케이션에서 사용되며, 각각의 세션마다 새로운 빈 인스턴스가 생성됩니다. 세션 범위 빈은 한 세션 내에서만 유지되며, 세션이 종료될 때 함께 소멸됩니다.

```java

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpSession;

@Component
@Scope("session")
public class SessionScopedBean {
    private final String sessionId;

    public SessionScopedBean(HttpSession session) {
        this.sessionId = session.getId();
    }

    public String getSessionId() {
        return sessionId;
    }
}

```

다음으로, 웹 컨트롤러를 만듭니다. 이 컨트롤러는 HTTP 세션을 처리하고 Session 범위 빈을 사용하여 세션 ID를 출력합니다:

```java

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

import javax.servlet.http.HttpSession;

@Controller
public class MyController {
    private final SessionScopedBean sessionScopedBean;

    @Autowired
    public MyController(SessionScopedBean sessionScopedBean) {
        this.sessionScopedBean = sessionScopedBean;
    }

    @GetMapping("/example")
    public String example(HttpSession httpSession, Model model) {
        // Session 범위 빈의 세션 ID를 가져와서 모델에 추가
        String sessionId = sessionScopedBean.getSessionId();
        model.addAttribute("sessionId", sessionId);

        return "example";
    }
}

```

마지막으로, 템플릿 엔진을 사용하여 결과를 렌더링할 "example.html" 템플릿을 만듭니다 (이전 예제와 동일):

```html

<!DOCTYPE html>
<html>
<head>
    <title>Session Scope Example</title>
</head>
<body>
    <h1>Session Scope Example</h1>
    <p>Session ID: <span th:text="${sessionId}"></span></p>
</body>
</html>

```

이제 스프링 부트 애플리케이션을 실행하고 "/example" 경로로 HTTP 요청을 보내면, 웹 세션마다 Session 범위 빈의 새로운 세션 ID가 출력됩니다. 이를 통해 Session 범위 빈이 각 세션에 대해 새로운 인스턴스를 생성함을 확인할 수 있습니다.

5. Global Session: 주로 포털 애플리케이션과 같이 여러 웹 애플리케이션을 포함하는 경우에 사용됩니다. 이 범위는 모든 웹 애플리케이션에 걸쳐 하나의 세션을 공유할 때 사용됩니다.

```java

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import javax.portlet.PortletRequest;
import javax.portlet.PortletSession;

@Component
@Scope("globalSession")
public class GlobalSessionScopedBean {
    private final String sessionId;

    public GlobalSessionScopedBean(PortletRequest request) {
        PortletSession session = request.getPortletSession(true);
        this.sessionId = session.getId();
    }

    public String getSessionId() {
        return sessionId;
    }
}

```

다음으로, 웹 컨트롤러를 만듭니다. 이 컨트롤러는 세션을 처리하고 Global Session 범위 빈을 사용하여 세션 ID를 출력합니다:

```java

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

import javax.portlet.PortletRequest;

@Controller
public class MyController {
    private final GlobalSessionScopedBean globalSessionScopedBean;

    @Autowired
    public MyController(GlobalSessionScopedBean globalSessionScopedBean) {
        this.globalSessionScopedBean = globalSessionScopedBean;
    }

    @GetMapping("/example")
    public String example(PortletRequest portletRequest, Model model) {
        // Global Session 범위 빈의 세션 ID를 가져와서 모델에 추가
        String sessionId = globalSessionScopedBean.getSessionId();
        model.addAttribute("sessionId", sessionId);

        return "example";
    }
}

```

마지막으로, 템플릿 엔진을 사용하여 결과를 렌더링할 "example.html" 템플릿을 만듭니다 (이전 예제와 동일):

```html

<!DOCTYPE html>
<html>
<head>
    <title>Global Session Example</title>
</head>
<body>
    <h1>Global Session Example</h1>
    <p th:text="${sessionId}"></p>
</body>
</html>

```

이제 스프링 부트 애플리케이션을 실행하고 "/example" 경로로 HTTP 요청을 보내면, 모든 웹 애플리케이션에 걸쳐 하나의 세션을 공유하는 Global Session 범위 빈의 세션 ID가 출력됩니다. 이를 통해 Global Session 범위 빈이 모든 웹 애플리케이션에서 하나의 세션을 공유함을 확인할 수 있습니다.