262 lines
8.9 KiB
Markdown
262 lines
8.9 KiB
Markdown
### Guice의 주요 어노테이션과 사용 예시
|
|
|
|
Google Guice는 의존성 주입(Dependency Injection, DI)을 간편하게 구현할 수 있는 경량 프레임워크로, 다양한 어노테이션을 통해 의존성을 정의하고 관리합니다. 아래에서는 Guice에서 자주 사용되는 주요 어노테이션들을 표로 정리하고, 각 어노테이션의 역할과 사용 예시를 설명하겠습니다.
|
|
|
|
---
|
|
|
|
#### Guice 주요 어노테이션 표
|
|
|
|
| 어노테이션 | 설명 | 사용 위치 | 주요 특징 및 용도 |
|
|
|-------------------|----------------------------------------------------------------------|-----------------------|-------------------------------------------------------|
|
|
| `@Inject` | 의존성을 주입할 위치를 지정합니다. 생성자, 필드, 메서드에 사용 가능합니다. | 생성자, 필드, Setter 메서드 | Guice가 자동으로 의존성을 주입하도록 지시. 선택적 주입 가능 (`@Inject(optional=true)`). |
|
|
| `@Named` | 동일한 타입의 여러 구현체 중 특정 구현체를 선택하기 위해 사용됩니다. | 필드, 매개변수 | 문자열 키로 구체적인 바인딩을 식별. |
|
|
| `@Singleton` | 클래스의 인스턴스가 단일 객체로 유지되도록 지정합니다. | 클래스 | 싱글턴 패턴을 구현하여 메모리 효율성 향상. |
|
|
| `@Provides` | 모듈 내에서 의존성을 제공하는 메서드를 정의합니다. | 모듈의 메서드 | 복잡한 객체 생성 로직을 직접 작성 가능. |
|
|
| `@ImplementedBy` | 인터페이스의 기본 구현체를 지정합니다. | 인터페이스 | 모듈 없이 기본 바인딩을 설정. |
|
|
| `@ProvidedBy` | 동적으로 의존성을 제공하는 클래스를 지정합니다. | 인터페이스 | Provider 클래스를 통해 의존성 공급. |
|
|
| `@Qualifier` | 사용자 정의 qualifier를 생성하기 위한 메타 어노테이션입니다. | 사용자 정의 어노테이션 | `@Named`보다 더 세밀한 의존성 구분 가능. |
|
|
|
|
---
|
|
|
|
### 어노테이션별 설명 및 예시
|
|
|
|
#### 1. `@Inject`
|
|
- **설명**: Guice가 의존성을 주입할 위치를 나타냅니다. 생성자 주입, 필드 주입, Setter 주입에 사용됩니다.
|
|
- **예시**:
|
|
```java
|
|
import com.google.inject.Inject;
|
|
|
|
class UserService {
|
|
private final Database database;
|
|
|
|
@Inject
|
|
public UserService(Database database) { // 생성자 주입
|
|
this.database = database;
|
|
}
|
|
|
|
@Inject
|
|
private Logger logger; // 필드 주입
|
|
|
|
@Inject
|
|
public void setConfig(Config config) { // Setter 주입
|
|
// 설정 로직
|
|
}
|
|
}
|
|
```
|
|
- **특징**: 생성자 주입이 가장 권장되며, 불변성을 보장합니다. 필드 주입은 간단하지만 테스트 시 불편할 수 있습니다.
|
|
|
|
---
|
|
|
|
#### 2. `@Named`
|
|
- **설명**: 동일한 인터페이스를 구현한 여러 클래스가 있을 때, 특정 구현체를 선택할 때 사용됩니다.
|
|
- **예시**:
|
|
```java
|
|
import com.google.inject.Inject;
|
|
import com.google.inject.name.Named;
|
|
|
|
interface Database {
|
|
void connect();
|
|
}
|
|
|
|
class MySQLDatabase implements Database {
|
|
public void connect() { System.out.println("MySQL 연결"); }
|
|
}
|
|
|
|
class PostgresDatabase implements Database {
|
|
public void connect() { System.out.println("Postgres 연결"); }
|
|
}
|
|
|
|
class MyModule extends AbstractModule {
|
|
@Override
|
|
protected void configure() {
|
|
bind(Database.class).annotatedWith(Names.named("mysql")).to(MySQLDatabase.class);
|
|
bind(Database.class).annotatedWith(Names.named("postgres")).to(PostgresDatabase.class);
|
|
}
|
|
}
|
|
|
|
class App {
|
|
@Inject @Named("mysql")
|
|
private Database database;
|
|
|
|
public void run() {
|
|
database.connect(); // 출력: MySQL 연결
|
|
}
|
|
}
|
|
```
|
|
- **특징**: 문자열 기반으로 동작하며, 오타에 주의해야 합니다.
|
|
|
|
---
|
|
|
|
#### 3. `@Singleton`
|
|
- **설명**: 클래스의 인스턴스를 싱글턴으로 관리하도록 지정합니다. Guice 인젝터가 단일 인스턴스를 재사용합니다.
|
|
- **예시**:
|
|
```java
|
|
import com.google.inject.Singleton;
|
|
import com.google.inject.Inject;
|
|
|
|
@Singleton
|
|
class Cache {
|
|
public void store(String key, String value) {
|
|
System.out.println("캐시에 저장: " + key + " -> " + value);
|
|
}
|
|
}
|
|
|
|
class App {
|
|
@Inject
|
|
private Cache cache;
|
|
|
|
public void run() {
|
|
cache.store("user", "data"); // 동일한 인스턴스 사용
|
|
}
|
|
}
|
|
```
|
|
- **특징**: 메모리 효율성을 높이지만, 상태를 공유하므로 주의가 필요합니다.
|
|
|
|
---
|
|
|
|
#### 4. `@Provides`
|
|
- **설명**: 모듈 내에서 복잡한 객체 생성 로직을 정의할 때 사용됩니다.
|
|
- **예시**:
|
|
```java
|
|
import com.google.inject.Provides;
|
|
import com.google.inject.AbstractModule;
|
|
|
|
interface Client {
|
|
void send(String msg);
|
|
}
|
|
|
|
class HttpClient implements Client {
|
|
private final String url;
|
|
public HttpClient(String url) { this.url = url; }
|
|
public void send(String msg) { System.out.println("Sending to " + url + ": " + msg); }
|
|
}
|
|
|
|
class MyModule extends AbstractModule {
|
|
@Provides
|
|
public Client provideClient() {
|
|
return new HttpClient("https://api.example.com");
|
|
}
|
|
}
|
|
|
|
class App {
|
|
@Inject
|
|
private Client client;
|
|
|
|
public void run() {
|
|
client.send("Hello"); // 출력: Sending to https://api.example.com: Hello
|
|
}
|
|
}
|
|
```
|
|
- **특징**: 동적 생성 로직을 커스터마이징할 수 있어 유연성이 높습니다.
|
|
|
|
---
|
|
|
|
#### 5. `@ImplementedBy`
|
|
- **설명**: 인터페이스의 기본 구현체를 지정하여 모듈 설정 없이도 의존성을 주입할 수 있습니다.
|
|
- **예시**:
|
|
```java
|
|
import com.google.inject.ImplementedBy;
|
|
import com.google.inject.Inject;
|
|
|
|
@ImplementedBy(DefaultService.class)
|
|
interface Service {
|
|
void execute();
|
|
}
|
|
|
|
class DefaultService implements Service {
|
|
public void execute() { System.out.println("기본 서비스 실행"); }
|
|
}
|
|
|
|
class App {
|
|
@Inject
|
|
private Service service;
|
|
|
|
public void run() {
|
|
service.execute(); // 출력: 기본 서비스 실행
|
|
}
|
|
}
|
|
```
|
|
- **특징**: 모듈 설정이 필요 없어 간단하지만, 유연성이 제한적입니다.
|
|
|
|
---
|
|
|
|
#### 6. `@ProvidedBy`
|
|
- **설명**: Provider 클래스를 통해 동적으로 의존성을 제공합니다.
|
|
- **예시**:
|
|
```java
|
|
import com.google.inject.ProvidedBy;
|
|
import com.google.inject.Provider;
|
|
import com.google.inject.Inject;
|
|
|
|
@ProvidedBy(DynamicServiceProvider.class)
|
|
interface Service {
|
|
void execute();
|
|
}
|
|
|
|
class DynamicService implements Service {
|
|
public void execute() { System.out.println("동적 서비스 실행"); }
|
|
}
|
|
|
|
class DynamicServiceProvider implements Provider<Service> {
|
|
@Override
|
|
public Service get() {
|
|
return new DynamicService();
|
|
}
|
|
}
|
|
|
|
class App {
|
|
@Inject
|
|
private Service service;
|
|
|
|
public void run() {
|
|
service.execute(); // 출력: 동적 서비스 실행
|
|
}
|
|
}
|
|
```
|
|
- **특징**: Provider를 통해 런타임에 객체를 생성할 수 있어 동적 처리가 가능합니다.
|
|
|
|
---
|
|
|
|
#### 7. `@Qualifier`
|
|
- **설명**: 사용자 정의 어노테이션을 만들어 더 세밀한 의존성 구분을 가능하게 합니다.
|
|
- **예시**:
|
|
```java
|
|
import com.google.inject.Qualifier;
|
|
import com.google.inject.Inject;
|
|
import java.lang.annotation.Retention;
|
|
import java.lang.annotation.RetentionPolicy;
|
|
|
|
@Qualifier
|
|
@Retention(RetentionPolicy.RUNTIME)
|
|
@interface PrimaryDB {}
|
|
|
|
class MyModule extends AbstractModule {
|
|
@Override
|
|
protected void configure() {
|
|
bind(Database.class).annotatedWith(PrimaryDB.class).to(MySQLDatabase.class);
|
|
}
|
|
}
|
|
|
|
class App {
|
|
@Inject @PrimaryDB
|
|
private Database database;
|
|
|
|
public void run() {
|
|
database.connect(); // 출력: MySQL 연결
|
|
}
|
|
}
|
|
```
|
|
- **특징**: `@Named`보다 타입 안전성이 높고, 오타 문제를 방지할 수 있습니다.
|
|
|
|
---
|
|
|
|
### Guice 어노테이션 사용 팁
|
|
- **생성자 주입 우선**: `@Inject`를 생성자에 사용해 불변성과 명확성을 유지하세요.
|
|
- **Qualifier 활용**: `@Named` 대신 사용자 정의 `@Qualifier`를 사용하면 더 안전합니다.
|
|
- **싱글턴 주의**: `@Singleton`은 상태를 공유하므로 스레드 안전성을 고려해야 합니다.
|
|
- **모듈 분리**: 복잡한 프로젝트에서는 `@Provides`를 활용해 모듈을 깔끔하게 관리하세요.
|
|
|
|
---
|
|
|
|
### 결론
|
|
Guice의 어노테이션들은 의존성 주입을 간단하고 유연하게 만들어줍니다. 위 예시를 통해 각 어노테이션의 사용법과 장점을 이해할 수 있으며, 프로젝트 요구사항에 맞게 적절히 선택해 사용하면 됩니다. 추가 질문이 있다면 언제든 물어보세요! |