热门标签 | HotTags
当前位置:  开发笔记 > 前端 > 正文

Javaclassloader和namespace详细介绍

这篇文章主要介绍了Javaclassloader和namespace详细介绍的相关资料,需要的朋友可以参考下

Java classloader和namespace详细介绍

  Java虚拟机通过装载、连接和初始化一个JAVA类型,使该类型可以被正在运行的JAVA程序所使用。其中,装载就是把二进制形式的JAVA类型读入JAVA虚拟机中。连接就是把这种已经读入虚拟机的二进制形式的类型数据合并到虚拟机的运行时状态中去。连接阶段分为三个步骤-验证、准备和解析。验证确保了JAVA类型数据格式正确并适于JAVA虚拟机使用。准备负责为该类分配它所需的内存,比如为它的类变量分配内存。解析把常量池中的符号引用转换为直接引用,如内存地址指针。在初始化期间,激活类的静态变量的初始化代码和静态代码块。

  装载步骤的最终产品是一个被装载类型的Class类的实例对象,它成为JAVA程序与内部数据结构之间的接口。对于每一个被装载的类型,虚拟机都会相应地为它创建一个Class类的实例。

1 类装载器的安全作用

  JAVA类装载器在JAVA安全体系结构中起着最关重要的作用,是JAVA安全沙箱的第一道防线。类装载器体系结构在三个方面对JAVA的沙箱起作用:

1) 它防止恶意代码去干涉善意的代码
2) 它守护了被信任的类库的边界
3) 它将代码归入某类(称为保护域),该类确定了代码可以进行哪些操作。

类装载器体系结构可以防止恶意代码去干涉善意的代码,这是通过为不同的类装载器装入的类提供不同的命名空间来实现的。

2双亲委派模型

  JAVA虚拟机规范定义了两种类型的类装载器-启动类装载器和用户自定义类装载器,启动类装载器是JAVA虚拟机实现的一部分,通过继承ClassLoader类,用户可以创建自定义的类装载器来完成特定要求的加载。JAVA虚拟机已经创建了2个自定义类装载器-扩展类装载器和系统类装载器。
每一个用户自定义的类装载器在创建时被分配一个“双亲”parent类装载器。如果没有显示地传递一个双亲类装载器给用户自定义的类装载器的构造方法,系统类装载器就默认被指定为双亲。如果传递到构造方法的是一个已有的用户自定义类装载器的引用,该用户自定义类装载器就作为双亲;如果向构造方法传递了null,启动类装载器就是双亲。
启动类装载器Bootstrap Classloader:它是JAVA虚拟机实现的一部分,是c/c++实现的,它没有双亲。启动类装载器装载JAVA核心库代码。

扩展类装载器Extension Classloader:继承自URLClassLoader,初始化向构造方法传递了null,所以双亲是Bootstrap Classloaser。它从java.ext.dirs扩展目录中装载代码。

系统类装载器Application Classloader:继承自URLClassLoader,双亲是Extension Classloaser。它从CLASSPATH路径中装载应用程序代码。

其中,网络类装载器URLClassLoader是JAVA库提供的一个类装载器,用来从网络其他位置装载类。

双亲孩子类装载器委派链

  在双亲委派模型下,当一个装载器被请求装载某个类时,它首先委托自己的双亲parent去装载,若parent能装载,则返回这个类所对应的Class对象,若parent不能装载,则由parent的请求者去装载。

现在假设要求Cindy去装载一个名为java.io.FileReader的类型。Cindy第一件事情就是去找Mom来装载那个类型;Mom所做的第一件事情就是去找Grandma来装载那个类型;而Grandma首先去找启动类装载器去装载。在这个例子中,启动类装载器可以装载那个类型,它就返回代表java.io.FileReader的Class实例给Grandma。Grandma传递该Class的引用 Mom,Mom再回传给Cindy,Cindy返回给程序。

 

  在此模型下,启动类装载器可以抢在扩展类装载器之前去装载类,而扩展类装载器可以抢在系统类装载器之前去装载那个类,系统类装载器又可以抢在网络类装载器之前去装载它。这样,使用双亲-孩子委派链的方式,启动类装载器会在最可信的类库-核心Java API-中首先检查每个被装载的类型,然后,才依次到扩展路径、系统类路径中检查被装载的类型文件。用这种方法,类装载器的体系结构就可以防止不可靠的代码用它们自己的版本来替代可以信任的类。

3命名空间 

由不同的类装载器装载的类将被放在虚拟机内部的不同命名空间。命名空间由一系列唯一的名称组成,每一个被装载的类有一个名字。JAVA虚拟机为每一个类装载器维护一个名字空间。例如,一旦JAVA虚拟机将一个名为Volcano的类装入一个特定的命名空间,它就不能再装载名为Valcano的其他类到相同的命名空间了。可以把多个Valcano类装入一个JAVA虚拟机中,因为可以通过创建多个类装载器从而在一个JAVA应用程序中创建多个命名空间。

1)  初始类装载器/ 定义类装载器

命名空间有助于安全的实现,因为你可以有效地在装入了不同命名空间的类之间设置一个防护罩。在JAVA虚拟机中,在同一个命名空间内的类可以直接进行交互,而不同的命名空间中的类甚至不能觉察彼此的存在,除非显示地提供了允许它们进行交互的机制,如获取Class对象的引用后使用反射来访问。

  如果要求某个类装载器去装载一个类型,但是却返回了其他类装载器装载的类型,这种装载器被称为是那个类型的初始类装载器 ;而实际装载那个类型的类装载器被称为该类型的定义类装载器 。任何被要求装载类型,并且能够返回Class实例的引用代表这个类型的类装载器,都是这个类型的初始类装载器。在上面的一个例子中,java.io.FileReader定义类装载器是启动类装载器,Cindy、Mom、Grandma、启动类装载器都是初始类装载器。

  虚拟机会为每一个类装载器维护一张列表,列表中是已经被请求过的类型的名字。这些列表包含了每一个类装载器被标记为初始类装载器的类型,它们代表了每一个类装载器的命名空间。虚拟机总是会在调用loadClass()之前检查这个内部列表,如果这个类装载器已经被标记为是这个具有该全限定名的类型的初始类装载器,就会返回表示这个类型的Class实例,这样,虚拟机永远不会自动在同一个用户自定义类装载器上调用同一个名字的类型两次。

2) 命名空间的类型共享

  前面提到过只有同一个命名空间内的类才可以直接进行交互,但是我们经常在由用户自定义类装载器定义的类型中直接使用Java API类,这不是矛盾了吗?这是类型共享 原因-如果某个类装载器把类型装载的任务委派给另外一个类装载器,而后者定义了这个类型,那么被委派的类装载器装载的这个类型,在所有被标记为该类型的初始类装载器的命名空间中共享。
例如上面的例子中,Cindy可以共享Mon、Grandma、启动类装载器的命名空间中的类型,Kenny也可以共享 Mon、Grandma、启动类装载器的 命名空间中的 类型,但是Cindy和Kenny的命名空间不能共享。

3) 运行时包

  每个类装载器都有自己的命名空间,其中维护着由它装载的类型。所以一个JAVA程序可以多次装载具有同一个全限定名的多个类型。这样一个类型的全限定名就不足以确定在一个JAVA虚拟机中的唯一性。因此,当多个类装载器都装载了同名的类型时,为了唯一表示该类型,还要在类型名称前加上装载该类型的类装载器来表示-[classloader class]。
  在允许两个类型之间对包内可见的成员进行访问前,虚拟机不但要确定这个两个类型属于同一个包,还必须确认它们属于同一个运行时包-它们必须有同一个类装载器装载的。这样,java.lang.Virus和来自核心的java.lang的类不属于同一个运行时包,java.lang.Virus就不能访问JAVA API的java.lang包中的包内可见的成员。

4自定义类装载器

  JAVA类型要么由启动类装载器装载,要么通过用户自定义的类装载器装载。启动类装载器是虚拟机实现的一部分,它以与实现无关的方式装载类型,JAVA提供了抽象类java.lang.ClassLoader,用户自定义的类装载器是类ClassLoader的子类实例,它以定制的方式装载类。所有用户自定义类装载器都实例化自ClassLoader的子类。
下面提供一个简单的用户自定义类装载器。

import java.io.*; 
public class UserDefinedClassLoader extends ClassLoader 
{ 
 private String directory = "d:/classes/"; 
 private String extensiOnType= ".class"; 
  
 public UserDefinedClassLoader() 
 { 
  super(); // this set the parent as the AppClassLoader by default 
 } 
  
 public UserDefinedClassLoader( ClassLoader parent ) 
 { 
  super( parent ); 
 } 
  
 public Class findClass( String name ) 
 { 
  byte[] data = loadClassData( name ); 
   
  return defineClass( name, data, 0, data.length ); 
 } 
  
 private byte[] loadClassData( String name ) 
 { 
  byte[] data = null; 
  try 
  { 
   FileInputStream in = new FileInputStream( new File( directory + name.replace( '.', '/') + extensionType ) ); 
   ByteArrayOutputStream out = new ByteArrayOutputStream(); 
   int ch = 0; 
    
   while( ( ch = in.read() ) != -1 ) 
   { 
    out.write( ch ); 
   } 
    
   data = out.toByteArray(); 
  } 
  catch ( IOException e ) 
  { 
   e.printStackTrace(); 
  } 
  return data; 
 } 
} 
 


public class Valcano 
{ 
 static 
 { 
  System.out.println("Valcano Class Initialized");  
 } 
  
 public Valcano() 
 { 
 } 
} 
public class ClassLoaderTest 
{ 
 public static void main( String[] args ) 
 { 
  try 
  { 
   UserDefinedClassLoader userLoader = new UserDefinedClassLoader(); 
   Class valcanoClass1 = userLoader.loadClass( "Valcano" ); 
    
   URL url = new URL("file:/d:/classes/" ); 
   ClassLoader urlLoader = new URLClassLoader( new URL[] { url } ); 
   Class valcanoClass2 = urlLoader.loadClass( "Valcano" ); 
   System.out.println( "valcanoClass1 classloaer = " + valcanoClass1.getClassLoader() ); 
   System.out.println( "valcanoClass2 classloaer = " + valcanoClass2.getClassLoader() ); 
    
   System.out.println( "valcanoClass1 = valcanoClass2 ? " + ( valcanoClass1 == valcanoClass2 ) ); 
  } 
  catch( Exception e ) 
  { 
   e.printStackTrace(); 
  } 
 } 
} 

输出结果:

valcanoClass1 classloaer = UserDefinedClassLoader@1fb8ee3
valcanoClass2 classloaer = java.NET.URLClassLoader@14318bb
valcanoClass1 = valcanoClass2 ? false

我们可以看到,有两个不同的Valcano的Class实例被加载到同一个虚拟机中。

另外我们看到Valcano类静态初始化语句没有被执行,意味着类没有被初始化,这是因为JAVA中只有当类被主动使用时类型才会进行初始化。

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!


推荐阅读
  • 本文探讨了Java编程的核心要素,特别是其面向对象的特性,并详细介绍了Java虚拟机、类装载器体系结构、Java类文件和Java API等关键技术。这些技术使得Java成为一种功能强大且易于使用的编程语言。 ... [详细]
  • 深入解析Java虚拟机(JVM)架构与原理
    本文旨在为读者提供对Java虚拟机(JVM)的全面理解,涵盖其主要组成部分、工作原理及其在不同平台上的实现。通过详细探讨JVM的结构和内部机制,帮助开发者更好地掌握Java编程的核心技术。 ... [详细]
  • Docker的安全基准
    nsitionalENhttp:www.w3.orgTRxhtml1DTDxhtml1-transitional.dtd ... [详细]
  • 本文介绍了一段使用jQuery实现的用户注册页面表单验证代码,适用于前端开发人员学习和参考。该示例结合了HTML、CSS和JavaScript,确保用户输入的数据格式正确。 ... [详细]
  • 本文详细介绍了Ionic框架的使用方法及其与Angular的集成。Ionic框架是一个强大的前端开发工具,适用于构建跨平台的移动应用程序。文章将探讨如何引入必要的CSS和JavaScript文件,并解释bundle.js中包含的核心功能,如路由等。 ... [详细]
  • 利用决策树预测NBA比赛胜负的Python数据挖掘实践
    本文通过使用2013-14赛季NBA赛程与结果数据集以及2013年NBA排名数据,结合《Python数据挖掘入门与实践》一书中的方法,展示如何应用决策树算法进行比赛胜负预测。我们将详细讲解数据预处理、特征工程及模型评估等关键步骤。 ... [详细]
  • 深入理解ExtJS:从入门到精通
    本文详细介绍了ExtJS的功能及其在大型企业前端开发中的应用。通过实例和详细的文件结构解析,帮助初学者快速掌握ExtJS的核心概念,并提供实用技巧和最佳实践。 ... [详细]
  • 本文汇集了一系列具有强烈设计感的网站模板,特别是来自知名平台WrapBootstrap的响应式网站模板。这些模板不仅美观,而且功能强大,适合各种类型的网站建设需求。 ... [详细]
  • Spring Boot 中静态资源映射详解
    本文深入探讨了 Spring Boot 如何简化 Web 应用中的静态资源管理,包括默认的静态资源映射规则、WebJars 的使用以及静态首页的处理方法。通过本文,您将了解如何高效地管理和引用静态资源。 ... [详细]
  • 本文详细探讨了Java中的ClassLoader类加载器的工作原理,包括其如何将class文件加载至JVM中,以及JVM启动时的动态加载策略。文章还介绍了JVM内置的三种类加载器及其工作方式,并解释了类加载器的继承关系和双亲委托机制。 ... [详细]
  • 本文探讨了2019年前端技术的发展趋势,包括工具化、配置化和泛前端化等方面,并提供了详细的学习路线和职业规划建议。 ... [详细]
  • Asp.net MVC 中 Bundle 配置详解:合并与压缩 JS 和 CSS 文件
    本文深入探讨了 Asp.net MVC 中如何利用 Bundle 功能来合并和压缩 JavaScript 和 CSS 文件,提供了详细的配置步骤和示例代码,适合开发人员参考学习。 ... [详细]
  • 本文深入探讨了CART(分类与回归树)的基本原理及其在随机森林中的应用。重点介绍了CART的分裂准则、防止过拟合的方法、处理样本不平衡的策略以及其在回归问题中的应用。此外,还详细解释了随机森林的构建过程、样本均衡处理、OOB估计及特征重要性的计算。 ... [详细]
  • 本文将详细介绍如何在Bootstrap 5中使用五种不同的表单控件样式,包括输入框、选择器和文本区域等元素。 ... [详细]
  • window下kafka的安装以及测试
    目录一、安装JDK(需要安装依赖javaJDK)二、安装Kafka三、测试参考在Windows系统上安装消息队列kafka一、安装JDKÿ ... [详细]
author-avatar
mobiledu2502920327
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有