- 浏览: 512816 次
- 性别:
- 来自: 长沙
-
文章分类
最新评论
-
wang1352083:
正在搭建tomcat源码.一会儿参照楼主经验搭建spring源 ...
Eclipse中阅读开源项目代码 -
w123456789zzzz:
谢谢你,问题解决了,楼主万岁!!
eclipse中如何安装插件 -
xiaoLee:
...
软件性能测试论文草稿 -
铃儿响叮当:
...
使用firefox调试js -
gogopengyou:
很细心啊
eclipse中如何安装插件
Java运行时系统组件,负责在运行时查找和装入类文件的类。创建自己的ClassLoader可以定制JVM,可以自定义如何将类文件引入系统。(ClassLoader:JVM中将类装入内存时使用)
缺省的ClassLoader只知道如何从本地文件系统装入类文件,定制的则可以在运行时从远程的web服务器装入代码。
一、 ClassLoader结构
1.1、 ClassLoader的基本不标是对类的请求提供服务,当JVM需要使用类时,它根据名称向ClassLoader请求这个类,然后ClassLoader试图返回一个表示这个类的Class对象。
请求类
JVM————————————————————ClassLoader
返回类对应的Class对象
通过覆盖这个过程不同阶段的方法,我们便可以定制ClassLoader。
1.2、 重要方法解析
loadClass(String name,boolean resolve) 是入口
defineClass:接受由原始字节组成的数组并把它转化成Class对象
findSystemClass:从本地文件系统装入类,它在本地文件系统寻找类文件。如果存在就使用defineClass将原始字节转换成Class对象
resolveClass:解析类
findLoadedClass:充当一个缓存,当请求loadClass装入类时,调用该方法来查看ClassLoader是否已经装入这个类(避免重新装入)。
工作流:
请求定制的ClassLoader装入类——检查远程web站点,查看是否存在所需的类——如果有,抓取这个类完成任务——没有,调用findSystemClass(事实上,为了效率一般是先调用findSystemClass)
二、 java 编译的工作方式
通常,Java编译器不止是编译你要求它编译的类(还会连带编译所需要的)。
Java编译器规则: 如果类不存在,或者与它的源码相比,类比较旧,那么类需要被编译
三: 附摘抄版ClassLoader 体系结构
原文出处:http://blog.chenlb.com/2009/06/java-classloader-architecture.html
jvm classLoader architecture:
Bootstrap ClassLoader/启动类加载器
主要负责jdk_home/lib目录下的核心 api 或 -Xbootclasspath 选项指定的jar包装入工作。
Extension ClassLoader/扩展类加载器
主要负责jdk_home/lib/ext目录下的jar包或 -Djava.ext.dirs 指定目录下的jar包装入工作。
System ClassLoader/系统类加载器
主要负责java -classpath/-Djava.class.path所指的目录下的类与jar包装入工作。
User Custom ClassLoader/用户自定义类加载器(java.lang.ClassLoader的子类)
在程序运行期间, 通过java.lang.ClassLoader的子类动态加载class文件, 体现java动态实时类装入特性。
类加载器的特性:
每个ClassLoader都维护了一份自己的名称空间, 同一个名称空间里不能出现两个同名的类。
为了实现java安全沙箱模型顶层的类加载器安全机制, java默认采用了 " 双亲委派的加载链 " 结构。
[img][/img]
classloader-architecture
[img][/img]
classloader-class-diagram
类图中, BootstrapClassLoader是一个单独的java类, 其实在这里, 不应该叫他是一个java类。因为,它已经完全不用java实现了。它是在jvm启动时, 就被构造起来的, 负责java平台核心库。
自定义类加载器加载一个类的步骤
classloader-load-class
ClassLoader 类加载逻辑分析, 以下逻辑是除 BootstrapClassLoader 外的类加载器加载流程:
// 检查类是否已被装载过
Class c = findLoadedClass(name);
if (c == null ) {
// 指定类未被装载过
try {
if (parent != null ) {
// 如果父类加载器不为空, 则委派给父类加载
c = parent.loadClass(name, false );
} else {
// 如果父类加载器为空, 则委派给启动类加载加载
c = findBootstrapClass0(name);
}
} catch (ClassNotFoundException e) {
// 启动类加载器或父类加载器抛出异常后, 当前类加载器将其
// 捕获, 并通过findClass方法, 由自身加载
c = findClass(name);
}
}
// 检查类是否已被装载过
Class c = findLoadedClass(name);
if (c == null ) {
// 指定类未被装载过
try {
if (parent != null ) {
// 如果父类加载器不为空, 则委派给父类加载
c = parent.loadClass(name, false );
} else {
// 如果父类加载器为空, 则委派给启动类加载加载
c = findBootstrapClass0(name);
}
} catch (ClassNotFoundException e) {
// 启动类加载器或父类加载器抛出异常后, 当前类加载器将其
// 捕获, 并通过findClass方法, 由自身加载
c = findClass(name);
}
}
线程上下文类加载器
java默认的线程上下文类加载器是 系统类加载器(AppClassLoader)。
// Now create the class loader to use to launch the application
try {
loader = AppClassLoader.getAppClassLoader(extcl);
} catch (IOException e) {
throw new InternalError(
"Could not create application class loader" );
}
// Also set the context class loader for the primordial thread.
Thread.currentThread().setContextClassLoader(loader);
// Now create the class loader to use to launch the application
try {
loader = AppClassLoader.getAppClassLoader(extcl);
} catch (IOException e) {
throw new InternalError(
"Could not create application class loader" );
}
// Also set the context class loader for the primordial thread.
Thread.currentThread().setContextClassLoader(loader);
以上代码摘自sun.misc.Launch的无参构造函数Launch()。
使用线程上下文类加载器, 可以在执行线程中, 抛弃双亲委派加载链模式, 使用线程上下文里的类加载器加载类.
典型的例子有, 通过线程上下文来加载第三方库jndi实现, 而不依赖于双亲委派.
大部分java app服务器(jboss, tomcat..)也是采用contextClassLoader来处理web服务。
还有一些采用 hotswap 特性的框架, 也使用了线程上下文类加载器, 比如 seasar (full stack framework in japenese).
线程上下文从根本解决了一般应用不能违背双亲委派模式的问题.
使java类加载体系显得更灵活.
随着多核时代的来临, 相信多线程开发将会越来越多地进入程序员的实际编码过程中. 因此,
在编写基础设施时, 通过使用线程上下文来加载类, 应该是一个很好的选择。
当然, 好东西都有利弊. 使用线程上下文加载类, 也要注意, 保证多根需要通信的线程间的类加载器应该是同一个,
防止因为不同的类加载器, 导致类型转换异常(ClassCastException)。
为什么要使用这种双亲委托模式呢?
因为这样可以避免重复加载,当父亲已经加载了该类的时候,就没有必要子ClassLoader再加载一次。
考虑到安全因素,我们试想一下,如果不使用这种委托模式,那我们就可以随时使用自定义的String来动态替代java核心api中定义类型,这样会存在非常大的安全隐患,而双亲委托的方式,就可以避免这种情况,因为String已经在启动时被加载,所以用户自定义类是无法加载一个自定义的ClassLoader。
java动态载入class的两种方式:
implicit隐式,即利用实例化才载入的特性来动态载入class
explicit显式方式,又分两种方式:
java.lang.Class的forName()方法
java.lang.ClassLoader的loadClass()方法
用Class.forName加载类
Class.forName使用的是被调用者的类加载器来加载类的。
这种特性, 证明了java类加载器中的名称空间是唯一的, 不会相互干扰。
即在一般情况下, 保证同一个类中所关联的其他类都是由当前类的类加载器所加载的。
public static Class forName(String className)
throws ClassNotFoundException {
return forName0(className, true , ClassLoader.getCallerClassLoader());
}
/** Called after security checks have been made. */
private static native Class forName0(String name, boolean initialize,
ClassLoader loader)
throws ClassNotFoundException;
public static Class forName(String className)
throws ClassNotFoundException {
return forName0(className, true , ClassLoader.getCallerClassLoader());
}
/** Called after security checks have been made. */
private static native Class forName0(String name, boolean initialize,
ClassLoader loader)
throws ClassNotFoundException;
上面中 ClassLoader.getCallerClassLoader 就是得到调用当前forName方法的类的类加载器
static块在什么时候执行?
当调用forName(String)载入class时执行,如果调用ClassLoader.loadClass并不会执行.forName(String,false,ClassLoader)时也不会执行.
如果载入Class时没有执行static块则在第一次实例化时执行.比如new ,Class.newInstance()操作
static块仅执行一次
各个java类由哪些classLoader加载?
java类可以通过实例.getClass.getClassLoader()得知
接口由AppClassLoader(System ClassLoader,可以由ClassLoader.getSystemClassLoader()获得实例)载入
ClassLoader类由bootstrap loader载入
NoClassDefFoundError和ClassNotFoundException
NoClassDefFoundError:当java源文件已编译成.class文件,但是ClassLoader在运行期间在其搜寻路径load某个类时,没有找到.class文件则报这个错
ClassNotFoundException:试图通过一个String变量来创建一个Class类时不成功则抛出这个异常
缺省的ClassLoader只知道如何从本地文件系统装入类文件,定制的则可以在运行时从远程的web服务器装入代码。
一、 ClassLoader结构
1.1、 ClassLoader的基本不标是对类的请求提供服务,当JVM需要使用类时,它根据名称向ClassLoader请求这个类,然后ClassLoader试图返回一个表示这个类的Class对象。
请求类
JVM————————————————————ClassLoader
返回类对应的Class对象
通过覆盖这个过程不同阶段的方法,我们便可以定制ClassLoader。
1.2、 重要方法解析
loadClass(String name,boolean resolve) 是入口
defineClass:接受由原始字节组成的数组并把它转化成Class对象
findSystemClass:从本地文件系统装入类,它在本地文件系统寻找类文件。如果存在就使用defineClass将原始字节转换成Class对象
resolveClass:解析类
findLoadedClass:充当一个缓存,当请求loadClass装入类时,调用该方法来查看ClassLoader是否已经装入这个类(避免重新装入)。
工作流:
请求定制的ClassLoader装入类——检查远程web站点,查看是否存在所需的类——如果有,抓取这个类完成任务——没有,调用findSystemClass(事实上,为了效率一般是先调用findSystemClass)
二、 java 编译的工作方式
通常,Java编译器不止是编译你要求它编译的类(还会连带编译所需要的)。
Java编译器规则: 如果类不存在,或者与它的源码相比,类比较旧,那么类需要被编译
三: 附摘抄版ClassLoader 体系结构
原文出处:http://blog.chenlb.com/2009/06/java-classloader-architecture.html
jvm classLoader architecture:
Bootstrap ClassLoader/启动类加载器
主要负责jdk_home/lib目录下的核心 api 或 -Xbootclasspath 选项指定的jar包装入工作。
Extension ClassLoader/扩展类加载器
主要负责jdk_home/lib/ext目录下的jar包或 -Djava.ext.dirs 指定目录下的jar包装入工作。
System ClassLoader/系统类加载器
主要负责java -classpath/-Djava.class.path所指的目录下的类与jar包装入工作。
User Custom ClassLoader/用户自定义类加载器(java.lang.ClassLoader的子类)
在程序运行期间, 通过java.lang.ClassLoader的子类动态加载class文件, 体现java动态实时类装入特性。
类加载器的特性:
每个ClassLoader都维护了一份自己的名称空间, 同一个名称空间里不能出现两个同名的类。
为了实现java安全沙箱模型顶层的类加载器安全机制, java默认采用了 " 双亲委派的加载链 " 结构。
[img][/img]

classloader-architecture
[img][/img]

classloader-class-diagram
类图中, BootstrapClassLoader是一个单独的java类, 其实在这里, 不应该叫他是一个java类。因为,它已经完全不用java实现了。它是在jvm启动时, 就被构造起来的, 负责java平台核心库。
自定义类加载器加载一个类的步骤

classloader-load-class
ClassLoader 类加载逻辑分析, 以下逻辑是除 BootstrapClassLoader 外的类加载器加载流程:
// 检查类是否已被装载过
Class c = findLoadedClass(name);
if (c == null ) {
// 指定类未被装载过
try {
if (parent != null ) {
// 如果父类加载器不为空, 则委派给父类加载
c = parent.loadClass(name, false );
} else {
// 如果父类加载器为空, 则委派给启动类加载加载
c = findBootstrapClass0(name);
}
} catch (ClassNotFoundException e) {
// 启动类加载器或父类加载器抛出异常后, 当前类加载器将其
// 捕获, 并通过findClass方法, 由自身加载
c = findClass(name);
}
}
// 检查类是否已被装载过
Class c = findLoadedClass(name);
if (c == null ) {
// 指定类未被装载过
try {
if (parent != null ) {
// 如果父类加载器不为空, 则委派给父类加载
c = parent.loadClass(name, false );
} else {
// 如果父类加载器为空, 则委派给启动类加载加载
c = findBootstrapClass0(name);
}
} catch (ClassNotFoundException e) {
// 启动类加载器或父类加载器抛出异常后, 当前类加载器将其
// 捕获, 并通过findClass方法, 由自身加载
c = findClass(name);
}
}
线程上下文类加载器
java默认的线程上下文类加载器是 系统类加载器(AppClassLoader)。
// Now create the class loader to use to launch the application
try {
loader = AppClassLoader.getAppClassLoader(extcl);
} catch (IOException e) {
throw new InternalError(
"Could not create application class loader" );
}
// Also set the context class loader for the primordial thread.
Thread.currentThread().setContextClassLoader(loader);
// Now create the class loader to use to launch the application
try {
loader = AppClassLoader.getAppClassLoader(extcl);
} catch (IOException e) {
throw new InternalError(
"Could not create application class loader" );
}
// Also set the context class loader for the primordial thread.
Thread.currentThread().setContextClassLoader(loader);
以上代码摘自sun.misc.Launch的无参构造函数Launch()。
使用线程上下文类加载器, 可以在执行线程中, 抛弃双亲委派加载链模式, 使用线程上下文里的类加载器加载类.
典型的例子有, 通过线程上下文来加载第三方库jndi实现, 而不依赖于双亲委派.
大部分java app服务器(jboss, tomcat..)也是采用contextClassLoader来处理web服务。
还有一些采用 hotswap 特性的框架, 也使用了线程上下文类加载器, 比如 seasar (full stack framework in japenese).
线程上下文从根本解决了一般应用不能违背双亲委派模式的问题.
使java类加载体系显得更灵活.
随着多核时代的来临, 相信多线程开发将会越来越多地进入程序员的实际编码过程中. 因此,
在编写基础设施时, 通过使用线程上下文来加载类, 应该是一个很好的选择。
当然, 好东西都有利弊. 使用线程上下文加载类, 也要注意, 保证多根需要通信的线程间的类加载器应该是同一个,
防止因为不同的类加载器, 导致类型转换异常(ClassCastException)。
为什么要使用这种双亲委托模式呢?
因为这样可以避免重复加载,当父亲已经加载了该类的时候,就没有必要子ClassLoader再加载一次。
考虑到安全因素,我们试想一下,如果不使用这种委托模式,那我们就可以随时使用自定义的String来动态替代java核心api中定义类型,这样会存在非常大的安全隐患,而双亲委托的方式,就可以避免这种情况,因为String已经在启动时被加载,所以用户自定义类是无法加载一个自定义的ClassLoader。
java动态载入class的两种方式:
implicit隐式,即利用实例化才载入的特性来动态载入class
explicit显式方式,又分两种方式:
java.lang.Class的forName()方法
java.lang.ClassLoader的loadClass()方法
用Class.forName加载类
Class.forName使用的是被调用者的类加载器来加载类的。
这种特性, 证明了java类加载器中的名称空间是唯一的, 不会相互干扰。
即在一般情况下, 保证同一个类中所关联的其他类都是由当前类的类加载器所加载的。
public static Class forName(String className)
throws ClassNotFoundException {
return forName0(className, true , ClassLoader.getCallerClassLoader());
}
/** Called after security checks have been made. */
private static native Class forName0(String name, boolean initialize,
ClassLoader loader)
throws ClassNotFoundException;
public static Class forName(String className)
throws ClassNotFoundException {
return forName0(className, true , ClassLoader.getCallerClassLoader());
}
/** Called after security checks have been made. */
private static native Class forName0(String name, boolean initialize,
ClassLoader loader)
throws ClassNotFoundException;
上面中 ClassLoader.getCallerClassLoader 就是得到调用当前forName方法的类的类加载器
static块在什么时候执行?
当调用forName(String)载入class时执行,如果调用ClassLoader.loadClass并不会执行.forName(String,false,ClassLoader)时也不会执行.
如果载入Class时没有执行static块则在第一次实例化时执行.比如new ,Class.newInstance()操作
static块仅执行一次
各个java类由哪些classLoader加载?
java类可以通过实例.getClass.getClassLoader()得知
接口由AppClassLoader(System ClassLoader,可以由ClassLoader.getSystemClassLoader()获得实例)载入
ClassLoader类由bootstrap loader载入
NoClassDefFoundError和ClassNotFoundException
NoClassDefFoundError:当java源文件已编译成.class文件,但是ClassLoader在运行期间在其搜寻路径load某个类时,没有找到.class文件则报这个错
ClassNotFoundException:试图通过一个String变量来创建一个Class类时不成功则抛出这个异常
发表评论
-
性能问题
2013-09-04 20:13 0<SERVICE CLASS=" ... -
ant中使用svn检出代码
2011-05-14 21:33 2966[size=large][size=large][size=l ... -
Ant与批处理(win环境)学习3
2011-04-10 23:48 1222此篇主要讲实践,大多数情况下是直接贴的代码了 ... -
VNC之代理
2011-03-27 22:48 2786[size=large] 背景:使用VNC客户端去连接DC上 ... -
1号~15号工作日志
2011-01-16 22:23 8951、 Flex的includeInLayout属 ... -
JAVA异常处理
2011-01-11 22:51 712在je上看到一篇有关异常处理的文章,觉得还不错... . ... -
Java配置项
2011-01-11 20:44 918背景:项目中有许多可选参数,这时如果采取硬编码的方式将非 ... -
offLineMap2工作日记之getBoolean
2011-01-06 23:25 7971、如字段不是get**开头的boolean 如: boole ... -
开发常用小工具集
2011-01-06 22:26 2030毕业也有半年了,我有幸能加入一家知名IT公司并从事时下最 ... -
Eclipse中阅读开源项目代码
2010-12-25 22:57 2725[size=large] 背景:由于最近较为系统地学习了 ... -
Eclipse调试深入
2010-12-25 18:59 1324背景:我个人的调 ... -
Java打包总结
2010-12-19 22:35 1417背景:最近下载了一 ... -
Ant与批处理(win环境)学习笔记(2)
2010-12-19 22:01 1240在《Ant与批处理(win环境)学习笔记》中学习了Ant的一些 ... -
Ant与批处理(win环境)学习笔记
2010-12-19 10:27 1451背景:最近个人附 ... -
JDK工具学习
2010-12-18 22:14 1036[size=large] 起因:在 ... -
Eclipse插件安装总结
2010-12-18 12:29 1211大学时一直使用的 ... -
使用Ant和Maven构建时出现OOM异常
2010-12-14 23:14 1759今日更新测试环境时报OOM错误(工程中使用了Ant和Ma ... -
JAVA技术见识集
2010-12-12 09:34 883[size=large] 将网上看到的一些适用于指定场景的 ... -
Eclipse异常集
2010-12-08 19:52 22951、 Eclipse异常说An internal Error ... -
将批处理文件注册成服务
2010-11-15 19:49 3535前两天完成了将java程序注册成win服务,如今本人有一 ...
相关推荐
### Java私塾基础入门笔记概览 #### 一、Java简介与版本 Java是一种功能强大的计算机编程语言,它不仅是一种软件开发平台,还是一种软件运行平台(Java Runtime Environment,简称JRE),支持软件的部署。Java的...
* 安全性:Java 语言提供了一个安全机制以防恶意代码的攻击,包括类 ClassLoader、SecurityManager 等。 * 体系结构中立性:Java 程序在 Java 平台上被编译为体系结构中立的字节码格式,然后可以在实现这个 Java ...
本教程从Java的入门开始讲起,最后落脚于网络编程,对Java中比较难懂的(可能对我来说目前比较难懂)诸如反射机制、ClassLoader类加载器还有动态代理暂时没有提及,打算在后面的培训课程中再给大家详细讲解。
1. 类装载器(ClassLoader):负责加载类文件,验证其合法性,并将其加载到内存中。 2. 运行时数据区(Runtime Data Area):包括堆、栈、方法区、本地方法栈和程序计数器。其中,堆存储对象实例,栈处理方法调用,...
深入了解JRE的ClassLoader机制,即如何加载Class,是解决CLASSPATH问题的关键。《Java深度历险》一书对此有详尽阐述,值得初学者细读。 2. **Package与Import机制**:Java中的package用于组织类,import则用于引入...
这通常通过类加载器(ClassLoader)的定制来实现,如DexClassLoader,它能够加载外部的DEX文件(编译后的Java代码)。资源合并则需要处理插件的资源文件与宿主资源的冲突,通常会通过反射或者AAPT工具进行处理,确保...
### OSGi 入门教程(mini) 关键知识点概览 #### 1. OSGi 概述 - **定义**:OSGi (Open Service Gateway Initiative) 是一种用于构建模块化 Java 应用程序的标准框架。它允许将应用程序划分为独立的、可重用的模块,...
J2ME入门-(6)CLDCAPI章节主要探讨的是CLDC API,这是Java Micro Edition (J2ME) 平台上针对小型设备和嵌入式系统的轻量级Java应用开发的关键组件。CLDC(Connected Limited Device Configuration)API是J2SE的一个...
- **安全性**: Java内置了多种安全机制,如沙箱模型(Sandbox)、类加载器(ClassLoader)等,能够有效地防止恶意代码的执行。 #### 二、Java环境搭建 - **下载JDK**: 访问Oracle官方网站或其他可信渠道下载最新版本的...
1. **类装载器(ClassLoader)**:负责加载.class文件,解析字节码并将其转换为运行时数据结构。 2. **运行时数据区(Run-Time Data Areas)**:包括方法区、堆、虚拟机栈、本地方法栈和程序计数器。 3. **执行引擎...
### 快速入门JVM知识点解析 #### 一、JVM简介 Java虚拟机(Java Virtual Machine,简称JVM)是运行所有Java程序的基础环境。它是一个虚构的计算机,包括一个即时编译器(JIT)、垃圾回收器(GC)和类加载器等核心...
JavaSE基础入门是Java编程学习的重要阶段,涵盖了Java语言的核心概念和基础语法。这个33天的视频教程针对初学者,旨在帮助他们掌握Java的基本知识,以便未来在IT行业中获得良好的就业机会,甚至达到10K以上的薪资...
本文将深入探讨2022年学习Java的三个关键过程,帮助你从入门到精通。 首先,安装JDK并编写Hello World程序是Java学习的第一步。JDK(Java Development Kit)是Java编程的基础,包含了编译、运行Java程序所需的所有...
【堆参数调优入门】 JVM堆内存的大小可以通过JVM启动参数来调整,如-Xms和-Xmx分别设置堆内存的初始大小和最大大小。新生代和老年代的比例可以通过-Xmn、-XX:NewRatio和-XX:SurvivorRatio进行调整。为了优化垃圾...
Java是世界上最流行的编程语言...以上是Java新手入门必须掌握的30个基本概念,这些知识构成了Java程序员的基础,也是进一步深入学习Java技术体系的关键。理解并熟练运用这些概念,将有助于你成为一名合格的Java开发者。
常见的ClassLoader包括Bootstrap ClassLoader、Extension ClassLoader和App ClassLoader。 #### 四、内存模型、锁与同步 **Java内存模型** 主要涉及以下方面: - **主内存**:存储共享变量。 - **工作内存**:每个...
- **Extension ClassLoader**:解析Extension ClassLoader的工作原理及其与系统类加载器的关系。 - **System ClassLoader**:阐述System ClassLoader的功能,包括如何加载应用程序类。 - **全盘负责委托机制**:深入...
Java经典入门教程pdf完整版Java私塾跟我学系列JAⅥ篇网址:htp:/www.lavass.Cn电话:010-86835215 3;Java是一种软件运行平台 3.1:什么是软件的运行平台 如同我们需要阳光、空气、水和食物才能正常存活一样,软件最终要...