Java:类加载器(ClassLoader)
听上去很高端,其实一般自定义类加载器不需要用户去实现解析的过程,只要负责实现获取类对应的.class字节流部分就ok了,摘录深入理解Java虚拟机的一段话
虚拟机设计团队把类加载阶段中的“通过一个类的全限定名来获取描述此类的二进制字节流”这个动作放到Java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需要的类。实现这个动作的代码模块称为“类加载器”
实现类加载器需要继承ClassLoader这个抽象类,用户只要实现其中的findClass方法即可。在该类的javadoc中给出了这样一个示例:
class NetworkClassLoader extends ClassLoader {
String host;
int port;
public Class findClass(String name) {
byte[] b = loadClassData(name);
return defineClass(name, b, 0, b.length);
}
private byte[] loadClassData(String name) {
// load the class data from the connection
}
}
即用户这个自定义的类加载器的类实现文件在网络的某个位置而不是本地的文件。defineClass是ClassLoader类中的一个函数,底层调用了本地方法用来做真正的类解析工作。用户定义的findClass方法会在已有加载器无法加载指定名称的类时被调用。不同的类加载器即使加载(defineClass执行者不同,如果一个自定义的类加载器最后还是调用了系统的类加载器加载那么和直接使用系统加载器加载的效果是一致的)相同的类在JVM看来也属于不一样。具体在loadClass方法中:
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
} if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name); // this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
我们继承的ClassLoader中含有一个parent ClassLoader的成员,如果它不为null,那么类先会让它去尝试着加载,当它找不到指定的类时再调用用户定义的findClass过程来加载。
Parents Delegation Model(双亲委派模型)
上述先让类加载器中存在parent类加载器,并且先让parent类加载器尝试类加载的过程涉及到类加载器的“双亲委派模型”。双亲其实就是一个祖先(parents对应的中文而已)即当前ClassLoader中的parent成员,委派就是先让parent加载器代理类加载过程,不行再用自己的类加载过程。按照深入理解JVM的说法有系统提供的三种类加载器它们的层次如下:
|———————————————|
| Bootstrap ClassLoader |
|———————————————|
|
|----------------------------------|
| Extension ClassLoder |
|----------------------------------|
|
|----------------------------------|
| Application ClassLoder |
|----------------------------------|
Bootstrap ClassLoader: 负责加载存放在JAVA_HOME/lib目录中的或者被-Xbootclasspath参数所指定的,并且是按名称被虚拟机识别的(如rt.jar,名字不符不会识别)
Extension ClassLoader: 负责加载JAVA_HOME/lib/ext目录中的或者被java.ext.dirs系统变量指定的路径中的所有类库
Application ClassLoader: 负责加载用户路径(classpath)上所指定的类库,一般情况下这个就是程序中默认的类加载器
bootstrap classloader不能被直接获取,如下代码将输出null,代表Integer这个类是由bootstrap加载的,也可以从ClassLoader的loadClass判断过程看出如果parent==null就采用bootstrap去加载。
System.out.println(Integer.class.getClassLoader());
application classloader可以通过ClassLoader.getSystemClassLoader()静态方法获取,如下代码将返回true,klass是一个用户定义的类的class属性
System.out.println(ClassLoader.getSystemClassLoader() == klass.getClassLoader());
自己定义的类加载器默认情况下将ApplicationClassLoader作为parent类加载器。另外线程体也可以设置上下文类加载器:
Thread.currentThread().setContextClassLoader(cl);
Thread.currentThread().getContextClassLoader();
应用
如果我们需要将jetty嵌入到已有的Java代码中,在初始化Jetty服务器前先实例化一个全局配置类。如果一个类在启动Jetty前的ClassLoader的搜索目录和Jetty的webroot/inf中都存在(但是对应的资源文件可能只有在前者对应的目录中存在),可以设置优先从parentClassLoader中进行载入。jetty除了碰到一些语言级别的类会从parent类加载器获取,其他都先从自己的类加载器获取(否则会使得各个容器下的app可以相互影响)。当使用嵌入式jetty时,一般就运行一个app所以,可以把这个选项打开,如下:
appContext.setParentLoaderPriority(true);
下面是jetty的WebAppClassLoader继承了URLClassLoader:
@Override
protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException
{
Class<?> c= findLoadedClass(name);
ClassNotFoundException ex= null;
boolean tried_parent= false; boolean system_class=_context.isSystemClass(name);
boolean server_class=_context.isServerClass(name); if (system_class && server_class)
{
return null;
} if (c == null && _parent!=null && (_context.isParentLoaderPriority() || system_class) && !server_class)
{
tried_parent= true;
try
{
c= _parent.loadClass(name);
if (LOG.isDebugEnabled())
LOG.debug("loaded " + c);
}
catch (ClassNotFoundException e)
{
ex= e;
}
} if (c == null)
{
try
{
c= this.findClass(name);
}
catch (ClassNotFoundException e)
{
ex= e;
}
} if (c == null && _parent!=null && !tried_parent && !server_class )
c= _parent.loadClass(name); if (c == null)
throw ex; if (resolve)
resolveClass(c); if (LOG.isDebugEnabled())
LOG.debug("loaded " + c+ " from "+c.getClassLoader()); return c;
}
其中的serverClass和systemClass见WebAppContext:
public final static String[] __dftSystemClasses =
{
"java.", // Java SE classes (per servlet spec v2.5 / SRV.9.7.2)
"javax.", // Java SE classes (per servlet spec v2.5 / SRV.9.7.2)
"org.xml.", // needed by javax.xml
"org.w3c.", // needed by javax.xml
"org.apache.commons.logging.", // TODO: review if special case still needed
"org.eclipse.jetty.continuation.", // webapp cannot change continuation classes
"org.eclipse.jetty.jndi.", // webapp cannot change naming classes
"org.eclipse.jetty.plus.jaas.", // webapp cannot change jaas classes
"org.eclipse.jetty.websocket.WebSocket", // WebSocket is a jetty extension
"org.eclipse.jetty.websocket.WebSocketFactory", // WebSocket is a jetty extension
"org.eclipse.jetty.websocket.WebSocketServlet", // webapp cannot change WebSocketServlet
"org.eclipse.jetty.servlet.DefaultServlet" // webapp cannot change default servlets
} ; // Server classes are classes that are hidden from being
// loaded by the web application using system classloader,
// so if web application needs to load any of such classes,
// it has to include them in its distribution.
public final static String[] __dftServerClasses =
{
"-org.eclipse.jetty.continuation.", // don't hide continuation classes
"-org.eclipse.jetty.jndi.", // don't hide naming classes
"-org.eclipse.jetty.plus.jaas.", // don't hide jaas classes
"-org.eclipse.jetty.websocket.WebSocket", // WebSocket is a jetty extension
"-org.eclipse.jetty.websocket.WebSocketFactory", // WebSocket is a jetty extension
"-org.eclipse.jetty.websocket.WebSocketServlet", // don't hide WebSocketServlet
"-org.eclipse.jetty.servlet.DefaultServlet", // don't hide default servlet
"-org.eclipse.jetty.servlet.listener.", // don't hide useful listeners
"org.eclipse.jetty." // hide other jetty classes
} ;
不懂啊!待续
Java:类加载器(ClassLoader)的更多相关文章
- 深入理解Java类加载器(ClassLoader)
深入理解Java类加载器(ClassLoader) Java学习记录--委派模型与类加载器 关于Java类加载双亲委派机制的思考(附一道面试题) 真正理解线程上下文类加载器(多案例分析) [jvm解析 ...
- 深入理解Java类加载器(ClassLoader) (转)
转自: http://blog.csdn.net/javazejian/article/details/73413292 关联文章: 深入理解Java类型信息(Class对象)与反射机制 深入理解Ja ...
- Java 类加载器(ClassLoader)
类加载器 ClassLoader 什么是类加载器? 通过一个类的全限定名来获取描述此类的二进制字节流这个动作放到Java虚拟机外部去实现, 以便让应用程序自己决定如何去获取所需要的类.实现这个动作的代 ...
- 浅析java类加载器ClassLoader
作为一枚java猿,了解类加载器是有必要的,无论是针对面试还是自我学习. 本文从JDK提供的ClassLoader.委托模型以及如何编写自定义的ClassLoader三方面对ClassLoader做一 ...
- 潜水 java类加载器ClassLoader
类加载器(class loader)用于装载 Java 类到 Java 虚拟机中.一般来说.Java 虚拟机使用 Java 类的方式例如以下:Java 源程序(.java 文件)在经过 Java 编译 ...
- java类加载器——ClassLoader
Java的设计初衷是主要面向嵌入式领域,对于自定义的一些类,考虑使用依需求加载原则,即在程序使用到时才加载类,节省内存消耗,这时即可通过类加载器来动态加载. 如果你平时只是做web开发,那应该很少会跟 ...
- Java类加载器ClassLoader总结
JAVA类装载方式,有两种: 1.隐式装载, 程序在运行过程中当碰到通过new 等方式生成对象时,隐式调用类装载器加载对应的类到jvm中. 2.显式装载, 通过class.forname()等方法,显 ...
- Java类加载器(ClassLoader)
类加载的机制的层次结构 每个编写的”.java”拓展名类文件都存储着需要执行的程序逻辑,这些”.java”文件经过Java编译器编译成拓展名为”.class”的文件,”.class”文件中保存着Jav ...
- Java类加载器(死磕5)
Java类加载器( CLassLoader ) 死磕5: 自定义一个文件系统classLoader 本小节目录 5.1. 自定义类加载器的基本流程 5.2. 入门案例:自定义文件系统类加载器 5 ...
- Java类加载器( 死磕9)
[正文]Java类加载器( CLassLoader ) 死磕9: 上下文加载器原理和案例 本小节目录 9.1. 父加载器不能访问子加载器的类 9.2. 一个宠物工厂接口 9.3. 一个宠物工厂管理 ...
随机推荐
- html基础整理(01居中 盒子问题)
01 文字居中 将一段文字置于容器的水平中点,只要设置text-align属性即可: text-align:center; 02 容器水平居中 先为该容器设置一个明确宽度,然后将margin的水平 ...
- python接口自动化2-发送post请求详解(二)
前言 发送post的请求参考例子很简单,实际遇到的情况却是很复杂的,首先第一个post请求肯定是登录了,但登录是最难处理的.登录问题解决了,后面都简单了. 一.查看官方文档 1.学习一个新的模块,其实 ...
- Cocoa对象——根类
[转载自:http://mobile.51cto.com/iphone-274229.htm] Cocoa对象 根类是本文要介绍的内容,仅凭Objective-C语言和运行环境并不足以构造哪怕是最简单 ...
- LARTC
大牛的博客 howto ,however, is simplify. another space ip link list ip address show ip route show route -n ...
- 《LeetBook》leetcode题解(14):Longest Common Prefix[E]
我现在在做一个叫<leetbook>的免费开源书项目,力求提供最易懂的中文思路,目前把解题思路都同步更新到gitbook上了,需要的同学可以去看看 书的地址:https://hk029.g ...
- Android AES加密工具类实现(基础回顾)
package com.powercreator.cms.util; import java.security.SecureRandom; import javax.crypto.Cipher; im ...
- mysql去除重复记录案例
例1,表中有主键(可唯一标识的字段),且该字段为数字类型 1 测试数据 /* 表结构 */ DROP TABLE IF EXISTS `t1`; CREATE TABLE IF NOT EXISTS ...
- jQuery插件开发之windowScroll
回首望,曾经洋洋得意的代码现在不忍直视.曾经看起来碉堡的效果现在也能稍微弄点出来.社会在往前发展,人也得向前迈进. 参考于搜狗浏览器4.2版本首页的上下滚动效果.主要实现整个窗口的上下和左右滚动逻辑, ...
- Ubuntu 安装 Caffe
Caffe Caffe 安装(Python2 CPU版本) 参考博文https://blog.csdn.net/pangyunsheng/article/details/79418896 安装环境 U ...
- [PY3]——IO——文件读写
文件打开和关闭 # 使用open 打开文件,返回时值是一个 File-like对象 f.open('/test/file') # 使用read读取文件 f.read( ) # 使用close关闭文件 ...