您的位置:首页 > 运维架构 > Tomcat

javawebday69(类加载器 自定义 Tomcat类加载器)

2018-03-30 10:14 423 查看
类加载器
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);//通过类名称找到.class文件,把文件加载到一个字节数组中
if(datas == null){//如果返回的字节数组为null,说明没有找到这个类,抛出异常
throw new ClassNotFoundException("类没有找到" + name);
}
//可以在这里对datas进行解密
return this.defineClass(name, datas, 0,datas.length);//可以把字节数组变成Class对象。defineClass()是ClassLoader的方法,作用是把字节数组变成Class对象
} 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);
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: