2015-11-03 20 views
7

Tôi muốn tạo một chiến lược quản lý thuộc tính thích hợp trong một ứng dụng web java chuyển tiếp trên google guice dưới dạng khung DI.Google Guice Properties Management

Tôi muốn có một cơ chế trả lời 3 yêu cầu sau:

  • Tôi muốn để có thể tiêm các thuộc tính sử dụng Guice (@Named)
  • Tôi muốn để có thể truy cập tài sản Theo cách tĩnh,
  • Cơ chế phải hỗ trợ ưu tiên các thuộc tính, có nghĩa là một thuộc tính có thể được bao bọc trong cuộc chiến được triển khai với một giá trị nhất định nhưng nó cũng có thể dư thừa ở cấp hệ thống đích hoặc hệ thống tệp cục bộ (của máy đích) Tôi triển khai trên), trong trường hợp này giá trị trong chiến tranh sẽ bị ghi đè bởi giá trị thứ tồn tại trong máy mục tiêu.

Tôi tin rằng đây là yêu cầu tiêu chuẩn. Bây giờ, bằng cách sử dụng chất kết dính tiêu chuẩn guice tôi có thể dễ dàng có được yêu cầu đầu tiên nhưng không phải là hai khác. Để có được hai người kia Tôi tạo ra lớp riêng tôi nào sau đây:

  • Wraps và đưa ra phương án ràng buộc của Guice (những người liên kết với tài sản) Ví dụ:

public static void bindString(AnnotatedBindingBuilder<String> binder, String property, String defaultValue) { binder.annotatedWith(Names.named(property)).toInstance(getProperty(property, defaultValue)); }

đâu phương thức getProperty biết cách xử lý các thuộc tính của tôi (lấy giá trị từ cấp độ chiến tranh hoặc hệ thống) và phơi bày các thuộc tính một cách tĩnh. Vì vậy, về cơ bản miễn là tôi đang sử dụng tiện ích này mà tôi tạo cho các thuộc tính ràng buộc tôi là tốt, nó bao gồm tất cả các yêu cầu của tôi, nhưng một khi tôi sử dụng các ràng buộc guice tiêu chuẩn tôi đang mất yêu cầu thứ hai và thứ ba.

Có cách nào để ghi đè ràng buộc guice và nhận được tất cả 3 yêu cầu đó không?

Khi tôi đã có cùng một challange trong một ứng dụng dựa trên mùa xuân và khá dễ dàng. Tôi thực hiện ApplicationContextInitializer với phương thức sau:

@Override public void initialize(ConfigurableWebApplicationContext ctx) { PropertySource<Map<String, Object>> localProps = null; try { localProps = new ResourcePropertySource(new ClassPathResource(LOCAL_PROPERTIES_FILE_NAME)); } catch (IOException e) { LOG.fatal("Could not load local properties from classpath " + LOCAL_PROPERTIES_FILE_NAME); return; } LOG.info("Loaded configuration from classpath local file " + LOCAL_PROPERTIES_FILE_NAME); ctx.getEnvironment().getPropertySources().addFirst(localProps); }

vì vậy đây đã cho tôi một cách để thêm các thuộc tính địa phương với ưu tiên cao nhất để Môi trường của tôi. Trong trường hợp chồng chéo với các đặc tính chiến tranh, những người địa phương có ưu tiên cao hơn. Ngoài ra, tôi tiếp xúc với Môi trường của mình tĩnh nên tôi có quyền truy cập tĩnh vào các thuộc tính của mình (đối với các dịch vụ không được quản lý bởi vùng chứa, phần lớn là cũ).

Làm cách nào để đạt được điều này bằng guice?

+0

Ý anh là gì, mà bạn muốn truy cập vào các thuộc tính trong một cách tĩnh? Điều đó có nghĩa là bạn có các trường hợp sử dụng mà bạn muốn truy cập vào một thuộc tính cụ thể, nhưng bạn không biết cho đến khi chạy tài sản nào bạn muốn truy cập? –

+0

Tôi muốn có thể truy cập vào một tài sản bằng cách sử dụng một cái gì đó như: SomeClass.getProperty ("my.property"); Điều này sẽ hữu ích cho các lớp không được quản lý bởi guice (thường là thường) và vẫn cần quyền truy cập vào các thuộc tính của tôi – forhas

Trả lời

1

Thật không may, tôi không nghĩ rằng bạn sẽ tìm thấy bất kỳ thứ gì mang đến cho bạn một triển khai thực sự sạch sẽ và thỏa mãn. Đặc biệt, tôi không nghĩ rằng bạn sẽ tìm thấy bất cứ điều gì cung cấp cho bạn chính xác những gì bạn muốn mà không thực hiện ít nhất một phần của nó cho mình.

Nếu tôi có những nhu cầu đó, tôi sẽ đảm bảo rằng vòi phun của tôi được tạo ra trong một trung tâm InjectorFactory. Nếu bạn yêu cầu một số lượng lớn các tham số từ bên ngoài để tạo ra bộ phun của bạn, tôi sẽ chỉ đơn giản là tạo nó một lần ở đầu của ứng dụng của tôi và sau đó cache bộ lọc vào một trường cuối cùng tĩnh. Điều này sẽ làm cho nó có sẵn cho một phương pháp tĩnh. Tôi sẽ ràng buộc tài sản "fall-back" của tôi tải đến một nhà cung cấp rõ ràng. Bằng cách đó, thay vì sử dụng các tiêu chuẩn Names.bindProperties (...), tôi sẽ liên kết trực tiếp với Nhà cung cấp. Nhà cung cấp này sau đó triển khai logic cần thiết để thực hiện dự phòng hoặc hợp nhất nhiều tệp thuộc tính. Có bộ đệm được lưu vào một trường tĩnh có nghĩa là tôi có thể gọi một phương thức tĩnh để truy cập các thuộc tính từ một bối cảnh chung bên ngoài các lớp được tiêm của tôi.

Sử dụng nhà cung cấp của riêng bạn có vẻ khó chịu, nhưng có thể cung cấp một số lợi ích bổ sung. Để bắt đầu, bạn có thể thực hiện chiến lược dự phòng của bạn chính xác như bạn muốn. Ngoài ra, bạn có thể thêm các hành vi bổ sung như tự động tải lại các tệp thuộc tính của bạn, v.v. (không được hiển thị trong mẫu mã của tôi).

public class InjectorFactory { 
    private static Injector injector = null; 
    public static synchronized Injector getOrCreateInjector() { 
     if(injector == null) { 
      injector = Guice.createInjector(new AbstractModule() { 
       @Override 
       protected void configure() { 
        Properties properties1 = createProperties("file1.properties"); 
        Properties properties2 = createProperties("file2.properties"); 
        Set<Object> propertyNames = new HashSet<Object>(); 
        propertyNames.addAll(properties1.keySet()); 
        propertyNames.addAll(properties2.keySet()); 

        for (Object object : propertyNames) { 
         String propertyName = (String) object; 
         bind(String.class).annotatedWith(Names.named(propertyName)).toProvider(new StringProvider(properties1, properties2, propertyName)); 
        } 
       } 

       private Properties createProperties(String propertyFileName) { 
        try { 
         InputStream stream = InjectorFactory.class.getResourceAsStream(propertyFileName); 
         try { 
          Properties properties = new Properties(); 
          properties.load(stream); 
          return properties; 
         } finally { 
          stream.close(); 
         } 

        } catch (IOException exception) { 
         throw new RuntimeException("Could not load properties file"); 
        } 
       } 
      }); 
     } 
     return injector; 
    } 

    public static String getProperty(String propertyName) { 
     return getOrCreateInjector().getInstance(Key.get(String.class, Names.named(propertyName))); 
    } 

} 

Với đoạn code trên và file1.properties:

property1=Property1Value 
property2=Property2Value 

Và file.properties:

property2=IncorrectProperty2Value 
property3=Property3Value 

với nhà cung cấp

public class StringProvider implements Provider<String> { 
    private Properties properties1; 
    private Properties properties2; 
    private String propertyName; 
    public StringProvider(Properties properties1, Properties properties2, 
      String propertyName) { 
     this.properties1 = properties1; 
     this.properties2 = properties2; 
     this.propertyName = propertyName; 
    } 
    public String get() { 
     if(properties1.containsKey(propertyName)) { 
      return properties1.getProperty(propertyName); 
     } 
     return properties2.getProperty(propertyName); 
    } 
} 

Việc sử dụng sau đây:

public class InjectorFactoryTest { 
    public static void main(String ... parameters) { 
     System.out.println(InjectorFactory.getProperty("property1")); 
     System.out.println(InjectorFactory.getProperty("property2")); 
     System.out.println(InjectorFactory.getProperty("property3")); 
    } 
} 

Đầu ra:

Property1Value 
Property2Value 
Property3Value 
+0

Rất tốt, nhưng vẫn có bất lợi - Không ai thi hành việc sử dụng nhà máy này. Ví dụ, nếu ai đó quyết định tạo ra một mô hình mới nhưng không sử dụng nhà máy này, tôi có thể kết thúc với một khoảng cách giữa các thuộc tính được quản lý guice đến các đặc tính của nhà máy, tôi có đúng không? Tôi đồng ý rằng miễn là mọi người sử dụng nhà máy để tạo mô hình, điều này sẽ cung cấp giải pháp, nhưng điều này là không đủ đối với tôi (tôi có một giải pháp tương tự vào lúc này, đơn giản hơn một chút :)) – forhas

+0

Có tất nhiên. Nói chung, bất cứ ai cũng có thể tạo ra các đối tượng mới nếu họ muốn sử dụng "mới" hoặc người nào khác họ có thể tạo ra vòi phun của riêng mình nếu họ lắp ráp danh sách các mô-đun của riêng mình. Trừ khi bạn muốn bắt đầu quản lý các chính sách JVM của mình và các lớp nào được phép truy cập vào các lớp khác, không có cách nào để ngăn chặn điều này. Mục tiêu, sau đó, là làm cho nó dễ dàng nhất có thể để mọi người làm những điều "đúng cách". Và như tôi đã nói trước đây, tôi nghĩ rằng không chắc rằng bạn sẽ tìm thấy một giải pháp mà cảm thấy rất thỏa mãn. –

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