Java中Class.getResourceAsStream每次调用都会读取文件吗?
问题解答
核心结论
每次调用Configuration.class.getResourceAsStream("MyProperties.properties")都会触发实际的资源读取操作(产生IO开销)。标准Java类加载器(如AppClassLoader)不会自动缓存这类资源内容,每次调用都会返回一个新的输入流,后续properties.load()会从头读取流中数据,等于每次调用方法都重新加载整个properties文件。
优化方案:实现内存缓存
既然频繁调用会重复产生IO开销,最直接的优化是把Properties对象缓存到内存中,仅加载一次。以下是几种常见的可靠实现方式:
1. 静态初始化加载(推荐,简单高效)
利用JVM类加载机制,在类初始化阶段一次性加载properties文件,后续调用直接复用缓存的对象:
public class Configuration { private static final Properties PROPERTIES = new Properties(); private static final Logger logger = Logger.getLogger(Configuration.class.getName()); // 静态初始化块,类加载时仅执行一次 static { try (InputStream is = Configuration.class.getResourceAsStream("MyProperties.properties")) { if (is == null) { logger.log(Level.SEVERE, "MyProperties.properties not found in classpath"); System.exit(1); } PROPERTIES.load(is); } catch (IOException e) { logger.log(Level.SEVERE, e.getMessage(), e); System.exit(1); } } @Override public String getPropertyValue(String property) { String prop = PROPERTIES.getProperty(property); if (prop == null) { logger.log(Level.SEVERE, "Property " + property + " not found"); throw new NullPointerException(); } return prop; } }
2. 懒加载+双重检查锁(适合延迟加载场景)
如果不想在类加载时就加载资源,可以用懒加载方式,第一次调用方法时才完成资源加载:
public class Configuration { private static volatile Properties PROPERTIES; private static final Logger logger = Logger.getLogger(Configuration.class.getName()); @Override public String getPropertyValue(String property) { // 双重检查锁确保线程安全且仅加载一次 if (PROPERTIES == null) { synchronized (Configuration.class) { if (PROPERTIES == null) { PROPERTIES = new Properties(); try (InputStream is = Configuration.class.getResourceAsStream("MyProperties.properties")) { if (is == null) { logger.log(Level.SEVERE, "MyProperties.properties not found in classpath"); System.exit(1); } PROPERTIES.load(is); } catch (IOException e) { logger.log(Level.SEVERE, e.getMessage(), e); System.exit(1); } } } } String prop = PROPERTIES.getProperty(property); if (prop == null) { logger.log(Level.SEVERE, "Property " + property + " not found"); throw new NullPointerException(); } return prop; } }
补充说明
- 静态初始化方式的优势是天然线程安全(JVM保证类加载过程的线程安全),代码更简洁。
- 懒加载方式适合资源体积较大、且存在不被调用可能的场景,但代码复杂度略高。
- 如果业务需要properties文件运行时动态刷新(比如修改文件后立即生效),则需要额外添加定时重新加载逻辑,需根据实际需求权衡复杂度。
内容的提问来源于stack exchange,提问作者kaddy
相关产品推荐
相关产品推荐

