Prólogo
java
Cuando contacté por primera vez , estaba confundido acerca de la File
ruta relativa de una cosa , qué directorio usar como referencia.
Con el desarrollo del modelo io, java de 1,7 nio
utilización Path
, Paths
y Files
así sucesivamente para facilitar io operación.
ClassLoader
Usado para obtener class 文件
el io, también podemos usarlo para obtener el archivo io, de modo que podamos leer el contenido del archivo.
Contenido del diseño de este artículo.
- File, ZipFile, JarFile leen la ruta relativa y el contenido absoluto del archivo de ruta.
- ¿Cómo surgió System.getProperty ("user.dir")?
- Rutas, Ruta, Archivos leen el contenido del archivo.
- El cargador de clases obtiene el contenido del archivo, Class.getResourceAsStream y ClassLoader.getResourceAsStream.
- Presente el modelo de delegación principal del cargador de clases y encuentre la lógica de carga correspondiente en el código.
El código <font color = red> se basa en Mac 10.15.4
JDK 1.8. </ font>
Obtener contenido de archivo basado en archivo
Obtener el contenido de la ruta absoluta es relativamente simple, obtenga directamente el archivo io y luego use la clase de herramienta para leer el contenido del archivo.
Obtener el contenido absoluto del archivo de ruta
final File file = new File("/Users/zhangpanqin/github/fly-java/demo.txt");
final byte[] bytes = cn.hutool.core.io.FileUtil.readBytes(file); System.out.println(new String(bytes, StandardCharsets.UTF_8));
Obtener el contenido de JarFile
JarFile
La herencia se ZipFile
utiliza para obtener el contenido del paquete jar. Por ejemplo, quiero obtener el contenido de un archivo en un jar.
final File file = new File("/Users/zhangpanqin/github/fly-java/src/main/resources/fastjson-1.2.68.jar");
final JarFile jarFile = new JarFile(file); final JarEntry jarEntry = jarFile.getJarEntry("META-INF/LICENSE.txt"); final InputStream inputStream = jarFile.getInputStream(jarEntry); // 工具类是 hutool System.out.println(IoUtil.read(inputStream, StandardCharsets.UTF_8)); IoUtil.close(inputStream);
Obtener contenido de ruta relativa
File.getAbsolutePath
Mirando el código fuente, puede ver que la ruta relativa está realmente cosida al frente System.getProperty("user.dir")
.
class UnixFileSystem extends FileSystem { public String resolve(File f) { if (isAbsolute(f)) return f.getPath(); return resolve(System.getProperty("user.dir"), f.getPath()); } }
Mientras lo resolvamos System.getProperty("user.dir")
, el problema estará resuelto. La introducción user.dir
en Java System Properties es el directorio de trabajo del usuario.
<font color = red> ¿Cuál es el directorio de trabajo del usuario? Es el directorio donde se ejecuta el comando java. </ font> Ejecutando comandos en ese directorio, usr.dir será asignado como la ruta para ejecutar el comando por la máquina virtual java. /Users/zhangpanqin/github/fly-java/test
Ejecuto el class
archivo compilado en el directorio . -cp
Especifique la ruta de classpath.
nio lee el contenido del archivo
Path
Se puede usar por analogía File
. Entonces Paths
se puede obtener la clase de herramienta Path
, y Files
proporciona una API rica para archivos de operación crud Path
.
Obtener contenido de ruta absoluto
@Test
public void run33() throws IOException { final Path path = Paths.get("/Users/zhangpanqin/github/fly-java/demo.txt"); final byte[] bytes = Files.readAllBytes(path); System.out.println(new String(bytes,StandardCharsets.UTF_8)); }
Obtener contenido de ruta relativa
Paths
Al obtener una ruta relativa, la ruta no se /
inicia. También se puede entender como relativo a la System.getProperty("user.dir")
ruta.
public static void main(String[] args) { System.out.println(System.getProperty("user.dir")); System.out.println(Paths.get("").toAbsolutePath()); }
Obtener contenido del archivo basado en ClassLoader
ClassLoader.getResourceAsStream
// ClassLoader.getResourceAsStream java 1.8 源码
public InputStream getResourceAsStream(String name) { URL url = getResource(name); try { return url != null ? url.openStream() : null; } catch (IOException e) { return null; } }
Puede ver en el código que la lógica principal todavía está concentrada getResource
.
public URL getResource(String name) {
URL url;
if (parent != null) { url = parent.getResource(name); } else { url = getBootstrapResource(name); } if (url == null) { url = findResource(name); } return url; }
La lógica del código anterior es lo que a menudo escuchamos 双亲委派机制
. Deje 父类加载
ir para cargar los recursos primero, y luego encuéntrelo usted mismo si no puede encontrarlo. 类加载器单独讲
.
El cargador de clases lee y lee el recurso, y primero busca desde la ruta de la que es responsable. Por ejemplo, el cargador de clases de la aplicación es sun.misc.Launcher.AppClassLoader#AppClassLoader
responsable de classpath
encontrar recursos. ¿Cuáles son las ventajas File
y Path
desventajas de los recursos de lectura del cargador de clases ? Por ejemplo, cuando quiero obtener uno jar
de los recursos, es más problemático usar la ruta. El ClassLoader se puede encontrar desde la ruta responsable, o se puede encontrar en el paquete jar.
final URL resource = Test2.class.getClassLoader().getResource("com/alibaba/fastjson/JSONArray.class"); System.out.println(resource);
El resultado de impresión anterior
jar:file:/Users/zhangpanqin/.m2/repository/com/alibaba/fastjson/1.2.62/fastjson-1.2.62.jar!/com/alibaba/fastjson/JSONArray.class
También podemos encontrar un camino inputstream
@Test
public void run222(){ final InputStream resourceAsStream = Test2.class.getClassLoader().getResourceAsStream("META-INF/maven/com.alibaba/fastjson/pom.properties"); System.out.println(IoUtil.read(resourceAsStream, StandardCharsets.UTF_8)); }
El resultado anterior es:
#Generated by Maven
#Mon Oct 07 22:09:36 CST 2019
version=1.2.62
groupId=com.alibaba
artifactId=fastjson
Class.getResourceAsStream
Class.getResourceAsStream
El ClassLoader
recurso de carga se llama realmente , pero agregará la ruta a la ruta relativa al paquete donde se encuentra la clase actual.
Por ejemplo
// com.fly.study.java.classloader.Test2
@Test
public void run555(){ System.out.println(Test2.class.getResource("name")); }
Los recursos reales encontrados son com.fly.study.java.classloader.name
. Relativo al recurso del paquete donde se encuentra la clase actual.
Cargador de clase
A menudo escuchamos sobre cargadores de clases 双亲委派模型
.
¿Dónde puedo ver estas clases cargadas?
启动类加载器
No podemos ver el código fuente si no está implementado en el código Java.
sun.misc.Launcher clase tiene que sabemos 扩展类加载器 sun.misc.Launcher.ExtClassLoader
y 应用类加载器 sun.misc.Launcher.AppClassLoader
.
java.lang.ClassLoader#getSystemClassLoader
Si observa el código, se devuelve el cargador de clase de aplicación real.
public static ClassLoader getSystemClassLoader() { initSystemClassLoader(); if (scl == null) { return null; } SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkClassLoaderPermission(scl, Reflection.getCallerClass()); } return scl; } private static synchronized void initSystemClassLoader() { if (!sclSet) { sun.misc.Launcher l = sun.misc.Launcher.getLauncher(); if (l != null) { Throwable oops = null; scl = l.getClassLoader(); } } }
La ejecución de la prueba de código devuelve el cargador de clases de la aplicación.
// sun.misc.Launcher$AppClassLoader@18b4aac2
@Test
public void run66(){
System.out.println(ClassLoader.getSystemClassLoader());
}
Estos cargadores de tres clases son responsables de la carga de clases bajo diferentes rutas.
Introducción al cargador de clases de arranque
启动类加载器 BootClassLoader
Responsable System.getProperty("sun.boot.class.path")
de la carga de clases. Esa es la siguiente categoría.
${JAVA_HOME}/jre/lib/*.jar
Y ${JAVA_HOME}/jre/classes
carga de clase.
/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/resources.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/rt.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/sunrsasign.jar /Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/jsse.jar /Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/jce.jar /Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/charsets.jar /Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/jfr.jar /Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/classes
@Test
public void run77() { final URLClassPath bootstrapClassPath = Launcher.getBootstrapClassPath(); final URL[] urLs = bootstrapClassPath.getURLs(); Stream.of(urLs).forEach(item->{ System.out.println(item.getFile()); }); }
Cargador de clase de extensión
扩展类加载器 sun.misc.Launcher.ExtClassLoader
Es la System.getProperty("java.ext.dirs")
clase de carga .
@Test
public void run99() { final String property = System.getProperty("java.ext.dirs"); final String[] split = property.split(":"); Stream.of(split).forEach(item -> { System.out.println(item); }); }
/Users/zhangpanqin/Library/Java/Extensions
/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/ext
/Library/Java/Extensions
/Network/Library/Java/Extensions
/System/Library/Java/Extensions
/usr/lib/java
Cargador de clase de aplicación
应用类加载器 sun.misc.Launcher.AppClassLoader
Cargando System.getProperty("java.class.path");
# -cp 指定 classpath 路径,多个路径可以使用 : 分开(linux 下为 :,window 下为 ;),
java -cp /Users/zhangpanqin/github/fly-java/target/classes com.fly.study.java.classloader.Test2