匕首不使用与Guice相同的机制.具体来说,Dagger并不透明地处理Guice所做的范围,使用各种范围注释,一个Injector和不同的实例在幕后高速缓存.相反,它使用两个原则.首先,@Singleton意味着“每个图表一个”(JSR-330的最严格的解释),其次,图形可以在层次结构中链接.
Dagger使用这个分层关联的图形树,您可以通过添加更多的模块并通过plus()方法来扩展它来创建一个图形,以创建一个可以具有更短生命周期的“作用域”图.这类似于gu子中的儿童注射器.这里的一个重要原则是,扩展图中的实例可以看到始发图中的实例,但不能反过来.因此,缩短生命周期的同心性在可见性中被镜像 – 一个较短寿命的对象可以看到(依赖)较长寿命的对象,但不能相反.所以一个生活在一个请求的生命中的对象可以看到一个生命在应用程序的生命中的对象,但不是相反的.
正是通过这种机制,人们期望更加狭窄地对缓存实例进行范围调整.
如果一个模块配置了一个图形,并且有一个单例,它将在该图中缓存一个实例,提供给所有依赖对象.如果通过plus()方法创建了该图形的扩展名,则使用包含@Singleton注释绑定的其他模块进行配置,那么这些其他模块将是一个一个图表,活着的ObjectGraph实例.
例如,我们来模拟一个响应请求的服务器,我们希望在应用程序的生命周期中生活一些对象,以及一些仅仅在一个请求的使用期限内生活的对象:
@Module()
public class MyAppModule {
@Provides ConnectionDictonary connectionDictionary() {
return new ConnectionDictonary(System.getProperty("some.property"));
}
/** Stateless mockable utilities for this app */
@Provides Util util() { new Util(); }
@Provides @Singleton DataStore store() {
return new DataStore();
}
@Provides @Singleton ConnectionPool pool(DataStore store,ConnectionDictionary dict) {
try {
return DataStore.connectionPool(dict,System.getProperty("pool.size"));
} catch (Exception e) {
// bad bad bad
throw new RuntimeException("Could not connect to datastore.",e);
}
}
}
// This module "adds to" MyAppModule by adding additional graph elements in
// an extended graph.
@Module(injects=MyRequestEndpoint.class,addsTo = MyAppModule.class)
public class MyRequestModule {
private Request req;
public MyRequestModule(Request req) { this.req = req; }
@Provides @Singleton RequestObject request() { return req; }
@Provides @Singleton User user(ConnectionPool pool,Request req,Util util) {
try {
Connection conn = pool.obtain();
// getUser cannot throw null;
return util.getUser(conn,req.get("user.id"),Crypto.hash(req.get("pass")));
} catch (UserNotFoundException e) {
return User.UNKNOWN;
} catch (Exception e) {
throw new RuntimeException("Could not obtain a user.",e);
} finally {
// TODO: try-with-resources in Java7
pool.release();
}
}
}
public class MyRequestEndpoint {
@Inject ConnectionPool pool;
@Inject Request req;
public Output performService() {
try {
Connection conn = pool.obtain();
// ... does stuff with request
} finally {
conn.release();
}
}
}
public class MyApp {
public void main(String ... args) {
graph = ObjectGraph.create(MyAppModule.class);
new ServiceListener(graph).start();
}
}
public ServiceListener {
private final ObjectGraph appGraph;
public ServiceListener(ObjectGraph appGraph) {
this.appGraph = appGraph;
}
//... infrastructure for listening and building request/response objects,etc.
public void serveRequest(Request req,Response res) {
// Take the application-scoped graph and create another graph we will
// use in this request and throw away.
ObjectGraph requestGraph = MyApp.graph().plus(new MyRequestModule(req));
Output output = requestGraph.get(MyRequestEndpoint.class).performService();
Util.populateResult(output,result);
result.flush();
}
}
在这个例子中,每个MyRequestEndpoint都将获得一个ConnectionPool的共享实例,但任何两个请求中的一个端点都将获得两个不同的RequestObject.
这是一个有点愚蠢的例子,建立在J2EE模式的头顶.这不是一件简单的事情,你不会这样构建,你需要更强大的脚手架来建立一个合适的服务器模型.事实上,Dagger项目可能会做这样的事情(尽管我尊重地建议使用注入的服务对象和一个调度servlet或过滤器).
但它希望在一个熟悉的模型中说明一个较窄的范围
关键不在注释中,而是在图形的一生中.您创建一个较短寿命图作为较长寿命图的“小孩”或“扩展”.在这些图形中记录的对象具有图形管理对象的寿命(或范围).