【第6章】深入分析ClassLoader工作机制

1.ClassLoader类结构分析

1.1.ClassLoader的几个方法

1.1.1.defineClass(byte[],int,int) //将byte字节流解析成JVM能够识别的Class对象

1.1.2.findClass(String) //实现类的加载规则,从而取得加载类的字节码

1.1.3.loadClass(String) //获取类的Class对象,例如:this.getClass().getClassLoader().getloadClass("x.class")

1.1.4.resolveClass(Class<?>)

2.ClassLoader的等级加载机制

2.1.上级委托接待机制

2.2.JVM平台提供三层ClassLoader,分为两种类型

2.2.1.Bootsharp ClassLoader:加载JVM自身工作需要的类

2.2.2.ExtClassLoader:此类加载器只是JVM自身的一部分,服务特定目标在System.getProperty("java.net.dirs")

2.2.3.AppClassLoader:加载某个路径下的类,System.getProperty("java.class.path")

2.3.自己的类加载器根据getSystemClassLoader()方法获取的是AppClassLoader类加载器

2.4.JVM加载class文件到内存有两种方式

2.4.1.隐式加载:通过JVM自动加载需要的类到内存,例如引用某个类,当JVM解析的时候,没有发现此类在内存,那么就会自动加载到内存

2.4.2.显示加载:通过代码调用,例如this.getClass().getClassLoader().getloadClass()

3.如何加载class文件

3.1.找到.class文件并把这个文件包含的字节码加载到内存中

3.1.1.加载字节码到内存

3.1.1.1.在URLClassoLoader()中通过一个URLClassPath类帮助取得要加载的class文件字节流

3.1.1.2.读取它的byte字节流,通过调用defineClass()方法来创建类对象

3.2.验证与解析

3.2.1.字节码验证:保证格式正确,行为正确

3.2.2.类准备:在这个阶段准备代表每个类中定义的字段、方法和实现接口所必需的数据结构

3.2.3.解析:在这个阶段类装入器装入类所引用的其他所有类.可以用许多方式引用类,如超类、接口、字段、方法签名、方法中使用的本地变量

3.3.初始化Class对象:在类中包含的静态初始化器都被执行,在这一阶段末尾静态字段被初始化为默认值

4.常见加载类的错误分析

4.1.ClassNotFoundException(文件不存在)

4.1.1.显示加载一个类的方式

4.1.1.1.通过类Class中的forName()方法

4.1.1.2.通过类ClassLoader中的loadClass()方法

4.1.1.3.通过类ClassLoader中的findSystemClass()方法

4.2.NoClassDefFoundError(找不到类)

4.3.UnsatisfiedLinkError(lib删除)

4.4.ClassCastExceptio(强制类型转换错误)

4.5.ExceptionlnlnitializerError

5.常用的ClassLoader分析

5.1.StandardClassLoader是在Bootsharp类的ininClassLoaders方法中创建的,调用ClassLoaderFactory的createClassLoader()方法

5.2.StandardClassLoader是代理类

5.3.Tomcat容器的加载ClassLoader:若ClassPath没有设置,则是StandardClassLoader,否则是AppClassLoader

5.4.servlet类的加载是显示加载方法

5.5.servlet的ClassLoader是WebAppClassLoader

5.6.所有的servlet都是InstanceManager实例化的

5.7.JVM的类加载规范是委托式加载

5.8.如果web应用直接放到webapp目录下,那么tomcat就通过StandardClassLoader直接加载

6.如何实现自己的ClassLoader

6.1.自定义ClassLoader应用的情况

6.1.1.在自定义路径下查找自定义的class类文件

6.1.2.对自己需要加载的类做特殊处理,比如将类经过加密后再传输,在加载到JVM之前需要对类的字节码再解密 //保证网络输出类的安全性

6.1.3.可以定义类的实现机制,检查类是否修改,如果修改,则重新加载这个类,从而实现热部署

7.实现类的热部署

7.1.判断JVM表示一个类是否是同一个类的两个条件

7.1.1.看这个类的完整类名是否一样(包括所在的包)

7.1.2.加载这个类的ClassLoader是否是同一个 //同一个ClassLoader类的不同实例是实现热部署的关键

8.Java应不应该动态加载类

8.1.根据JVM的工作机制,Java不可以动态加载类

8.2.JVM的设计原则

8.2.1.对象的引用关系只有对象的创建者持有和使用

8.2.2.JVM不可以干预对象的引用关系

8.2.3.JVM不知道对象是怎么被使用的,因为JVM并不知道对象的运行时类型而只知道编译时类型

8.2.4.不能动态加载类,是因为对象的状态被保存了,并且被其它对象引用了.解决办法就是创建对象使用后就被释放掉,例如JSP

Remark:

1.ClassLoader是类加载器

2.ClassLoader作用

2.1.将Class加载到JVM

2.2.审查每个类应该由谁加载

2.3.将Class字节码重新解析成JVM统一要求的对象格式

热部署示例

package com.ninemax.utils.ClassLoader;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.InputStream;

/**
 * Created by AckMan on 2016/8/31.
 */
public class ClassReloader extends ClassLoader {

    private String classPath;

    String classname = "compile.Yufa";

    public ClassReloader(String classPath){

        this.classPath = classPath;
    }

    /**
     * 创建类对象
     * @param name
     * @return
     * @throws ClassNotFoundException
     */
    protected Class<?> findClass(String name)throws ClassNotFoundException{

       byte[] classData = getData(name);

        if(classData == null){
            throw new ClassNotFoundException();
        }else{
            return defineClass(classname,classData,0,classData.length);
        }

    }
    // 构建数据
    private byte[] getData(String className){

        String path = classPath + className;

        try {
            InputStream is = new FileInputStream(path);

            ByteArrayOutputStream stream = new ByteArrayOutputStream();

            byte[] buffer = new byte[2048];

            int num = 0;

            while ((num = is.read(buffer))!=-1){

                stream.write(buffer, 0, num);

            }

            return stream.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    public static void main(String args[]){

        try{
            String path = "F:/Workspaces/IdeaUI_15/darker/target/classes/compile/";

            ClassReloader c = new ClassReloader(path);

            Class r = c.findClass("Yufa.class");

            System.out.println(r.newInstance());

            ClassReloader c2 =  new ClassReloader(path);
            //Class r2 = c.findClass("Yufa.class");
            Class r2 = c2.findClass("Yufa.class");

            System.out.println(r2.newInstance());
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

运行结果

若采用同一个ClassLoader实例,则运行结果

ClassLoader关系图

WebappClassLoader加载机制

 

转载于:https://my.oschina.net/Tsher2015/blog/740585

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值