1. Google Guice?
- Spring은 DI 뿐만 아니라 다양한 기능을 제공하는 반면에 Google Guice는 DI 프레임워크이다.
- 작은규모의 프로젝트나 경량성이 중요한 경우에 사용하는 것이 적합하다.
Communicator 인터페이스를 정의했다고 가정하자. Communicator 구현체는 CommunicatorImpl이다. 만약 구현체를 변경해야 하는 상황이 오면 Communication과 Communicator 는 강하게 결합되어 있어 유지보수에 상당한 어려움이 생길 수 있다.
2. 문제 코드
public interface Communicator {
}
public class CommunicatorImpl implements Communicator{
}
public class Communication {
private Communicator communicator = new CommunicatorImpl; // DIP, OCP 위반
}
- 클라이언트(Communication)이 구현체에 의존하고 있기 때문에 객체지향 설계원칙(DIP, OCP)에 위반한다.
- 구현체를 언제든지 쉽게 갈아 끼울 수 있도록 외부에서 의존관계를 주입(DI)하도록 해야한다. DI 프레임 워크인 Guice 사용해서 유지보수성을 높힐 수 있다. Guice를 사용 방법에 대해 간략히 정리하겠다.
3. @Inject
컨텍스트가 관리하는 바인딩 된 객체를 의존관계를 주입받을 때 사용
public class Communication {
@Inject
private Communicator communicator; // DI(의존관계 주입)
@Inject
private Logger logger; // DI(의존관계 주입)
public Communication(Boolean keepRecords) {
if (keepRecords) {
System.out.println("Message logging enabled");
}
}
public boolean sendMessage(String message) {
return communicator.sendMessage(message);
}
}
4. 의존관계 주입 방법 4가지
a. 메서드
public class Communication {
private Communicator communicator; // DI(의존관계 주입)
@Inject
public Communication(@Named("DefaultCommunicator") Communicator communicator) {
this.communicator = communicator;
}
}
b.필드
public class Communication {
@Inject
private Communicator communicator; // DI(의존관계 주입)
}
c. 생성자
public class Communication {
private Communicator communicator; // DI(의존관계 주입)
@Inject
public Communication(Communicator communicator) {
this.communicator = communicator;
}
}
d. 암시적 주입
- binding이 없어도 Guice는 일부 범용 구성 요소를 암시적으로 주입한다.
- Logger는 바인딩이 되어있지 않다. 하지만 Guice는 Logger와 같이 범용적으로 사용되는 요소는 암시적으로 주입하게 된다.
public class Communication {
@Inject
private Logger logger; // DI(의존관계 주입)
}
5. Guice 바인딩
바인딩은 의존관계를 주입을 위해 사용되며, 인터페이스가 어떤 구현체와 연결되는지를 명시한다.
a. 기본 사용
public class Communication {
@Inject
private Communicator communicator; // DI(의존관계 주입)
...
}
public class BasicModule extends AbstractModule {
@Override
protected void configure() {
bind(Communicator.class).to(DefaultCommunicatorImpl.class);
}
}
b. 이름 지정
public class BasicModule extends AbstractModule {
@Override
protected void configure() {
bind(Communicator.class)
.annotatedWith(Names.named("DefaultCommunicator")) // 이름 설정
.to(DefaultCommunicatorImpl.class);
}
public class Communication {
...
@Inject @Named("DefaultCommunicator")
private Communicator communicator; // DI(의존관계 주입)
...
}
c. 생성자 바인딩
public class Communication {
private final Boolean isActive;
public Communication(Boolean isActive) {
this.isActive = isActive;
}
}
public class BasicModule extends AbstractModule {
@Override
protected void configure() {
// Boolean 클래스를 true로 매핑
bind(Boolean.class).toInstance(true);
// Communication 클래스의 생성자에 부울 값을 주입
try {
bind(Communication.class).toConstructor(
Communication.class.getConstructor(Boolean.class));
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
}
d. 인스턴스 바인딩
public class Communication {
private final Boolean isActive;
public Communication(Boolean isActive) {
this.isActive = isActive;
}
}
public class BasicModule extends AbstractModule {
@Override
protected void configure() {
// Communication 클래스의 인스턴스를 직접 제공
bind(Communication.class).toInstance(new Communication(true));
}
}
6. Scope 지정
a. Singleton
- 처음 호출시 싱글톤 객체를 생성
@Override
protected void configure() {
bind(Communicator.class).annotatedWith(Names.named("DefaultCommunicator"))
.to(Communicator.class).in(Scopes.SINGLETON);
}
b. AsEagerSingleton
- 애플리케이션 실행시점에 싱글톤 객체를 생성
@Override
protected void configure() {
bind(Communicator.class).annotatedWith(Names.named("DefaultCommunicator"))
.to(Communicator.class)
.asEagerSingleton();
}
Guice 자체에서 제공하는 웹 스코프(Session 스코프, Requst 스코프 등)은 없다. Jakarta EE에서 제공하는 웹 전용 @RequestScoped 및 @SessionScoped 어노테이션을 활용할 수 있다.
7. @Provides
- 지금까지는 바인딩 정의했다. @Provides를 사용해서 인터페이스와 구현체의 관계를 정의할 수 있다.
- @Provides는 싱글톤 객체가 아니기 때문에 호출될 때마다 인스턴스를 생성한다.
- @SingleTon 에노테이션 사용하면 싱글톤 객체로 정의할 수 있다.
@Provides
public Communicator communicator() {
return new CommunicatorImpl();
}
@Provides
@Sigleton
public Communicator communicator() {
return new CommunicatorImpl();
}
8.Injector
- 바인딩 된 객체를 검색할 때 사용
Injector injector = Guice.createInjector(new BasicModule());
Communication comms = injector.getInstance(Communication.class);
'Back-end > 기타' 카테고리의 다른 글
[Netty] 바이트버퍼(ByteBuffer) (0) | 2024.01.15 |
---|---|
[Netty] 이벤트 모델 (0) | 2024.01.15 |
[Netty] 채널 파이프라인과 코덱 (0) | 2024.01.12 |
[Netty] Netty의 Bootstrap(부트스트랩) (0) | 2024.01.12 |
[Netty] 네트워크 프레임워크 Netty란? (1) | 2024.01.11 |