在静态初始化块中加载Java属性

21

我有一个静态的工具类,用于对一些敏感数据进行字符串操作。在使用这个类之前,我需要初始化某些静态变量的值,例如用户名/密码,而这些值我希望存储在.properties文件中。

我不太了解Java中.properties文件的加载方式,尤其是在没有使用*Spring DI*容器的情况下。能否有人帮我/给我洞察一下如何实现呢?

谢谢!

补充说明: .properties文件的精确位置未知,但它将位于类路径下。有点像classpath:/my/folder/name/myproperties.properties


你提到了Spring - 你在应用程序中使用这个静态实用类的框架吗? - teabot
嗯,有点奇怪。类将在使用Spring容器的应用程序内部使用。但是该类本身不会使用Spring进行装配,它只需要是一个静态实用程序类,由被Spring装配的工作线程调用。我可以修改工作线程,但我不能修改这些线程的装配(因此我无法使用PropertyPlaceHolderConfigurer)……嗯,这有任何意义吗? :) - xelurg
8个回答

29
首先,从一个InputStream中获取要加载的属性。这可以来自多个位置,包括一些最常见的位置:
  • FileInputStream,通过硬编码或通过系统属性指定文件名创建。文件名可以是相对路径(相对于Java进程的当前工作目录)或绝对路径。
  • 资源文件(类路径上的文件),通过在Class(相对于类文件)或ClassLoader(相对于类路径根目录)上调用getResourceAsStream获得。请注意,这些方法返回null(而不是引发异常)如果资源丢失。
  • URL,就像文件名一样,可以通过硬编码或通过系统属性指定。
然后创建一个新的Properties对象,并将InputStream传递给它的load()方法。无论任何异常都要确保关闭流。
在类初始化器中,必须处理像IOException这样的已检查异常。可以抛出未经检查的异常,这将防止类被初始化。这反过来通常会阻止应用程序运行。在许多应用程序中,可能希望改用默认属性,或者回退到另一个配置源,例如在交互式上下文中提示用户。整个过程看起来可能像这样:
private static final String NAME = "my.properties";

private static final Properties config;

static {
  Properties fallback = new Properties();
  fallback.put("key", "default");
  config = new Properties(fallback);

  URL res = MyClass.getResource(NAME);
  if (res == null) throw new UncheckedIOException(new FileNotFoundException(NAME));
  URI uri;
  try { uri = res.toURI(); }
  catch (URISyntaxException ex) { throw new IllegalArgumentException(ex); }

  try (InputStream is = Files.newInputStream(Paths.get(uri))) { config.load(is); } 
  catch (IOException ex) { throw new UncheckedIOException("Failed to load resource", ex); }
}

6
  1. 请查看java.util.Properties

  2. 您可以使用静态初始化程序。因此,在类的顶部,您可以执行以下操作:


 static {
    Properties props = new Properties();
    InputStream steam = ...; // open the file
    props.load(stream);

    // process properties content
    String username = props.getProperty("username");
  }

对不起,我猜你在我格式化代码的时候已经做了。 - Michael Myers
2
你可能需要一些异常处理,因为我认为不能从静态块中抛出异常。 - Peter
1
RuntimeExceptions 可以从静态块中抛出。您需要处理文件操作的已检查异常。 - akf
1
这里提出的实现主要是为了说明。为了使其达到生产质量,您需要处理与文件相关的异常(例如安全性、存在性、IOException),在finally块中关闭连接,处理加密(我希望他不会将密码保存为明文),等等。 - notnoop

3

请使用以下任一方式:

CurrentClassName.class.getResourceAsStream 
new FileInputStream(File)

根据类是否在类路径中,获取输入流。然后使用。

Properties.load

加载属性。


1

对于我来说,MyClass.class.getClassLoader().getResourceAsStream(..)起了作用:

private static final Properties properties;

static {
    Properties fallback = new Properties();
    fallback.put(PROP_KEY, FALLBACK_VALUE);

    properties = new Properties(fallback);

    try {
        try (InputStream stream = MyClass.class.getClassLoader().getResourceAsStream("myProperties.properties")) {
            properties.load(stream);
        }
    } catch (IOException ex) {
        // handle error
    }
}

1

已经有一段时间了,但如果我记得正确,你只需要像这样做:

Properties prop = new Properties();
prop.load(new FileInputStream(filename));

//For each property you need.
blah = prop.getProperty(propertyname);

1

对于静态属性,最好将它们初始化为单例模式,该模式仅在类中加载一次。以下是一个示例:

class Example
{
    public final static String PROPSFILE = "test.properties";

    private static Properties props;

    protected static Properties getProperties()
    {
        if(props == null)
        {
            props = new Properties();
            props.load(new FileInputStream(new File(PROPSFILE));
        }
        return props;
    }

    public static User getUser()
    {
        String username = getProperties().getProperty("username");
        return new User(username);
    }
}

如果您使用相对路径名,您应该确保您的类路径设置正确。

3
那不是单例模式,只是一个静态变量和方法。问题并没有要求公开访问这些属性,而是需要从一个属性文件初始化静态成员。 - Robin
个人而言,我不太喜欢静态初始化,因为它在我正在处理的项目中引起了一些麻烦。我建议尽可能使用静态工厂方法(我已更新示例)。但是,确实,那并不是问题的实质。 - Daff

0

我同意 @Daff 的观点,也许最好使用单例模式...这是我在类似需求的项目中所使用的,也许可以帮到你:

该类的客户端可以像这样使用它:

ConfigsLoader configsLoader = ConfigsLoader.getInstance("etc/configs.xml");

System.out.format("source dir %s %n", configsLoader.getSourceDir());

然后是类:

public class ConfigsLoader {

private String sourceDir;
private String destination;
private String activeMqUrl;

private static Logger log = Logger.getLogger(ConfigsLoader.class.getName());

private static ConfigsLoader instance = null;

private ConfigsLoader(String configFileName) {
    log.info("loading configs");
    Properties configs = new Properties();
    try {
        configs.loadFromXML(new FileInputStream(configFileName));

        sourceDir = configs.getProperty("source.dir");
        destination = configs.getProperty("destination");
        activeMqUrl = configs.getProperty("activemqconnectionurl");
        configs.setProperty("lastLoaded", new SimpleDateFormat("yyyy-M-d HH:mm").format(new Date()));
        configs.storeToXML(new FileOutputStream(configFileName), "saving last modified dates");

    } catch (InvalidPropertiesFormatException e) {
        log.log(Level.SEVERE,"Error occured loading the properties file" ,e);
    } catch (FileNotFoundException e) {
        log.log(Level.SEVERE,"Error occured loading the properties file" ,e);
    } catch (IOException e) {
        log.log(Level.SEVERE,"Error occured loading the properties file" ,e);
    }
}

public static ConfigsLoader getInstance(String configFileName) {
    if(instance ==null) {
        instance = new ConfigsLoader(configFileName);
    }

    return instance;
}

public String getSourceDir() {
    return sourceDir;
}

public void setSourceDir(String sourceDir) {
    this.sourceDir = sourceDir;
}

public String getDestination() {
    return destination;
}

public void setDestination(String destination) {
    this.destination = destination;
}

public String getActiveMqUrl() {
    return activeMqUrl;
}

public void setActiveMqUrl(String activeMqUrl) {
    this.activeMqUrl = activeMqUrl;
}

}


0
最终,我使用与编写静态代码块的类相关联的getResourceAsStream()函数来完成此操作。
//associate Property and ImputStream imports
public class A {
    static Properties p;
    static {
      p = new Properties();
      try {
          InputStream in = A.class.getResourceAsStream("filename.properties");
          p.load(in);
      } catch (FileNotFoundException e) {
        System.out.println("FileNotFoundException");
        e.printStackTrace();
      } catch (IOException e) {
        System.out.println("IOException");
        e.printStackTrace();
      }
    }
    .
    .
    .
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接