[Spring] 스프링 컨테이너와 빈
2023. 6. 11. 17:24
Section 3 들어가기 전 한 Section 1에서 실습했던 자바 프로젝트를 스프링으로 전환하는 연습 중.
그 전에 순수 자바 코드로 작성된 프로그램과 스프링으로 전환한 프로그램의 차이는 "스프링 컨테이너의 존재 여부"
스프링으로 전환되면서 AppConfigurer 클래스는 스프링 컨테이너의 관리를 받게 된다.
✔️ 코드를 통해 살펴보기
1. 스프링 컨테이너
public class Main {
public static void main(String[] args) {
// AppConfigurer appConfigurer = new AppConfigurer();
//
// OrderApp orderApp = new OrderApp(
// appConfigurer.productRepository(),
// appConfigurer.menu(),
// appConfigurer.cart(),
// appConfigurer.order()
// );
// (1)스프링 컨테이너 생성
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfigurer.class);
// (2)스프링 빈 조회
ProductRepository productRepository = applicationContext.getBean("productRepository", ProductRepository.class);
Menu menu = applicationContext.getBean("menu", Menu.class);
Cart cart = applicationContext.getBean("cart", Cart.class);
Order order = applicationContext.getBean("order", Order.class);
// (3)불러온 빈의 사용 --> 의존성 주입
OrderApp orderApp = new OrderApp(
productRepository,
menu,
cart,
order
);
// (4) 프로그램 실행
orderApp.start();
}
}
➡️ 스프링 컨테이너는 스프링에서 자바 객체들을 관리하는 공간을 말한다. 그리고 스프링 빈의 생성부터 소멸까지 개발자를 대신하여 관리해주는 곳이라고 할 수 있다.
➡️ 컨테이너는 BeanFactory, ApplicationContext로 나눌 수 있지만 ApplicationContext가 BeanFactory(인터페이스)를 상속받으며 추가적인 기능을 제공하기 때문에 일반적으로 ApplicationContext(인터페이스)를 스프링 컨테이너라고 부른다.
- 위 코드는 기존에 개발자가 AppConfigurer 클래스를 사용하여 직접 객체를 생성하고 DI를 통해 객체를 연결해 주었던 역할을 스프링 컨테이너가 가져가겠다는 의미이다.
- ApplicationContext의 구현 객체인 AnnotationConfigAppicationContext가 매개변수로써 AppConfigurer.class를 구성 정보로 넘겨주고 있는 것을 알 수 있다.
- 스프링 컨테이너는 전달받은 구성 정보를 바탕으로 빈 객체들을 생성하고, 객체들 간의 의존 관계를 연결하게 된다.
→ getBean() 메서드를 활용하여 필요한 객체(스프링 빈)를 필요할 때마다 스프링 컨테이너에서 불러와서 사용할 수 있다는 의미.
→ getBean()을 호출함으로써 인스턴스가 생성되고 스프링 컨테이너의 Singleton으로 등록이 된다.
getBean() 은 사용할 빈 객체를 구하는 메서드 첫 번째 인자는 빈의 이름, 두 번째 인자는 빈의 타입이라고 생각하면 된다.
2. 스프링 빈(Bean)
@Configuration // 스프링 컨테이너가 만들어질 때 AppConfigurer 클래스를 스프링 컨테이너의 구성 정보로 사용한다는 의미
public class AppConfigurer { // 객체를 생성하고 의존 관계를 연결시키는 역할
@Bean // 스프링이 실행되었을 때 빈으로 등록된 메서드들을 모두 호출하여 반환된 객체를 스프링 컨테이너에 등록하고 관리하겠다는 의미
public Menu menu() {
return new Menu(productRepository());
}
@Bean
public ProductRepository productRepository() {
return new ProductRepository();
}
@Bean
public Cart cart() {
return new Cart(productRepository(), menu());
}
@Bean
public Order order() {
return new Order(cart(), discount());
}
@Bean
public Discount discount() { // 코드를 변경하여 손쉽게 할인 정책을 추가하거나 의존 관계 변경 가능
return new Discount(new DiscountCondition[] {
new CozDiscountCondition(new FixedRateDiscountPolicy()),
new KidDiscountCondition(new FixedAmountDiscountPolicy())
});
}
}
➡️ 스프링 컨테이너가 관리하는 자바 객체를 스프링 빈(Bean)이라고 한다. 빈은 클래스의 등록 정보, getter/setter 메서드를 포함하며 구성 정보를 통해 생성된다.
➡️ 스프링 컨테이너는 호출되는 메서드의 이름을 기준으로 빈의 이름을 등록한다.
- @Bean 애너테이션이 붙어있는 menu()라는 이름의 메서드의 호출 결과로 반환된 new Menu(productRepository()) 객체 빈은 menu 라는 이름으로 스프링 컨테이너의 빈 리스트에 저장된다.
- 아래와 같이 빈의 이름을 다르게 설정해 줄 수도 있으나 같은 이름의 빈이 등록되는 경우 에러가 나기 때문에 항상 다른 이름의 빈의 생성하도록 주의해야 한다.
@Configuration
public class AppConfigurer {
@Bean(name="menu2")
public Menu menu() {
return new Menu(productRepository());
}
}
➡️ 스프링 빈을 등록하는 방법
- 스프링 빈 직접 등록
: 위에서 작성한 코드와 같이 @Configuration과 @Bean 애너테이션으로 가능하다. - 컴포넌트 스캔
: @Component 애너테이션을 사용하여 빈을 등록할 수 있다. (참고)
➡️ 스프링 빈 조회
- 위에서 설명한 것과 같이 getBean() 메서드를 통해 등록한 빈을 조회할 수 있다.
- getBean(빈 이름, 타입) : applicationContext.getBean("menu", Menu.class)
- getBean(타입) : applicationContext.getBean(Menu.class)
- 조회하고자 하는 빈이 존재하지 않으면 NosuchBeanDefinitionExeption 발생
- getBeanDefinitionNames()
: 스프링에 등록된 모든 빈 이름 조회 - BeanDefinition.getRole()
: 빈의 역할 출력, 빈의 역할은 크게 두 가지로 나눌 수 있다
: ROLE_INFRASTRUCTURE → 스프링이 내부 동작을 위해 사용하는 빈이라는 의미
: ROLE_APPLICATION → 사용자가 정의한 빈이라는 의미 - getBeansOfType()
: 해당 타입에 해당하는 모든 빈 조회할 수 있다.
'Spring > 기본' 카테고리의 다른 글
[Spring] @Configuration, @Component (0) | 2023.06.21 |
---|---|
[Spring] 싱글톤 컨테이너 (1) | 2023.06.11 |
[Spring] AppConfigurer 클래스의 역할 (0) | 2023.06.11 |
[Spring] 스프링 프레임워크 주요 모듈 알아보기 (0) | 2023.05.31 |