2013-06-04 18 views
9

Làm cách nào để tạo phạm vi tùy chỉnh với Dagger?Dagger tùy chỉnh phạm vi, làm thế nào?

Có nguyên tắc nào không? Tôi không tìm thấy chúng.

Tôi đang phát triển ứng dụng Vaadin và sẽ cần phạm vi tùy chỉnh. Một cái gì đó như UiScoped.

Trân trọng

Trả lời

28

Dagger không phạm vi sử dụng cùng một loại cơ chế mà Guice làm. Dagger, cụ thể, không minh bạch xử lý phạm vi theo cách của Guice, với các chú thích phạm vi khác nhau, một Injector và các cache khác nhau đằng sau hậu trường. Thay vào đó, nó sử dụng hai nguyên tắc. Thứ nhất, @Singleton có nghĩa là "một trên mỗi đồ thị" (giải thích chặt chẽ nhất về JSR-330) và, thứ hai, các đồ thị đó có thể được liên kết trong một hệ thống phân cấp. Dagger sử dụng cây này của biểu đồ liên kết phân cấp, nơi bạn tạo biểu đồ bằng cách thêm nhiều mô-đun hơn và mở rộng nó thông qua phương thức plus() để tạo biểu đồ "có phạm vi" có tuổi thọ ngắn hơn. Điều này tương tự như Child Injectors trong guice. Một nguyên tắc quan trọng ở đây là các trường hợp trong biểu đồ mở rộng có thể thấy các trường hợp trong biểu đồ gốc, nhưng không phải là ngược lại. Vì vậy, bản chất đồng tâm của thời gian sống ngắn hơn được nhân đôi trong tầm nhìn - một đối tượng sống ngắn hơn có thể nhìn thấy (phụ thuộc vào) một đối tượng sống lâu hơn, nhưng không phải ngược lại. Vì vậy, một đối tượng sống cho cuộc sống của một yêu cầu có thể thấy một đối tượng sống cho một ứng dụng, nhưng không phải là đối tượng ngược lại.

Chính cơ chế này được mong đợi là phạm vi trường hợp được lưu trong bộ nhớ cache hẹp hơn.

Nếu một cấu hình đồ thị với một số mô-đun, và có một singleton nó sẽ có một thể hiện được lưu trong biểu đồ được cung cấp cho tất cả các đối tượng phụ thuộc. Nếu tạo một phần mở rộng cho đồ thị đó thông qua phương thức plus(), cấu hình nó với các mô-đun khác có chứa các liên kết được chú thích @Singleton, thì các mô-đun khác sẽ là một biểu đồ ... nhưng một lần cho mỗi ngắn hơn- sống ObjectGraph dụ.

Ví dụ, chúng ta hãy mô phỏng một máy chủ đáp ứng các yêu cầu, nơi mà chúng tôi muốn có một số đối tượng mà sống cho cuộc sống của các ứng dụng, và một số đối tượng mà chỉ sống cho cuộc sống ngắn hơn một yêu cầu:

@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(); 
    } 
} 

Trong ví dụ này, mỗi MyRequestEndpoint sẽ nhận được một cá thể chia sẻ của ConnectionPool, nhưng một điểm cuối trong bất kỳ hai yêu cầu nào sẽ nhận được hai RequestObject khác nhau.

Đây là một ví dụ hơi ngớ ngẩn được xây dựng trên đỉnh đầu của tôi trên mẫu J2EE. Một cái gì đó tầm thường này bạn sẽ không cấu trúc theo cách này, và bạn sẽ cần giàn giáo mạnh mẽ hơn cho một mô hình máy chủ thích hợp. Thật vậy, dự án Dagger có khả năng sẽ làm một điều như vậy (mặc dù tôi khuyên bạn nên sử dụng các đối tượng dịch vụ được tiêm và một servlet hoặc bộ lọc).

Nhưng hy vọng nó minh họa một phạm vi hẹp hơn trong một mô hình quen thuộc

Mấu chốt không phải là trong chú thích, nhưng trong cuộc đời của đồ thị. Bạn tạo biểu đồ có tuổi thọ ngắn hơn dưới dạng "con" hoặc "tiện ích" của biểu đồ tồn tại lâu hơn. Các đối tượng được ghi nhớ trong các biểu đồ này có thời gian sống (hoặc phạm vi) của các đối tượng quản lý đồ thị.

+0

Là một lưu ý phụ, Dagger hiện không tương thích với GWT, mặc dù chúng tôi có hy vọng cao. Chúng tôi hy vọng có cách tiếp cận kiểu Ginjector có thể hoạt động trong GWT, nhưng ưu tiên thấp hơn các vấn đề khác ngay bây giờ. Vì vậy, bạn không thể sử dụng nó ở phía khách hàng. –

+0

Chính xác hơn, bạn có thể sử dụng Dagger với GWT _via_ [Vỏ bọc] (https: // github.com/tbroyer/sheath), nhưng nó sẽ chậm hơn nhiều so với GIN (không hỗ trợ phạm vi hoặc BTW). –

+0

@ChristianGruber cảm ơn vì đã dành thời gian cho câu trả lời này! – Jako