Google Guice结合模式

于Guice于,喷油器装配工作是一个对象图,当请求类型实例,喷油器根据推断对象如何映射到创建的实例、解决依赖。要确定如何解决的依赖就需要配置喷油器结合的方式。

要创建绑定(Binding)对象,能够继承自AbstractModule类,然后覆盖其configure方法,在方法调用bind()方法来指来定每一次绑定。这些方法带有类型检查,假设你使用了错误的类型编译器就会报告编译错误。假设你已经写好了Module类,则创建一个Module类对象作为參数传递给Guice.createInjector()方法用于创建一个注入器。

通过Module对象能够创建链接绑定(linked bindings)、实例绑定(instance bindings)、@Provides methods、提供者绑定(provider bindings)、构建方法绑定(constructor bindings)与无目标绑定(untargetted bindings)。

这些绑定方式统称为内置绑定,相相应的还有种及时绑定。假设在解析一个依赖时假设在内置绑定中无法找到。那么Guice将会创建一个及时绑定。

一、链接绑定(LinkdedBindings)

链接绑定即映射一类型到它的实现类,比如映射TransactionLog接口到实现类DatabaseTransactionLog:

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

这样,当你调用injector.getInstance(TransactionLog.class)方法,或者当注入器碰到TransactionLog依赖时,就会使用DatabaseTransactionLog对象。链接是从一类型到它不论什么的子类型,这包含接口实现类,类的子类;所以例如以下映射也是能够的:bind(DatabaseTransactionLog.class).to(MySqlDatabaseTransactionLog.class);

而且链接绑定支持链式写法:

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

在这样的情况下,当请求一个TransactionLog类型对象时,注入器将返回一个MySqlDatabaseTransactionLog对象。

二、绑定注解

某些情况下你可能想为同一种类型设置多种绑定。这就能够通过绑定注解来实现,该注解与绑定的类型用于唯一结识一个绑定,

合在一起称为Key。演示样例:

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 {}

这里关键的是@BindingAnnotation元注解,当Guice描写叙述到该注解时,就会把PayPal作为绑定注解。

然后在Module的configure方法中使用annotatedWith语句,例如以下:

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

这样就把CreditCardProcessor映射到了PayPalCreditCardProcessor。

使用方法:

public class RealBillingService implements BillingService {

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

另一种情况,我们能够使用Guice已经定义好的@Named注解。比如:

public class RealBillingService implements BillingService {

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

要绑定一详细名称,使用Names.named()来创建一个实现传给annotatedWith方法:

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

由于编译器不会对字符串进行检查,Guice建议我们少使用@Named注解,可是我个人觉得,仅仅要自己写代码时仅仅要名称不要写错,

通过这样的方法式是最easy为同一类型映射多个绑定的。这非常类似Spring中的实现方式,Spring的@Service,@Controller,@Repository不就能够指定名称吗?

三、实例绑定(Instance Bindings)

通过实例绑定我们能够为某类型绑定一个详细的实例,这只适用于这些实例类型没有其他依赖的情况,比如值对象:

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

使用方式:

@Inject @Named("JDBC URL")
private String url

Guice建议我们避免使用.toInstance来创建复杂的对象。由于这会延迟应用启动。类似地,能够使用@Provides方法实现。

四、@Provides方法

当使用@Provides方法创建对象时。该方法必须定义在Module类中。而且它必须加以@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;
  }
}

假设在@Provides方法上有@PayPal或@Named("Checkout")绑定注解。Guice以绑定注解优先。Guice在调用@Provides方法之前会先解析该方法的依赖:

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

关于异常:

Guice不同意在@Provides方法中抛出异常。

假设有异常抛出。那么异常将会被包装在ProvisionException对象中。

五、提供者绑定(Provider Bindings)

假设@Provides方法越来越复杂。我们可能会想把它们移到一个单独的类中。一个提供者类实现了Provider接口。它是一个

用于提供值的简单通用接口。

public interface Provider<T> {
  T get();
}

假设提供者实现类有其自己的依赖时,能够通过在其构造方法上加入@Inject注解进行注入,以保证值安全返回。

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;
  }
}

最后使用.toProvider语句来绑定到提供者:

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

六、无目标绑定

Guice同意我们创建绑定时不指定目标类。也就是没有to语句,这对于详细类或者使用了@ImplementedBy或@ProvidedBy注解类型非常实用。比如:

bind(MyConcreteClass.class);

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

然而,在使用绑定注解时,我们依赖必须指定绑定目标。即它是一个详细类,比如:

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

七、构造方法绑定

有些时候你可能须要将某一类型绑定到任一构建方法,比如在@Inject注解无法加入到目标类构造方法,其原因可能是这个类是

第三方提供的。或者说该类有多个构建方法參与依赖注入。此时@Provides方法是解决问题的最好方案,由于它能够明白指定

调用哪个构造方法。并且不须要使用反射机制。

可是使用@Provides方法在某些地方有限制,比如:手动创建对象不能在AOP中使用。

正是由于这个原因,Guice使用了toConstructor()进行绑定。这须要我们使用反射来选择构造方法与处理异常。

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

上这个样例中DatabaseTransactionLog类必须有一个带DatabaseConnection參数的构造方法,该构造方法中不须要使用@Inject注解Guice会自己主动调用该构造方法。每一条toConstructor()语句创建的绑定。其作用域是独立的,假设你创建了多个单例绑定而且使用目标类的同一个构造方法,每个绑定还是拥有各自的实例。

八、及时绑定

当注入器须要某一类型实例的时候。它须要获取一个绑定。在Module类中的绑定叫做显示绑定,仅仅要它们可用,注入器就能够使用它们。假设须要某一类型实例,但它又不是显示绑定。那么注入器将试图创建一个及时绑定(Just-In-Time bindings),它也被称为JIT绑定与隐式绑定。

可用于创建及时绑定的情况例如以下:

a.有一个合适的构建方法,即非私有。不带參数或者标有@Inject注解的构造方法,比如:

public class PayPalCreditCardProcessor implements CreditCardProcessor {
  private final String apiKey;

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

Guice不会创建内部类实例除非它有static修饰符,由于内部类含有一个指向外问类的隐式引用,而这个隐式引用无法注入。

b. @ImplementedBy

@ImplementedBy注解于用告诉注入器某类型的缺省实现类型是什么,这与链接绑定非常相似。

为某一类型绑定一子类型例如以下:

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

@ImplementedBy(PayPalCreditCardProcessor.class)等效于以下的bind()语句:

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

假设某一类型即有bind()语句又有@ImplementedBy注解。则bind()语句优先。使用@ImplementedBy请小心,由于它为接口加入了编译时依赖。

c. @ProvidedBy

@ProvidedBy注解用于告诉注入器。Provider类的实现是什么,比如:

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

这等价于bind(TransactionLog.class).toProvider(DatabaseTransactionLogProvider.class);

类似@ImplementedBy注解,假设某个类型既使用了bind()语句,又使用了@ProvidedBy注解。然后,bind()声明优先。

版权声明:本文博主原创文章,博客,未经同意不得转载。

时间: 2024-11-10 11:20:52

Google Guice结合模式的相关文章

Google Guice之牛刀小试

Google Guice由google推出的一开源软件,是超轻量级的,下一代的,为Java 5及后续版本设计的依赖注入容器,其功能类似于如日中天的Spring. 下面我们就来了解一下Guice,在此之前,先看一个官方例子:在应用程序中,要把所有的东西装配起来是一件很乏味的事件,这要涉及到连接数据,服务,表现层类等方面,这是一个比萨饼订购网站的计费代码例子用于这些方面的对比. public interface BillingService { /** * Attempts to charge th

Google Guice 系列教程 - 基础实践

转载:http://www.cnblogs.com/youngC/archive/2012/12/21/2828419.html 前言 Google Guice 是一个轻量级的依赖注入框架,它支持Java 5或者更高版本的JDK,得利于Java 5中提供的泛型 (Generics) 和注释 (Annotations) ,它可以使得代码类型安全 (type-safe) .那么何时使用在代码中使用 Guice 进行注入呢?一般来说,如果在你的应用代码中业务对象 (Business Objects)

Google Guice 入门教程

01 - 依赖注入 1. 依赖注入 1.1 类依赖注入 所谓的绑定就是将一个接口绑定到具体的类中,这样客户端不用关心具体的实现,而只需要获取相应的接口完成其服务即可. HelloWorld.java 1     public interface HelloWorld { 2 3         String sayHello(); 4     } 5 然后是具体的实现,HelloWorldImpl.java 1     public class HelloWorldImpl implements

超轻量级DI容器框架Google Guice与Spring框架的区别教程详解及其demo代码片段分享

原创不易,转载请注明出处:超轻量级DI容器框架Google Guice与Spring框架的区别教程详解及其demo代码片段分享 代码下载地址:http://www.zuidaima.com/share/1759689106541568.htm 依赖注入,DI(Dependency Injection),它的作用自然不必多说,提及DI容器,例如spring,picoContainer,EJB容器等等,近日,google诞生了更轻巧的DI容器--Guice! 废话不多讲了,先看看Guice是如何实现

jdbc框架 commons-dbutils+google guice+servlet 实现一个例子

最近闲着无聊,于是看了一下jdbc框架 commons-dbutils与注入google guice. 我就简单的封装了一下代码,效率还是可以的.... jdbc+google guice+servlet 的web实现: http://pan.baidu.com/s/1i4OpyTJ 觉得不错点个赞...hello world!

史上最好用的依赖注入框架Google Guice【转】

Guice是Google开发的一个轻量级,基于Java5(主要运用泛型与注释特性)的依赖注入框架(IOC).Guice非常小而且快. (其他的依赖注入框架还有Dagger,Spring) Spring框架的依赖注入是家喻户晓的,但是在实际的开发中我们想使用便捷的依赖注入功能,但是又不想引入Spring框架的复杂性,该怎么办呢? 有了Google Guice,这个问题便简单了,首先在你的maven项目里引入 <dependency> <groupId>com.google.injec

开源介绍:Google Guava、Google Guice、Joda-Time

一.Guava 是一个 Google 的基于java1.6的类库集合的扩展项目,包括 collections, caching, primitives support, concurrency libraries, common annotations, string processing, I/O, 等等. 这些高质量的 API 可以使你的JAVa代码更加优雅,更加简洁,让你工作更加轻松愉悦.下面我们就开启优雅Java编程学习之旅! 项目相关信息: 官方首页:http://code.googl

Google Guice

Guice (读作"juice")是超轻量级的,下一代的,为Java 5及后续版本设计的依赖注入容器. 简介 Java企业应用开发社区在连接对象方面花了很大功夫.你的Web应用如何访问中间层服务?你的服务如何连接到登录用户和事务管理器?关于这个问题你会发现很多通用的和特定的解决方案.有一些方案依赖于模式,另一些则使用框架.所有这些方案都会不同程度地引入一些难于测试或者程式化代码重复的问题.你马上就会看到,Guice 在这方面是全世界做得最好的:非常容易进行单元测试,最大程度的灵活性和可

Google Guice之AOP

为增强依赖注入功能,Guice支持方法拦截器.通过这个特性可以让方法在每次执行前调用一个匹配(过滤)方法.这适用于横切性关注点(切面),例如事务控制,权限与日志记录等.因为拦截器将一个问题分割成切面而不是对象:所以拦截器使用又被称为面向切面编程(AOP). 大多数开发者不会直接编写方法拦截器,但是可能在一些类库中见到,需要进方法进行选择,创建一个拦截器并将它配置在Module中:例如Warp Persist. <span style="font-size:14px;">@R