Classloader 结构
类加载器从虚拟机方面看只存在两类类加载器
- 启动类加载器
- 扩展类加载器
从开发人员来开类加载器包括:
- 启动类加载器
- 扩展类加载器
- 应用程序类加载器
- 自定义类加载器
1.启动类加载器,用于加载Java API,加载<JAVA_HOME>\lib目录下的类库。
2.扩展类加载类,由sun.misc.Launcher$ExtClassLoader实现,用于加载<JAVA_HOME>\lib\ext目录下或者被java.ext.dirs系统变量指定路径下的类库。
3.应用程序类加载器,也成为系统类加载器,由sun.misc.Launcher$AppClassLoader实现,用于加载用户类路径(ClassPath)上所指定的类库。
4.自定义类加载器,继承系统类加载器,实现用户自定义加载逻辑。
各个类加载器之间是组合关系,并非继承关系。
双亲委派模型
当一个类加载器收到类加载的请求,它将这个加载请求委派给父类加载器进行加载,每一层加载器都是如此,最终,==所有的请求都会传送到启动类加载器中==。只有当父类加载器自己无法完成加载请求时,子类加载器才会尝试自己加载。
双亲委派模型可以确保安全性,可以保证所有的Java类库都是由启动类加载器加载。
如用户编写的java.lang.Object,加载请求传递到启动类加载器,启动类加载的是系统中的Object对象,而用户编写的java.lang.Object不会被加载。如用户编写的java.lang.virus类,加载请求传递到启动类加载器,启动类加载器发现virus类并不是核心Java类,无法进行加载,将会由具体的子类加载器进行加载,而经过不同加载器进行加载的类是无法访问彼此的。由不同加载器加载的类处于不同的运行时包。所有的访问权限都是基于同一个运行时包而言的。
当一个类加载器收到类加载的请求,它将这个加载请求委派给父类加载器进行加载,每一层加载器都是如此,最终,所有的请求都会传送到启动类加载器中。只有当父类加载器自己无法完成加载请求时,子类加载器才会尝试自己加载。
为什么要使用这种双亲委托模式呢?
可以避免重复加载,当父亲已经加载了该类的时候,就没有必要子ClassLoader再加载一次。
考虑到安全因素,我们试想一下,如果不使用这种委托模式,那我们就可以随时使用自定义的String来动态替代java核心api中定义类型,这样会存在非常大的安全隐患,而双亲委托的方式,就可以避免这种情况,因为String已经在启动时被加载,所以用户自定义类是无法加载一个自定义的ClassLoader。双亲委派机制能在很大程度上防止内存中出现多个相同的字节码文件。
在Java沙箱中,类装载体系结构是第一道防线,可以防止而已代码去干扰正常程序代码,这是通过由不同的类装载器装入的类提供不同的命名空间来实现的。
类加载器的作用:
1.它防止恶意代码区干涉善意的代码
2.它守护了被信任的类库边界
3.它将代码归入保护域,该域确定了代码可以进行哪些操作。
沙箱机制是由基于双亲委派机制上采取的一种JVM的自我保护机制,假设你要写一个java.lang.String 的类,由于双亲委派机制的原理,此请求会先交给Bootstrap试图进行加载,但是Bootstrap在加载类时首先通过包和类名查找rt.jar中有没有该类,有则优先加载rt.jar包中的类,因此就保证了java的运行机制不会被破坏。
网友评论