2013-06-04 67 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