일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 31 |
- 푸시
- JPA
- 디자인패턴
- 도메인 주도 개발
- 성능
- Design Pattern
- 푸시 번역
- 자바스크립트
- 카프카
- 카프카 트랜잭션
- 웹사이트최적화기법
- Push
- ddd
- APNS
- 페이스북 번역
- graphql
- php
- 웹사이트 성능
- nginx
- GCM
- notification
- nginx설치
- Java
- git
- nginx설정
- gcm 푸시 번역
- kafka
- 웹사이트성능
- GCM 번역
- Today
- Total
간단한 개발관련 내용
Dependency Injection 에 대한 올바른 이해와 사용. 본문
Java의 의존성 주입 (Dependency Injection, DI)
소개
Java 기반 웹 서비스 개발자라면 Spring Framework는 필수 도구입니다. Spring의 핵심은 Spring Container를 통해 의존성 주입(DI) 원칙을 구현하는 데 있습니다. 대부분의 개발자는 @Autowired
애너테이션을 통해 DI를 처음 접하게 됩니다.
아래는 @Autowired
를 가장 간단하게 사용하는 예제입니다.
public class MyTest {
@Autowired
MyService1 myService1;
}
의존성 주입 확장하기
개발자가 프레임워크에 익숙해지면, 생성자나 Setter를 사용하여 DI를 확장하게 됩니다. 기본적으로 @Autowired
는 byType으로 Bean을 주입하며, 타입이 일치하는 Bean이 없으면 byName으로 찾습니다. 필수적인 의존성은 생성자(Constructor)를 통해 주입하고, 선택적인 의존성은 Setter를 사용해 주입할 수 있습니다.
예시: @Autowired
를 사용한 생성자와 Setter 기반 DI:
public class MyTest {
private MyService2 myService2;
private MyService3 myService3;
@Autowired
public MyTest(MyService2 myService2) { // 필수 의존성
this.myService2 = myService2;
}
@Autowired(required = false)
public void setMyService3(MyService3 myService3) { // 선택적 의존성
this.myService3 = myService3;
}
}
의존성 주입의 역사와 개념
DI의 개념과 제어의 역전(IoC, Inversion of Control) 간의 관계를 이해해 봅시다.
- IoC (Inversion of Control): 프로그램 제어 흐름을 역전시키는 개념입니다.
- DI (Dependency Injection): IoC를 구현하는 구체적인 설계 패턴입니다.
2004년부터 DI는 Spring과 Guice 같은 프레임워크를 통해 Java 개발에서 중요한 프로그래밍 패러다임이 되었습니다. DI는 유지 보수성, 테스트 용이성, 결합도 감소와 같은 장점을 제공합니다.
2009년 5월, Rod Johnson(Spring의 창시자)과 Bob Lee(Guice의 창시자)가 협업하여 JSR-330 표준을 발표했습니다. 이 표준은 @Inject
와 같은 통일된 DI 애너테이션을 정의합니다.
마틴 파울러의 관점
Martin Fowler는 다음과 같이 설명합니다:
- IoC는 개념입니다.
- DI는 IoC를 구현하는 패턴입니다.
IoC를 구현한 다른 패턴으로는 다음과 같은 것들이 있습니다:
- 팩토리 패턴 (Factory Pattern)
- 서비스 로케이터 패턴 (Service Locator Pattern)
자세한 내용은 Fowler의 글을 참고하세요: Inversion of Control Containers and the Dependency Injection pattern.
프로토타입 빈의 고급 의존성 조회 전략
프로토타입 범위의 Bean(매번 새 인스턴스를 반환해야 하는 경우)을 사용할 때는 @Autowired
만으로는 충분하지 않습니다. Spring은 이를 위해 몇 가지 전략을 제공합니다.
1. ObjectFactory
- ObjectFactory는 프로토타입 빈의 새 인스턴스를 지연 초기화(lazy initialization)할 수 있도록 합니다.
@Component
public class MyBean {
@Autowired
private ObjectFactory<PrototypeBean> prototypeBeanFactory;
public PrototypeBean getPrototypeBean() {
return prototypeBeanFactory.getObject();
}
}
2. ServiceLocatorFactoryBean
- ServiceLocatorFactoryBean을 사용하면 서비스 로케이터 인터페이스를 정의하여 프로토타입 빈을 가져올 수 있습니다.
public interface PrototypeBeanFactory {
PrototypeBean getPrototypeBean();
}
@Configuration
public class AppConfig {
@Bean
public ServiceLocatorFactoryBean prototypeBeanFactory() {
ServiceLocatorFactoryBean factoryBean = new ServiceLocatorFactoryBean();
factoryBean.setServiceLocatorInterface(PrototypeBeanFactory.class);
return factoryBean;
}
}
3. Provider<T> (JSR-330)
- Provider<T>는 JSR-330의 표준 방법으로 프로토타입 빈을 새로 가져옵니다.
import javax.inject.Provider;
@Component
public class MyBean {
@Autowired
private Provider<PrototypeBean> prototypeBeanProvider;
public PrototypeBean getPrototypeBean() {
return prototypeBeanProvider.get();
}
}
4. @Lookup 메서드 주입
- @Lookup 애너테이션은 Spring이 런타임에 메서드를 오버라이드하여 프로토타입 빈을 반환하도록 합니다.
@Component
public abstract class MyBean {
public PrototypeBean getPrototypeBean() {
return createPrototypeBean();
}
@Lookup
protected abstract PrototypeBean createPrototypeBean();
}
Spring의 의존성 주입(DI)은 의존성을 관리하고 느슨한 결합을 구현하는 강력하고 유연한 방법입니다. @Autowired
, 생성자 주입, 또는 ObjectFactory
, @Lookup
과 같은 고급 전략을 사용하면 더 깨끗하고 유지 보수 가능한 코드를 작성할 수 있습니다.
특히 JSR-330 표준은 Java에서 의존성 주입을 통일된 방식으로 정의한 결과이며, 이를 통해 DI의 진화를 확인할 수 있습니다.
참고 자료:
- Martin Fowler의 글: Inversion of Control Containers and the Dependency Injection pattern
- JSR-330 명세
- "The Well-Grounded Java Developer"