在Argo中用到了Google-guice依赖注入框架:http://code.google.com/p/google-guice/
Google-guice 依赖注入框架主要由@Inject注解、AbstractModule基类组成
//google code上的例子
RealBillingService类构造时依赖CreditCardProcessor和TransactionLog接口,添加@Inject注解后将由Guice调用RealBillingService构造器。
class RealBillingService implements BillingService {
private finalCreditCardProcessor processor;
private finalTransactionLog transactionLog;
@Inject
RealBillingService(CreditCardProcessor processor,
TransactionLog transactionLog){
this.processor= processor;
this.transactionLog= transactionLog;
}
@Override
public Receipt chargeOrder(PizzaOrder order,CreditCard creditCard){
...
}
}
AbstractModule构建Guice的object-graph,重载Configure方法实现接口和实现类的绑定。
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); } }
由此也可以看出@Inject 和 bind是一起出现的
用Module子类创建新的Guice注解器实例
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. */ RealBillingService billingService = injector.getInstance(RealBillingService.class); ... }
Argo中的注入
public class Argo {
public ArgoDispatcher init(ServletContext servletContext,
GroupConvention groupConvention) {
…
List<Module> modules = Lists.newArrayList();
modules.add(new ArgoModule(this));
Module groupModule = groupConvention.group().module();
if (null != groupModule)
modules.add(groupModule);
Module projectModule = groupConvention.currentProject().module();
if (null != projectModule)
modules.add(projectModule);
servletContext.log("preparing an injector");
this.injector = buildInjector(modules);
servletContext.log("injector completed");
…
}
private Injector buildInjector(List<Module> modules) {
return Guice.createInjector(modules);
}
public class ArgoModule extends AbstractModule {
@Override
protected void configure() {
bind(ServletRequest.class).to(HttpServletRequest.class);
bind(ServletResponse.class).to(HttpServletResponse.class);
bind(BeatContext.class)
.annotatedWith(ArgoSystem.class)
.to(DefaultBeatContext.class);
bind(ActionResult.class)
.annotatedWith(Names.named("HTTP_STATUS=404"))
.toInstance(StatusCodeActionResult.defaultSc404);
bind(ActionResult.class)
.annotatedWith(Names.named("HTTP_STATUS=405"))
.toInstance(StatusCodeActionResult.defaultSc405);
bind(Action.class).annotatedWith(StaticActionAnnotation.class)
.to(StaticFilesAction.class);
bind(ClientContext.class).to(DefaultClientContext.class);
bind(Model.class).to(DefaultModel.class);
bind(MultipartConfigElement.class)
.toProvider(DefaultMultipartConfigElementProvider.class)
.in(Singleton.class);
// bind all controllers.
for (Class<? extends ArgoController> clazz : argo.getControllerClasses())
bind(clazz).in(Singleton.class);
}
}
由此可见,Argo中的init方法首先构造Module实例集合,然后调用Guice的CreateInjector方法绑定对应的接口和实现类。
argo.getControllerClasses()中的Module应该是在Argo框架注解过的集合。