ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • IoC 컨테이너와 빈(2) - 빈의 스코프
    카테고리 없음 2020. 3. 16. 23:10
    반응형

    빈의 스포크

    싱글톤

    애플리케이션 전반에 걸쳐서 해당 빈의 인스턴스가 1개뿐

     

    @Service
    public class Proto {
    	@Autowired
    	private Single single;
    
    	public Single getSingle() {
    		return single;
    	}
    
    	public void setSingle(Single single) {
    		this.single = single;
    	}
    }
    @Service
    public class Single{	
    }
    
    @Controller
    public class HomeController {
    	@Autowired
    	Proto proto;
    	@Autowired
    	Single single;
    	@RequestMapping(value = "/", method = RequestMethod.GET)
    	public String home(Locale locale, Model model) {
    		System.out.println(single);
    		System.out.println(proto.getSingle());
    		System.out.println(single);
    		return "home";
    	}
    }

    위의 코드 실행 결과

     

    프로토타입 

    매번 새로운 인스턴스를 만들어서 사용

    • Request
    • Session
    • WebSocket
    @Service
    @Scope("prototype")
    public class Proto {
    }
    @Service
    public class Single{
    }
    @Controller
    public class HomeController {
    	@Autowired
    	ApplicationContext ctx;
    	
    	@RequestMapping(value = "/", method = RequestMethod.GET)
    	public String home(Locale locale, Model model) {
    		System.out.println("proto");
    		System.out.println(ctx.getBean(Proto.class));
    		System.out.println(ctx.getBean(Proto.class));
    		System.out.println(ctx.getBean(Proto.class));
    		
    		System.out.println("single");
    		System.out.println(ctx.getBean(Single.class));
    		System.out.println(ctx.getBean(Single.class));
    		System.out.println(ctx.getBean(Single.class));
    		return "home";
    	}
    }

    Single proto 차이

    프로토타입 빈이 싱글톤 빈을 참조시

    싱글 인스턴스는 매번 같은 인스턴스를 가져오기 때문에 아무 문제 없음

    @Service
    @Scope("prototype")
    public class Proto {
    	@Autowired
    	Single single;
    }

     

    싱글톤 빈이 프로토타입 빈을 참조하면? 

    프로토타입 빈이 업데이트가 되어야 되는데 업데이트가 안된다.

    @Service
    @Scope("prototype")
    public class Proto {
    	@Autowired
    	Single single;
    }
    
    @Service
    public class Single{
    	@Autowired
    	private Proto proto;
    	
    	public Proto getProto() {
    		return proto;
    	}
    }	
    @Controller
    public class HomeController {
    	@Autowired
    	ApplicationContext ctx;
    	
    	@RequestMapping(value = "/", method = RequestMethod.GET)
    	public String home(Locale locale, Model model) {
    		System.out.println("proto");
    		System.out.println(ctx.getBean(Proto.class));
    		System.out.println(ctx.getBean(Proto.class));
    		System.out.println(ctx.getBean(Proto.class));
    		
    		System.out.println("single");
    		System.out.println(ctx.getBean(Single.class));
    		System.out.println(ctx.getBean(Single.class));
    		System.out.println(ctx.getBean(Single.class));
    		
    		System.out.println("proto by single");
    		System.out.println(ctx.getBean(Single.class).getProto());
    		System.out.println(ctx.getBean(Single.class).getProto());
    		System.out.println(ctx.getBean(Single.class).getProto());
    		
    		return "home";
    	}
    }

    싱글톤 빈이 프로토타입 빈을 참조할 때

     

    이유 및 해결 방안

    • 아래 코드를 설명하면 class기반의 빈을 프록시를 감싸서 그 프록시 빈을 사용하게 해라라고 설정
    • 직접 사용하게 된다면 매번 프록시를 바꿔줘야되는데 매번 바꿔줄 수 없기 때문에 proxy를 상속받는 클래스를 만들어서 사용
    • CG라이브러리기반에 클래스를 상속받아 프록시를 만들게 한다.
    • 다이나믹 프록시(JDK)는 인터페이스의 프록시밖에 만들지 못한다.

    싱글톤 빈이 프로로타입 빈을 참조할 때

     

    scodped-proxy   

    proxyMode = ScopedProxyMode.TARGET_CLASS

    @Scope 어노테이션에 proxyMode 사용  - 백기선님이 추천함

    // CG라이브러리를 상속받는 프록시 사용
    @Component @Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
    public class Proto {
    }
    
    // 다이내믹 프록시 사용(JDK)
    @Component @Scope(value = "prototype", proxyMode = ScopedProxyMode.INTERFACES)
    public class Proto {
    }
    

     

    Object-Provider

    @Component @Scope(value = "prototype")
    public class Proto {
    }
    
    
    @Service
    public class Single{
    	@Autowired
    	private ObjectProvider<Proto> proto;
    	
    	public Proto getProto() {
    		return proto.getIfAvailable();
    	}
    }	
    
    
    @Controller
    public class HomeController {
    	@Autowired
    	ApplicationContext ctx;
    	
    	@RequestMapping(value = "/", method = RequestMethod.GET)
    	public String home(Locale locale, Model model) {
    		System.out.println("proto");
    		System.out.println(ctx.getBean(Proto.class));
    		System.out.println(ctx.getBean(Proto.class));
    		System.out.println(ctx.getBean(Proto.class));
    		
    		System.out.println("single");
    		System.out.println(ctx.getBean(Single.class));
    		System.out.println(ctx.getBean(Single.class));
    		System.out.println(ctx.getBean(Single.class));
    		
    		System.out.println("proto by single");
    		System.out.println(ctx.getBean(Single.class).getProto());
    		System.out.println(ctx.getBean(Single.class).getProto());
    		System.out.println(ctx.getBean(Single.class).getProto());
    		
    		return "home";
    	}
    }

     

     

     

     

     

    반응형
Designed by Tistory.