[퍼비톡] DI와 IoC

Song Chae Won·2023년 9월 27일

퍼비톡

목록 보기
10/10
post-thumbnail

🪴 Spring

정의

  • 스프링(Spring)은 프레임 워크

Frame(틀) + work(동작) = 틀 안에서 동작

  • 스프링은 오픈 소스이다
    - 소스코드가 공개되어 있다
    - 내부에서 불편한 부분이 있으면 수정하여 컨트리뷰트(기여) 할 수 있음

• 스프링(Spring)은 DI와 IoC 적용에 중요한 역할
➡️ 의존성 관리와 객체 생명주기 효율적 관리 가능 !

IoC (Inversion of Control)

제어의 역전, 프로그램의 제어 흐름을 외부에서 관리
• 스프링의 핵심 Inversion of Control(제어의 역전)
• 프로그램의 제어 흐름을 개발자가 아닌 외부에서 관리
• 주도권을 스프링에게 빼앗김

DI (Dependency Injection)

정의

의존성 주입
Spring에서 DI는 어떤 객체에 스프링 컨테이너가 또 다른 객체와 의존성을 맺어주는데, 사용자가 객체를 직접 생성하는 게 아니라 외부에서 생성 한 후 주입시켜 주는 것을 의미

의존성 주입 방법

1. 생성자 주입

  • 생성자에 @Autowired를 붙이는 방법
  • 생성자가 하나인 경우, @Autowired를 붙이지 않아도 실행됨 (Spring 4.3 버전부터)
  • Spring에서 가장 권장하는 방식
    - 생성자 주입은 객체를 호출할 때 딱 한 번만 호출되므로 불변성 확보
    - 순환 참조 방지 가능
    ➕ 순환 참조: 두 개 이상의 스프링 빈이 서로를 참조하며 무한하게 참조하는 상황

➡️ 프레임워크에 의존하지 않고 순수 자바 언어의 특징을 가장 잘 살리는 방법

  • 최근에는 생성자를 딱 1개 두고, @Autowired를 생략하는 방식 주로 사용
  • 여기에 Lombok 라이브러리의 @RequiredArgsConstructor를 함께 사용

➡️ 기능은 다 제공하면서, 깔끔한 코드 완성 !

@Component
public class OrderServiceImpl implements OrderService {
 
    private final MemberRepository memberRepository;
    private final DiscountPolicy discountPolicy;
 
    @Autowired // 생략해도 자동 주입
    public OrderServiceImpl(MemberRepository memberRepository, 
														DiscountPolicy discountPolicy) {
        this.memberRepository = memberRepository;
        this.discountPolicy = discountPolicy;
    }
}

2. Setter 메소드 주입

  • Setter 메소드를 정의해서 사용
  • 변경 가능성이 있는 상태를 가질 수 있음
  • Setter 메서드를 public으로 두어야 함 ➡️ 오류에 취약
  • 순수 자바 코드를 통해 단위 테스트를 하는 경우 의존 관계가 누락 시
    ➡️ NullPointerException 을 통해서만 확인 가능
public class OrderServiceImpl implements OrderService {
 
    private MemberRepository memberRepository;
    private DiscountPolicy discountPolicy;
 
    @Autowired
    public void setMemberRepository(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }
 
    @Autowired
    public void setDiscountPolicy(DiscountPolicy discountPolicy) {
        this.discountPolicy = discountPolicy;
    }
}

3. 필드 주입

  • 클래스 내부 필드에 @Autowired를 붙여 의존성 주입
  • 코드가 간결한 가장 간단한 방법

❗가급적 사용을 지양

  • final을 선언할 수 없어 객체의 불변성 위반
  • 테스트 용이성 감소
  • 순환 의존성 감지 어려움
  • 리플렉션 의존

➕ 리플렉션 : 실행 시간에 클래스, 인터페이스, 필드, 메소드 등의 메타데이터 정보를 조회하거나, 수정하고 새로운 인스턴스를 생성하는 등의 작업을 할 수 있게 해주는 기능

@Component
public class OrderServiceImpl implements OrderService {
 
    @Autowired
    private MemberRepository memberRepository;
    @Autowired
    private DiscountPolicy discountPolicy;
 
}

4. 일반 메서드 주입

  • 일반 메서드를 통해 의존 관계를 주입하는 방식
  • 한번에 여러 필드를 주입 받을 수 있음
  • 일반적으로 사용하지 않음
@Component
public class OrderServiceImpl implements OrderService {
 
    private MemberRepository memberRepository;
    private DiscountPolicy discountPolicy;
 
    @Autowired
    public void init(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
        this.memberRepository = memberRepository;
        this.discountPolicy = discountPolicy;
    }
}

의존성 주입 Annotation

@Component
• 기본적인 컴포넌트로, 스프링 빈으로 자동 등록
• @Repository, @Service, @Controller 등은 모두 @Component를 포함하는 애노테이션

@Autowired
• 해당 타입의 객체를 찾아서 자동으로 빈을 연결, Spring에서 지원

@Qualifier
• @Autowired와 함께 사용되어 특정 빈의 이름을 이용하여 의존성을 주입

@Resource
• 해당 타입의 객체를 찾아서 자동으로 할당, 객체의 이름을 이용하여 의존성 주입
➕ XML 파일: 별도 파일인 .xml 파일에 등록할 Bean들을 모두 정의

@Autowired

• 필요한 의존 객체의 타입에 해당하는 Bean을 찾아 주입
• 생성자, setter, 필드 에서 사용 가능

❗ 사용시 주의할 점
• DI는 스프링이 관리하는 객체에서만 동작함
➡️ Spring Bean으로 등록하지 않고 직접 생성한 객체에서는 동작 X

• Bean이 없는 경우 의존성 주입이 불가능
➡️ 주입한 Bean이 없어도 동작해야 하는 경우 존재!

Lombok

반복되는 메서드를 어노테이션을 사용하여 자동으로 작성해주는 라이브러리

Lombok을 사용하는 이유

코드 간결성
반복적으로 작성되는 메서드를 애노테이션을 통해 자동 생성한다

유지 보수 용이성
필드가 추가/변경되었을 때, 관련 메서드를 일일이 수정할 필요가 없다

가독성 향상
중복되는 코드를 줄여 클래스의 핵심 로직에 집중할 수 있게 한다

Lombok을 사용한 의존성 주입 Annotation

@RequiredArgsConstructor
Final 또는 @NonNull로 선언된 필드에 대한 생성자를 자동 생성

@AllArgsConstructor
클래스의 모든 필드에 대한 생성자를 자동으로 생성
➡️ 단, 모든 필드에 대한 생성자를 만들기 때문에 의존성 주입이 필요하지 않은 필드도 생성자의 인자로 포함될 수 있음

@NoArgsConstructor
매개 변수가 없는 기본 생성자를 생성

profile
@chhaewxn

0개의 댓글