DEV Community

NeNoVen
NeNoVen

Posted on

스프링 부트에서 제공하는 주요한 빈의 범위(scope)

  1. Singleton: 이는 기본적으로 스프링 빈의 범위입니다. 스프링 컨테이너에서 해당 빈의 인스턴스를 오직 하나만 생성하며, 이 인스턴스를 여러 곳에서 공유하여 사용합니다. 예제
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;
    }
}

Enter fullscreen mode Exit fullscreen mode

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

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();
    }
}

Enter fullscreen mode Exit fullscreen mode

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

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();
    }
}

Enter fullscreen mode Exit fullscreen mode

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

  1. Prototype: 이 범위를 가지는 빈은 매번 요청할 때마다 새로운 인스턴스가 생성됩니다. 즉, 요청할 때마다 독립적인 빈 인스턴스가 제공됩니다.
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;
    }
}

Enter fullscreen mode Exit fullscreen mode

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


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";
    }
}

Enter fullscreen mode Exit fullscreen mode

마지막으로, 템플릿 엔진을 사용하여 결과를 렌더링할 "example.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>

Enter fullscreen mode Exit fullscreen mode

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

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

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;
    }
}

Enter fullscreen mode Exit fullscreen mode

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


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";
    }
}

Enter fullscreen mode Exit fullscreen mode

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


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

Enter fullscreen mode Exit fullscreen mode

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

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

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;
    }
}

Enter fullscreen mode Exit fullscreen mode

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


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";
    }
}

Enter fullscreen mode Exit fullscreen mode

마지막으로, 템플릿 엔진을 사용하여 결과를 렌더링할 "example.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>

Enter fullscreen mode Exit fullscreen mode

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

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

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;
    }
}

Enter fullscreen mode Exit fullscreen mode

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


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";
    }
}

Enter fullscreen mode Exit fullscreen mode

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


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

Enter fullscreen mode Exit fullscreen mode

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

AWS Security LIVE!

Join us for AWS Security LIVE!

Discover the future of cloud security. Tune in live for trends, tips, and solutions from AWS and AWS Partners.

Learn More

Top comments (0)

AWS Security LIVE!

Join us for AWS Security LIVE!

Discover the future of cloud security. Tune in live for trends, tips, and solutions from AWS and AWS Partners.

Learn More

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay