🔸 싱글톤 : 기본 스코프. 스프링 컨테이너의 시작과 종료까지 유지되는 가장 넓은 범위의 스코프
🔸 프로토 타입 : 스프링 컨테이너는 프로토 타입의 빈의 생성과 의존관계 주입까지만 관여. 매우 짧은 범위의 스코프
🔸 웹 관련 스코프들
- request : 한 번의 웹 요청이 들어오고 나갈 때까지 유지되는 스코프
- session : 웹 세션이 생성되고 종료될 때까지 유지되는 스코프
- application : 웹의 서블릿 컨텍스트와 같은 범위로 유지되는 스코프
빈 스코프(Bean Scope) : 스프링 빈이 존재할 수 있는 범위
기본적으로 스프링 빈이 싱글톤 스코프로 생성되기 때문에 스프링 컨테이너의 시작과 함께 생성되어 스프링 컨테이너가 종료될 때까지 유지된다.
🔸 컴포넌트 자동등록
@Scope("prototype") @Component public class HelloBean{}
🔸직접 등록
@Scope("prototype") @Bean PrototypeBean HelloBean(){ return new HelloBean(); }
🔸 싱글톤 빈은 스프링 컨테이너의 생성시점에 빈 생성 및 초기화 메서드가 실행된다.
🔸프로토타입 스코프의 스프링 빈은 스프링 컨테이너에서 빈을 조회할 때 생성, 초기화 메서드가 실행된다.
🔸프로토타입 스코프의 경우에는 클라이언트가 요청한 빈을 반환한 후 관리하지 않는다 ➡️ 종료메서드(@PreDestroy)를 호출하지 않는다.
➡️ 종료메서드를 호출할 필요가 있을 경우, 스프링 컨테이너가 아닌 클라이언트가 호출해야 한다.
🔸 프로토타입 빈이 목적은 호출할 때마다 새로운 빈을 생성하기 위함인데, 싱글톤 빈의 생성자로 의존관계 주입을 받게된다면?
🔸 예public 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; } } public class SigletonUsePrototype{ AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(ClientBean.class, PrototypeBean.class); ClientBean clientBean1 = ac.getBean(ClientBean.class); ClientBean clientBean2 = ac.getBean(ClientBean.class); int count1 = clientBean1.logic(); int count2 = clientBean2.logic(); }
count1 = 1, count2 = 1이 우리의 기대값이지만 실제 결과는 count1 = 1, count2 = 2;
➡️ 처음 생성할 때 한 번 의존관계 주입을 받고 이후에는 계속해서 같은 참조값을 가진 프로토타입 빈을 사용하게 된다.
🔹 ObjectProvider, ObjectFactory
public class ClinetBean{ @Autowired private ObjectProvider<PrototypeBean> prototypeBeanProvider; public int logic() { PrototypeBeanProvider prototypeBean = prototypeBeanProvider.getObject(); prototypeBean.addCount(); int count = prototypeBean.getCount(); return count; } }
🔸ObjectProvider.getObject() : 스프링 컨테이너를 통해 해당 빈을 찾아서 반환한다. ➡️ 항상 새로운 프로토 타입 빈을 생성할 수 있다.
🔸 별동의 라이브러리는 필요없지만, 스프링에 의존적이라는 단점.
🔹JSR-330 Provider
🔸 javax.inject.Provider 라는 자바표준을 이용
➡️ build.gradle에 'javax.inject:javax.inject:1'을 추가해야 사용가능import javax.inject.Provider; public class ClinetBean{ @Autowired private Provider<PrototypeBean> prototypeBeanProvider; public int logic() { PrototypeBean prototypeBean = prototypeBeanProvider.get(); prototypeBean.addCount(); int count = prototypeBean.getCount(); return count; } }
🔸Provider.get() : 스프링 컨테이너를 통해 해당 빈을 찾아서 반환한다. ➡️ 항상 새로운 프로토 타입 빈을 생성할 수 있다.
🔸 별도의 라이브러리가 필요하다는 단점
🔸 자바 표준이기 때문에 스프링이 아닌 다른 컨테이너에서도 사용이 가능하다.
🔸의존관계 조회(Dependency Lookup) : 의존관계를 외부에서 주입받는 것이 아니라 직접 필요한 의존관계를 찾는 것
매번 사용할 때마다 의존관계 주입이 완료된 새로운 객체가 필요할 때 사용
‼️하지만 실무에서는 싱글톤 빈으로 대부분의 문제가 해결가능
➡️ObjectProvider, JSR-330 Provider는 프로토타입에만 사용하는 기능이 아니라 DL이 필요한 경우 언제든 사용가능하다.