本章主要描述 MyBatis 资源加载模块中的 ClassLoaderWrapper 类和 Java 加载配置文件的三种方式。
ClassLoaderWrapper
上一章的案例,使用 org.apache.ibatis.io.Resources#getResourceAsStream(java.lang.String) 方法加载 MyBatis 的配置文件。Resources 是一个提供了多个静态方法的工具类,内部封装了 ClassLoaderWrapper 类的静态字段,Resources 提供的方法都是在 ClassLoaderWrapper 对象中实现的。
ClassLoaderWrapper 主要提供了三类方法:classForName() 方法、getResourceAsStream() 方法、getResourceAsURL() 方法,这三个方法都有多个重载。这里以 getResourceAsStream() 方法为例进行介绍。
org.apache.ibatis.io.ClassLoaderWrapper#getResourceAsStream(java.lang.String, java.lang.ClassLoader[]) 方法源码如下:
public InputStream getResourceAsStream(String resource, ClassLoader classLoader) { return getResourceAsStream(resource, getClassLoaders(classLoader)); } // 该方法返回ClassLoader[]数组,该数组指明了类加载器的使用顺序 ClassLoader[] getClassLoaders(ClassLoader classLoader) { return new ClassLoader[]{ classLoader,// 参数指定的类加载器 defaultClassLoader,// 类中指定的默认类加载器 Thread.currentThread().getContextClassLoader(),// 当前线程绑定的类加载器 getClass().getClassLoader(),// 加载当前类所使用的类加载器 systemClassLoader};// 系统类加载器 } InputStream getResourceAsStream(String resource, ClassLoader[] classLoader) { // 遍历ClassLoader数组 for (ClassLoader cl : classLoader) { if (null != cl) { // 调用ClassLoader.getResourceAsStream方法加载指定的资源 InputStream returnValue = cl.getResourceAsStream(resource); // 尝试以“/”开头,再次查找 if (null == returnValue) { returnValue = cl.getResourceAsStream("/" + resource); } if (null != returnValue) { return returnValue; } } } return null; }
getResourceAsStream() 方法本质还是使用 Java 类加载器的方式加载配置文件。
Java 加载配置文件的三种方式
项目结构是普通的 Java 项目,非 Maven 项目。如果是 Maven 项目,配置文件会放在 resources 目录下,打成 jar 文件后,配置文件会存在 classpath 根目录下,所以一般使用类加载器的方式加载配置文件。
以下内容转载自:《Java中加载配置文件的三种方式》
配置文件放置位置如下图所示:
1. 通过文件路径加载
/** * 通过文件路径加载 * * @throws Exception */ public static void loadByFilePath() { InputStream in = null; try { in = new FileInputStream( "E:/project/test/src/com/resource/config.properties"); Properties props = new Properties(); props.load(in); String host = props.getProperty("host"); System.out.println(host); } catch (Exception e) { e.printStackTrace(); } finally { if (in != null) { try { in.close(); } catch (IOException e) { e.printStackTrace(); } } } }
FileInputStream 中的参数是配置文件的真实路径。
2. 通过的 Class 的 getResourceAsStream 进行加载
采用相对路径的方式:
/** * 通过的 Class 的 getResourceAsStream 进行加载,相对路径 */ public static void loadByClassRelativePath() { InputStream in = null; try { in = ResourceLoader.class.getResourceAsStream("config.properties"); Properties props = new Properties(); props.load(in); String host = props.getProperty("host"); System.out.println(host); } catch (Exception e) { e.printStackTrace(); } finally { if (in != null) { try { in.close(); } catch (IOException e) { e.printStackTrace(); } } } }
采用绝对路径的方式:
/** * 通过的 Class 的 getResourceAsStream 进行加载,绝对路径 */ public static void loadByClassAbsolutePath() { InputStream in = null; try { in = ResourceLoader.class.getResourceAsStream("/com/resource/config.properties"); Properties props = new Properties(); props.load(in); String host = props.getProperty("host"); System.out.println(host); } catch (Exception e) { e.printStackTrace(); } finally { if (in != null) { try { in.close(); } catch (IOException e) { e.printStackTrace(); } } } }
3. 通过类加载器的方式进行加载
/** * 通过类加载器的方式进行加载 */ public static void loadByClassLoader() { InputStream in = null; try { // ClassLoader会在classpath所在的根目录下查找文件 // 注意:目录最前面不要加 / in = ResourceLoader.class.getClassLoader().getResourceAsStream("com/resource/config.properties"); Properties props = new Properties(); props.load(in); String host = props.getProperty("host"); System.out.println(host); } catch (Exception e) { e.printStackTrace(); } finally { if (in != null) { try { in.close(); } catch (IOException e) { e.printStackTrace(); } } } }
MyBatis 源码篇