`
shallon
  • 浏览: 73139 次
  • 性别: Icon_minigender_2
  • 来自: 0
文章分类
社区版块
存档分类
最新评论

CLASSLOADER与类的依赖关系

阅读更多
起因:为了排查一个生产环境的问题,需要打印特殊的调试日志。能否做到通过配置,调试的类优先于原有类的载入,回退的时候修改配置即可?

一般的情况下:可以将 CLASSPATH设置成:/opt/lib/debug.jar:/opt/lib/c.jar的时候debug.jar的类优先于c.jar的载入,调试类生效和打印调试日志。CLASSPATH设置成:/opt/lib/c.jar则还原回正式的类。

在多层ClassLoader的情况下,调试类放在ClassPath路径中,c.jar放在子ClassLoader加载路径中,却出了“意外”。为了说明情况,做了一个测试项目。系统载入结构如下:


被载入类Container和Item,Item是Container的成员类

public class Container {
	private Item item=null;
	public Container(){
		println();
		this.item=new Item();
		
	}
	public void println(){
		System.out.println("Container:"+this.getClass().getClassLoader());
	}
}
public class Item {
public Item(){
	println();
}
public void println(){
	System.out.println("Item:"+this.getClass().getClassLoader());
}
}

载入类为StartServer,其关键的载入代码如下:
private void start() {
        try {
        	System.out.println("***************************");
            // Load up the bootstrap container
            final ClassLoader parent = findParentClassLoader();

            String libDirString = System.getProperty("load_dir");

            File libDir;
            if (libDirString != null) {
                libDir = new File(libDirString);
                if (!libDir.exists()) {
                    throw new NullPointerException("dir not exit");
                }
            }
            else {
            		throw new NullPointerException("dir not exit");
            }

            System.out.println("parent is:"+parent.getClass());
            ClassLoader loader = new MYClassLoader(parent, libDir);
            
            Thread.currentThread().setContextClassLoader(loader);
            Class containerClass = loader.loadClass(
                    "Container");
            containerClass.newInstance();
        }
        catch (Exception e) {
            e.printStackTrace();
        }
}



测试结果:

1、Class Item放在AppClassLoader载入,Class Container放在MYClassLoader载入 上述载入正常运行。
E:\javaproject\ws2007\tempProject\bin>java -Dload_dir=E:/javaproject/ws2007/tempProject -cp . StartServer
***************************
parent is:class sun.misc.Launcher$AppClassLoader
file:/E:/javaproject/ws2007/tempProject/c.jar
Container:MYClassLoader@61de33
Item:sun.misc.Launcher$AppClassLoader@19821f



测试结果:2、Class Container放在AppClassLoader载入,Class Item放在MYClassLoader载入  出现NoClassDefFoundError错误
E:\javaproject\ws2007\tempProject\bin>java -Dload_dir=E:/javaproject/ws2007/tempProject -cp . StartServer
***************************
parent is:class sun.misc.Launcher$AppClassLoader
file:/E:/javaproject/ws2007/tempProject/c.jar
Container:sun.misc.Launcher$AppClassLoader@19821f
Exception in thread "main" java.lang.NoClassDefFoundError: Item
        at Container.<init>(Container.java:6)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
        at java.lang.Class.newInstance0(Class.java:355)
        at java.lang.Class.newInstance(Class.java:308)
        at StartServer.start(StartServer.java:48)
        at StartServer.main(StartServer.java:18)

分析:
根据大名鼎鼎的类加载委托规则,ClassLoader 类使用委托模型来搜索类和资源。每个 ClassLoader 实例都有一个相关的父类加载器。需要查找类或资源时,ClassLoader 实例会在试图亲自查找类或资源之前,将搜索类或资源的任务委托给其父类加载器。虚拟机的内置类加载器(称为 "bootstrap class loader")本身没有父类加载器,但是可以将它用作 ClassLoader 实例的父类加载器。

由于子ClassLoader含有父ClassLoader的引用,并且可以将委托父ClassLoader搜索类和资源,反之则不行。于是在上述第二个测试中,MYClassLoader被显式加载Container,MYClassLoader委托AppClassLoader进行加载该类,AppClassLoader加载Container的时候发现无法加载Item类,其父ClassLoader是ExtClassLoader和Bootstrap ClassLoader当然也无法加载Item类,  因为Item仅出现在MYClassLoader的加载路径中,因而出错。

结论:

父ClassLoader与子ClassLoader加载的类必须有正确的依赖关系,子ClassLoader加载的类可以依赖饮用父ClassLoader加载的类,反之不行,如果需要将一个类移动上父ClassLoader加载则需要将该类依赖的所有类移到同一ClassLoader或者移动到更高层的ClassLoader。

另外,在测试过程中,中了-jar的招,以此纪念。一个可执行的 JAR 必须通过 menifest 文件的头引用它所需要的所有其他从属 JAR。如果使用了 -jar 选项,那么环境变量 CLASSPATH 和在命令行中指定的所有类路径都被 JVM 所忽略。 (http://www-128.ibm.com/developerworks/cn/java/j-jar/index.html)
分享到:
评论

相关推荐

    ClassLoader 详解.doc

    理解ClassLoader的工作原理对于排查类冲突、处理依赖关系以及优化大型J2EE应用的性能具有重要意义。开发者可以通过日志输出、调试工具等方式监控和分析ClassLoader的行为,以解决诸如类找不到、类加载错误等问题。 ...

    classloader体系结构(含hotswap)

    最后,`ClassLoader.getCallerClassLoader()`用于获取调用者类的类加载器,这在某些场景下非常有用,例如在处理类的依赖关系时。 总结来说,Java的类加载器体系结构是其动态性和灵活性的关键组成部分。通过理解这个...

    classloader源码

    6. `lib`:这个目录通常存放项目的外部依赖库,`ClassLoader`可能需要加载这些库中的类。 7. `classes`:编译后的`.class`文件可能会放在这里,`ClassLoader`可以直接加载这些类。 在分析`ClassLoader`源码时,我们...

    jboss 5 原理 2 classloader

    这意味着开发人员将根据策略进行编程,而不是直接与类加载器的具体细节打交道。 JBoss 5的ClassLoader项目分为三个子项目: 1. `classloader`:包含了自定义的`java.lang.ClassLoader`扩展,但没有特定的类加载...

    java classLoader 的全面讲解

    2. 静态初始化器问题:多个类加载器加载同一类,可能导致静态初始化器被执行多次,需要谨慎处理类的加载关系。 3. 类循环依赖:类之间相互引用可能导致加载延迟,合理设计类结构和加载顺序可避免此类问题。 综上所...

    Understanding the Java ClassLoader.pdf

    它的存在使得Java应用程序能够动态地加载类,而无需在编译时就确定所有依赖关系,这极大地增强了Java程序的灵活性和可扩展性。 ### 类加载器的结构 Java类加载器遵循一种层次结构,这种结构确保了类加载的正确性和...

    java查看sun包源码-land:Land是一个通过类加载器的简单Java:trade_mark:依赖隔离容器

    类加载会在上下级ClassLoader之间有委托关系,如: 是否允许在上级ClassLoader中查找类。 即是否 委托。 允许在上级ClassLoader查找哪些类/包。 即可以配置 委托 的粒度。 只允许在某级ClassLoader查找哪些类/包,会...

    找出Web程序依赖的所有的JAR

    在给定的文件列表中,`WebappClassLoader`相关的内部类表明它们与类加载和资源查找有关。这些类可能在运行时动态地处理和定位Web应用的类和资源,因此,它们是理解Web程序依赖的重要线索。但是,仅凭这些类无法直接...

    java类加载器

    ### Java 类加载器详解 #### 一、类加载器概述 在Java中,类加载器(Class ...通过理解和掌握类加载器的工作原理及其不同类型的加载器,可以帮助开发者更好地管理Java应用程序的依赖关系,提高程序的性能和可维护性。

    springboot+java类热加载

    **自动引用依赖**:在大型项目中,管理依赖关系是一项重要任务。热加载时,确保新编译的类能正确引用到所有必要的依赖是一项挑战。这通常需要一个自动化机制来处理。例如,项目构建工具如Maven或Gradle可以自动管理...

    金蝶Apusic应用服务器V6参考b手册b.doc

    Classloader的层次结构显示了Classloader之间的关系。在给定层次上的Classloader不能引用任何层次低于它的Classloader,另外,它的子Classloader装载的类对于其是不可见的。在上图中,如果 Foo.class 是由...

    Java类热替换(热部署)源码

    然而,实际应用可能更复杂,需要考虑类的依赖关系、接口兼容性、资源管理等问题。在开发过程中,务必测试热替换的效果,确保应用的稳定性和正确性。 总之,Java类热替换是一种强大的开发和调试工具,通过自定义...

    译 Java类加载机制(二)

    类加载机制在理解和调试Java程序中起着关键作用,尤其是在处理类的依赖关系和解决类冲突时。例如,在大型企业级应用和容器(如Tomcat)中,类加载机制的理解和利用是优化系统性能和维护性的关键。 总的来说,Java类...

    java class loader(JAVA类加载器)

    在JDK9引入的模块系统(Jigsaw项目)中,类加载机制有所改变,模块间的依赖关系影响了类的加载方式,使得类加载更加可控和安全。 总之,Java类加载器是Java平台的核心机制之一,它不仅关乎程序的运行,还直接影响...

    JVM、Tomcat、OSGI等类加载器整理文档

    在Java世界中,类加载器(ClassLoader)是关键组件,它们负责将类的字节码加载到Java虚拟机(JVM)中。JVM、OSGI(Open Service Gateway Initiative)和Tomcat等容器都涉及到了类加载器的概念,理解它们的工作原理对...

    性能调优专题-jvm类加载机制-performance-jvmclassloader.zip

    这是因为类加载器与类的关系是“父子关系”,而非“拥有关系”,只有当类加载器被回收,它所加载的类才会一同卸载。 6. **类加载器优化** 优化类加载机制可以减少内存消耗和提高程序启动速度。例如,使用自定义类...

    类加载说明.pdf

    类加载器不仅负责找到这些类文件,还需要确保它们按照正确的顺序被加载,并且正确处理不同类之间的依赖关系。 #### 三、类加载器结构 Java中的类加载器采用了一种分层的结构,这种结构可以确保安全性并支持模块化...

    类加载的工具

    4. **Jarscan**:这是一个轻量级的命令行工具,专门用来查找特定类或接口在哪些JAR文件中,这对于理解依赖关系和排查问题非常有用。 5. **ClassGraph**:这是一个Java库,用于扫描类路径和模块图,可以方便地获取类...

    spring framework体系结构及模块jar依赖关系详解

    3. spring-instrument:提供了一些类级的工具支持和 ClassLoader 级的实现,用于服务器,对应 spring-instrument-4.3.6.RELEASE.jar,同时提供针对 Tomcat 的 Instrument 实现 jar 包 spring-instrument-tomcat-...

    classloader:重新设计的 DICIoC 解决方案,包括类别名

    通过将依赖关系的创建和管理交由容器处理,开发者可以更容易地替换和测试组件,因为它们不再直接依赖于具体的实现,而是依赖于接口。这使得代码更易于解耦,符合面向对象设计原则。 重新设计的DIC/IoC解决方案可能...

Global site tag (gtag.js) - Google Analytics