java的ClassLoader

本文解析了Java中的ClassLoader类,介绍其作为抽象类如何负责加载类的对象,并解释了类加载器的委托模型及不同类加载器间的关系。同时,通过开源产品Exo的例子展示了在复杂架构中ClassLoader的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先ClassLoader 类是一个抽象类,负责加载类的对象,如果给定类的二进制名称,那么类加载器会试图查找或生成构成类定义的数据。一般策略是将名称转换为某个文件名,然后从文件系统读取该名称的“类文件”。每个 Class 对象都包含一个对定义它的 ClassLoader 的引用。数组类的 Class 对象不是由类加载器创建的,而是由 Java 运行时根据需要自动创建。数组类的类加载器由 Class.getClassLoader() 返回,该加载器与其元素类型的类加载器是相同的;如果该元素类型是基本类型,则该数组类没有类加载器。 应用程序需要实现 ClassLoader 的子类,以扩展 Java 虚拟机动态加载类的方式。ClassLoader 类使用委托模型来搜索类和资源。每个 ClassLoader 实例都有一个相关的父类加载器。需要查找类或资源时,ClassLoader 实例会在试图亲自查找类或资源之前,将搜索类或资源的任务委托给其父类加载器。虚拟机的内置类加载器(称为 "bootstrap class loader")本身没有父类加载器,但是可以将它用作 ClassLoader 实例的父类加载器。通常情况下,Java 虚拟机以与平台有关的方式,从本地文件系统中加载类。例如,在 UNIX 系统中,虚拟机从 CLASSPATH 环境变量定义的目录中加载类。类加载器所创建对象的方法和构造方法可以引用其他类。为了确定引用的类,Java 虚拟机将调用最初创建该类的类加载器的 loadClass 方法。 Classloader存在下面问题:在一个JVM中可能存在多个ClassLoader,每个ClassLoader拥有自己的NameSpace。一个ClassLoader只能拥有一个class对象类型的实例,但是不同的ClassLoader可能拥有相同的class对象实例,这时可能产生致命的问题。如ClassLoaderA,装载了类A的类型实例A1,而ClassLoaderB,也装载了类A的对象实例A2。逻辑上讲A1=A2,但是由于A1和A2来自于不同的ClassLoader,它们实际上是完全不同的,如果A中定义了一个静态变量c,则c在不同的ClassLoader中的值是不同的。因此,研究JBoss的ClassLoader策略,对于更好地实现EJB组件拼装是用好处的,因为,一个项目中可能要用其他项目的EJB组件,如何实现运行时EJB组件共享,如何实现EJB组件打包是很重要的。为了说明ClassLoader对于复杂架构是至重关键,列举开源Portal产品Exo中ServivesManager类内容。该类是Exo利用PicoCOntainer实现功能性Service JavaBeans初始化,在将那些Service性质的JavaBeans加载到pico中时,需要使用到Classloader, Exo专门设立一个ServiceContext类: public class ServiceContext {  private ClassLoader cl;  //包含Classloader信息  private Services services;  public ServiceContext(ClassLoader cl, Services services) {    this.cl = cl;    this.services = services;  }  public ClassLoader getCl() {    return cl;  }  public Services getServices() {    return services;  }} 在ServicesManager中,有: private ClassLoader updatedClassLoader; 它的初始值是: Thread.currentThread().getContextClassLoader(); 如果,这里写Class.forName 那么简单,那么你头疼去吧。但是这样不够:在addService方法中,根据加入的不同ServiceContext实现类装载:  public void addService(ServiceContext context) {    Services servicesToAdd = context.getServices();    String name = servicesToAdd.getName();    URLClassLoader cl = null;    if(context.getCl() instanceof URLClassLoader) {      cl = (URLClassLoader) context.getCl();    } else {      cl = URLClassLoader.newInstance(new URL[]{}, context.getCl());    }    updatedClassLoader = new URLClassLoader(cl.getURLs(), updatedClassLoader);    synchronized (servicesContext) {      servicesContext.put(name, context);      reloadContainer();    }  } 其实向Picocontainer中加入一个服务很简单,上述方法的主要代码是处理Classloader,考虑到Classloader有嵌套关系,上述代码小心使用这个Service服务的父Classloader,使用父Classloader装载服务Service。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值