Notice
Recent Posts
Recent Comments
Link
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | ||||||
| 2 | 3 | 4 | 5 | 6 | 7 | 8 |
| 9 | 10 | 11 | 12 | 13 | 14 | 15 |
| 16 | 17 | 18 | 19 | 20 | 21 | 22 |
| 23 | 24 | 25 | 26 | 27 | 28 | 29 |
| 30 |
Tags
- LLM
- kt_aivle_school
- 컴공
- 보상함수
- 프론트엔드
- 배치사이즈
- 테킷
- 개념
- kt_aivle
- 에이블러
- 이미지
- 오블완
- 논문리뷰
- HTML
- 인공지능
- kt부트캠프
- git
- 머신러닝
- 티스토리챌린지
- kt_부트캠프
- 바틀넥
- 깃허브
- Github
- 멋쟁이사자처럼
- AIVLE
- llm-ma
- 깃
- CSS
- 딥러닝
- 후기
Archives
- Today
- Total
공부하는 안씨의 기록
[정리] 백엔드 기초 - 의존성 주입 (DI) 본문
DI - 의존성 주입
필요한 객체(의존성)를 외부에서 넣어주는 것
- 방법: 생성자 주입 / 세터 주입 / 필드 주입(@ Autowired)
(1) 생성자 주입
- final 사용 가능 → 불변성 보장
- 의존성 누락 방지(주입 안되면 컴파일 에러)
- 테스트 용이
- 순환 참조 문제 조기 발견
@Component
public class Jihyun {
private final Phone phone;
@Autowired
public Jihyun(Phone phone) {
this.phone = phone;
}
}
(2) 필드 주입
- 의존성이 보이지 않고 숨겨져 있음
- 생성자 호출 시 완전한 객체가 아니게 됨
- 순환 참조 문제 늦게 발견됨
- spring 없으면 이 코드 자체가 작동 불가→ 강한 스프링 종속
@Component
public class Jihyun {
@Autowired
private Phone phone;
**// 바로 필드에 꽂아버림**
}
생성자 주입 예시 코드(Phone에 Galaxy 만 implement 하는 경우)
- Jihyun은 Phone 인터페이스만 알고 있음 → 결합도↓, 테스트↑, 교체 용이
import org.springframework.stereotype.Component;
@Component
public class Galaxy implements Phone {
@Override
public void powerOn() {
System.out.println("Hello Galaxy");
}
@Override
public void payment(){
System.out.println("Use SamsungPay");
}
}
@Component
public class Jihyun { **//지현 클래스는 galaxy나 iphone을 직접 생성하지 않음**
private final Phone phone;
// 스프링이 Phone 타입 빈을 찾아 자동 주입
public Jihyun(Phone phone) {
this.phone = phone;
}
public void usePhone() {
phone.powerOn();
phone.payment();
}
}
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(basePackages = "com.example.demo") // 패키지 경로
public class AppConfig {
}
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext ctx =
new AnnotationConfigApplicationContext(AppConfig.class);
Jihyun jihyun = ctx.getBean(Jihyun.class);
jihyun.usePhone(); // Hello Galaxy
}
}
❗만일 IPhone 클래스가 추가되면?
@Primary : 기본 폰은 Galxy로 선언하기
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
@Component
**@Primary // Phone 주입 시 기본으로 선택될 구현체**
public class Galaxy implements Phone {
@Override
public void powerOn() {
System.out.println("Hello Galaxy");
}
@Override
public void payment() {
System.out.println("Use SamsungPay");
}
}
@Component
public class Iphone implements Phone {
@Override
public void powerOn() {
System.out.println("Hello iPhone");
}
@Override
public void payment() {
System.out.println("Use ApplePay");
}
}
//////////////////////////////////////////
import org.springframework.stereotype.Component;
@Component
public class Jihyun { // 여전히 구현체를 모름(Phone 인터페이스만 의존)
private final Phone phone;
public Jihyun(Phone phone) { // Phone 타입 요청
this.phone = phone;
}
public void usePhone() {
phone.powerOn();
phone.payment();
}
}
@Qualifier : Jihyun은 Galaxy만 쓰겠다고 명시
- 사실 @Component만 써도 bean 이름은 자동으로 galaxy, iphone이라서 @Component("galaxy") 는 생략 가능 (명시적으로 써주면 더 눈에 잘 보임)
- 지현은 Galaxy, 다른 사람은 Iphone 처럼 사람마다 다른 구현체를 쓰고 싶을 때 서비스/컨트롤러별로 @Qualifier를 다르게 줄 수 있음
import org.springframework.stereotype.Component;
@Component("galaxy") // bean 이름은 기본이 className camelCase라서 생략 가능
public class Galaxy implements Phone {
@Override
public void powerOn() { System.out.println("Hello Galaxy"); }
@Override
public void payment() { System.out.println("Use SamsungPay"); }
}
@Component("iphone")
public class Iphone implements Phone {
@Override
public void powerOn() { System.out.println("Hello iPhone"); }
@Override
public void payment() { System.out.println("Use ApplePay"); }
}
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
@Component
public class Jihyun {
private final Phone phone;
**public Jihyun(@Qualifier("galaxy") Phone phone) {**
this.phone = phone;
}
public void usePhone() {
phone.powerOn();
phone.payment();
}
}
- 위 두 방법은 들 다 jihyun은 인터페이스(Phone에만 의존한다는 것.)
- 이렇게 하면 DI 조건이 깨짐(이렇게는 x. 의존성 주입이 X)
- 이러면 Jihyun은 Galaxy에 강하게 결합되고,
- 나중에 Iphone으로 바꿀 때 코드 수정을 직접 해야 함
- 테스트 시 Mock/Stub 주입도 힘듦
- -> IoC/DI 원칙 위반
'KT AIVLE 8기 AI 트랙 활동' 카테고리의 다른 글
| [정리] 백엔드 Spring 기초 (프레임워크, OOP+POJO, IoC) (0) | 2025.11.25 |
|---|---|
| [후기] (스터디) 배운 내용은 그날 그날 조금씩 복습하기 (10/28~11/10) (0) | 2025.11.10 |
| [정리&후기] 2차미니프로젝트: AI Agent 설계 (0) | 2025.11.03 |
| [후기] KT AIVLE 8기 오프닝 데이-2주차 (0) | 2025.10.28 |
