빈 공간(03/23/26)

– 빈 공간

범위: Bean이 존재할 수 있는 범위입니다.

– Spring이 지원하는 분야

원링, 프로토타입

-웹 관련 분야

요청: 들어오고 나가는 웹 요청에 의해 유지되는 영역.

session: 웹 세션이 생성되고 종료될 때까지 유지되는 범위

응용 프로그램: 웹의 서블릿 컨텍스트와 동일한 범위로 유지되는 범위

-싱글톤, 프로토타입 차이

싱글톤 빈의 경우 스프링 컨테이너는 사용자가 빈을 가져올 때 항상 같은 인스턴스의 빈을 반환하지만 사용자가 프로토타입 범위에서 빈을 가져올 때 스프링 컨테이너는 항상 새 인스턴스를 생성하고 종속성 주입 및 – 초기화만 처리합니다. 클라이언트가 반환되고 더 이상 Spring 컨테이너에 의해 관리되지 않습니다. 따라서 @Predestroy와 같은 종료 메서드는 호출되지 않습니다.

-테스트 프로토타입 스코프 빈

package hello.core.scope;

import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Scope;

public class PrototypeTest {

    @Test
    void prototypeBeanFind(){
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(PrototypeBean.class);
        System.out.println("find prototypeBean1");
        PrototypeBean prototypeBean1 = ac.getBean(PrototypeBean.class);
        System.out.println("find prototypeBean2");
        PrototypeBean prototypeBean2 = ac.getBean(PrototypeBean.class);
        System.out.println("prototypeBean1 = "+ prototypeBean1);
        System.out.println("prototypeBean2 = "+ prototypeBean2);

        Assertions.assertThat(prototypeBean1).isNotSameAs(prototypeBean2);

        ac.close();
    }

    @Scope("prototype")
    static class PrototypeBean{
        @PostConstruct
        public void init(){
            System.out.println("PrototypeBean.init");
        }

        @PreDestroy
        public void destory(){
            System.out.println("PrototypeBean.destroy");
        }
    }
}

-prototype scope – 싱글톤 bean과 함께 사용할 때의 문제

package hello.core.scope;

import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Scope;

public class SingletonWithPrototypeTest1 {

    @Test
    void prototypeFind(){
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(PrototypeBean.class);
        PrototypeBean prototypeBean1 = ac.getBean(PrototypeBean.class);
        prototypeBean1.addCount();
        Assertions.assertThat(prototypeBean1.getCount()).isEqualTo(1);

        PrototypeBean prototypeBean2 = ac.getBean(PrototypeBean.class);
        prototypeBean2.addCount();
        Assertions.assertThat(prototypeBean2.getCount()).isEqualTo(1);
    }
    @Test
    void singletonClientUsePrototype(){
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(ClientBean.class, PrototypeBean.class);

        ClientBean clientBean1 = ac.getBean(ClientBean.class);
        int count1 = clientBean1.logic();
        Assertions.assertThat(count1).isEqualTo(1);

        ClientBean clientBean2 = ac.getBean(ClientBean.class);
        int count2 = clientBean2.logic();
        Assertions.assertThat(count2).isEqualTo(2);


    }

    @Scope("singleton")
    static class ClientBean{
        private final PrototypeBean prototypeBean; //생성시점에 주입

        @Autowired
        public  ClientBean(PrototypeBean prototypeBean){
            this.prototypeBean = prototypeBean;
        }
        public int logic(){
            prototypeBean.addCount();
            int count = prototypeBean.getCount();
            return count;
        }
    }

    @Scope("prototype")
    static class PrototypeBean {
        private int count = 0;

        public void addCount(){
            count++;
        }
        public int getCount() {
            return count;
        }
        @PostConstruct
        public void init(){
            System.out.println("PrototypeBean.init"+this);
        }

        @PreDestroy
        public void destroy(){
            System.out.println("PrototypeBean.destroy");
        }
    }
}

싱글톤 빈은 빌드 시 의존성 주입만 받고 프로토타입 빈은 재구축되지만 싱글톤 빈과 함께 유지되기 때문에 프로토타입 범위의 기능을 사용할 수 없다.