6

我正在使用 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 配置您的应用程序......”

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

4

4 回答 4

3

配置注解

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

带有解释和 Arquillian 测试的教程

于 2013-04-10T13:21:54.970 回答
1

尽管它没有完全涵盖您的问题,但您可能会对 Weld 文档的这一部分感兴趣。

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

您链接到的方法肯定是一个非常好的方法 - 即使它可能满足您的需求,这取决于您计划注入的属性类型。

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

于 2012-04-16T17:48:53.240 回答
1

请参阅 Apache DeltaSpike 的 @ConfigProperty

于 2012-04-26T17:28:58.940 回答
1

这样做的唯一“标准”方法是使用带有非绑定注释成员的限定符,并确保所有注入都是依赖范围的。然后在您的生产者中,您可以获得 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);
}

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

于 2012-04-16T21:07:21.913 回答