2012-11-06 46 views
9

Tôi muốn tạo một Mô-đun tự động liên kết các cá thể với các chú thích được đặt tên. Trường hợp sử dụng là tôi muốn tự động ràng buộc các giá trị trong cấu hình của tôi với khóa trong tệp thuộc tính là giá trị @Named.Làm thế nào để bạn thực hiện các liên kết động trong Guice mà yêu cầu một Instance tiêm?

Tuy nhiên cấu hình bị ràng buộc trong một mô-đun khác vì vậy tôi cần cấu hình để được tiêm. Giải pháp mà tôi đã xem xét là:

  1. Ràng buộc trong phương thức configure(). Phương pháp này không được tiêm vào và tôi không thể lấy cấu hình cơ bản.

  2. Sử dụng nhà cung cấp/@ Cung cấp. Nhà cung cấp chỉ liên kết một trường hợp duy nhất.

  3. Sử dụng MultiBinder. Trường hợp sử dụng của tôi hơi khác một chút, những gì được cung cấp bởi tiện ích mở rộng này. Multi-binding cho phép bạn liên kết nhiều cá thể một cách riêng biệt và sau đó chúng được tiêm như một Bộ sưu tập kiểu chứa phức tạp hơn. Tôi muốn ràng buộc từng cá thể riêng biệt và có chúng bằng cách nhận dạng duy nhất để tiêm sau này.

  4. Sử dụng childInjector. Thật không may điều này là không thể mà không có một số sửa đổi rộng rãi của mã hiện có. This answer là một mô tả rất tốt về cách giải quyết vấn đề này theo cách này.

  5. Tiêm chất kết dính bằng cách nào đó. (Tôi bắt đầu nhận được một chút tin tặc) Guice cho phép tiêm Injector để sử dụng sau, tôi đã thử tiêm Binder vào Module mặc dù phương thức @Provides và sau đó sử dụng trực tiếp liên kết để tạo nhiều liên kết trong phương thức. Guice sẽ không tiêm chất kết dính.

Trả lời

8

Hãy nhớ rằng tất cả của configure phương pháp cấu hình tất cả các ràng buộc trong một Injector trước bất kỳ tiêm có thể xảy ra. Điều đó nói rằng, một vài điều:

  1. Binding @Named tính đến nội dung của một Properties trường hợp duy nhất là rất hữu ích, có một phương pháp Names.bindProperties(...) mà hiện nó tự động cho bạn. Bí quyết duy nhất là bạn cần có phiên bản Properties tại thời điểm configure() được chạy.

    Nếu tất cả đều có sẵn cùng một lúc, đừng lo lắng về việc ràng buộc các thuộc tính trong một mô-đun và ràng buộc ứng dụng trong một mô-đun khác. Miễn là tất cả chúng đi vào cùng một Injector, Guice sẽ kết hợp tất cả chúng và cho phép chúng thỏa mãn các phụ thuộc của nhau.

  2. Nhà cung cấp có thể trả về các phiên bản khác nhau và thường làm - nhưng bạn nói đúng là nhà cung cấp sẽ không giúp bạn phân biệt giữa các khóa. Nếu tiêm dụ Thuộc tính trực tiếp là quá xấu xí, hãy xem xét thực hiện một nhà máy nhẹ thay vì:

    public class ConfigOracle { 
        @Inject private Properties properties; 
    
        public String getAsString(String key) { ... } 
        public int getAsInt(String key) { ... } 
    } 
    
    public class SomeConfigUser { 
        @Inject private ConfigOracle configOracle; 
    
        public void doStuff() { 
        doStuffBasedOn(configOracle.getAsString("my.properties.key")); 
        } 
    } 
    
  3. Bạn không bao giờ nên cần phải tiêm một Binder (hoặc bất cứ điều gì khác) vào một mô-đun.

    • Nếu bạn thực hiện Module, các binder sẽ là một tham số của configure(). Nếu bạn mở rộng AbstractModule như bạn nên, chỉ cần gọi phương thức binder().
    • Bạn có thể chuyển các phụ thuộc thông qua các đối số hàm dựng cho Mô-đun, nếu cần thiết, cái mà (theo như tôi quan tâm) là cách duy nhất Mô-đun nên thay đổi các ràng buộc mà chúng tạo ra.
    • Không có lý do gì bạn không thể tạo Mô-đun thông qua một Đầu phun, nhưng trước tiên bạn phải có một Đầu phun, và có vẻ như bạn đang cố gắng tránh xa chỉ với một cái.
    • Nếu bạn cần các trường hợp khác từ Injector, bạn luôn có thể viết Provider thực hiện với @Inject trường/phương thức/nhà thầu hoặc thậm chí tham số trong phương thức @Provides (sẽ là filled in with dependencies automatically).

Nói chung tôi vẫn ủng hộ cách tiếp cận injector con (nhờ các liên kết và lời khen cho câu trả lời trước của tôi!), Mà phù hợp với bạn "bindings động dựa trên một thể hiện tiêm" mô tả tốt nhất, và sẽ theo nghĩa đen đơn giản như vậy:

class PropertiesModule extends AbstractModule { 
    Properties properties; 

    PropertiesModule(Properties properties) { 
    this.properties = properties; 
    } 

    @Override public void configure() { 
    Names.bindProperties(binder(), properties); 
    } 
} 

Injector oldInjector = Guice.createInjector(allYourOtherModules); 
Module myModule = new PropertiesModule(oldInjector.get(Properties.class)); 
Injector injector = oldInjector.createChildInjector(myModule); 
+0

Một câu trả lời hay khác, cảm ơn! Tôi không biết về phương thức Names.bindProperties(), tôi sẽ phải lưu nó cho sau này. Tôi đã thử các giải pháp bạn đề xuất trong 2 đêm qua và nó chủ yếu là làm việc, mặc dù không phải là sạch sẽ tôi đã có thể thích nó. Về cơ bản tôi đã đi đến kết luận rằng những gì tôi thực sự muốn làm nằm ngoài thiết kế của Guice. Tôi không sở hữu khuôn khổ mà tôi đang triển khai và tôi không tin rằng những người tiêm chích trẻ em sẽ là một tính năng có sẵn bất kỳ lúc nào, vì vậy tôi sẽ làm lại cấu hình của mình một chút khác biệt. Cảm ơn bạn đã trả lời nhanh chóng! –

Các vấn đề liên quan