ClassLoader
classloader的最终目标是将我们的class文件变成字节,然后加载进来
BootStrap的classloader是为null,是由C++编写的。
- 加载jre/目录下的核心库
Launcher内部包含ExtClassLoader和AppClassLoader
- ExtClassLoader:加载/jre/lib/ext/目录下的扩展包
- AppClassLoader:加载CLASSPATH路径下的包
- 上述的Launcher类使用两个classloader加载我们永远无法debugger,在我们项目启动好的时候已经完成了加载。
- 这个2个classLoader基本都是继承了URLClassLoader
URLClassLoader
-
该classloader用于把一切资源变成URL(这边URL不是指的我们网址,而是指可以统一资源定位的意思,即通过URL可以找到我们的资源)
-
以/结尾的认为是目录,否则就是JAR文件
-
同时该URL还增加了访问全限
自定义的classloader
- 个人觉得自定义classloader主要是为了修改2个地方
- 1.classloader加载的逻辑,即是否遵循主流的双亲委派模式,还是设置自己的加载模式
- 2.获取class文件二进制流的方式,目前urlClassloader只是提供了目录和jar文件,我们可以增加从网络,本地class文件等等。
classLoader的拾遗
-
每次调用defineClass 传入的必须是一个完整的class文件
-
当我们使用文件的时候她回去这个文件下面寻找com.marshall.Controller.class文件
File file = new File("D:\\controller");
MyClassLoader myClassLoader = new MyClassLoader(new URL[]{file.toURI().toURL()});
Class clazz1 = myClassLoader.loadClass("com.marshall.Controller");
Object o= clazz1.newInstance();
clazz1.getDeclaredMethod("getSay").invoke(o);
System.out.println("");
- 当我们使用Jar包是使用JarFile去获取JAR包然后去com/marshall/Controller.class寻找com.marshall.Controller.class
- 需要注意的是我们一般打包出来的boot类型的目录都是包含
BOOT-INF
,所以我们需要特殊处理。
File file = new File("D:\\springTest-1.0-SNAPSHOT2.jar");
MyClassLoader myClassLoader = new MyClassLoader(new URL[]{file.toURI().toURL()});
JarFile jarFile=new JarFile("D:\\springTest-1.0-SNAPSHOT2.jar");
Class clazz1 = myClassLoader.loadClass("com.marshall.Controller");
-
tomcat 通过解压war得方式得到文件进而可以对Class文件进行处理 对于lib中得jar包也可以处理。具体解压方法可以看ContextConfig的fixDocBase方法,最终调用的是ExpandWar.expand(host, war, pathName);
-
tomcat的解压就是创建一个文件然后把war里面的复制到薪文件中即可
-
loadClass:重写它就无法按照双亲加载模式
-
findClass:留给子类实现,URLClassLoader是从ClassPathsURL中获取Resource
-
resolveClass:一般是去进行连接这一步,包含各种验证(字节验证等)
-
defineClass:这个方法JDK 重载了很多主要是为了方便各种形式的入参,但是最终都是获取字节数组然后生成Class
网友评论