【Java 安全技术探索之路系列:J2SE安全架构】之五:类加载器
2015-06-10 09:39
691 查看
作者:郭嘉
邮箱:allenwells@163.com
博客:http://blog.csdn.net/allenwells
github:https://github.com/AllenWells
【Java 安全技术探索之路系列:J2SE安全架构】之五:类加载器
【Java 安全技术探索之路系列:J2SE安全架构】之六:安全管理工具
类加载器作为命名空间
Java程序中包名的存在是为了消除名字的冲突,而在同一个虚拟机中,可以有两个类,它们的类名和包名都是相同的,类是由它的全名和类加载器来确定的。这些名字相同的类可以被彻底的区分开而没有任何冲突,虚拟机是通过java类的全名和它的类加载器来区分一个java类的。
为什么使用代理模式
所有Java应用都至少引用java.lang.Object类,也就是在运行的时候,java.lang.Object这个类需要被加载到Java虚拟机中,如果这个加载过程由Java自己的类加载器来完成,则在虚拟机中会存在多个版本的java.lang.Object类,而且这些类是不兼容的,代理模式就是为了保证Java核心库的类型安全。
类加载器的树状图如下所示:
类加载器的树状图Visio源文件下载
注意:如果将JAR文件放入jre/lib/ext目录中,并且它的类中有一个类需要调用系统类或者扩展类,那么就会遇到麻烦,扩展类加载器并不使用类路径,在使用扩展目录类解决类文件的冲突之前,要牢记这种情况。
**上下文类加载 .3
.器**
每一个线程都有一个对类加载器的引用,称为上下文类加载器。主线程的上下文类加载器是系统类加载器,当新线程创建时,它的上下文加载器就会被设置成为创建线程的上下文类加载器。因此,如果你不做任何特殊的操作,所有线程的类加载器都会被设置成为系统类加载器。我们也可以通过以下方式为线程设置任何类型的类加载器。
设置类加载器
获取类加载器
FindClass(String className)方法的实现需要做到以下两点:
为来自本地文件系统或其他来源的类加载其字节码。
调用ClassLoader超类的defineClass()方法,向虚拟机提供字节码。
举例:下面写一个文件系统类加载器,该加载器可以加载存储在文件系统上的Java字节码。
注:MyClass表示加载的类
装载:查找并加载类的二进制数据。
链接
验证:确保被加载类的正确性。
准备:为类的静态变量分配内存,并将其初始化为默认值。
解析:把类中的符号引用转换为直接引用。
初始化:为类的静态变量赋予正确的初始值。
创建类的实例。
访问某个类或接口的静态变量,或者对该静态变量赋值。
反射:Class.forName(“com.allenwells.MyBlog”);
初始化父类,初始化父类的子类。
JVM启动时标明的启动类(即文件名和类名相同的那个类),此种情况下才会导致类的初始化,
如果这个类没有被加载和链接,那就先进行加载和链接。
如果这个类存在直接父类,并且这个类还没有初始化(在一个类加载器中,类只能被初始化一次),那就先初始化直接父类(不适用于接口)。
加入类中存在的初始化语句(如static变量和static块),那就先执行这些初始化语句。
加载类:具体流程如下图所示:
类加载流程图Visio源文件下载
邮箱:allenwells@163.com
博客:http://blog.csdn.net/allenwells
github:https://github.com/AllenWells
【Java 安全技术探索之路系列:J2SE安全架构】章节列表
【Java安全技术探索之路系列:J2SE安全架构】之一:J2SE安全架构开篇【Java 安全技术探索之路系列:J2SE安全架构】之五:类加载器
【Java 安全技术探索之路系列:J2SE安全架构】之六:安全管理工具
一 类加载器的作用
1.1 名字空间的隔离(Name Space Separation)
把名字空间隔离以防止有意或无意的名字冲突问题。1.2 包边界保护(Package Boundary Protection)
类加载器拒绝加载不可靠的类到核心Java包中,这些核心包包含可靠的系统类和其他受限包。1.3 访问权限分配(Access Right Assignment)
类加载器有能力把每个被加载的类和一组授权关联起来,授权被描述为java.security.Permission类型对象。1.4 搜索顺序的加强(Search order Enforcement)
类加载机制加强搜索顺序,以防止可靠的类被来自不太可靠的源中的类替换。二 类加载器的分类
类加载器有一种父子关系,除了引导类加载器,每个类都有一个父类加载器,可以通过getParent()方法获得,根据规定,类加载器会为它的父类加载器提供一个机会,以便加载任何给定的类,并且只有父类加载失败时,子类才会去加载给定的类,这种关系也称为代理模式.类加载器作为命名空间
Java程序中包名的存在是为了消除名字的冲突,而在同一个虚拟机中,可以有两个类,它们的类名和包名都是相同的,类是由它的全名和类加载器来确定的。这些名字相同的类可以被彻底的区分开而没有任何冲突,虚拟机是通过java类的全名和它的类加载器来区分一个java类的。
为什么使用代理模式
所有Java应用都至少引用java.lang.Object类,也就是在运行的时候,java.lang.Object这个类需要被加载到Java虚拟机中,如果这个加载过程由Java自己的类加载器来完成,则在虚拟机中会存在多个版本的java.lang.Object类,而且这些类是不兼容的,代理模式就是为了保证Java核心库的类型安全。
类加载器的树状图如下所示:
类加载器的树状图Visio源文件下载
2.1 系统类加载器
2.1.1 引导类加载器
引导类加载器负责加载系统类,通常从JAR文件rt.jar中进行加载,它是虚拟机整体中的一部分,通常是用C语言来实现的,引导类加载器没有对应的ClassLoader对象。2.1.2 扩展类加载器
扩展类加载器用于从jre/lib/ext目录加载标准的扩展,可以将JAR文件放入该路径,这样即使没有任何类路径,扩展类加载器也可以找到其中的各个类。注意:如果将JAR文件放入jre/lib/ext目录中,并且它的类中有一个类需要调用系统类或者扩展类,那么就会遇到麻烦,扩展类加载器并不使用类路径,在使用扩展目录类解决类文件的冲突之前,要牢记这种情况。
2.1.3 系统类加载器
系统加载器根据Java应用的类路径(CLASSPATH)来加载Java类,一般来说Java应用的类都是由它来加载的,可以通过ClassLoader.getSystemclassloader()来获取它。**上下文类加载 .3
.器**
每一个线程都有一个对类加载器的引用,称为上下文类加载器。主线程的上下文类加载器是系统类加载器,当新线程创建时,它的上下文加载器就会被设置成为创建线程的上下文类加载器。因此,如果你不做任何特殊的操作,所有线程的类加载器都会被设置成为系统类加载器。我们也可以通过以下方式为线程设置任何类型的类加载器。
设置类加载器
Thread thread = Thread.currentThread(); thread.setContextClassLoader(loader);
获取类加载器
Thread thread = Thread.currentThread(); ClassLoader loader = thread.getContextClassLoader(); Class class = loader.loadClass(className);
2.2 自定义类加载器
自定义类加载器用来实现某些特殊目的,比如类加密或类检查等。要编写自己的类加载器,只需要继承ClassLoader类,并实现其中的FindClass(String className)方法即可。FindClass(String className)方法的实现需要做到以下两点:
为来自本地文件系统或其他来源的类加载其字节码。
调用ClassLoader超类的defineClass()方法,向虚拟机提供字节码。
举例:下面写一个文件系统类加载器,该加载器可以加载存储在文件系统上的Java字节码。
public class FileSystemClassLoader extends ClassLoader { private String rootDir; public FileSystemClassLoader(String rootDir) { this.rootDir = rootDir; } protected Class<?> findClass(String name) throws ClassNotFoundException { byte[] classData = getClassData(name); if (classData == null) { throw new ClassNotFoundException(); } else { return defineClass(name, classData, 0, classData.length); } } private byte[] getClassData(String className) { String path = classNameToPath(className); try { InputStream ins = new FileInputStream(path); ByteArrayOutputStream baos = new ByteArrayOutputStream(); int bufferSize = 4096; byte[] buffer = new byte[bufferSize]; int bytesNumRead = 0; while ((bytesNumRead = ins.read(buffer)) != -1) { baos.write(buffer, 0, bytesNumRead); } return baos.toByteArray(); } catch (IOException e) { e.printStackTrace(); } return null; } private String classNameToPath(String className) { return rootDir + File.separatorChar + className.replace('.', File.separatorChar) + ".class"; } }
三 类的加载流程
Java类加载器负责加载Java类字节码到Java虚拟机中。一般说来,类的编译和加载会经过以下几个流程。注:MyClass表示加载的类
装载:查找并加载类的二进制数据。
链接
验证:确保被加载类的正确性。
准备:为类的静态变量分配内存,并将其初始化为默认值。
解析:把类中的符号引用转换为直接引用。
初始化:为类的静态变量赋予正确的初始值。
创建类的实例。
访问某个类或接口的静态变量,或者对该静态变量赋值。
反射:Class.forName(“com.allenwells.MyBlog”);
初始化父类,初始化父类的子类。
JVM启动时标明的启动类(即文件名和类名相同的那个类),此种情况下才会导致类的初始化,
如果这个类没有被加载和链接,那就先进行加载和链接。
如果这个类存在直接父类,并且这个类还没有初始化(在一个类加载器中,类只能被初始化一次),那就先初始化直接父类(不适用于接口)。
加入类中存在的初始化语句(如static变量和static块),那就先执行这些初始化语句。
加载类:具体流程如下图所示:
类加载流程图Visio源文件下载
相关文章推荐
- 移动架构设计摘录
- 转移服务器,DEDE网站遇到no input file specified!
- 下载一个网站的html并保存到文件中
- stm32.cube(一)——系统架构及目录结构
- 刘子琪公益歌《爸爸妈妈辛苦了》首播 感恩天下父母
- 投注技巧 投注网 投注站 涂山娱乐城 外围赌球网站 万宝路娱乐城
- VS2010, VS2008发布网站,无法显示网站数据
- LVS-dr架构原理与实现方案
- 网站迁移到其他机子上时显示空白解决方法
- Heatbeat高可用集群
- LVS-nat架构原理与实现方案
- Citrix VDI 跨平台桌面虚拟化架构的研究
- 美国网站空间如何选择
- 理解arcgis server 10.1及其架构
- Web网站服务(一)
- 推荐几个配色和图标网站
- 软件架构杂谈(四) --- P2P
- Platform 驱动架构
- 如何快速开发网站?
- 收藏一些有用的的网站