2015-11-03 49 views
7

我想创建在对谷歌吉斯的DI框架中继一个java web应用程序的适当性管理策略。谷歌吉斯物业管理

我想有一个机构回答下列三个条件:

  • 我想能够注入使用吉斯(@Named)属性
  • 我想能够访问属性以静态方式
  • 机制应该支持性的优先级,这意味着一个属性可以被包裹在某一个值,部署战争,但它也可以在目标系统级或本地文件系统(目标机的冗余我部署),在这种情况下,战争中的价值将被价值th覆盖在目标机器中存在。

我相信这是一个标准的要求。现在,使用guice标准活页夹,我可以很容易地得到第一个要求,但不是其他两个。为了让其他两个我创建了自己的类,执行以下操作:

  • 包裹和暴露吉斯的结合方法(那些结合性质)例如:

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

在哪里getProperty方法知道如何处理我的属性(从战争或系统级别获取值)以及静态公开属性。

所以基本上只要我使用我为属性绑定创建的这个实用工具,我很好,它涵盖了我所有的需求,但是一旦我使用标准的guice绑定,我就失去了第二个和第三个需求。

有没有办法覆盖吉斯绑定,并得到所有3个要求?

有一次,我在弹簧基于应用程序相同的challange,是很容易的。我实现ApplicationContextInitializer以下方法:

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

所以这给了我一个方式具有最高优先级添加本地属性,以我的环境。在与战争财产重叠的情况下,当地优先权较高。另外,我静静地公开了我的环境,因此我可以静态访问我的属性(对于不受容器管理的服务,主要是遗留的)。

如何我吉斯实现这一目标?

+0

你什么意思,你想在一个静态的方式来访问属性?这是否意味着您有用于访问特定属性的用例,但直到运行时才知道要访问哪个属性? –

+0

我希望能够使用像SomeClass.getProperty(“my.property”);这对于那些不受guice管理的类(通常是遗留的)并且仍然需要访问我的属性很有帮助 – forhas

回答

1

不幸的是,我不认为你会找到任何让你真正干净和令人满意的实现。尤其是,我不认为你会发现任何能够让你完全得到你想要的东西,而无需自己实施至少部分功能的东西。

如果我有这些需求,我会确保我的注射器是在中央InjectorFactory中创建的。如果您需要大量来自外部的参数来创建您的注入器,我只需在应用程序的一开始就创建一次,然后将注入器缓存到静态最终字段中。这将使其可用于静态方法。我会将我的“回退”属性加载绑定到显式提供者。这样,而不是使用标准的Names.bindProperties(...)方法,我会直接绑定到一个提供者。此提供程序然后实现执行回退或合并多个属性文件所必需的逻辑。将注入器缓存到静态字段意味着我可以调用静态方法从我的注入类之外的全局上下文中访问属性。

使用自己的提供者似乎最初不愉快,但可以提供一些额外的好处。对于初学者来说,您可以按照自己的想法来实施回退策略。此外,您可以添加其他行为,例如自动重新载入属性文件等(未在我的代码示例中显示)。

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

} 

鉴于上面的代码和file1.properties:

property1=Property1Value 
property2=Property2Value 

而且file.properties:

property2=IncorrectProperty2Value 
property3=Property3Value 

与供应商

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

以下用途:

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")); 
    } 
} 

输出:

Property1Value 
Property2Value 
Property3Value 
+0

不错,但仍然有缺点 - 没有人强制使用这个工厂。例如,如果有人决定创建一个新的模型,但不使用这个工厂,我可能最终会在guice管理的属性和工厂属性之间产生差距,对吗?我同意,只要每个人都使用工厂创建模型,这将提供解决方案,但这对我来说还不够(我目前有类似的解决方案,只是更简单:)) – forhas

+0

当然可以。一般来说,如果想要使用“新”,任何人都可以创建新对象,否则如果他们要组装自己的模块列表,他们可以创建自己的注入器。除非你想开始管理你的JVM策略,并且允许哪些类访问哪些类,否则没有任何方法可以禁止它。那么,我们的目标就是尽可能让人们以“正确的方式”做事。就像我之前说过的,我认为你不可能找到一个令人满意的解决方案。 –