Java와 Spring의 철학 — 읽기 자료
@Component 계열클래스를 Bean 으로 등록하는 어노테이션. @Service, @Repository, @Controller 모두 같은 역할 + 의미상의 구분.@Autowired컨테이너 안의 적절한 Bean 을 자동으로 찾아 주입하는 어노테이션.전 차시 IoC 는 발상(원칙)이고, 이번 차시 DI 는 그 발상을 코드로 실제 구현하는 방식입니다.
요리사(클래스)가 매번 시장 가서 재료(부품)를 사 오면 요리에 집중할 수 없습니다. 「필요한 재료를 주방으로 배달받는」 방식이 DI. 요리사는 요리(비즈니스 로직)에만 집중하면 됩니다.
@Service
public class OrderService {
@Autowired
private MessageSender sender;
public void order() {
sender.send("주문 완료");
}
}
@Service — "이 클래스를 컨테이너에 등록하라" (Bean 등록)@Autowired — "이 자리에 적절한 Bean 을 끼워넣어라" (Bean 주입)| 어노테이션 | 의미적 자리 |
|---|---|
@Component | 일반 Bean (특별한 의미 없음) |
@Service | 비즈니스 로직 계층 |
@Repository | 데이터 접근 계층 (DB 다루는 곳) |
@Controller | 웹 요청 진입점 |
기능적으로는 모두 동일합니다 — Spring 이 같은 일을 합니다. 의미적으로 어떤 계층에 속한 클래스인지를 표시할 뿐.
@Service
class OrderService {
@Autowired
private MessageSender sender; // 필드에 직접
}
@Service
class OrderService {
private final MessageSender sender;
@Autowired // (생성자가 1개면 생략 가능)
public OrderService(MessageSender sender) {
this.sender = sender;
}
}
@Service
class OrderService {
private MessageSender sender;
@Autowired
public void setSender(MessageSender sender) {
this.sender = sender;
}
}
생성자 주입이 ① 의존성을 final 로 만들 수 있고 ② 테스트가 쉽고 ③ 순환 참조를 컴파일 타임에 잡아주기 때문에 가장 권장됩니다. 학습 단계에선 필드 주입으로 시작해도 OK.
// main 에서 직접
MessageSender s = new GmailSender();
OrderService svc = new OrderService(s);
svc.order();@Service
class OrderService {
@Autowired
private MessageSender sender;
}
// main 에서 직접 주입할 필요 없음IoC 의 발상은 알지만 직접 main 에서 주입했다.
@Autowired 한 줄이면 자동 주입. Spring 의 가장 핵심적인 어노테이션 두 개 (@Service, @Autowired) 를 안다.