
bean scope이란 스프링 빈이 생성될 때 생성되는 인스턴스의 범위를 의미한다.
🔎 Bean Scope의 종류

여기에서는 Singleton과 Prototype에 관해서 알아볼 것이다.
1번과 2번은 Singleton과Prototype에 관한 설명과 이것들을 자바 파일에서 어떻게 설정하는지에 관한 부분이고 3번은 XML 파일에서 어떻게 설정하는지에 관한 부분이다.
스프링 프레임워크에서 Bean의 기본 범위는
singleton이다.
✅ Scope : 범위를 지정해준다. Singletone이 기본값이다. ⭐
✅ DependsOn : 어떤 빈이 다른 빈보다 먼저 생성될 수 있게 강제화 하는 것이다.
✅ Lazy : 컨테이너 동작 시점이 아닌 해당 객체가 필요한 시점에 인스턴스를 생성할 수 있게 한다.
(1) ContextConfiguration.java
import com.dbwls.common.Beverage;
import com.dbwls.common.Bread;
import com.dbwls.common.Product;
import com.dbwls.common.ShoppingCart;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;
public class ContextConfiguration {
@Bean
public Product carpBread() {
System.out.println("붕어빵 생성 시점");
return new Bread("붕어빵", 1000, new java.util.Date());
}
@Bean
// 만약 이렇게 명시한 빈 중 하나라도 생성되지 않으면,
// cart는 생성되지 않고, BeanCreationException이 발생하게 된다.
@DependsOn({"carpBread", "milk", "water"})
@Lazy
@Scope("singleton") // 기본값
public ShoppingCart cart() {
System.out.println("쇼핑 카트 생성 시점");
return new ShoppingCart();
}
@Bean
public Product milk() {
System.out.println("딸기우유 생성 시점");
return new Beverage("딸기우유", 1500, 500);
}
@Bean
public Product water() {
System.out.println("물 생성 시점");
return new Beverage("지리산암반수", 3000, 500);
}
}
(2) Application.java
import com.dbwls.common.Product;
import com.dbwls.common.ShoppingCart;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Application {
public static void main(String[] args) {
ApplicationContext applicationContext
= new AnnotationConfigApplicationContext(ContextConfiguration.class);
/* 슈퍼에 상품이 진열 되어 있다. */
Product carpBread = applicationContext.getBean("carpBread", Product.class);
Product milk = applicationContext.getBean("milk", Product.class);
Product water = applicationContext.getBean("water", Product.class);
System.out.println("쇼핑 카트 객체 꺼내기 전");
/* 쇼핑 카트를 꺼내 상품을 담는다 */
ShoppingCart shoppingCart = applicationContext.getBean("cart", ShoppingCart.class);
System.out.println("쇼핑 카트 객체 꺼낸 다음");
shoppingCart.addItem(carpBread);
shoppingCart.addItem(milk);
System.out.println("cart에 담긴 물품 : " + shoppingCart.getItem());
/* 다음 손님이 와서 쇼핑 카트를 사용한다. */
ShoppingCart shoppingCart2 = applicationContext.getBean("cart", ShoppingCart.class);
shoppingCart2.addItem(water);
System.out.println("cart2에 담긴 물품 : " + shoppingCart2.getItem());
/* 손님이 바꼈지만 동일한 카트를 사용하고 있음 */
// 같은 해시코드가 나옴
System.out.println("1번째 쇼핑 카트의 해시코드 : " + shoppingCart.hashCode());
System.out.println("2번째 쇼핑 카트의 해시코드 : " + shoppingCart2.hashCode());
}
}
필요할 때 마다 새로운 객체를 생성해서 반환하는 것이다. 이를 통해 의존성 주입 등의 작업에서 객체 생성에 대한 부담을 줄일 수 있다.
💡 필요한 순간에만 객체를 생성하므로
(1) ContextConfiguration.java
@Scope("prototype")으로 지정해주면 해당 Bean을 프로토타입으로 인식한다. import com.dbwls.common.Beverage;
import com.dbwls.common.Bread;
import com.dbwls.common.Product;
import com.dbwls.common.ShoppingCart;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
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("prototype") // scope를 prototype으로 지정
public ShoppingCart cart() {
return new ShoppingCart();
}
}
(2) Application.java
import com.dbwls.common.Product;
import com.dbwls.common.ShoppingCart;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Application {
public static void main(String[] args) {
ApplicationContext applicationContext
= new AnnotationConfigApplicationContext(ContextConfiguration.class);
/* 슈퍼에 상품이 진열 되어 있다. */
Product carpBread = applicationContext.getBean("carpBread", Product.class);
Product milk = applicationContext.getBean("milk", Product.class);
Product water = applicationContext.getBean("water", Product.class);
/* 쇼핑 카트를 꺼내 상품을 담는다 */
ShoppingCart shoppingCart = applicationContext.getBean("cart", ShoppingCart.class);
shoppingCart.addItem(carpBread);
shoppingCart.addItem(milk);
System.out.println("cart에 담긴 물품 : " + shoppingCart.getItem());
/* 다음 손님이 와서 쇼핑 카트를 사용한다. */
ShoppingCart shoppingCart2 = applicationContext.getBean("cart", ShoppingCart.class);
shoppingCart2.addItem(water);
System.out.println("cart2에 담긴 물품 : " + shoppingCart2.getItem());
/* 손님이 바뀔 경우 카트가 달라지게 됨 */
System.out.println("1번째 쇼핑 카트의 해시코드 : " + shoppingCart.hashCode()); // 2028555727
System.out.println("2번째 쇼핑 카트의 해시코드 : " + shoppingCart2.hashCode()); // 1625082366
}
}
위에서 알아본 것들은 모두 Java코드를 통해 설정하는 방법이다. 만약 java 코드가 아닌 XML 파일을 이용해 applicationContext에게 Configuration metadata를 넘기고 싶다면, bean 태그 안에 scope 상태를 추가해서 원하는 범위를 넣어주면 된다.
(1) xml에서 singleton 설정
<bean id="cart" class="패키지명.ShoppingCart" scope="singleton"/>
(2) xml에서 prototype설정
<bean id="cart" class="패키지명.ShoppingCart" scope="prototype"/>