【问题标题】:Dependency injection using ".properties" file使用“.properties”文件进行依赖注入
【发布时间】:2012-04-15 19:21:44
【问题描述】:

我正在使用 Java EE 6,需要从“.properties”文件加载配置。有没有推荐的方式(最佳实践)使用依赖注入从配置文件中加载值?我在 Spring 中找到了这个注解,但我没有找到 Java EE 的“标准”注解。

这家伙从头开发了一个解决方案:

http://weblogs.java.net/blog/jjviana/archive/2010/05/18/applicaction-configuration-java-ee-6-using-cdi-simple-example

“我找不到如何配置应用程序的简单示例 通过从文件中读取配置属性来使用 CDI..."

但我想知道是否有更标准的方式来代替创建配置工厂...

【问题讨论】:

    标签: configuration dependency-injection annotations java-ee-6 cdi


    【解决方案1】:

    配置注释

    package com.ubiteck.cdi;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import javax.enterprise.util.Nonbinding;
    import javax.inject.Qualifier;
    
    @Qualifier
    @Retention(RetentionPolicy.RUNTIME)
    public @interface InjectedConfiguration {
        /**
         * Bundle key
         * @return a valid bundle key or ""
         */
        @Nonbinding String key() default "";
        /**
         * Is it a mandatory property
         * @return true if mandator
         */
        @Nonbinding boolean mandatory() default false;
        /**
         * Default value if not provided
         * @return default value or ""
         */
        @Nonbinding String defaultValue() default "";
     }
    

    配置工厂可能如下所示:

    import java.text.MessageFormat;
    import java.util.MissingResourceException;
    import java.util.ResourceBundle;
    import javax.enterprise.inject.Produces;
    import javax.enterprise.inject.spi.InjectionPoint;
    
    public class ConfigurationInjectionManager {
        static final String INVALID_KEY="Invalid key '{0}'";
        static final String MANDATORY_PARAM_MISSING = "No definition found for a mandatory configuration parameter : '{0}'";
        private final String BUNDLE_FILE_NAME = "configuration";
        private final ResourceBundle bundle = ResourceBundle.getBundle(BUNDLE_FILE_NAME);
    
        @Produces
        @InjectedConfiguration
        public String injectConfiguration(InjectionPoint ip) throws IllegalStateException {
            InjectedConfiguration param = ip.getAnnotated().getAnnotation(InjectedConfiguration.class);
            if (param.key() == null || param.key().length() == 0) {
                return param.defaultValue();
            }
            String value;
            try {
                value = bundle.getString(param.key());
                if (value == null || value.trim().length() == 0) {
                    if (param.mandatory())
                        throw new IllegalStateException(MessageFormat.format(MANDATORY_PARAM_MISSING, new Object[]{param.key()}));
                    else
                        return param.defaultValue();
                }
                return value;            
            } catch (MissingResourceException e) {
                if (param.mandatory()) throw new IllegalStateException(MessageFormat.format(MANDATORY_PARAM_MISSING, new Object[]{param.key()}));
                return MessageFormat.format(INVALID_KEY, new Object[]{param.key()});
            }
        }
    

    Tutorial with explanation and Arquillian test

    【讨论】:

    • 谢谢!我们如何在此处以编程方式更改 BUNDLE_FILE_NAME?例如,程序 A a 可能使用“a.properies”,程序 B 可能使用“b.properties”,但希望共享此代码。
    • 你如何定义被注入的文件?它是从哪里读取的?
    【解决方案2】:

    即使它没有完全涵盖您的问题,您可能会对 Weld 文档的this part 感兴趣。

    已经提到了这一点 - 不,没有标准的方法可以注入任意资源/资源文件。我想标准化这种高度依赖于自定义的需求完全超出了规范的范围(Spring 不是规范,他们可以简单地实现他们喜欢的任何东西)。然而,CDI 提供的是一种强大的(又名类型安全)机制,用于在一侧注入配置持有 bean,而在另一侧提供灵活的生产者机制来读取和创建此类 bean。这绝对是您所询问的推荐方式。

    您链接到的方法肯定是一种非常好的方法 - 尽管它可能无法满足您的需求,具体取决于您计划注入的属性类型。

    一种非常类似于 CDI 的继续方式是开发一个 CDI 扩展(它可以很好地封装所有必需的类)并在您的项目中独立部署它。当然,您也可以为CDI-extension catalog 甚至Apache Deltaspike 做出贡献。

    【讨论】:

    • “Spring 没有规范,他们可以简单地实现他们喜欢的任何东西” - 是的,但规范并非来自天堂。有人写过,就像有人写过 Spring。
    【解决方案3】:

    查看 Apache DeltaSpike 的 @ConfigProperty

    【讨论】:

      【解决方案4】:

      这样做的唯一“标准”方法是使用带有非绑定注释成员的限定符,并确保所有注入都是依赖范围的。然后在您的生产者中,您可以获得 InjectionPoint 并从注入点的限定符中获取密钥。你会想要这样的东西:

      @Qualifier
      public @interface Property {
          @Nonbinding String value default "";
      }
      
      ...
      @Inject @Property("myKey") String myKey;
      
      
      ...
      @Produces @Property public String getPropertyByKey(InjectionPoint ip) {
          Set<Annotation> qualifiers = ip.getQualifiers
      
          // Loop through qualifers looking for Property.class save that off
          return ResourceBundle.getBundle(...).getString(property.key);
      }
      

      显然,您可以对该代码进行一些增强,但这应该足以让您走上正确的道路。

      【讨论】:

        猜你喜欢
        • 2015-09-26
        • 2014-01-19
        • 2014-03-25
        • 2019-11-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多