[스터디] DI, IoC 등 스프링 부트 컨셉트

suhwani·2024년 8월 17일
0
post-thumbnail

스프링 부트의 출시

스프링은 장점이 많은 개발 도구이지만, 설정이 매우 복잡하다는 단점이 있다.
그래서 단점을 보완하고자 나온 게 스프링 부트이다.

스프링 부트는 스프링 프레임워크를 더 쉽고 빠르게 이용할 수 있도록 만들었다.
”의존성 세트” 라고 불리는 스타터를 사용해 간편하게 의존성을 사용하고, 관리한다.

스프링과 다른 스프링 부트 특징


  • 구성의 차이
    • 스프링
      • 필요한 환경을 수동으로 구성하고, 정의해야 한다.
    • 스프링부트
      • 스프링 코어, 스프링 MVC의 모든 기능을 자동으로 로드하므로, 수동으로 개발환경을 구성할 필요가 없다.
  • 내장 WAS
    • 스프링 부트는 자체적으로 WAS을 가지고 있다.
      jar 파일만 만들면, WAS 설정을 하지 않아도 애플리케이션을 실행할 수 있다.
    • 내장 WAS에는 톰캣, 제티, 언더토우가 있고, 상황에 따라 선택할 수 있다.
      기본적으로는 톰캣이다.
  • 스프링 액츄에이터(spring actuator)를 제공한다.
  • XML 설정을 하지 않고, 자바 코드로 모두 작성할 수 있다.

스프링 콘셉트 공부하기


스프링은 모든 기능의 기반을 제어의 역전(IoC)과 의존성 주입(DI)에 두고 있다.

IoC 제어의 역전 Inversion of Control

제어의 역전은 사용할 객체를 직접 생성하지 않고, 객체의 생명주기 관리를 외부(스프링 컨테이너)에 위임하는 것이다.

  • 아래 그림을 보면, 객체를 생성할 때는 객체가 필요한 곳에서 직접 생성한다.

  • 제어의 역전은 다른 객체를 직접 생성하거나, 제어하는 것이 아니라 외부에서 관리하는 객체를 가져와 사용하는 것을 말한다. 위 그림에 제어의 역전을 적용하면 다음과 같이 바뀐다.

  • 그림을 보면 클래스 A 내에서 직접 B 객체를 생성하는 게 아니라, 어딘가에서 생성된 B 객체를 가져와서 사용하는 것이다. 이런 객체를 관리, 제공하는 역할을 스프링 컨테이너가 한다.

DI 의존성 주입 Dependency Injection

의존성 주입은 제어 역전의 방법 중 하나로, 사용할 객체를 직접 생성하지 않고, 외부 컨테이너가 생성한 객체를 주입받아 사용하는 방식이다.

  • 아래 그림에서 @Autowired 애너테이션은 스프링 컨테이너에 있는 빈을 주입하는 역할이다.

  • 빈은 스프링 컨테이너에서 관리하는 객체를 말하는데, 위 그림에서 보면, 객체를 생성하지 않고 선언만 할 뿐이다.
  • 다시 말해서 객체를 주입받고 있다. 이처럼 코드를 작성해도 잘 작동하는 이유는 스프링 컨테이너에서 객체를 주입했기 때문이다.

  • 스프링 컨테이너에서 B 객체를 만들어서 클래스 A에게 넘겨준 것이다.
  • 기존 코드에서는 클래스 A 내에서 B 객체를 직접 생성했다면, 이제는 스프링 컨테이너에서 객체를 생성하고, 생성된 객체를 클래스 A에서 주입 받아서 사용한다는 것이다.

DI(의존성 주입) 방법

Bean을 등록할 때는 @Component를 통해 등록하고, ( ← 이건 아래에서 얘기 )
다른 곳에서 Bean을 주입 받을 때는 @Autowired를 사용해 의존성을 주입받는다.

[ 3가지 방법 ]
1. 생성자를 통한 의존성 주입
2. 필드 객체 선언을 통한 의존성 주입
3. setter를 통한 의존성 주입

  • 생성자 주입
@Autowired
    public DIController(MyService myService) {
        this.myService = myService;
    }
  • 필드 주입
@Autowired
    private MyService myService;
  • Setter 주입
@Autowired
    public void setMyService(MyService myService) {
        this.myService = myService;
    }
  • 가장 좋은 의존성 주입 방법: 생성자를 통해 의존성을 주입받는 방법
    • 필수적인 의존성의 주입 시점을 보장
    • 필드를 final로 선언이 가능하여 외부의 변경 가능성을 낮춤
    • 의존성 주입이 한 곳(생성자)에서만 일어나므로, 의존성을 한 곳에 모을 수 있음
    • Bean의 순환 참조 문제를 방지할 수 있음
      • 생성자 주입을 사용하면 생성자를 호출하고 필요한 의존성 주입하는 과정이 일련에 일어나기 때문에, 서로를 의존하는 경우에는 빈 등록 자체가 불가능하다.
      • 하지만 필드 주입의 경우 빈을 생성하고, 의존성을 연결하는데 이 때 순환 참조가 발생하면 컴파일 타임에는 문제가 없으나 런타임 시 method를 실행시키는 과정에서 StackOverFlow가 발생하여 서버가 죽게 된다.
      • 따라서 생성자 주입을 사용하면 서버가 운영 중에 꺼지는 사태를 방지할 수 있다.

스프링 컨테이너

스프링 컨테이너는 스프링에서 제공하는 것으로, 빈을 생성하고 관리하는 역할이다.
즉, 빈의 생명주기를 스프링 컨테이너에서 관리하는 것이다.
또한 애너테이션(@Autowired)를 사용해 빈을 주입받을 수 있도록 DI를 지원한다.

빈은 스프링 컨테이너가 생성하고 관리하는 객체를 말한다.
앞서 본 코드에서 B가 바로 빈이다.
빈을 스프링 컨테이너에 등록하기 위해 XML 파일 설정, 애너테이션 추가 등
여러 방법을 제공한다.

  • 아래와 같이 @Component 애너테이션을 붙여서 Class MyBean을 스프링 컨테이너에 빈으로 등록하고 있다. 이 때 빈의 이름은 클래스 이름의 첫 글자를 소문자로 바꿔서 관리한다.
  • 클래스 이름: MyBean 빈 이름: myBean

빈 생명주기

스프링 컨테이너가 생성될 때 객체(Bean)을 생성하고, 의존성을 주입한다.
의존관계 주입 후 Bean을 초기화하고, 스프링 컨테이너를 종료하기 전에 객체를 소멸시킨다.

스프링 컨테이너 생성 → Bean 생성 → 의존성 주입 → 초기화 콜백 → Bean 사용
→ 소멸 전 콜백 → 스프링 종료

객체를 초기화 하는 것은 생성 이외에 외부 커넥션 연결, 초기값 등록 등 여러 작업을 의미한다. 따라서 초기화는 객체 생성을 포함하여 비교적 무거운 일을 수행한다.

  • 초기화 콜백 Init
    • Bean이 생성되고, Bean의 의존성 주입 후 호출
  • 소멸 전 콜백 Destroy
    • 스프링 종료 전, Bean이 소멸되기 직전에 호출된다.

Bean 초기화, 소멸 전 특정 메소드 실행

  • 클래스 내 메서드에서 지정
    • Bean 초기화 콜백 메소드 지정
      • @PostConstruct : 메서드에 해당 에너테이션을 추가하면, Bean 초기화 시점에 실행된다.
    • Bean 소멸 콜백 메소드 지정
      • @PreDestory : 메소드에 해당 에너테이션을 추가하면, Bean 소멸 직전에 실행된다.
  • @Configuration 에서 지정
    • @Bean(initMethod = “init”, destoryMethod = “close”) : 해당 형태로 @Configuration에서 지정할 수 있다.

AOP 관점 지향 프로그래밍 Aspect Oriented Programming

관점을 기준으로 핵심 관점과 부가 관점으로 나눠 모듈화하는 것이다.

  • 계좌 이체, 고객 관리 프로그램이 있다면 둘다 로깅을 위한 DB 연결 기능이 포함된다.
  • 이 때 로깅을 위한 DB 연결 기능을 모듈화해 개발한다면, 하나의 코드를 각 프로그램에서 사용할 수 있다.
  • 이처럼 핵심 관점 코드와 부가 관점 코드를 나눠 모듈화하는 것이 AOP이다.

PSA 이식 가능한 서비스 추상화 Portable Service Abstraction

스프링에서 제공하는 다양한 기술들을 추상화해 개발자가 쉽게 사용하는 인터페이스

  • 대표적인 예) 애너테이션, 매핑, JPA, MyBatis, JDBC…
    • 어떤 기술을 사용하든 일관된 방식으로 DB에 접근하도록 인터페이스를 지원하는 것
    • WAS를 톰캣이 아닌 언더토우, 네티와 같은 다른 곳에서 실행해도 기존 코드를 그대로 사용하는 것

한 줄 정리

IoC : 객체의 생성과 관리를 개발자가 아닌 스프링 프레임워크에세 대신하는 것
DI : 외부에서 객체를 주입받아 사용하는 것
AOP : 프로그래밍을 할 때 핵심 관점과 부가 관점을 나눠 모듈화하는 것
PSA : 어느 기술을 사용하던 일관된 방식으로 처리해 코드 변경 없이 사용하는 것

스프링 부트 3 기본적인 애너테이션


@SpringBootApplication

자바의 main() 메서드와 같은 역할로, 여기서 스프링 부트가 시작된다.

  • 해당 애너테이션은 여러 애너테이션으로 구성된다.
  • @SpringBootApplication을 구성하는 세 가지 애너테이션을 봐야한다.
    • @SpringBootConfiguration
    • @ComponentScan
    • @EnableAutoConfiguration

@SpringBootConfiguration

@Configuration을 상속해서 만든 애너테이션

@ComponentScan

@Component라는 애너테이션을 가진 클래스들을 찾아 빈으로 등록하는 역할

  • 개발자가 등록한 빈을 읽고 빈을 등록하는 애너테이션이다.
  • 모든 빈을 @Component만 사용하는 것은 아니다. 용도에 따라 다른 애너테이션을 사용한다.
    • @Configuration : 설정 파일 등록
    • @Repository : ORM 매핑
    • @Controller & @RestController : 라우터
    • @Service : 비즈니스 로직

번외. @RestController

  • @RestController의 구성을 살펴보면 @Controller & @ResponseBody가 포함되어 있다.
  • 그 중 @Controller 구성을 살펴보면 @Component 애너테이션이 포함되어있다.
  • 따라서 @RestController → @Controller → @Component가 있기 때문에 @ComponentScan을 통해 빈으로 등록되는 것을 알 수 있다.
  • 결국 빈을 등록하기 위해서는 @Component를 가지고 있다.
    @Component와 이름을 다르게 해서 각각 어떤 용도로 사용하고,
    어떤 역할을 하는지 구분할 뿐이다.

@EnableAutoConfiguration

스프링 부트에서 자동 구성을 활성화하는 애너테이션
서버가 실행될 때 스프링 부트의 메타 파일을 읽고 정의된 설정들을 자동으로 구성하는 역할을 수행

profile
Backend-Developer

0개의 댓글