wildfly:从配置目录读取属性

wildfly: reading properties from configuration directory

我正在尝试从我的 wildfly 配置文件夹中的属性文件中读取特定于部署的信息。我试过这个:

@Singleton
@Startup
public class DeploymentConfiguration {

  protected Properties props;

  @PostConstruct
  public void readConfig() {

    props = new Properties();
    try {
      props.load(getClass().getClassLoader().getResourceAsStream("my.properties"));
    } catch (IOException e) {
      // ... whatever
    }
  }

但显然这不起作用,因为配置文件夹不再位于类路径中。现在我找不到一个简单的方法来做到这一点。我最喜欢的是这样的:

@InjectProperties("my.properties")
protected Properties props;

到目前为止,我在网上找到的唯一解决方案是制作我自己的 OSGi 模块,但我相信一定有更简单的方法(没有 OSGi 的方法!)。谁能告诉我怎么做?

您可以做的最简单的事情是 运行 standalone.sh 使用 -P 选项引用您的属性文件(您需要 URL file:/path/to/my.properties,或者将文件放在 $WILDFLY_HOME/bin).

然后文件中的所有属性都将作为系统属性加载。

要将配置属性注入到您的应用程序 类,请查看 DeltaSpike Configuration,它支持不同的 属性 来源,例如系统属性、环境变量、JNDI 条目并隐藏特定的来自您的应用程序。

或者,为了避免设置系统属性(在部署到您的 WildFly 实例的所有应用程序可见的意义上,这将是全局的),您还可以定义自定义 属性 源,供 DeltaSpike 读取属性来自任何给定位置的文件,这些属性将是您的应用程序的本地属性。

如果您想明确地从配置目录(例如$WILDFLY_HOME/standalone/configurationdomain/configuration)中读取文件,那么系统属性 中包含路径。只需执行 System.getProperty("jboss.server.config.dir"); 并将您的文件名附加到该文件名即可获取文件。

虽然您不会将其作为资源来阅读,所以...

String fileName = System.getProperty("jboss.server.config.dir") + "/my.properties";
try(FileInputStream fis = new FileInputStream(fileName)) {
  properties.load(fis);
}

然后将为您加载文件。

此外,由于 WildFly 不再附带 OSGi 支持,我不知道创建 OSGi 模块对您有何帮助。

这是一个仅使用 CDI 的完整示例,取自此 site

  1. 在 WildFly 配置文件夹中创建并填充属性文件

    $ echo 'docs.dir=/var/documents' >> .standalone/configuration/application.properties
    
  2. 在 WildFly 配置文件中添加系统 属性。

    $ ./bin/jboss-cli.sh --connect
    [standalone@localhost:9990 /] /system-property=application.properties:add(value=${jboss.server.config.dir}/application.properties)
    

这会将以下内容添加到您的服务器配置文件(standalone.xml 或 domain.xml):

<system-properties>
    <property name="application.properties" value="${jboss.server.config.dir}/application.properties"/>
</system-properties>
  1. 创建加载和存储应用程序范围属性的单例会话 bean

    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Properties;
    
    import javax.annotation.PostConstruct;
    import javax.ejb.Singleton;
    
    @Singleton
    public class PropertyFileResolver {
    
        private Logger logger = Logger.getLogger(PropertyFileResolver.class);
        private String properties = new HashMap<>();
    
        @PostConstruct
        private void init() throws IOException {
    
            //matches the property name as defined in the system-properties element in WildFly
            String propertyFile = System.getProperty("application.properties");
            File file = new File(propertyFile);
            Properties properties = new Properties();
    
            try {
                properties.load(new FileInputStream(file));
            } catch (IOException e) {
                logger.error("Unable to load properties file", e);
            }
    
            HashMap hashMap = new HashMap<>(properties);
            this.properties.putAll(hashMap);
        }
    
        public String getProperty(String key) {
            return properties.get(key);
        }
    }
    
  2. 创建 CDI 限定符。我们将在我们希望注入的 Java 变量上使用此注释。

    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    import javax.inject.Qualifier;
    
    @Qualifier
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR })
    public @interface ApplicationProperty {
    
        // no default meaning a value is mandatory
        @Nonbinding
        String name();
    }
    
  3. 创建生产者方法;这会生成要注入的对象

    import javax.enterprise.inject.Produces;
    import javax.enterprise.inject.spi.InjectionPoint;
    import javax.inject.Inject;
    
    public class ApplicaitonPropertyProducer {
    
        @Inject
        private PropertyFileResolver fileResolver;
    
        @Produces
        @ApplicationProperty(name = "")
        public String getPropertyAsString(InjectionPoint injectionPoint) {
    
            String propertyName = injectionPoint.getAnnotated().getAnnotation(ApplicationProperty.class).name();
            String value = fileResolver.getProperty(propertyName);
    
            if (value == null || propertyName.trim().length() == 0) {
                throw new IllegalArgumentException("No property found with name " + value);
            }
            return value;
        }
    
        @Produces
        @ApplicationProperty(name="")
        public Integer getPropertyAsInteger(InjectionPoint injectionPoint) {
    
            String value = getPropertyAsString(injectionPoint);
            return value == null ? null : Integer.valueOf(value);
        }
    }
    
  4. 最后将 属性 注入你的一个 CDI bean

    import javax.ejb.Stateless;
    import javax.inject.Inject;
    
    @Stateless
    public class MySimpleEJB {
    
        @Inject
        @ApplicationProperty(name = "docs.dir")
        private String myProperty;
    
        public String getProperty() {
            return myProperty;
        }
    }
    

听起来您要解决的问题是在不同环境(即生产、QA 甚至不同客户)中为 运行 您的应用程序管理不同(但可能相似)的配置文件。如果是这样,请查看 Jfig http://jfig.sourceforge.net/ 。它将避免在类路径之外存储 属性 文件的需要(但你仍然可以)。

What is needed is a hierarchical approach to configuration files. The ninety percent of configuration values that do not change can be maintained in a base file. The other ten percent (or less) may be maintained in their own distinct configuration file. At run time, the files are layered on top of each other to provide a flexible, manageable configuration. For example, in a development environment myhost.config.xml combines with dev.config.xml and base.config.xml to form my unique configuration.

Each configuration file may then be maintained in version control as they have unique names. Only the base files need to be modified when base values change, and it is easy to see the difference between versions. Another major benefit is that changes to the base configuration file will be exhaustively tested before deployment.

InputStream in = null;
File confDir = new File(System.getProperty("jboss.server.config.dir"));
File fileProp = new File(confDir, "my.properties");

try{
    //teste fileProp.exists etc.

    in = new FileInputStream(fileProp);
    Properties properties = new Properties();
    properties.load(in);

    //You should throws or handle FileNotFoundException and IOException
}finally{
    try{
        in.close();
    }catch(Exception ignored){
    }
}

为了避免此类问题,问题是在 VM 参数中设置 jboss.server.config.dir,如下所示:

-Djboss.server.config.dir="[jboss_repository]/server/[default-all-standard-standalone]/conf" –server

如果你在 standalone.xml 属性:

<property name="my.properties" value="propertyValue"/>

您可以轻松阅读它:

static final String MY_PROPERTY = System.getProperty("my.properties");

或者如果您在 web.xml 中指定上下文参数,例如:

<context-param>
    <param-name>MyProperty</param-name>
    <param-value>MyPropertyValue</param-value>
</context-param>

可以在Javabean中阅读:

String myProperty= getServletContext().getInitParameter("MyProperty");