Java类加载器学习总结

上传人:磨石 文档编号:108907372 上传时间:2022-06-16 格式:DOC 页数:12 大小:117.50KB
收藏 版权申诉 举报 下载
Java类加载器学习总结_第1页
第1页 / 共12页
Java类加载器学习总结_第2页
第2页 / 共12页
Java类加载器学习总结_第3页
第3页 / 共12页
资源描述:

《Java类加载器学习总结》由会员分享,可在线阅读,更多相关《Java类加载器学习总结(12页珍藏版)》请在装配图网上搜索。

1、加载器概念类加载器(class loader)用来加载 Java 类到 Java 虚拟机中。一般来说,Java 虚拟机使用 Java 类的方式如下:Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件)。类加载器负责读取 Java 字节代码,并转换成java.lang.Class类的一个实例。每个这样的实例用来表示一个 Java 类。通过此实例的 newInstance()方法就可以创建出该类的一个对象。类加载器分类JDK 默认提供了如下几种ClassLoader:1、Bootstrp Class LoaderBootstrp加

2、载器是用C+语言写的,它是在Java虚拟机启动后初始化的,它主要负责加载%JAVA_HOME%/jre/lib或者-Xbootclasspath参数指定的路径以及%JAVA_HOME%/jre/classes中的类,虚拟机出于安全等因素考虑,不会加载%JAVA_HOME%/jre/lib路径下存在的陌生类,开发者通过将要加载的非JDK自身的类放置到此目录下期待启动类加载器加载是不可能的。2、ExtClassLoader Bootstrp class loader加载ExtClassLoader,并且将ExtClassLoader的父加载器设置为Bootstrp loader。ExtClassL

3、oader是用Java写的,具体来说就是sun.misc.Launcher$ExtClassLoader,ExtClassLoader主要加载%JAVA_HOME%/jre/lib/ext,此路径下的所有classes目录以及java.ext.dirs系统变量指定的路径中类库。3、AppClassLoader Bootstrp class loader加载完ExtClassLoader后,就会加载AppClassLoader,并且将AppClassLoader的父加载器指定为ExtClassLoader。AppClassLoader也是用Java写成的,它的实现类是sun.misc.Launc

4、her$AppClassLoader,另外我们知道ClassLoader中有个getSystemClassLoader方法,此方法返回的正是AppclassLoader。AppClassLoader主要负责加载classpath所指定的位置的类或者是jar文档,它也是Java程序默认的类加载器。综上所述,它们之间的关系可以通过下图形象的描述:双亲委托模型Java中ClassLoader的加载采用了双亲委托机制,采用双亲委托机制加载类的时候采用如下的几个步骤:1 当前ClassLoader首先从自己已经加载的类中查询是否此类已经加载,如果已经加载则直接返回原来已经加载的类。每个类加载器都有自己的

5、加载缓存,当一个类被加载了以后就会放入缓存,等下次加载时可以直接返回。2 当前classLoader的缓存中没有找到被加载的类时,委托父类加载器去加载,父类加载器采用同样的策略,首先查看自己的缓存,然后委托父类的父类去加载,一直到bootstrp ClassLoader。3 当所有的父类加载器都没有加载的时候,再由当前的类加载器加载,并将其放入它自己的缓存中,以便下次有加载请求的时候直接返回。线程上下文类加载器ContextClassLoader是java.lang.Thread类的一个属性,Thread类中的方法 getContextClassLoader()和setContextClass

6、Loader(ClassLoader cl)用来获取和设置线程的上下文类加载器。如果没有通过 setContextClassLoader(ClassLoader cl)方法进行设置的话,线程将继承其父线程的上下文类加载器。Java 应用运行的初始线程的上下文类加载器是系统类加载器(AppClassLoader),在线程中运行的代码可以通过此类加载器来加载类和资源。双亲委托模型并不能解决 Java 应用开发中会遇到的类加载器的全部问题。Java 提供了很多服务提供者接口(Service Provider Interface,SPI),允许第三方为这些接口提供实现。常见的 SPI 有 JDBC、J

7、CE、JNDI、JAXP 和 JBI 等。这些 SPI 的接口由 Java 核心库来提供,如 JAXP 的 SPI 接口定义包含在 javax.xml.parsers包中(rt.jar)。这些 SPI 的实现代码很可能是作为 Java 应用所依赖的 jar 包被包含进来,可以通过类路径(CLASSPATH)来找到,如实现了 JAXP SPI 的 Apache Xerces所包含的 jar 包。SPI 接口中的代码经常需要加载具体的实现类。如 JAXP 中的 javax.xml.parsers.DocumentBuilderFactory类中的 newInstance()方法用来生成一个新的 D

8、ocumentBuilderFactory的实例。这里的实例的真正的类是继承自 javax.xml.parsers.DocumentBuilderFactory,由 SPI 的实现所提供的。如在 Apache Xerces 中,实现的类是 org.apache.xerces.jaxp.DocumentBuilderFactoryImpl。而问题在于,SPI 的接口是 Java 核心库的一部分,是由引导类加载器(BootstrpClassLoader)来加载的;SPI 实现的 Java 类一般是由系统类加载器(APPClassLoader)来加载的。引导类加载器是无法找到 SPI 的实现类的,因

9、为它只加载 Java 的核心库。它也不能代理给系统类加载器,因为它是系统类加载器的祖先类加载器。也就是说,类加载器的双亲委托模型无法解决这个问题。线程ContextClassLoader正好解决了这个问题。如果不做任何的设置,Java 应用的线程的ContextClassLoader默认就是系统上下文类(AppClassLoader)加载器。在 SPI 接口的代码中使用线程ContextClassLoader,就可以成功的加载到 SPI 实现的类。线程ContextClassLoader在很多 SPI 的实现中都会用到。以下是一个简单的Java 应用,用于测试ContextClassLoade

10、r。import javax.xml.parsers.DocumentBuilderFactory;public class TestClassLoader public static void main(String args) throws Exception TestClassLoader test = new TestClassLoader();test.testLoad();private void testLoad() throws Exception / 1System.out.println(Thread.currentThread();/ Threadmain,5,main/

11、 2System.out.println(Thread.currentThread().getContextClassLoader();/ sun.misc.Launcher$AppClassLoader19821f/ 3DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(org.apache.xerces.jaxp.DocumentBuilderFactoryImpl, null);注释/2显示当前主线程使用的上下文类加载器是AppClassLoader,注释/3由DocumentBuilderFactory

12、负责加载并实例化它的一个实现类,该实现类由Apache Xerces提供,同时在newInstance中传入了一个空的加载器。public class DocumentBuilderFactorypublic static DocumentBuilderFactory newInstance(String factoryClassName, ClassLoader classLoader) try return (DocumentBuilderFactory) FactoryFinder.newInstance(factoryClassName, classLoader, false); ca

13、tch (FactoryFinder.ConfigurationError e) throw new FactoryConfigurationError(e.getException(), e.getMessage(); /.DocumentBuilderFactory中的newInstance方法将加载的任务交给FactoryFinder来完成。class FactoryFinder static Object newInstance(String className, ClassLoader cl, boolean doFallback) throws ConfigurationError

14、 try /使用给定的加载器cl,获取DocumentBuilderFactoryImpl类的Class对象,此处的cl为null Class providerClass = getProviderClass(className, cl, doFallback); /创建DocumentBuilderFactoryImpl的实例 Object instance = providerClass.newInstance(); return instance; catch (ClassNotFoundException x) throw new ConfigurationError( Provide

15、r + className + not found, x); catch (Exception x) throw new ConfigurationError( Provider + className + could not be instantiated: + x, x); /.获取DocumentBuilderFactoryImpl实现类的Class对象在getProviderClass方法中完成。class FactoryFinder static private Class getProviderClass(String className, ClassLoader cl, bool

16、ean doFallback) throws ClassNotFoundException try if (cl = null) /1 cl = ss.getContextClassLoader(); if (cl = null) throw new ClassNotFoundException(); else /2由上下文类加载器完成实现类的加载 return cl.loadClass(className); else return cl.loadClass(className); catch (ClassNotFoundException e1) /. /.由于cl传入的是一个null值,

17、所以需要从ss对象中获取一个上下文类加载器,那ss对象中的getContextClassLoader方法如何获取一个上下文加载器的呢?class SecuritySupport ClassLoader getContextClassLoader() throws SecurityExceptionreturn (ClassLoader)AccessController.doPrivileged(new PrivilegedAction() public Object run() ClassLoader cl = null; /1 cl = Thread.currentThread().getC

18、ontextClassLoader(); if (cl = null) cl = ClassLoader.getSystemClassLoader(); return cl; );/.该方法中的其他代码不需要管,由注释/1处可以看出最后return语句返回的cl加载器,就是从当前线程中获得的上下文类加载器。使用myeclipse调试跟踪代码可以看出,当前只有一个mian主线程。主线程中的上下文类加载器默认就是AppClassLoader。方法getProviderClass()中的注释/2处使用AppClassLoader加载器来完成实现类的加载。在注释/2处为什么不使用FactoryFind

19、er.Class.getClassLoader()来完成实现类的加载呢?因为FactoryFinder类位于核心类库中,由Bootstrp类加载器完成加载,而实现类DocumentBuilderFactoryImpl在我们自己的java应用中,在Bootstrp加载器的搜索范围中,找不到该实现类,因此这样的方式无法完成类的加载。另外一个原因,即使将实现类放到Bootstrp加载器的搜索范围中,也是不能完成加载,因为Bootstrp只负责加载固定的核心类库,其他的字节码文件一律都不加载。正常的双亲委派模型中,下层的类加载器可以使用上层父加载器加载的对象,但是上层父类的加载器不可能使用子类加载的对

20、象(因为,正常情况下加载器只会向上搜索被加载的类,不会向下搜索)。而有些时候程序的确需要上层调用下层,这时候就需要线程上下文类加载器来处理,以上就是这样的一个例子。自定义类加载器虽然在绝大多数情况下,系统默认提供的类加载器实现已经可以满足需求。但是在某些情况下,您还是需要为应用开发出自己的类加载器。比如您的应用通过网络来传输 Java 类的字节代码,为了保证安全性,这些字节代码经过了加密处理。这个时候您就需要自己的类加载器来从某个网络地址上读取加密后的字节代码,接着进行解密和验证,最后定义出要在 Java 虚拟机中运行的类来。下面将通过具体的实例来说明类加载器的开发。文件系统类加载器第一个类加

21、载器用来加载存储在文件系统上的 Java 字节代码。完整的实现下所示。public class extends ClassLoader private String rootDir;public (String rootDir) this.rootDir = rootDir;protected Class findClass(String name) throws ClassNotFoundException byte classData = getClassData(name);if (classData = null) throw new ClassNotFoundException();

22、 else return defineClass(name, classData, 0, classData.length);private byte getClassData(String className) String path = classNameToPath(className);try InputStream ins = new (path);ByteArrayOutputStream baos = new ByteArrayOutputStream();int bufferSize = 4096;byte buffer = new bytebufferSize;int byt

23、esNumRead = 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 + + className.replace(., ) + .class;类 继承自类 java.lang.ClassL

24、oader。一般来说,自己开发的类加载器只需要覆写 findClass(String name)方法即可。java.lang.ClassLoader类的方法 loadClass()封装了前面提到的双亲委托机制的实现。loadClass()方法会首先调用 findLoadedClass()方法来检查该类是否已经被加载过;如果没有加载过的话,会调用父类加载器的 loadClass()方法来尝试加载该类;如果父类加载器无法加载该类的话,就调用 findClass()方法来查找该类。因此,为了保证类加载器都正确实现双亲委托机制,在开发自己的类加载器时,最好不要覆写 loadClass()方法,而是覆写 findClass()方法。类 的 findClass()方法首先根据类的全名在硬盘上查找类的字节代码文件(.class 文件),然后读取该文件内容,最后通过 defineClass()方法来把这些字节代码转换成 java.lang.Class类的实例。参考12 / 12

展开阅读全文
温馨提示:
1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
2: 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
3.本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
关于我们 - 网站声明 - 网站地图 - 资源地图 - 友情链接 - 网站客服 - 联系我们

copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!