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

类加载器
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);
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值