카테고리 없음

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

 

 

 

 

 

반응형