아래 코드는 이번 차시의 테스트에 공통적으로 사용할 Product , Beverage , Bread , ShoppingCart 클래스이다.
Product(abstract class)
public abstract class Product {
private String name; //상품명
private int price; //상품가격
public Product() {}
public Product(String name, int price) {
super();
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
@Override
public String toString() {
return name + " " + price;
}
}
Beverage
public class Beverage extends Product {
private int capacity; //용량
public Beverage() {
super();
}
public Beverage(String name, int price, int capacity) {
super(name, price);
this.capacity = capacity;
}
public int getCapacity() {
return this.capacity;
}
public void setCapacity(int capacity) {
this.capacity = capacity;
}
@Override
public String toString() {
return super.toString() + " " + this.capacity;
}
}
Bread
public class Bread extends Product {
private java.util.Date bakedDate; //생산시간
public Bread() {
super();
}
public Bread(String name, int price, java.util.Date bakedDate) {
super(name, price);
this.bakedDate = bakedDate;
}
public java.util.Date getBakedDate() {
return this.bakedDate;
}
public void setBakedDate(java.util.Date bakedDate) {
this.bakedDate = bakedDate;
}
@Override
public String toString() {
return super.toString() + " " + this.bakedDate;
}
}
ShoppingCart
public class ShoppingCart {
private final List<Product> items; //쇼핑카트에 담긴 상품들
public ShoppingCart() {
items = new ArrayList<>();
}
public void addItem(Product item) {
items.add(item);
}
public List<Product> getItem() {
return items;
}
}
bean scope란 스프링 빈이 생성될 때 생성되는 인스턴스의 범위를 의미한다. 스프링에서는 다양한 bean scope를 제공한다.
| Bean Scope | Description |
|---|---|
| Singleton | 하나의 인스턴스만을 생성하고, 모든 빈이 해당 인스턴스를 공유하여 사용한다. |
| Prototype | 매번 새로운 인스턴스를 생성한다. |
| Request | HTTP 요청을 처리할 때마다 새로운 인스턴스를 생성하고, 요청 처리가 끝나면 인스턴스를 폐기한다. 웹 애플리케이션 컨텍스트에만 해당된다. |
| Session | HTTP 세션 당 하나의 인스턴스를 생성하고, 세션이 종료되면 인스턴스를 폐기한다. 웹 애플리케이션 컨텍스트에만 해당된다. |
<aside>
💡 Spring Framework에서 Bean의 기본 스코프는 singleton이다. singleton은 애플리케이션 내에서 하나의 인스턴스만을 생성하고, 모든 빈이 해당 인스턴스를 공유하여 사용한다. 이를 통해 메모리 사용량을 줄일 수 있으며, 성능 향상을 기대할 수 있다.
</aside>
@Configuration
public class ContextConfiguration {
@Bean
public Product carpBread() {
return new Bread("붕어빵", 1000, new java.util.Date());
}
@Bean
public Product milk() {
return new Beverage("딸기우유", 1500, 500);
}
@Bean
public Product water() {
return new Beverage("지리산암반수", 3000, 500);
}
@Bean
@Scope("singleton") //기본값
public ShoppingCart cart() {
return new ShoppingCart();
}
}
ContextConfiguration 설정 파일에 Bread 타입의 붕어빵과 Beaverage 타입의 딸기우유와 지리산암반수, ShoppingCart 타입의 쇼핑카트를 bean으로 등록 한다. @Scope 어노테이션에 기본 값에 해당하는 singleton 설정도 기재하였다.
/* 빈 설정 파일을 기반으로 IoC 컨테이너 생성 */
ApplicationContext context = new AnnotationConfigApplicationContext(ContextConfiguration.class);
/* 붕어빵, 딸기우유, 지리산 암반수 등의 빈 객체를 반환 받는다. */
Product carpBread = context.getBean("carpBread", Bread.class);
Product milk = context.getBean("milk", Beverage.class);
Product water = context.getBean("water", Beverage.class);
/* 첫 번째 손님이 쇼핑 카트를 꺼낸다. */
ShoppingCart cart1 = context.getBean("cart", ShoppingCart.class);
cart1.addItem(carpBread);
cart1.addItem(milk);
/* 붕어빵과 딸기우유가 담겨있다. */
System.out.println("cart1에 담긴 내용 : " + cart1.getItem());
/* 두 번째 손님이 쇼핑 카트를 꺼낸다. */
ShoppingCart cart2 = context.getBean("cart", ShoppingCart.class);
cart2.addItem(water);
/* 붕어빵과 딸기우유와 지리산암반수가 담겨있다. */
System.out.println("cart2에 담긴 내용 : " + cart2.getItem());
/* 두 카드의 hashcode를 출력해보면 동일한 것을 볼 수 있다. */
System.out.println("cart1의 hashcode : " + cart1.hashCode());
System.out.println("cart2의 hashcode : " + cart2.hashCode());
이 예제에서 손님 두 명이 각각 쇼핑 카트를 이용해 상품을 담는다고 가정했지만 singleton으로 관리되는 cart는 사실 하나의 객체이므로 두 손님이 동일한 카트에 물건을 담는 상황이 발생한다. 상황에 따라서 기본 값인 singleton 스코프가 아닌 prototype 스코프가 필요할 수 있다.