ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 빈 스코프(Singleton, Prototype)
    개발/Spring 2023. 5. 16. 17:07

    https://literate-t.tistory.com/405 내용에서 조금 더 보완하고자 한다.

     

    @Configuration

    테스트 코드를 작성하는데, 클래스에 @Configuration을 붙이지 않아도 getBean 메서드로 빈이 획득됐다. 관련 내용을 찾아 보니 공식 문서에 꽤나 친절하게 설명이 있었다. https://docs.spring.io/spring-framewo

    literate-t.tistory.com

    위 포스트의 내용은 @Bean 어노테이션을 이용해 빈으로 등록된 객체에 관한 문제다.

    클래스에 @Configuration 어노테이션을 붙이면 빈은 정식 스프링 빈이 되어 싱글톤으로 관리되고,

    붙이지 않으면 싱글톤으로 관리되지 않는다. 여기서 관리되지 않는 지점에 대해 부연하자면

    B bean이 생성될 때 A bean이 필요하다면 그냥 새로운 A bean이 만들어진다는 의미다.


    @Scope("singleton")

    이와 별개로 @Bean을 가지고 있는 클래스(@Configuration 어노테이션이 붙는 클래스)는 기본적으로 싱글톤이다.

    다음 테스트를 통과한다. SingletonBean의 close 함수도 호출된다.

    public class SingletonTest {
        @Test
        void findSingletonBean() {
            ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(SingletonBean.class);
    
            SingletonBean singletonBean1 = context.getBean(SingletonBean.class);
            SingletonBean singletonBean2 = context.getBean(SingletonBean.class);
    
            System.out.println("singletonBean1 = " + singletonBean1);
            System.out.println("singletonBean2 = " + singletonBean2);
    
            Assertions.assertThat(singletonBean1).isSameAs(singletonBean2);
    
            context.close();
        }
    
        @Scope("singleton") // default 이므로 안 붙여도 된다
        static class SingletonBean {
            @PostConstruct
            void init() {
                System.out.println("SingletonBean.init");
            }
    
            @PreDestroy
            void close() {
                System.out.println("SingletonBean.close");
            }
        }
    }

    AnnotationConfigApplicationContext의 생성자의 파라미터 중 하나는 componentClasses다.

    즉, 인수로 넣는 클래스는 @Component를 붙이는 것과 동일한 효과를 가지므로 위의 코드가 동작할 수 있다.


    @Scope("prototype")

    빈의 스코프를 프로토타입으로 바꾸면 빈 생성 후 DI까지만 진행된다.

    그러고 나서 스프링 컨테이너에서 해당 빈들이 반환되어 싱글톤으로 관리되지 않는다.

    다음 테스트를 통과하며 close 함수는 각 빈에서 명시적으로 호출하지 않으면 호출되지 않는다.

    public class PrototypeTest {
    
        @Test
        void findPrototypeBean() {
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(PrototypeBean.class);
    
            System.out.println("find Prototype Bean1");
            PrototypeBean p1 = context.getBean(PrototypeBean.class);
            System.out.println("find Prototype Bean1");
            PrototypeBean p2 = context.getBean(PrototypeBean.class);
            System.out.println("p1 = " + p1);
            System.out.println("p2 = " + p2);
    
            assertThat(p1).isNotSameAs(p2);
    
    //        p1.close();
    //        p2.close();
    
            context.close();
        }
    
        @Scope("prototype")
        static class PrototypeBean {
            @PostConstruct
            void init() {
                System.out.println("PrototypeBean.init");
            }
    
            @PreDestroy
            void close() {
                System.out.println("PrototypeBean.close");
            }
        }
    }

    '개발 > Spring' 카테고리의 다른 글

    세션 인증 때 커스텀 애노테이션 적용하기  (0) 2023.06.26
    Validation에서 에러 문구 설정  (0) 2023.06.20
    컨트롤러(핸들러)가 조회되는 과정  (2) 2023.06.11
    @Configuration  (0) 2023.05.10
    [AOP] before의 우선순위  (0) 2023.04.30

    댓글

Designed by Tistory.