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()声明优先。
版权声明:本文博主原创文章,博客,未经同意不得转载。
Google Guice结合模式的更多相关文章
- 依赖注入框架Google Guice 对象图
GettingStarted · google/guice Wiki https://github.com/google/guice/wiki/GettingStarted sameb edited ...
- jdbc框架 commons-dbutils+google guice+servlet 实现一个例子
最近闲着无聊,于是看了一下jdbc框架 commons-dbutils与注入google guice. 我就简单的封装了一下代码,效率还是可以的.... jdbc+google guice+servl ...
- Google Guice学习
学习动力:公司项目使用 官方文档:https://github.com/google/guice/wiki/Motivation 学习阶段:入门 主要部份: 简介 Bindings方式 Scopes设 ...
- Google Guice 之绑定1
绑定和依赖注入区别 绑定,使用时 需要通过 injector 显示获取 依赖注入,只需要显示获取主类,他的依赖是通过@Injector 和 绑定关系 隐式注入的 http://blog.csdn.ne ...
- 微软和Google的盈利模式对比分析
一: 微软和Google是世界上最成功科技巨头之一,但他们之间却有着不同的产品和业务,二者的盈利方式也各有不同,本文将分析和探讨的二者盈利模式的异同. 微软的盈利模式 在1975年由大学肄业的Bill ...
- google guice
1 google guice是什么 google guice是一个轻量的DI容器. 2 guice和spring对比 spring的配置放在xm文件中,guice的配置放在Module中. guice ...
- 史上最好用的依赖注入框架Google Guice【转】
Guice是Google开发的一个轻量级,基于Java5(主要运用泛型与注释特性)的依赖注入框架(IOC).Guice非常小而且快. (其他的依赖注入框架还有Dagger,Spring) Spring ...
- 【曹工杂谈】Maven IOC容器的下半场:Google Guice
Maven容器的下半场:Guice 前言 在前面的文章里,Maven底层容器Plexus Container的前世今生,一代芳华终落幕,我们提到,在Plexus Container退任后,取而代之的底 ...
- 开源介绍:Google Guava、Google Guice、Joda-Time
一.Guava 是一个 Google 的基于java1.6的类库集合的扩展项目,包括 collections, caching, primitives support, concurrency lib ...
随机推荐
- 在前端一定要了解的HTML,CSS知识
盒子模型 每个盒子都有4个属性:内容(content).填充(padding).边框(border).边界(margin) 每个属性都有四个部分:上.右.下.左 块级元素 内联元素 块级元素(bloc ...
- 【Android基础】listview控件的使用(1)------最简单的listview的使用
listview控件是项目开发中最常用的空间之一,我将慢慢推出关于listview的一系列的文章,先从最简单的,系统自带的listview开始吧! 先上效果图: activity_one.xml &l ...
- Sqlserver2000联系Oracle11G数据库进行实时数据的同步
Sqlserver2000联系Oracle11G数据库进行实时数据的同步 1,前提条件 我有sqlserver2000环境,已经存在oracle11g环境,准备这两个数据库,建立各自的訪问账号,两者之 ...
- ZOJ 3820 2014ACM/ICPC牡丹江司B称号
3797714 2014 - 10 - 12 21:58 : 19 Accepted 3820 C++ 1350 70240 zz_1215 比較麻烦的一道题吧,開始的时候不停的段异常,后面知道是爆栈 ...
- 数据库管理——安全管理——识别SQLServer中空密码或者弱密码的登录名
原文:数据库管理--安全管理--识别SQLServer中空密码或者弱密码的登录名 原文译自: http://www.mssqltips.com/sqlservertip/2775/identify-b ...
- C++四种类型的转换
在C/C++使用的语言 (type) value(您还可以使用type(value))对于显式类型转换,经常提到投.转换程序猿的精度等完全掌握手,一个传统投往往是过度使用.成为C++要根源. 为了降低 ...
- UFLDL接听教程练习(来自编码器和矢量编程疏)
最近想在深入学习研究,开始看UFLDL(unsuprisedfeature learning and deep learning)教程了.特将课后习题答案放在这里,作为一个笔记. 笔记: 1:自编码算 ...
- SQL Server 连接问题-命名管道
原文:SQL Server 连接问题-命名管道 出自:http://blogs.msdn.com/b/apgcdsd/archive/2011/01/12/sql-server-1.aspx 一.前言 ...
- A*寻路算法lua实现
前言:并在相当长的时间没有写blog该,我觉得有点"颓废"该,最近认识到各种同行,也刚刚大学毕业,我认为他们是优秀的.认识到与自己的间隙,有点自愧不如.我没有写blog当然,部分原 ...
- Spring 通过来AOP 实现前置,环绕,异常通知,注解(转)
本节主要内容: 1. Spring AOP前置通知案例 2. Spring AOP环绕通知案例 3. Spring AOP异常通知案例 4. Spring AOP注解使 ...