简体   繁体   中英

wildfly: reading properties from configuration directory

I'm trying to read deployment specific information from a properties file in my wildfly configuration folder. I tried this:

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

But apparently this is not working since the configuration folder is not in the classpath anymore. Now I can't find an easy way to do it. My favorite would be something like this:

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

The only solution I found on the web so far involves making my own OSGi module, but I believe there must be an easier way to do it (one without OSGi!). Can anyone show me how?

If you want to explicitly read a file from the configuration directory (eg $WILDFLY_HOME/standalone/configuration or domain/configuration ) there's a system property with the path in it. Simply do System.getProperty("jboss.server.config.dir"); and append your file name to that to get the file.

You wouldn't read it as a resource though, so...

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

Then the file would be loaded for you.

Also, since WildFly doesn't ship with OSGi support anymore, I don't know how creating an OSGi module would help you here.

Here is a full example using just CDI, taken from this site .

  1. Create and populate a properties file inside the WildFly configuration folder

    $ echo 'docs.dir=/var/documents' >> .standalone/configuration/application.properties
  2. Add a system property to the WildFly configuration file.

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

This will add the following to your server configuration file (standalone.xml or domain.xml):

<system-properties>
    <property name="application.properties" value="${jboss.server.config.dir}/application.properties"/>
</system-properties>
  1. Create the singleton session bean that loads and stores the application wide properties

     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. Create the CDI Qualifier. We will use this annotation on the Java variables we wish to inject into.

     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. Create the producer method; this generates the object to be injected

    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. Lastly inject the property into one of your CDI beans

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

The simplest thing you can do is to run standalone.sh with a -P option referencing your properties file (you need a URL file:/path/to/my.properties , or put the file in $WILDFLY_HOME/bin ).

Then all properties from the file will be loaded as system properties.

For injecting configuration properties into your application classes, have a look at DeltaSpike Configuration , which supports different property sources like system properties, environment variables, JNDI entries and hides the specific source from your application.

Alternatively, to avoid setting system properties (which will be global in the sense of being visible to all applications deployed to your WildFly instance), you can also define a custom property source for DeltaSpike reading a properties file from any given location, and these properties will be local to your application.

It sounds like the problem you are trying to solve is managing different (but probably similar) configuration files for running your application in different environments (ie, Production, QA, or even different customers). If that is the case, take a look at Jfig http://jfig.sourceforge.net/ . It would obviate the need for storing property files outside your classpath (but you still could).

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

If you have in standalone.xml property:

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

you can wasily read it with:

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

Or if you specify context param in web.xml like:

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

You can read it in Java bean:

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

If your application is deployed in a MicroProfile compatible environment, the standard solution would be to place properties in a ConfigSource element (such as the microprofile-config.properties file) or in a custom defined ConfigSource. WildFly supports MicroProfile API out of the box.

See this tutorial as an example of Using MicroProfile Config API with WildFly

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM