错误重现
当我们在项目中自定义JdbcUtils时
public class JdbcUtils {
private static DataSource dataSource = null;
static{
try {
Properties properties = new Properties();
System.out.println(properties);
InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");
properties.load(is);
dataSource = DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection(){
try {
return dataSource.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
public static void main(String[] args) {
}
public static void close(Connection conn){
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
或者使用德鲁伊连接池时
private static DataSource source;
static {
try {
Properties pros=new Properties();
InputStream in=ClassLoader.getSystemClassLoader().getResourceAsStream("db.properties");
pros.load(in);
source= DruidDataSourceFactory.createDataSource(pros);
}
自定义的ClassLoader.getSystemClassLoader().getResourceAsStream(“db.properties”);这个方法在不涉及 Tomcat 服务器时,在本地测试没有问题,可以连接数据库,但启动 Tomcat测试就报错。
报错异常:
java.lang.NullPointerException
at java.util.Properties$LineReader.readLine(Properties.java:434)
at java.util.Properties.load0(Properties.java:353)
at java.util.Properties.load(Properties.java:341)
at com.atguigu.utils.JdbcUtils.<clinit>(JdbcUtils.java:24)
发现在获取properties文件处也就是下方代码处出现空指针异常
InputStream in=ClassLoader.getSystemClassLoader().getResourceAsStream("db.properties");
有两种解决方法:
第一种方法:使用自定义类的加载器替换系统类加载器,即把上方代码替换成
InputStream is =
JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
第二种方法:更改掉加载配置文件的方式
将此处的 jdbc.properties 文件放置在 idea 的 module 一级目录下,然后在上述代码处使用如下代码代替:
FileInputStream is =
new FileInputStream(new File("jdbc.properties"));
即可
原因
ClassLoader.getSystemResourceAsStream使用系统类加载(ClassLoader.getSystemClassLoader)来搜索资源。
this.getClass().getClassLoader().getResourceAsStream()
使用为“this”对象加载类的相同ClassLoader。该 ClassLoader 可能是系统 ClassLoader的子级,因此可以访问系统 ClassLoader 没有的资源。但由于它是 System ClassLoader的子类,它也会请求其父级(System)帮助它查找资源。因此,使用此方法将允许您在该 ClassLoader 和 SystemClassLoader 中找到内容。 搜索顺序在 ClassLoader.getResource 的 javadoc中定义(首先是父级,然后是子级)。
例如,假设您正在从 Servlet 运行一些代码。SystemClassLoader 包含您在启动 Web Server 时放入 CLASSPATH 中的任何内容,但 servlet 类可能由服务器为处理 WebApp 的WEB-INF/lib 和 WEB-INF/classes 目录而创建的另一个ClassLoader 加载。使用该 WebApp的ClassLoader 可以访问这些目录中的内容,但不会在 CLASSPATH 中 ,因此 System ClassLoader不知道它们。因此,如果您想从静态方法中获取属性,最好使用:SomeClass.class.getClassLoader().getResourceAsStream(“XX.properties”));