java.net.URLClassLoader#findClass解析

​jdk1.8 中 AppClassLoader 与 ExtClassLoader 都继承于 URLClassLoader。
在这里插入图片描述
AppClassLoader 与 ExtClassLoader 没有重写 findClass 方法,URLClassLoader重写了 findClass 方法。
故 findClass 都指向 URLClassLoader。

protected Class<?> findClass(final String name)                                      
    throws ClassNotFoundException                                                    
{                                                                                    
    final Class<?> result;                                                           
    try {                                                                            
        result = AccessController.doPrivileged(                                      
            new PrivilegedExceptionAction<Class<?>>() {                              
                public Class<?> run() throws ClassNotFoundException {                
                    String path = name.replace('.', '/').concat(".class");           
                    Resource res = ucp.getResource(path, false);                     
                    if (res != null) {                                               
                        try {                                                        
                            return defineClass(name, res);                           
                        } catch (IOException e) {                                    
                            throw new ClassNotFoundException(name, e);               
                        }                                                            
                    } else {                                                         
                        return null;                                                 
                    }                                                                
                }                                                                    
            }, acc);                                                                 
    } catch (java.security.PrivilegedActionException pae) {                          
        throw (ClassNotFoundException) pae.getException();                           
    }                                                                                
    if (result == null) {                                                            
        throw new ClassNotFoundException(name);                                      
    }                                                                                
    return result;                                                                   
}                                                                                    
Resource res = ucp.getResource(path, false); 
private final URLClassPath ucp;

http://hg.openjdk.java.net/jdk8/jdk8/jdk/raw-file/687fd7c7986d/src/share/classes/sun/misc/URLClassPath.java

public Resource getResource(String name, boolean check) {
        if (DEBUG) {
            System.err.println("URLClassPath.getResource(\"" + name + "\")");
        }

        Loader loader;
        for (int i = 0; (loader = getLoader(i)) != null; i++) {
            Resource res = loader.getResource(name, check);
            if (res != null) {
                return res;
            }
        }
        return null;
    }
private static class Loader implements Closeable {
        private final URL base;
        private JarFile jarfile;

        Loader(URL var1) { this.base = var1; }
        URL getBaseURL() { return this.base; }
      	// 子类实现
        URL findResource(String var1, boolean var2) {}
        Resource getResource(final String var1, boolean var2) {}
      	// .........
        Resource getResource(String var1) { return this.getResource(var1, true); }
        public void close() throws IOException {
            if (this.jarfile != null) {
                this.jarfile.close();
            }
        }
        URL[] getClassPath() throws IOException {
            return null;
        }
    }

Loader 的实现有两个:
private static class FileLoader extends URLClassPath.Loader {}
static class JarLoader extends URLClassPath.Loader {}

sun.misc.URLClassPath.JarLoader#getResource(java.lang.String, boolean)

@Override                                                
Resource getResource(final String name, boolean check) {
  	// 
    if (metaIndex != null) {                             
        if (!metaIndex.mayContain(name)) {               
            return null;                                 
        }                                                
    }                                                    
                                                         
    try {
      	// 确保 jar 存在
        ensureOpen();                                    
    } catch (IOException e) {                            
        throw new InternalError(e);                      
    }                                                    
    final JarEntry entry = jar.getJarEntry(name);        
    if (entry != null) {                                 
        return checkResource(name, check, entry);        
    }                                                    
                                                         
    if (index == null) {                                 
        return null;                                     
    }                                                    
                                                         
    HashSet<String> visited = new HashSet<String>();     
    return getResource(name, check, visited);            
}                                                                                                               

metaIndex 需要调用 sun.misc.MetaIndex#registerDirectory 注册。
JVM 默认注册的如下:
在这里插入图片描述
JarFile JarEntry的使用:

@Test                                                                                                                        
public void test1() {                                                                                                        
    JarFile jar = null;                                                                                                      
    InputStream inputStream = null;                                                                                          
    try {                                                                                                                    
        jar = new JarFile("/Users/N3verL4nd/.m2/repository/com/sankuai/mms/mms-boot-jetty9/1.3.5/mms-boot-jetty9-1.3.5.jar");
        JarEntry entry = jar.getJarEntry("jetty9.xml");                                                                      
        inputStream = jar.getInputStream(entry);                                                                             
        StreamUtils.copy(inputStream, System.out);                                                                           
    } catch (IOException e) {                                                                                                
        e.printStackTrace();                                                                                                 
    } finally {                                                                                                              
        if (inputStream != null) {                                                                                           
            try {                                                                                                            
                inputStream.close();                                                                                         
            } catch (IOException e) {                                                                                        
                e.printStackTrace();                                                                                         
            }                                                                                                                
        }                                                                                                                    
        if (jar != null) {                                                                                                   
            try {                                                                                                            
                jar.close();                                                                                                 
            } catch (IOException e) {                                                                                        
                e.printStackTrace();                                                                                         
            }                                                                                                                
        }                                                                                                                    
    }                                                                                                                        
}                                                                                                                                                                                                                                                    

sun.misc.URLClassPath.FileLoader#getResource 就是文件夹和文件的拼接。

在这里插入图片描述
可以看到查找都是相对路径。

参考

https://mp.weixin.qq.com/s/U16h0njbAk6aMC27S_XDZA

发布了778 篇原创文章 · 获赞 323 · 访问量 209万+

猜你喜欢

转载自blog.csdn.net/lgh1992314/article/details/104460728