쿠릉쿠릉 쾅쾅
쿠릉쿠릉 쾅쾅
쿠릉쿠릉 쾅쾅
250x250
전체 방문자
오늘
어제
  • 분류 전체보기
    • HTML CSS
    • 잡담
    • 프로그래밍 꿀팁 사이트
    • 코딩 도서
    • [자바]
      • 디자인 패턴
      • 자바의 정석 - 3판
      • 자바
      • 자바 문법
    • git
    • [TDD]
    • 개발 서적 독후감
      • 클린 코더
      • 토비 스프링3
      • 객체지향의 사실과 오해
      • 모던 자바 인 액션
      • 엘레강트 오브젝트
    • CS
      • 운영체제
      • HTTP
    • [SQL]
      • SQL 기초
      • 혼자공부하는SQL
    • [ Spring ]
      • REST API
      • Spring Toy
      • Spring 에러
      • Spring
      • Spring 입문
      • Spring 핵심 원리
      • SpringMVC 1편
      • SpringMVC 2편
      • Spring Boot를 이용한 RESTful We..
      • Batch
    • [JPA]
      • JPA
      • JPA 에러
      • JPA 프로그래밍 - 기본편
      • 스프링 부트와 JPA 활용 1 - 웹 애플리케이..
      • 실전! 스프링 부트와 JPA 활용2 - API 개..
      • 실전! 스프링 데이터 JPA
      • 실전! Querydsl
    • 인텔리제이
    • [DB]
      • DB
      • H2
    • Gradle
    • 면접
    • [알고리즘]
      • 알고리즘
      • 자료구조
      • 자바 알고리즘 공부
    • [프로젝트]
    • 쿠릉식 객체지향 사고
    • 리눅스

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • querydsl
  • MVC
  • 함수형인터페이스
  • SQL
  • 백준
  • java
  • JPA
  • Git
  • 스프링
  • springboot
  • REST API
  • GitHub
  • 깃허브
  • http
  • 스프링부트
  • 자료구조
  • 자바
  • Spring
  • 재귀
  • 알고리즘

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
쿠릉쿠릉 쾅쾅

쿠릉쿠릉 쾅쾅

[Spring] DI (의존성 주입)
[ Spring ]/Spring

[Spring] DI (의존성 주입)

2022. 1. 22. 15:06
728x90

 

 

 

📌 Spring 삼각형

스프링이란, IoC와 AOP를 지원하는 경량의 컨테이너 프레임 워크다.

스프링의 기반이 되는 설계 개념을 표현한 것

📌 DI (Dependency Injection)

  • DI는 의존관계 주입이라고 부른다.
  • 의존관계 주입은 어떤 객체 내부에서 특정 객체를 직접 생성해서 사용하는 것이 아니라 외부에서 생성한 후 주입 받은 후 사용하는 방법이다.
  • 의존관계 주입은 어떤 객체 내부에서 특정 객체를 직접 생성해서 사용하는 것이 아니라 외부에서 생성한 후 주입 받은 후 사용하는 방법이다.
  • 의존관계는 정적인 클래스 의존관계와 실행 시점에 결정되는 동적인 객체(인스턴스) 의존관계 둘을 분리해서 생각해야 한다.
  • 애플리케이션 실행 시점(런타임)에 외부에서 실제 구현 객체를 생성하고 클라이언트에 전달해서 클라이언트와 서버의 실제 의존관계가 연결 되는 것을 의존관계 주입이라고 한다.
  • 의존관계 주입을 사용하면 클라이언트 코드를 변경하지 않고, 클라이언트가 호출하는 대상의 타입 인스턴스를 변경할 수 있다.
  • DI(의존관계 주입 or 의존성 주입)를 통해서 모듈 간의 결합도가 낮아지고 유연성이 높아진다.
  • DI는 IoC(제어의 역전) 프로그래밍 모델을 구현하는 방식 중 하나다.
  • 스프링에서는 IoC를 구체적으로 DI라는 방식을 통해서 제어의 역전을 형성하고 있다.

 

🔍 DI 실생활 예시

  • 장난감들은 배터리가 있어야 움직일 수 있다. 즉, 배터리에 의존하고 있다.
  • 장난감에 배터리를 넣는 것이 의존성 주입이다.

 

  • 배터리 일체형인 경우에는 생성자에서만 의존성을 주입해주는 상황이라 배터리를 교체할수가 없다. 유연하지 못한 설계 방식이다. 
  • 배터리 일체형처럼 클래스 내부에 new 연산자를 통해 새로운 클래스를 만드는 방식은 강현 결합력을 가지고 있다.
  • 배터리 분리형인 경우 생성자 주입 방식 또는 setter 메서드를 이용하여 배터리를 외부에서 주입받고 있다. 이처럼 외부에서 주입 받는 방식은 유연한 설계가 가능하다. 스프링에서는 이 방법을 권장하고 있다.
  • 배터리 분리형처럼 클래스 외부에서 인터페이스 타입으로 다른 클래스의 객체를 받는 방식은 느슨한 결합이라고 한다.

 

🔍 의존관계 주입하는 방법

  • 생성자 주입 (Consturctor Injection)
  • 수정자 주입 (Setter Injection)
  • 필드 주입 (Field Injection)
  • 일반 메서드 주입 (method Injection)

 

✔ 생성자 주입

  • 객체가 생성되는 시점에 의존성이 주입된다.
  • 최근에 가장 많이 쓰이며 생성자를 1개만 만들어서 @Autowired를 생략한다.
  • 한 번에 여러개의 의존관계를 주입 받을 수 있다.
  • 필드값의 불변성(final)을 보장한다.

✔ 수정자 주입

  • 객체의 SetXxxx()가 호출되는 시점에 의존성이 주입된다.
  • 필드값을 변경할 수 있기 때문에 특별한 경우에만 쓴다. 
  • 한 번에 오직 한 개의 의존관계를 주입 받을 수 있다.

✔ 필드 주입

  • 객체의 인스턴스 필드에 의존성을 주입한다.
  • 안 쓰는것이 좋다.

 

💡 수정자 주입 방식 단점

  • 런타임에 수정자(set)메서드를 통해서 객체를 건드리는 습관은 좋지 않다.
  • 이 경우 NullPointerException이 발생하거나 예상치 못한 버그가 발생할 확률이 높다.
  • 그렇기 때문에 객체의 멤버변수는 항상 불변객체(final)로 해주는 습관이 좋다. 

 

🧷 생성자 주입 방식이 제일 안전하다.
✔ 단일 책임의 원칙(SRP)을 지키기 쉽다.
한눈에 해당 객체에 대한 의존관계와 복잡도를 알 수 있다.

✔ 테스트가 용이하다.
DI 컨테이너를 사용하지 않고도 인스턴스화 할 수 있고, 다른 DI 프레임워크로 쉽게 바꿀 수 있다.

✔ Immutablity
객체의 불변성(final)을 보장할 수 있다.

✔ 순환 의존성
생성자 주입에서는 객체가 서로 순환 의존성을 가질 경우 BeanCurrentlyCreationException이 발생한다. 

 

🔍 의존성 예시

@Component
public class BookService {

    private BookRepository bookRepository;

    public BookService(BookRepository bookRepository) {
        this.bookRepository = bookRepository;
    }
}

@Component
public class BookRepository {
}
  • 위 코드와 같이 BookService 클래스는 BookRepository 클래스가 필요하다. 이 때 BookService 클래스는 BookRepository 클래스의 의존성을 가진다 라고 한다.
  • 외부 클래스 객체를 어떤 방식으로 받냐에 따라서 결합도가 높고 낮음이 결정된다.
    • 위 코드는 낮은 결합 방식이다. 스프링은 낮은 결합 방식을 선호한다.

 

💡 강한 결합 

@Component
class B {}

@Component
class C {}
@Component
class A {
    B b = new B();
}
  • 객체 내부에서 다른 객체를 생성하는 것은 강한 결합도를 가진다.
  • A 클래스 내부에서 B 객체를 직접 생성하고 있다면, B 객체를 C 객체로 바꾸고 싶은 경우에 A 클래스도 수정해야하는 방식이기 때문에 강한 결합이다.

 

💡 느슨한 결합

interface Repository {}

@Component
class B implements Repository {}

@Component
class C implements Repository {}
@Component
class A {
    private final Repository repository;

    A(Repository repository) {
        this.repository = repository;
    }
}
  • 객체를 주입 받는 것은 외부에서 생성된 객체를 인터페이스 타입을 통해서 넘겨 받는 것이다.
  • 이렇게 하면 결합도를 낮출 수 있고, 런타임시에 의존관계가 결정되기 때문에 유연한 구조를 가진다.
  • 위 코드처럼 생성자 주입 방식이 제일 많이 쓰인다.

 

 

 

👀 참고 자료

  • https://biggwang.github.io/2019/08/31/Spring/IoC,%20DI%EB%9E%80%20%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C/#-3
  • https://devlog-wjdrbs96.tistory.com/165?category=882236

 

728x90

'[ Spring ] > Spring' 카테고리의 다른 글

[Spring] HttpServletRequest 객체  (0) 2022.02.06
[Spring] 빈(Bean) 스코프(scope)  (0) 2022.01.31
[Spring] 빈(Bean) 생명주기 콜백 시작  (0) 2022.01.29
[Spring] 조회한 빈(Bean)을 List, Map에 담기  (0) 2022.01.24
[Spring] 스프링 빈(Bean) 등록 수동, 자동 결정 기준  (0) 2022.01.24
    '[ Spring ]/Spring' 카테고리의 다른 글
    • [Spring] 빈(Bean) 스코프(scope)
    • [Spring] 빈(Bean) 생명주기 콜백 시작
    • [Spring] 조회한 빈(Bean)을 List, Map에 담기
    • [Spring] 스프링 빈(Bean) 등록 수동, 자동 결정 기준
    쿠릉쿠릉 쾅쾅
    쿠릉쿠릉 쾅쾅
    깃허브 주소 : https://github.com/kureung

    티스토리툴바