Java Servlet项目部署Tomcat后加载properties配置报文件不存在(IDE运行正常)
问题核心成因
这个问题是Java Web非框架开发场景下的经典类加载冲突问题,两个因素叠加导致Eclipse本地运行正常、Tomcat部署后读取配置失败:
- 资源路径写法和类加载器的匹配规则不兼容
当前代码用Thread.currentThread().getContextClassLoader().getResourceAsStream()加载资源,这个方法的入参要求是类路径下的相对路径,绝对不能以斜杠/开头。但代码里定义的常量FILE_PROPERTIES = "/com/DAO/dbInfos.properties"带了前导斜杠:- Eclipse本地运行时的类加载逻辑有兼容特性,会自动忽略路径开头的斜杠,所以本地能正常读到文件;
- Tomcat的Webapp类加载器严格按照Java规范实现,带前导斜杠的路径会被判定为无效资源,直接返回null,最终触发"properties file not exist EXCEPTION"异常。
容易混淆的规则:如果用类对象的
XXX.class.getResourceAsStream()方法加载资源,带前导斜杠的路径表示从类路径根目录开始查找,是合法的;但只要是用ClassLoader本身的方法加载,带前导斜杠就是非法路径,必然找不到资源。 - Eclipse部署非Maven项目时,非Java文件不会自动拷贝到类路径输出目录
没有Maven、Spring这类框架的资源管理机制时,Eclipse默认只把src目录下的.java文件编译后输出到Tomcat对应的WEB-INF/classes目录,对同目录下的.properties这类资源文件,如果没开启资源导出开关,是不会自动拷贝过去的。本地运行时Eclipse是直接从src源码目录读文件,所以不会出问题,但部署到Tomcat后,WEB-INF/classes下根本不存在这个properties文件,类加载器自然找不到。
可落地的解决步骤
- 第一步:修正资源路径写法
把原来带前导斜杠的常量值删掉开头的斜杠,改成:private final static String FILE_PROPERTIES = "com/DAO/dbInfos.properties"; - 第二步:检查Eclipse的资源导出配置
右键项目 -> 选择Build Path->Configure Build Path-> 切换到Source标签页:
找到项目的src源目录,展开配置项,确认:- 没有把*.properties文件加入排除列表
- 源目录的输出文件夹是
WEB-INF/classes,且勾选了导出输出文件夹的选项
部署完成后可以直接去Tomcat的webapps目录下,找到项目对应的WEB-INF/classes/com/DAO/路径,确认里面真的存在dbInfos.properties文件——如果不存在,说明导出配置没生效,手动把文件拷过去也可以临时验证。
- 第三步(推荐的最优写法):改用无歧义的同包读取方式
因为dbInfos.properties和DAOFactory类就在同一个包com/DAO下,完全可以去掉全路径,用类对象的方法直接读取,彻底避开前导斜杠、类加载器规则的歧义:
把原来的类加载读取代码替换成:
这种写法和当前类绑定在同一个包路径下,不管是本地IDE运行还是Tomcat部署,都能准确找到同目录下的配置文件,不需要写复杂的全路径。// 原有加载逻辑 // ClassLoader loader = Thread.currentThread().getContextClassLoader(); // InputStream input = loader.getResourceAsStream(FILE_PROPERTIES); // 替换为同包读取逻辑 InputStream input = DAOFactory.class.getResourceAsStream("dbInfos.properties");
避坑提醒
- 不要把dbInfos.properties放到WebContent根目录或者WEB-INF的非classes路径下,类加载器没有权限读取这些web资源路径下的文件
- 不要用硬编码绝对路径的FileInputStream读取配置,换Tomcat部署位置、换服务器环境就会直接失效
- 修改配置文件时要改src目录下的源文件,不要直接改Tomcat部署目录下的文件,重新部署会被覆盖
内容的提问来源于stack exchange,提问作者user X
相关产品推荐
相关产品推荐

