Backend

Spring Core (1) IoC - 1

wrallee 2020. 6. 26. 00:33

Spring Design Philosophy

스프링의 디자인 철학(원문)

  • 모든 단계마다 선택지를 제공합니다.
  • 다양한 관점을 수용합니다.
  • 강력한 하위 호환성을 유지합니다.
  • API 설계에 신경써야 합니다.
  • 코드 품질에 엄격합니다

IoC Container & Bean

IoC: 의존 관계 주입(Dependency Injection)이라고도 한다. 어떤 객체를 의존성으로 주입받아 사용하는 것.

스프링에서 관리하는 객체들을 Bean이라고 하며, 이를 생성하고, 관리하며 제공하는 중앙저장소를 IoC Container라고 한다. IoC Container의 가장 최상위에 있는 인터페이스는 BeanFactory이며, 아주 핵심적인 클래스이다.

Bean을 사용함으로써

  • 싱글톤으로 하나의 객체를 재사용함으로써 메모리, 성능 최적화에 이점을 가진다.
    • Bean은 기본적으로 싱글톤 스코프(단 하나)로 생성된다.
    • 반대는 프로토타입 스코프(매번 다른 객체)이다.
  • 라이프사이클 인터페이스를 활용할 수 있다(ex. @PostConstruct).
  • 의존성 관리를 편리하게 할 수 있다.

1. ApplicationContext

기존에는 Xml방식의 applicationContext를 사용하며 일일이 bean 등록하고 연관관계를 정의해주었다. 그러나 이러한 과정들이 너무 번거로워 Spring 2.5부터 context:component-scan이 등장하게 되었다.

ClassPathXmlApplicationContext

이후 Xml 말고 Java로 만들 수 없을까 해서 나온게 Annotation 방식의 Java Configuration이다. @Configuration 어노테이션과 @Bean을 활용하여 작성할 수 있으며, 마찬가지로 @ComponentScan을 적용할 수 있다.

AnnotationConfigApplicationContext

ComponentScan에 의해 탐지되는 Bean은 기본적으로 @Component를 붙여 정의할 수 있으며, 이외에도 이 어노테이션을 확장한 @Service, @Repository도 사용할 수 있다.

이러한 Configuration, ComponentScan을 포함하여 확장시킨 어노테이션이 바로 @SpringBootApplication이다.

2. @Autowired

Constructor, Setter, Field에 적용 가능한 의존성 주입 어노테이션. 옵션으로 required가 있으며, default는 true이므로 주입이 실패하면 컨테이너가 뜨지 않는다.

required를 false로 설정하면 애플리케이션은 뜨지만 의존성이 주입되지 않은채로 Bean이 생성될 수 있다.

  • @Primary: 빈이 여러개일 때 우선적으로 주입할 Bean임을 정의
  • @Quarlifier: 빈 ID를 새로 정의한다(default는 첫글자가 소문자인 카멜케이스).
  • 모두 주입 받으려면 List<상위클래스명>으로 타입을 선언하면 된다.

Bean은 기본적으로 필드명을 ID에 매칭하게 되는데, 필드명을 바꿔서 주입 우선순위를 바꾸는건 권장되지 않는 방법이다. 차라리 @Primary를 쓸 것!!

Spring의 추상화 로직들은 BeanFactory가 BeanPostProcessor들을 찾고, 관련 로직을 실행하면서 적용된다. Autowired 역시 AutowiredAnnotationBeanPostProcessor가 실행되면서 적용(주입)된다.

3. @ComponentScan

컴포넌트 스캔에서는 스캔 위치와 필터가 중요하다. 어디서부터 스캔을 시작할지, 어떤 어노테이션을 스캔할지 안할지를 정의할 수 있다. 스캔 위치를 벗어나면 @Component로 정의해도 Bean으로도 생성되지 않는다. 당연히 주입도 안된다. 실제 스캐닝은 ConfigurationClassPostProcessor라는 BeanFactoryPostProcessor에 의해 처리된다.

@Repository, @Service, @Controller, @Configuration 모두 @Component를 확장한 어노테이션이며, Bean으로 등록된다.

ApplicationContextInitializer의 펑션을 사용하여 빈을 직접등록하면 성능상 이점을 가질 수 있지만 또 다시 장황한 설정파일이 생기게 된다. 필요할때만 쓰자