1. Bean

아래 코드는 이번 차시의 테스트에 공통적으로 사용할 Product , Beverage , Bread , ShoppingCart 클래스이다.

  1. 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;
    	}
    }
    
  2. 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;
    	}
    }
    
  3. 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;
    	}
    }
    
  4. 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;
    	}
    }
    

1-1. Bean Scope

bean scope란 스프링 빈이 생성될 때 생성되는 인스턴스의 범위를 의미한다. 스프링에서는 다양한 bean scope를 제공한다.

Bean Scope Description
Singleton 하나의 인스턴스만을 생성하고, 모든 빈이 해당 인스턴스를 공유하여 사용한다.
Prototype 매번 새로운 인스턴스를 생성한다.
Request HTTP 요청을 처리할 때마다 새로운 인스턴스를 생성하고, 요청 처리가 끝나면 인스턴스를 폐기한다. 웹 애플리케이션 컨텍스트에만 해당된다.
Session HTTP 세션 당 하나의 인스턴스를 생성하고, 세션이 종료되면 인스턴스를 폐기한다. 웹 애플리케이션 컨텍스트에만 해당된다.

1-1-1. singleton

<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 스코프가 필요할 수 있다.

1-1-2. prototype