스프링 스터디, #2

박주진·2021년 8월 25일
0

스프링 스터디

목록 보기
2/3

아래 내용은 김영한 님의 스프링 핵심 원리 기본편의 내용에 기반한다.

스프링 컨테이너와 스프링 빈

Application Context는 스프링 컨테이너이며 인터페이스 이다.
인터페이스이기 때문에 XML기반, 애노테이션 기반 등 다양한 방식으로 스프링 컨테이너를 생성할 수 있다.

스프링 컨테이너 생성과정

1 구성정보(예)AppConfig.class)를 기반으로 ApplicationContext 생성
2 설정 클래스 정보를 기반으로 빈 등록
3 스프링 빈 의존관계 설정

참고로 보통 스프링은 빈을 생성하고, 의존관계를 주입하는 단계가 나누어져 있다 하지만 자바코드로 스프링 빈을 등록하면 생성자 호출과 동시에 의존관계 주입도 처리된다.

  • AppConfig 예시
@Configuration
public class AppConfig {
 
  @Bean
 public MemberService memberService() {
 return new MemberServiceImpl(memberRepository());
 }
 
 @Bean
 public MemberRepository memberRepository() {
 return new MemoryMemberRepository();
 }
 
}

컨테이너에서 빈 조회 하는방법

  • 기본방식 (ac.getBean(빈이름, 타입),ac.getBean(타입))
  • 동일한 타입 있을시 (ac.getBeansOfType())를 통해 모두 조회 가능

참고로 부모 타입으로 조회하면, 자식 타입도 함께 조회한다. 예) Object 타입으로 조회시 Object를 상속하는 모든 객체(즉 등록된 모든 객체)가 같이 조회된다.

beanFactory와 applicationContext

아래와 같은 의존 구조이다.
BeanFactory(interface) <- ApplicationContext(interface) <- AnnotationConfigApplicationContext(class)

BeanFactory - 최상위 인터페이스로써 스프링 빈을 관라하고 조회하는 역할 담당 (getBean 메서드 제공)
ApplicationContext- BeanFactory 기능을 모두 상속받고 추가적을 아래와 같은 부가 기능 제공

  • 메세지 소스 활용한 국제화 (MessageSource interface)
  • 환경 변수 (EnvironmentCapable interface)
  • 애플리케이션 이벤트 (ApplicationEventPublisher interface)
  • 편리한 리소스 조회 (ResourceLoader interface)

ISP 원칙에 지켜 부가 기능을 제공하는 인터페이스가 분리되어 있다.
ApplicationContext는 부가 기능을 제공하기 위해 여러 인터페이스를 상속받는다.

다양한 설정형식

스프링은 XML,Groovy, 자바 코드 등 다양한 설정 정보를 받아드릴 수 있도록 유연하게 설계되어 있다.
설정 정보에 따라 AnnotationConfigApplicationContext, GenericXmlApplicationContext 와 같은 클래스를 이용해 스프링 컨테이너인 ApplicationContext를 생성할 수 있다.

스프링 빈 설정 메타 정보

스프링은 BeanDefinition 추상화로 다양한 설정 형식을 지원할 수 있다.
스프링 컨테이너는 BeanDefinition에만 의존하고 설정 정보가 어떤것 이든(xml, 자바코드)읽어서 BeanDefinition만 생성하면 되도록 되어 있다.

스프링 빈을 만드는 두가지 방법

  • 직접 등록
  • factory bean (java config)

웹 애플리케이션과 싱글톤?

웹 애플리케이션은 고객 요청이 빈번하다 그럴때마다 객채를 생성하면 메모리 낭비에 우려가 있다. 그래서 싱글톤을 도입하면 하나의 객체로 많은 요청을 처리할 수 있어 성능향상에 이점이 있다.

싱글톤 패턴 구현법

싱글톤 구현방법에은 여러가지가 있다. 그중에 가장 간단하고 안전한 방법은 아래와 같다.

public class SingletonExample {

 private static final SingletonExample instance = new SingletonExample();

 public static SingletonExample getInstance() {
 return instance;
 }

 private SingletonExample() {
 }

}

싱글톤 단점

  • 싱글톤 패턴을 구현하는 코드를 추가해야 한다.
  • 클라이언트가 구체 클래스에 의존한다. (DIP,OCP 위반할 가능성 있음)
  • 테스트 하기 어렵다.
  • 내부 속성을 변경하거나 초기화 하기 어렵다.
  • 상속하기 어렵다.
  • 유연하지 못하다.
    이러한 문제점이 존재하기 때문에 스프링에서는 싱글톤 패턴 없이 객체 인스턴스를 싱글톤으로 관리 해주는 싱글톤 컨테이너를 제공한다.

싱글톤 컨테이너

싱글톤 컨테이너를 활용하면 지저분한 코드 없이 그리고 위에 언급된 제약사항으로 부터 자유롭게 싱글톤을 구현할 수 있다.

싱글톤 방식의 주의점

무상태로 설계해야한다.

  • 특정 클라이언트에 의존적인 필드 x
  • 특정 클라이언트가 값을 변경할 수 있는 필드 x
  • 가급적 읽기만!
  • 필요하다면 공유되지 않는 지역변수, 파라미터, ThreadLocal 등을 사용!

무상태로 설계하지 않는다면 의도치 않게 여러 쓰레드간에 값이 공유되어 정말 해결하기 어려운 오류가 발생될 수 있다.

@Configuration?

@Configuration 애노테이션이 객체를 생성할 때 싱글톤을 보장하게 해준다.
스프링에서 @Configuration 붙은 클래스는 CGLIB 바이트 조작 라이브러를 통해 싱글톤을 보장하게끔 코드르 변경한뒤 빈으로 등록시킨다.

예를 들면 아래와 같다.
-변환전

@Configuration
public class AppConfig {
 
 @Bean
 public MemberRepository memberRepository() {
 return new MemoryMemberRepository();
 }
 
}

-변환후

@Configuration
public class AppConfig {
 
 @Bean
 public MemberRepository memberRepository() {
   if (memoryMemberRepository가 스프링 컨테이너에 등록되어 있나?) {
          return 스프링 컨테이너에서 반환
   } else { 
   //스프링 컨테이너에 없으면
   기존 로직을 호출해서 MemoryMemberRepository를 생성하고 스프링 컨테이너에 등록
   return 반환
      }
 }
 
}

간략하게 이런식으로 변경되기 때문에 memberRepository()메서드가 여러번 호출되어도 싱글톤이 보장 된다.

0개의 댓글