2013-06-04 37 views
9

如何使用Dagger创建自定义范围?匕首自定义范围,如何?

是否有指导方针?我没有找到他们。

我正在开发一个Vaadin应用程序,并且需要一个自定义范围。就像UiScoped。

问候

回答

28

匕首没有使用相同的排序机制,吉斯做的不做范围。 Dagger并没有像Guice那样透明地处理范围,在各种范围注释,一个注入器以及幕后的不同实例缓存中。相反,它使用两个原则。首先,@Singleton表示“每个图表一个”(对JSR-330的最严格解释),其次,图表可以在层次结构中链接。

Dagger使用分级链接图的树,通过添加更多模块并通过plus()方法扩展它来创建图,创建一个可缩短生命周期的“范围”图。这与Guice中的儿童注射器类似。这里的一个重要原则是扩展图中的实例可以在原始图中看到实例,但不是相反的。因此,较短生命时间的同心性质反映在可见性中 - 一个寿命较短的物体可以看到(依赖于)较长寿的物体,但不是相反。因此,一个在请求生命中存活的对象可以看到一个在应用程序生命周期中存在的对象,但不是相反的。

正是通过这种机制,人们希望更狭窄地将缓存实例的范围。

如果用一些模块配置一个图,并且有一个单例,那么它将有一个实例缓存在提供给所有相关对象的图中。如果通过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的共享实例,但是任何两个请求中的一个端点会得到两个不同的RequestObjects。

这是一个有点愚蠢的例子,建立在J2EE模式之上。有些东西这么微不足道,你不会以这种方式构建,而你需要更强大的脚手架才能构建合适的服务器模型。事实上,Dagger项目可能会做这样的事情(尽管我恭敬地推荐使用注入的服务对象和一个调度servlet或过滤器)。

但它希望示出在一个熟悉的模型

关键是不要在注解较窄范围,但在图的寿命。您创建寿命较短的图作为较长寿命图的“子”或“扩展”。在这些图表中记忆的对象具有图形管理对象的生命周期(或范围)。

+0

作为一个便笺,匕首目前不是GWT兼容的,尽管我们寄予厚望。我们希望有一种可以在GWT中工作的Ginjector风格的方法,但它现在比其他问题的优先级低。所以你不能在客户端使用它。 –

+0

更准确地说,您可以使用Dagger和GWT _via_ [Sheath](https:// github。com/tbroyer/sheath),但它会比GIN慢得多(它不支持范围或BTW)。 –

+0

@ChristianGruber感谢您花时间回答这个问题! – Jako