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共有以下几类:
- linked bindings
- instance bindings
- @Provides methods
- provider bindings
- constructor bindings
- untargetted bindings
- built-in bindings
- 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
详情查阅文档。