关于类加载器的理解以及双亲委派模型

来源:互联网 发布:ubuntu iptables启用 编辑:程序博客网 时间:2024/05/01 10:07

我们知道,java字节码文件需要jvm进行加载到内存中才能执行,那么这个是怎么加载机制是怎样的呢?

加载阶段需要完成的事情:

1.通过一个类的全限定名获取定义此类的二进制字节流

2.将这个字节流代表的静态存储结构转化为方法区的运行时数据结构

3,在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口


而完成加载阶段,靠的就是类加载器完成。

顾名思义,类加载器(class loader)用来加载 Java 类到 Java 虚拟机中。一般来说,Java 虚拟机使用 Java 类的方式如下:Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件)。类加载器负责读取 Java 字节代码,并转换成 java.lang.Class类的一个实例。每个这样的实例用来表示一个 Java 类。通过此实例的 newInstance()方法就可以创建出该类的一个对象。实际的情况可能更加复杂,比如 Java 字节代码可能是通过工具动态生成的,也可能是通过网络下载的。

双亲委派模型:

java会提供三种类加载器:

1 启动类加载器

2.扩展类加载器

3.应用程序类加载器

当然,用户可以自己定义自己的类加载器

双亲委派模型的工作过程:如果一个类加载器收到了类加载的请求,首先不会自己加载,而是把这个请求委派给父类加载器去完成,最终所有的请求都会传送到顶层的启动类加载器中,只有当父类无法完成这个加载请求(搜索范围内没有找到所需的类),子加载器才回尝试自己去加载。

那么我们什么时候需要用到自己定义类加载器呢?

  1. 加密:众所周知,java代码很容易被反编译,如果你需要把自己的代码进行加密,可以先将编译后的代码用某种加密算法加密,然后实现自己的类加载器,负责将这段加密后的代码还原。

  2. 从非标准的来源加载代码:例如你的部分字节码是放在数据库中甚至是网络上的,就可以自己写个类加载器,从指定的来源加载类。

  3. 动态创建:为了性能等等可能的理由,根据实际情况动态创建代码并执行。


  虽然在绝大多数情况下系统默认提供的类加载器实现已经可以满足需求。但是在某些情况下,您还是需要为应用开发出自己的类加载器。比如您的应用通过网络来传输 Java 类的字节代码,为了保证安全性,这些字节码经过了加密处理。这个时候您就需要自己的类加载器来从某个网络地址上读取加密后的字节代码,接着进行解密和验证,最后定义出要在 Java 虚拟机中运行的类来。

接下来一个很重要的问题,因为双亲委派机制的存在,如何使自己定义的类加载器去加载特定的类呢?

方法1:改变class文件的路径,因为系统的类加载器只会加载特定目录下的文件,如果我们将能找到路径的文件换个目录,那么当前类加载器就不能找到类了,就会抛异常,由子类加载

方法2:重写loadClass方法,定义自己的加载顺序(默认的加载顺序是先加载父亲的)

</pre><pre code_snippet_id="1662646" snippet_file_name="blog_20160426_1_2592827" name="code" class="java"> Class c=findLoadedClass(name);//检查请求的类是否被加载过if(c==null)//没被加载{try{c=findClass(name);//先自己加载}catch(ClassNotFoundException e){}}if(c==null)//自己没法加载,调用父类{try{if(parent!=null)c=parent.loadClass(name,false);}catch(ClassNotFoundException e){}}
</pre><pre code_snippet_id="1662646" snippet_file_name="blog_20160426_1_2592827" name="code" class="java">      return c;














0 0
原创粉丝点击