[Spring] 스프링 핵심 원리(기본편) 강의 정리 - 2
🌱Spring - 스프링 컨테이너와 스프링 빈
📌 싱글톤 컨테이너 주의점
✏️싱글톤 컨테이너 주의점
- 싱글톤 패턴이든, 스프링 같은 싱글톤 컨테이너를 사용하든, 객체 인스턴스를 하나만 생성해서 공유하는 싱글톤 방식은 여러 클라이언트가 하나의 같은 객체 인스턴스를 공유하기 때문에 싱글톤 객체는 상태를 유지하게 설계하면 안된다.
- 무상태로 설계해야 한다.
(1). 특정 클라이언트에 의존적인 필드가 있으면 안된다.
(2). 특정 클라이언트가 값을 변경할 수 있는 필드가 있으면 안된다.
(3). 가급적 읽기만 가능해야 한다.
(4). 필드 대신에 자바에서 공유되지 않는, 지역변수, 파라미터, ThreadLocal 등을 사용해야 한다.
- 스프링 빈의 필드에 공유 값을 설정하면 큰 장애가 발생할 수 있다.
✏️예시 코드

- statefulService의 “price”필드는 공유되는 필드인데, 특정 클라이언트가 값을 변경한다.
- 사용자A의 주문금액은 10000원이 되어야 하는데, 20000원이라는 결과가 나왔다.
- 진짜 공유 필드는 조심해야한다. 스프링 빈은 항상 무상태(stateless)로 설계한다.
✏️오류 고치기
📌 스프링 컨테이너 생성

다음과 같이 스프링 컨테이너를 생성한다.
✏️스프링 컨테이너 생성과정
- 스프링 컨테이너 생성

- 스프링 컨테이너를 생성할 때는 구성 정보를 지정해주어야 한다.
- 여기서 "AppConfig.class"를 구성 정보로 지정 함
2. 스프링 빈 등록

- 스프링 컨테이너는 파라미터로 넘어온 설정 클래스 정보를 사용해서 스프링 빈을 등록 함
3. 스프링 빈 의존관계 설정 - 준비

4. 스프링 빈 의존관계 설정 - 완료

- 스프링 컨테이너는 설정 정보를 참고해서 의존관계를 주입(DI)한다.
- 단순히 자바 코드를 호출하는 것 같지만, 차이가 있다. 이 차이는 뒤에 싱글톤 컨테이너에서 설명이 이어진다
📌 컨테이너에 등록된 모든 빈 조회
:스프링 컨테이너에 실제 스프링 빈이 잘 등록 되었는지 확인
src/test/java/hello.core/beanfind/ApplicationContextInfoTest

✏️등록된 빈 조회 방법
- 모든 빈 출력하기
- 실행하면 스프링에 등록 된 모든 빈 정보 출력 가능
- 'ac.getBeanDefinitionNames()': 스프링에 등록된 모든 빈 이름 조회
- 'ac.getBean()':빈 이름으로 빈 객체(인스턴스) 조회
2. 애플리케이션 빈 출력하기
- 내가 등록한 빈만 출력 (스프링이 내부에서 사용하는 빈은 'getRole()'로 구분 가능)
- 'ROLE_APPLICATION': 일반적으로 사용자가 정의한 빈
- 'ROLE_INFRASTRUCTURE': 스프링이 내부에서 사용하는 빈
📌 스프링 빈 조회 - 기본
src/test/java/hello.core/beanfind/ApplicationContextBasicFindTest

📌 스프링 빈 조회 - 동일한 타입이 둘 이상
src/test/java/hello.core/beanfind/ApplicationContextSameBeanFindTest

📌 스프링 빈 조회 - 상속 관계
:부모 타입으로 조회하면, 자식 타입도 함께 조회되어 모든 자바 객체의 최고 부모인 Object타입으로 조회하면, 모든 스프링 빈을 조회한다.
:src/test/java/hello.core/beanfind/ApplicationContextExtendsFindTest
✏️상속관계

부모 타입을 조회하면 자식 타입도 함께 조회 됨
모든 자바 객체의 최고 부모는 ‘Object’ (모든 클래스에는 보이지 않아도 자동으로 extends Object가 되어있음)
1번을 조회하면 2,3,4,5,6,7 다 딸려나오고, 2번을 조회시 4,5이 나오고 3번을 조회시 6,7가 나옴

📌 BeanFactory & ApplicationContext
✏️BeanFactory & ApplicationContext

:위는 상속관계를 표현함
BeanFactory (최상위 인터페이스)를 ApplicationContext 인터페이스가 상속받음(BeanFactory 인터페이스에 부가기능을 더한 것)
- ‘BeanFactory’
- 스프링 컨테이너의 최상위 인터페이스, 스프링 빈 관리 및 조회하는 역할
- “getBean()”을 제공
2. ‘ApplicationContext’
- “BeanFactory”의 기능을 상속받아서 제공
- 애플리케이션을 개발할 때는 빈 관리,조회 기능을 물론, 수 많은 부가기능이 필요함
- ApplicationContext가 제공하는 부가 기능
✏️ApplicationContext가 제공하는 부가기능

- 메세지 소스를 활용한 국제화 기능
- 예를 들어서 한국에서 들어오면 한국어로, 영어권에서 들어오면 영어로 출력
2. 환경 변수
- “로컬, 개발, 운영등을 구분해서 처리 (로컬개발환경 - 내 PC에서 개발하는 환경, 테스트 서버에 띄워두고 테스트할 수 있는 개발 환경, 실제 프러덕션에 나가는 운영 환경 등이 각각 어떤 데이터베이스에 연결해야 하는지)
3. 애플리케이션 이벤트
- 이벤트를 발행하고 구독하는 모델을 편리하게 지원
4. 편리한 리소스 조회
- 파일, 클래스패스, 외부 등에서 리소스를 편리하게 조회(외부의 url등을 내부에서 쓸 때 추상화해서 편리하게 쓸 수 있는 기능 제공)
정리

📌 스프링 빈 조회 - 자바 코드, XML
: 스프링 컨테이너는 다양한 형식긔 설정 정보를 받아드릴 수 있게 유연한 설계 구조(Java, XML, Groovy등)

AnnotationConfigApplicationContext = ApplicationContext를 구현 한 우리가 사용했던 AnnotationConfig를 설정 정보로 사용하는 ApplicationContext임
✏️애노테이션 기반 자바 코드 설정 사용
- “New AnnotationConfigApplicationContext(AppConfig.class)”
- ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class); //MemberApp.java 코드
- “AnnotationConfigApplicationContext”클래스를 사용하면서 자바 코드로 된 설정 정보를 넘기면 됨
✏️XML 설정 사용
- “GenericXmlApplicationContext”를 사용하면서 “xml”설정 파일을 넘기면 됨
Xml 기반의 “accpConfig.xml”스프링 설정 정보와 자바 코드로 된 “AppConfig.java”설정 정보를 비교해보면 거의 비슷하다는 것을 알 수 있다.
📌 스프링 빈 설정 메타 정보 - “BeanDefinition”
: 스프링의 다양한 설정 형식의 중심에는 “BeanDefinition”이라는 추상화가 있다.
- 쉽게 이야기 해서 “역할”과 “구현”을 개념적으로 나눈 것
- 스프링 컨테이너는 자바 코드인지, XML인지 몰라도 된다. 오직 “BeanDefinition”만 알면 된다.
✏️“BeanDefinition”
- 빈 설정 메타정보라고 한다.
- “@Bean”, “<bean>”당 각각 하나씩 메타 정보가 생성 됨. 스프링 컨테이너는 이 메타정보를 기반으로 스프링 빈을 생성함

“코드 레벨로 조금 더 깊이 있게 들어가보자면”(사실 몰라도 됨)

정리
- “BeanDefinition”을 직접 생성해서 스프링 컨테이너에 등록할 수 도 있다 하지만 실무에서 BeanDefinition을 직접 정의하거나 사용할 일은 거의 없다 => 어려우면 그냥 넘어가면 된다 ~~
- “BeanDefinition”에 대해서는 너무 깊이있게 이해하기 보다는 스프링이 다양한 형태의 설정 정보를 “BeanfDefinition”으로 추상화해서 사용하는 것 정도만 알면 된다
강의와 강의자료 출처 : https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8