guice

boilerplate

注入类:

class BillingService {
  private final CreditCardProcessor processor;
  private final TransactionLog transactionLog;

  @Inject
  BillingService(CreditCardProcessor processor, 
      TransactionLog transactionLog) {
    this.processor = processor;
    this.transactionLog = transactionLog;
  }

  public Receipt chargeOrder(PizzaOrder order, CreditCard creditCard) {
    ...
  }
}

配置object graph

public class BillingModule extends AbstractModule {
  @Override 
  protected void configure() {

     /*
      * This tells Guice that whenever it sees a dependency on a TransactionLog,
      * it should satisfy the dependency using a DatabaseTransactionLog.
      */
    bind(TransactionLog.class).to(DatabaseTransactionLog.class);

     /*
      * Similarly, this binding tells Guice that when CreditCardProcessor is used in
      * a dependency, that should be satisfied with a PaypalCreditCardProcessor.
      */
    bind(CreditCardProcessor.class).to(PaypalCreditCardProcessor.class);
  }
}

Application

public static void main(String[] args) {
    /*
     * Guice.createInjector() takes your Modules, and returns a new Injector
     * instance. Most applications will call this method exactly once, in their
     * main() method.
     */
    Injector injector = Guice.createInjector(new BillingModule());

    /*
     * Now that we've got the injector, we can build objects.
     */
    BillingService billingService = injector.getInstance(BillingService.class);
    ...
  }

Bindings

Guice的任务是组织对象,解决各实例间的依赖关系,对象的配置是通过各Bindings来实现。bindings共有以下几类:

  1. linked bindings
  2. instance bindings
  3. @Provides methods
  4. provider bindings
  5. constructor bindings
  6. untargetted bindings
  7. built-in bindings
  8. just-in-time binding

linked bindings

public class BillingModule extends AbstractModule {
  @Override 
  protected void configure() {
    bind(TransactionLog.class).to(DatabaseTransactionLog.class);
    bind(DatabaseTransactionLog.class).to(MySqlDatabaseTransactionLog.class);
  }
}

说明:

这种方式可以是链式的,比如上述示例中,TransactionLog最终的实例是MySqlDatabaseTransactionLog

BindingAnnotations

如果一个类型需要不同实现的实例,则可以采用这种方式,通过注解和类型唯一确定实例。

注解实现如下:

package example.pizza;

import com.google.inject.BindingAnnotation;
import java.lang.annotation.Target;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;

@BindingAnnotation @Target({ FIELD, PARAMETER, METHOD }) @Retention(RUNTIME)
public @interface PayPal {}

说明:

@Target:注解作用目标。
@Target(ElementType.TYPE)   //接口、类、枚举、注解
@Target(ElementType.FIELD) //字段、枚举的常量
@Target(ElementType.METHOD) //方法
@Target(ElementType.PARAMETER) //方法参数
@Target(ElementType.CONSTRUCTOR)  //构造函数
@Target(ElementType.LOCAL_VARIABLE)//局部变量
@Target(ElementType.ANNOTATION_TYPE)//注解
@Target(ElementType.PACKAGE) ///包   

@Retention:注解保留位置
@Retention(RetentionPolicy.SOURCE)   //注解仅存在于源码中,在class字节码文件中不包含
@Retention(RetentionPolicy.CLASS)     // 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得,
@Retention(RetentionPolicy.RUNTIME)  // 注解会在class字节码文件中存在,在运行时可以通过反射获取到

使用注解:

public class RealBillingService implements BillingService {

  @Inject
  public RealBillingService(@PayPal CreditCardProcessor processor,
      TransactionLog transactionLog) {
    ...
  }

配置:

bind(CreditCardProcessor.class)
        .annotatedWith(PayPal.class)
        .to(PayPalCreditCardProcessor.class);

@Name:Guice提供的内置的注解

public class RealBillingService implements BillingService {

  @Inject
  public RealBillingService(@Named("Checkout") CreditCardProcessor processor,
      TransactionLog transactionLog) {
    ...
  }


bind(CreditCardProcessor.class)
        .annotatedWith(Names.named("Checkout"))
        .to(CheckoutCreditCardProcessor.class);

注意:

不推荐使用@Name,该方式不保证类型安全。

InstanceBindings

将类型绑定到一个具体的实例上,该方式一般用于不依赖任何类的类,如果对于复杂的对象,这种方式会降低程序启动过程,如果需要可以用@Provides。

bind(String.class)
    .annotatedWith(Names.named("JDBC URL"))
    .toInstance("jdbc:mysql://localhost/pizza");
bind(Integer.class)
    .annotatedWith(Names.named("login timeout seconds"))
    .toInstance(10);

ProvidesMethods

这种方式只能在module中使用,方法返回需要注入的对象类型(base类型),方法需要加@Provides注解。

public class BillingModule extends AbstractModule {
  @Override
  protected void configure() {
    ...
  }

  @Provides
  TransactionLog provideTransactionLog() {
    DatabaseTransactionLog transactionLog = new DatabaseTransactionLog();
    transactionLog.setJdbcUrl("jdbc:mysql://localhost/pizza");
    transactionLog.setThreadPoolSize(30);
    return transactionLog;
  }
}

可以对ProvidesMethods进行限定,比如加别的一些注解。

@Provides @PayPal
  CreditCardProcessor providePayPalCreditCardProcessor(
      @Named("PayPal API key") String apiKey) {
    PayPalCreditCardProcessor processor = new PayPalCreditCardProcessor();
    processor.setApiKey(apiKey);
    return processor;
  }

注意:

该方式不允许异常被抛出,所有抛出的异常都被包装成ProvisionException的形式,如果需要抛异常,采用@CheckedProvides

ProviderBindings

如果@Provides Method方法变得复杂,可以采用这种方式,将其封装成一个实现了Provider接口的类。

public class DatabaseTransactionLogProvider implements Provider<TransactionLog> {
  private final Connection connection;

  @Inject
  public DatabaseTransactionLogProvider(Connection connection) {
    this.connection = connection;
  }

  public TransactionLog get() {
    DatabaseTransactionLog transactionLog = new DatabaseTransactionLog();
    transactionLog.setConnection(connection);
    return transactionLog;
  }
}

绑定:

public class BillingModule extends AbstractModule {
  @Override
  protected void configure() {
    bind(TransactionLog.class)
        .toProvider(DatabaseTransactionLogProvider.class);
  }

UntargettedBindings

无需to方法。

bind(MyConcreteClass.class);
bind(AnotherConcreteClass.class).in(Singleton.class);

当需要指明bingdings annotation时,必须指明to,哪怕和bind类型一致。

bind(MyConcreteClass.class)
    .annotatedWith(Names.named("foo"))
    .to(MyConcreteClass.class);
bind(AnotherConcreteClass.class)
    .annotatedWith(Names.named("foo"))
    .to(AnotherConcreteClass.class)
    .in(Singleton.class);

ToConstructorBindings

public class BillingModule extends AbstractModule {
  @Override 
  protected void configure() {
    try {
      bind(TransactionLog.class).toConstructor(
          DatabaseTransactionLog.class.getConstructor(DatabaseConnection.class));
    } catch (NoSuchMethodException e) {
      addError(e);
    }
  }
}

JustInTimeBindings

Eligible Constructors

根据non-private、无参构造函数或者被@Inject修饰的构造函数创建实例。不需要显示绑定。

public class PayPalCreditCardProcessor implements CreditCardProcessor {
  private final String apiKey;

  @Inject
  public PayPalCreditCardProcessor(@Named("PayPal API key") String apiKey) {
    this.apiKey = apiKey;
  }

@ImplementedBy

指示默认实现类型。

@ImplementedBy(PayPalCreditCardProcessor.class)
public interface CreditCardProcessor {
  ChargeResult charge(String amount, CreditCard creditCard)
      throws UnreachableException;
}

//和上述等同
bind(CreditCardProcessor.class).to(PayPalCreditCardProcessor.class);

@ProvidedBy

@ProvidedBy(DatabaseTransactionLogProvider.class)
public interface TransactionLog {
  void logConnectException(UnreachableException e);
  void logChargeResult(ChargeResult result);
}

//和上述等同
bind(TransactionLog.class)
        .toProvider(DatabaseTransactionLogProvider.class);

scopes

种类:

  • @Singleton
  • @SessionScoped
  • @RequestScoped

示例:

@Singleton
public class InMemoryTransactionLog implements TransactionLog {
  /* everything here should be threadsafe! */
}

bind(TransactionLog.class).to(InMemoryTransactionLog.class).in(Singleton.class);

@Provides @Singleton
  TransactionLog provideTransactionLog() {
    ...
  }

注意:

scope是针对bind对象,而不是针对to对象。

AOP

详情查阅文档。

阅读文档:https://github.com/google/guice/wiki/Motivation

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值