본문 바로가기
Back-End/Spring Boot

예습) 스프링 입문

by newny 2023. 5. 11.
반응형

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

댓글