ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Bean ( @Scope , Provider )
    백엔드/SPRING MVC 2024. 8. 22. 16:45

    빈 스코프란?

    • Bean이 존재할 수 있는 범위
    • 종류
      • 싱글톤 스코프
      • 프로토타입 스코프
      • 웹 관련 스코프

     

    스코프 지정 방법

    //Component 등록
    @Scope("[스코프 지정]")
    @Component
    public class Test(){}
    
    
    
    // 수동 등록
    @Scope("[스코프 지정]")
    @Bean
    public class Test(){
        return new Test();
    }
    • scope
      • singleton
      • prototype
      • request
      • session
      • application

     

    스코프 특징

    • 싱글톤 빈
      • 객체 생성 -> 의존관계 주입 -> 초기화 -> 사용 -> 소멸전 콜백 -> 소멸
    • 프로토타입 빈
      • 객체 생성 -> 의존관계 주입 -> 초기화
      • 프로토타입의 경우 1) 초기화 진행 후 클라이언트 코드에게 관리 위임
      • 프로토타입의 경우 2) 프로토타입 빈 요청이 올때마다 새로운 객체를 생성하게 됨\ 
    • 웹 스코프
      • 웹 요청 -> 객체 생성 -> 의존관계 주입 -> 초기화 -> 웹 응답 -> 소멸전 콜백
      • 웹 스코프 종류 : Request, application, session, websocket
        • Request : 웹 요청이 들어왔을때 객체생성
        • application : application이 시작 될때 객체 생성
        • session : session 연결이 시작될때 객체 생성
        • websocket : 웹 소켓 세션이 시작될때 객체 생성

     

    싱글톤 + 프로토타입

    • 싱글톤 객체 생성 후 프로토타입 빈을 호출하는 경우
      •  싱글톤 객체는 한번 생성 후 공유해서 사용하므로 딱 1개만 생성되게 된다
      • 하지만, 프로토타입의 경우 싱글톤에서 호출이 될뿐 새롭게 요청이 오는게 아니므로 싱글톤처럼 사용되게 된다.
    public class Test{
        
        @Test
        void testExample(){
            AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SingletonBean.class, PrototypeBean.class);
            
            SingletonBean singletonBean1 = ac.getBean(SingletonBean.class);
            int count1 = singletonBean1.logic();
            
            
            SingletonBean singletonBean2 = ac.getBean(SingletonBean.class);
            int count2 = singletonBean2.logic();
        
        }
        
        
        static class SingletonBean {
           private final PrototypeBean prototypeBean;
             
           @Autowired
           //여기서 Prototype이 싱글톤 생성시 같이 생성됨 (의존관계 주입)
           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++;
            }
    
        }
    }

     

    • logic()이 호출되어서, prototype을 사용하는건 처음 싱글톤 객체 생성시 만들어졌던 프로토타입 빈을 사용한것이다.
    • 따라서, 결과가 count1 = 1, count2 = 2 가 되게된다 (원래는 프로토타입이 계속 새로 생성되기를 원함)

     

    • 해결1) logic이 호출될때마다, Prototype Bean을 조회해서 사용 (Dependency Lookup)
    public class Test{
        
        @Test
        void testExample(){
            AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SingletonBean.class, PrototypeBean.class);
            
            SingletonBean singletonBean1 = ac.getBean(SingletonBean.class);
            int count1 = singletonBean1.logic();
            
            
            SingletonBean singletonBean2 = ac.getBean(SingletonBean.class);
            int count2 = singletonBean2.logic();
        
        }
        
        
        static class SingletonBean {
           
           @Autowired
           private ApplicationContext ac;
            
           
           public int logic() {
               //DL (조회를 통한 Bean get)
               PrototypeBean prototypeBean = ac.getBean(PrototypeBean.class);
               prototypeBean.addCount();
               int count = prototypeBean.getCount();
               return count;
           }
           
        }
    
        @Scope("prototype")
        static class PrototypeBean {
            private int count = 0;
             
            public void addCount() {
                count++;
            }
    
        }
    }

     

    • 해결2) ObjectProvider , ObjectFactory
      • ObjectProvider : 스프링에서 지원하는 provider (다른 컨테이너를 사용하지 않는다면 기능이 다양한 해당 provider 추천)
      • Provider  : java에서 지원하는 provider ( spring 컨테이너 이외의 컨테이너에서도 사용할 수 있음, 스프링에 종속적이지 않음)
    public class Test{
        
        @Test
        void testExample(){
            AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SingletonBean.class, PrototypeBean.class);
            
            SingletonBean singletonBean1 = ac.getBean(SingletonBean.class);
            int count1 = singletonBean1.logic();
            
            
            SingletonBean singletonBean2 = ac.getBean(SingletonBean.class);
            int count2 = singletonBean2.logic();
        
        }
        
        
        static class SingletonBean {
           
           /*
           // java 지원 provider
           
           private Provider<PrototypeBean> provider;
           
           */
           
           // spring 지원 provider
           @Autowired
           private ObjectProvider<PrototypeBean> prototypeBeanProvider;
            
           
           public int logic() {
               //DL (조회를 통한 Bean get)
               // PrototypeBean prototypeBean = provider.get();
               PrototypeBean prototypeBean = prototypeBeanProvider.getObject();
               prototypeBean.addCount();
               int count = prototypeBean.getCount();
               return count;
           }
           
        }
    
        @Scope("prototype")
        static class PrototypeBean {
            private int count = 0;
             
            public void addCount() {
                count++;
            }
    
        }
    }

     

     

     

    Web Scope

    • Web Scope 생명주기
      • 웹 관련 스코프의 경우 해당 요청이 들어왔을 때 생성되고, 응답 후 소멸하게 되는 생명주기를 가지게 된다.
      • 하지만, 스프링 컨테이너의 경우 싱글톤 빈으로 관리하게 되고 application 시작시 생성되고 application이 종료될때까지 생명주기를 가지게 된다.
      • 생명주기 : web Scope < spring container singleton Scope
    • Proxy 사용
      • 싱글톤 생명주기를 맞추기 위해서 , Proxy를 사용해서 Web Scope를 맞추게 됨
      • 웹 요청이 오기전에 spring에서 미리 생성하게됨
    public class TestExample{
    
        @Test
        public void testExample(){
            AnnotaionConfigApplicationContext ac = new AnnotaionConfigApplicationContext(AppConfig.class);
            
            RequestBean requestBean = ac.getBean(RequestBean.class);
            System.out.println("Request Count up" + requestBean.incrementAndGet());
            
            ac.close();
        }
        
        
        
        @Configuration
        static class AppConfig{
             
             @Bean
             // "value=" 의 경우, 파라미터가 2개이상일때는 value를 지정해서 작성해야함
             // 파라미터를 한개만 넘길경우 value 생략가능
             @Scope(value = "request" , proxyMode = ScopedProxyMode.TARGET_CLASS)
             public RequestBean requestBean(){
                  return new RequestBean();
             }
             
        }
        
        
        
        static class RequestBean{
             privage int count = 0;
             
             public int incrementAndGet(){
                 count++;
                 
                 return count;
            }
        }
        
        
     }
Designed by Tistory.