ObjectProvider의 getObject() 를 호출하면 내부에서는 스프링 컨테이너를 통해 해당 빈을 찾아서 반환한다.
prototypeBeanProvider.getObject()을 통해서 항상 새로운 prototype 빈이 생성된다.
public class ProtoTypeTest {
@Test
void providerTest() {
AnnotationConfigApplicationContext ac = new
AnnotationConfigApplicationContext(ClientBean.class, PrototypeBean.class);
ClientBean clientBean1 = ac.getBean(ClientBean.class);
int count1 = clientBean1.logic();
assertThat(count1).isEqualTo(1);
ClientBean clientBean2 = ac.getBean(ClientBean.class);
int count2 = clientBean2.logic();
assertThat(count2).isEqualTo(1);
}
static class ClientBean {
@Autowired
private ObjectProvider<PrototypeBean> prototypeBeanProvider;
public int logic() {
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++;
}
public int getCount() {
return count;
}
@PostConstruct
public void init() {
System.out.println("PrototypeBean.init " + this);
}
@PreDestroy
public void destroy() {
System.out.println("PrototypeBean.destroy");
}
}
}
로그 남기기 예시
@Controller
@RequiredArgsConstructor
public class LogDemoController {
private final LogDemoService logDemoService;
private final MyLogger myLogger;
//private final ObjectProvider<MyLogger> myLoggerProvider;
@RequestMapping("log-demo")
@ResponseBody
public String logDemo(HttpServletRequest request){
String requestURL = request.getRequestURI().toString();
//MyLogger myLogger = myLoggerProvider.getObject();
myLogger.setRequestURL(requestURL);
myLogger.log("controller test");
logDemoService.logic("testId");
return "ok";
}
}
@Service
@RequiredArgsConstructor
public class LogDemoService {
private final MyLogger myLogger;
//private final ObjectProvider<MyLogger> myLoggerProvider;
public void logic(String id) {
//MyLogger myLogger = myLoggerProvider.getObject();
myLogger.log("service id = " + id);
}
}
@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class MyLogger {
private String uuid;
private String requestURL;
public void setRequestURL(String requestURL) {
this.requestURL = requestURL;
}
public void log(String message){
System.out.println("[" + uuid + "]" + "[" + requestURL + "] " + message);
}
@PostConstruct
public void init(){
uuid = UUID.randomUUID().toString();
System.out.println("[" + uuid + "] request scope bean create : " + this);
}
@PreDestroy
public void close(){
System.out.println("[" + uuid + "] request scope bean close : " + this);
}
}
따라서 myLogger.log()을 호출했을 때 가짜 프록시 객체의 메서드를 호출하지만 그 가짜 프록시 객체가 request 스코프의 진짜 myLogger.log()를 호출한다. 가짜 프록시 객체는 원본 클래스를 상속받아서 만들어졌기 때문에 이 객체를 사용하는 클라이언트는 원본인지 가짜인지 상관없이 동일하게 사용할 수 있다.(다형성)