반응형
ApplicationContext
- 스프링 컨테이너라 한다 → 정확히는 스프링 컨테이너를 BeanFactory, ApplicationContext로 구분하여 불러야 하지만, BeanFactory를 직접 사용하는 경우는 거의 없으므로 ApplicationContext를 스프링 컨테이너라 한다.
- ApplicationContext 객체를 생성할 때 매개값으로 Java 코드로 된 설정 정보를 넘긴다.
- ApplicationContext 에 정의한 @Bean 설정 정보를 읽어와 Greeter 객체를 생성, 초기화한다.
- AnnotationConfigApplicationContext 는 ApplicationContext 인터페이스의 구현체이다
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
getBean() 메소드
- ApplicationContext가 생성한 빈 객체를 검색할 때 사용된다.
- 조회 대상 스프링 빈이 없으면 예외 발생 (NoSuchBeanDefinitionException: No bean named 'xxxxx' available)
// 찾아올 객체의 타입을 알 때
FixDiscountPolicy bean1 = applicationContext.getBean("discountPolicy", FixDiscountPolicy.class);
FixDiscountPolicy bean2 = applicationContext.getBean(FixDiscountPolicy.class);
// 찾아올 객체의 타입을 모를 때
Object bean3 = applicationContext.getBean(beanDefinitionName);
BeanDefinition
- Bean 설정 메타 정보
- @Bean 당 하나씩 메타 정보가 생성된다.
- 스프링 컨테이너는 이 메타정보를 기반으로 스프링 빈을 생성한다.
getRole() 메소드
- BeanDefinition 의 메소드
- 스프링이 내부에서 사용하는 빈은 getRole()로 구분 가능
- ROLE_APPLICATION: 직접 등록한 애플리케이션 빈
- Role ROLE_INFRASTRUCTURE: 스프링이 내부에서 사용하는 빈
스프링 빈 조회 - 상속관계
- 부모타입으로 조회하면, 자식타입도 함께 조회된다.
- 모든 자바 객체의 최고 부모인 ‘Object’ 타입으로 조회하면, 모든 스프링 빈을 조회한다.
싱글톤 패턴
- 클래스의 인스턴스가 딱 1개만 생성되는 것을 보장하는 디자인 패턴
- 싱글톤 패턴을 사용하지 않으면 객체가 호출되는 만큼 생성되기때문에 메모리 낭비가 심해짐
싱글톤 패턴의 문제점
- 싱글톤 패턴을 구현하는 코드 자체가 많이 들어감
- 의존관계상 클라이언트가 구체 클래스에 의존한다. → DIP를 위반한다.
- 클라이언트가 구체 클래스에 의존해서 OCP 원칙을 위반할 가능성이 높다.
- 테스트하기 어렵다.
- 내부 속성을 변경하거나 초기화 하기 어렵다.
- private 생성자로 자식 클래스를 만들기 어렵다.
- 결론적으로 유연성이 떨어진다.
- 안티패턴으로 불리기도 한다.
싱글톤 컨테이너
- 스프링 컨테이너는 싱글톤 패턴을 적용하지 않아도, 객체 인스턴스를 싱글톤으로 관리한다.
- 스프링 컨테이너는 싱글톤 컨테이너 역할을 한다 → 이 기능을 싱글톤 레지스트리라 한다.
싱글톤 방식의 주의점
- 여러 클라이언트가 하나의 같은 객체 인스턴스를 공유하기 때문에 싱글톤 객체는 상태 유지하게 설계하면 안된다.
- 무상태(stateless)로 설계해야한다.
- 스프링 빈의 필드에는 공유값을 설정하면 안된다. (private)
@Configuration
- @Configuration 어노테이션으로 인해 스프링 빈의 싱글톤이 보장된다!!
- 그러므로 스프링 설정 정보는 항상 @Configuration 을 사용하자!!!
[코드 뜯기]
package hello.core.beanfind;
import hello.core.AppConfig;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
// Test 코드 public 생략 가능
class ApplicationContextInfoTest {
// 스프링 컨테이너 생성 -> 매개 값으로 설정 정보를 넘김
// getBeanDefinition()메소드 사용을위해 구현객체타입 그대로 객체 생성함
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
@Test
@DisplayName("모든 빈 출력하기") // 모든 빈(스프링이 내부에서 사용하는 빈 + 내가 등록한 빈) 출력
void findAllBean() {
// getBeanDefinitionNames() : 컨테이너의 모든 빈의 이름을 배열로 가져옴
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
// 인텔리제이 iter 키워드 사용하여 향상된 for문 자동 완성
for (String beanDefinitionName : beanDefinitionNames) {
// 객체의 타입을 하나로 명시할 수 없기 때문에 Object로 받음
Object bean = applicationContext.getBean(beanDefinitionName);
System.out.println("name = " + beanDefinitionName + ", object = " + bean);
}
}
@Test
@DisplayName("애플리케이션 빈 출력하기") //내가 등록한 빈만 출력
void findApplicationBean() {
// getBeanDefinitionNames() : 컨테이너의 모든 빈의 이름 배열로 가져옴
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
// 빈의 정보 추출
BeanDefinition beanDefinition = applicationContext.getBeanDefinition(beanDefinitionName);
// 스프링이 내부에서 사용하는 빈은 getRole()로 구분 가능
// ROLE_APPLICATION: 직접 등록한 애플리케이션 빈
// ROLE_INFRASTRUCTURE: 스프링이 내부에서 사용하는 빈
if (beanDefinition.getRole() == BeanDefinition.ROLE_APPLICATION) { //직접 등록한 애플리케이션일 때
Object bean = applicationContext.getBean(beanDefinitionName); // 빈 객체 가져오기
System.out.println("name = " + beanDefinitionName + ", object = " + bean);
}
}
}
}
반응형
'Back-End > Spring Boot' 카테고리의 다른 글
Spring Boot (0) | 2023.05.22 |
---|---|
예습)스프링 입문 (0) | 2023.05.11 |
예습) 스프링 입문 (0) | 2023.05.03 |
댓글