2023. 12. 11. 22:49ㆍ카테고리 없음
과제
@Component 같은 애너테이션을 POJO 인스턴스에 붙이는 건 빈 생성에 관한 템플릿을 정의하는 것이지, 실제 빈 인스턴스를 정의하는 게 아니다.
getBean() 메서드로 빈을 요청하거나 다른 빈에서 참조할 때 스프링은 빈 스코프에 따라 어느 빈 인스턴스를 반환할지 결정해야 한다. 이때 기본 스코프 이외의 다른 빈 스코프를 지정할 경우가 있다.
해결책
@Scope는 빈 스코프를 지정하는 애너테이션이다. 스프링은 IoC 컨테이너에 선언한 빈마다 정확히 인스턴스 하나를 생성하고 이렇게 만들어진 인스턴스는 전체 컨테이너 스코프에 공유된다.
getBean() 메서드를 호출하거나 빈을 참조하면 이러한 유일무이한 인스턴스가 반환된다.
이 스코프가 바로 모든 빈의 기본 스코프인 singleton이다.
전체 스프링 빈 스코프 표
스코프 | 설명 |
singleton | IoC 컨테이너당 빈 인스턴스 하나 생성 |
prototype | 요청할 때마다 빈 인스턴스를 새로 만듦 |
request | HTTP 요청당 하나의 빈 인스턴스 생성. 웹 애플리케이션 컨텍스트에만 해당 |
session | HTTP 세션당 빈 인스턴스 하나를 생성. 웹 애플리케이션 컨텍스트에만 해당 |
globalSession | 전연 HTTP 세션당 빈 인스턴스 하나를 생성. 포털 애플리케이션 컨텍스트에만 해당 |
풀이
쇼핑몰 애플리케이션의 카트를 예로 들어보자
Product를 담을 Cart 클래스
@Component
public class ShoppingCart {
private List<Product> items = new ArrayList<>();
public void addItem(Product item) {
items.add(item);
}
public List<Product> getItems() {
return items;
}
}
상품 빈이 등록되어있는 자바 구성파일
@Configuration
@ComponentScan("com.spring.study.chapter02.shop")
public class ShopConfiguration {
@Bean
public Product aaa() {
Battery p1 = new Battery("AAA", 2.5);
p1.setRechargeable(true);
return p1;
}
@Bean
public Product cdrw() {
Disc p2 = new Disc("CD-RW", 1.5);
p2.setCapacity(700);
return p2;
}
@Bean
public Product dvdrw() {
Disc p2 = new Disc("DVD-RW", 3.0);
p2.setCapacity(700);
return p2;
}
}
아래 컨테이너에서 shoppingCart 빈을 IoC 컨테이너에서 두 번 호출해서 cart1과 cart2 변수에 담았는데, 두 객체는 같은 참조를 갖는다.
public static void main(String[] args) {
ApplicationContext context =
new AnnotationConfigApplicationContext(ShopConfiguration.class);
Product aaa = context.getBean("aaa", Product.class);
Product cdrw = context.getBean("cdrw", Product.class);
Product dvdrw = context.getBean("dvdrw", Product.class);
ShoppingCart cart1 = context.getBean("shoppingCart", ShoppingCart.class);
cart1.addItem(aaa);
cart1.addItem(cdrw);
System.out.println("Shopping cart 1 contains " + cart1.getItems());
ShoppingCart cart2 = context.getBean("shoppingCart", ShoppingCart.class);
cart2.addItem(dvdrw);
System.out.println("Shopping cart 2 contains " + cart2.getItems());
}
=>
Shopping cart 1 contains [Product{name='AAA', price=2.5}, Product{name='CD-RW', price=1.5}]
Shopping cart 2 contains [Product{name='AAA', price=2.5}, Product{name='CD-RW', price=1.5}, Product{name='DVD-RW', price=3.0}]
스프링 기본 스코프가 singleton이라서 IoC 컨테이너당 카트 인스턴스가 한 개만 생성되었으니 말이다.
getBean() 메서드 호출 시 상이한 카트 인스턴스를 가져오려면 shoppingCart 빈 스코프를 prototype으로 설정하면 된다.
스프링은 getBean() 호출할 때마다 빈 인스턴스를 새로 만들 것이다.
@Component
@Scope("prototype")
public class ShoppingCart {
private List<Product> items = new ArrayList<>();
public void addItem(Product item) {
items.add(item);
}
public List<Product> getItems() {
return items;
}
}
System.out.println("Shopping cart 1 contains " + cart1.getItems());
System.out.println("Shopping cart 2 contains " + cart2.getItems());
=>
Shopping cart 1 contains [Product{name='AAA', price=2.5}, Product{name='CD-RW', price=1.5}]
Shopping cart 2 contains [Product{name='DVD-RW', price=3.0}]