类加载器
1、类加载器
把.class文件加载到JVM的方法区中,变成一个Class对象
2、得到类加载器
Class#getClassLoader()
3、类加载器的分类
都是片警。
引导:类库rt.jar
扩展:扩展jar包
系统:应用下的class,包含开发人员写的类,和第三方的jar包。classpath下的类
系统类加载器的上层领导:扩展
扩展类加载器的上传领导:引导
引导没上层,是BOSS
4、类加载器的委托机制
代码中出现了这么一行:new A();
系统发现了自己加载的类,其中包含了new A();说明需要系统去加载A类
系统会给自己的领导打电话,让扩展去自己的地盘去加载A类
扩展会给自己的领导打电话,让引导去自己的地盘去加载A类
引导自己会去rt.jar中寻找A类
如果找到了,那么加载。然会返回A对应的Class对象给扩展,扩展也会把这个Class返回给系统,完成
如果没找到:
引导给扩展返回一个NULL,扩展会自己去自己的地盘,寻找A类
如果找到了,那么加载,返回A对应的Class对象给系统,结束
如果没找到
扩展返回一个null给系统了,系统去自己的地盘(应用程序下)加载A类
如果找到了,那么加载,然后返回这个Class,结束
如果没找到,抛出异常ClassNotFoundException
5、类的解析过程
class MyApp{
main(){
A a new A();
String s = new String();
}
}
因为谁导致的加载就 谁就负责加载全部
class String{
private Integer i;
}
Thread.getContextClassLoader()获取当前线程的类加载器
代理模式保证了JDK中的类一定是由类加载加载的,这样就不会出现多个版本的类,也是代理模式的好处
3、自定义类加载器
可以通过继承ClassLoader类来完成自定义类加载器,自定义类加载器的目的一般是为了加载网络上的类,
class在网上传输经过加密,需要用自定义的类加载器来加载(自定义的类加载器需要做解密工作)
ClassLoader加载类都是通过loadClass()方法来完成的,loadClass()工作流程
调用findLoadedClass()方法查看该类是否已经被加载过了,如果该类没有加载过,那么这个方法返回null
【在JVM的方法区中查看已加载过的类,即判断当前类是否已被加载过】
判断findLoadedClass()方法返回的是否为null,如果不是null,那么直接返回,可以避免同一个类被加载两次
如果findLoadedClass()返回的是null那么就启动代理模式(委托机制),即调用上级的loadClass(),获取上级的方法是getParent()如果上级还有上级,就一直往上
如果getParent().loadClass()返回的不是null,那么说明上级加载成功了,那么加载结果
如果上级返回的是null,就说明需要自己出手了,这时loadClass()方法会调用本类的findClass()方法来加载类
只需要重写ClassLoader的findClss()方法就可以覆盖代理模式
6、自定义类加载器
继承ClassLoader
重写findClass
类加载器没有继承关系 父类加载器-->上层加载器
类加载器都是引导类加载器加载的。因为都是类库的一部分
引导类加载器是JVM的一部分不需要别人加载。JVM出生时就带引导类加载器过来了。加载完类库就出现扩展和系统类加载器 然后就加载其他的
7、Tomcat的类加载器
Tomcat提供了两种类加载器
服务器类加载器:${CATALINA_HOME}\lib,tomcat服务器类加载器,负责加载这个下面的类
应用类加载器:${CONTEXT_HOME}\WEB-INFO\lib、${CONTEXT_HOME}\WEB-INFO\classes,应用类加载器,负责加载这两个路径下的类。
Tomcat可以使自己项目下的类优先被加载
引导
扩展
系统
特性:
服务器类加载器:先自己动手,然后再去委托
应用类加载器: 先自己动手,然后再去委托【比服务器优先级高,最好还是放在应用类】
public class Demo1 {
@Test
public void fun1(String name) throws ClassNotFoundException{
System.out.println("1");
System.out.println(name);
}
public static String fun2(String name) {
System.out.println(name);
return "a";
}
}
public class FileSystemClassLoader extends ClassLoader {
private String classpath;
public FileSystemClassLoader() {
}
public FileSystemClassLoader(String classpath) {
this.classpath = classpath;
}
@Override
public Class<?> findClass(String name) throws ClassNotFoundException {
try {
byte[] datas = getClassData(name);
if(datas == null){
throw new ClassNotFoundException("类没有找到" + name);
}
return this.defineClass(name, datas, 0,datas.length);
} catch (Exception e) {
e.printStackTrace();
throw new ClassNotFoundException("类找不到:"+name);
}
}
private byte[] getClassData(String name) throws IOException {
name = name.replace(".", "\\") + ".class";
File classFile = new File(classpath,name);
return FileUtils.readFileToByteArray(classFile);
}
}
public class Test01 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
ClassLoader loader = new FileSystemClassLoader("D:\\myeclipsework\\day09_01\\src\\");
Class clazz = loader.loadClass("my.demo1.Demo1");
Method method = clazz.getMethod("fun2", String.class);
String result = (String) method.invoke(null, "abc");
System.out.println(result);
}
}