类加载器的收获
最近读了很多关于ClassLoader的文章,收获不少。在这里赶紧总结回顾一下,吸收吸收。
首先,关于ClassLoader的一些基本的概念我就不再详细说了。如果连系统中不仅有一个ClassLoader,ClassLoader的作用,ClassLoader是有层次结构,为什么要有自定义类加载器,这些问题都还不明白,那么下文读起来肯定很吃力。
ClassLoader这个东西本身是很简单的,就是加载类。类加载分两步,一步是定义和加载,对应着ClassLoader的loadClass(define)方法,这个方法的作用是找到对应的Class文件,读取后,创建一个为这个类创建一个Class类的实例,并对字节码进行三遍验证;一个是初始化,这个进行的操作是将类的符号引用进行验证,对依赖的类进行加载,并且执行各种初始化方法(比如类中的static块)。经过这两步后,才能够真正的去使用一个类(调用方法、访其各个字段、创建对象等)。
ClassLoader之所以变的复杂,是因为在实际运用因为其层次关系和寻找的类路径不同而发生混淆。这主要发生在App Server上和一些使用代理的应用上。
这里有几点常识要提醒一下自己:
l 一个类在JVM中的类型是由类的全限定名+其所在的类加载器共同确定的。有一个不一样,JVM也会认为它们不是一个类,那么强制类型转换的时候就会出错。
l 每个 ClassLoader都有一个唯一的父ClassLoader,每次需要加载一个类的时候,使用委托的方式回溯递归到最根的ClassLoader(也就是启动类加载器,专门加载java核心类的),然后一层层的尝试去加载,也就是说,最先调用 loadClass的ClassLoader是最后一个去加载它的。
l 每个ClassLoader都有一个已经加载了的类的列表,基于以下两个事实:已经被一个ClassLoader加载了的类是不会这个ClassLoader被二次加载的;类加载采用委托模式。那么,子ClassLoader能够看到父ClassLoader和它自己加载的类,而无法看到其子ClassLoader和兄ClassLoader加载的类,这就是混淆的关键。
l 并不是调用loadClass(MyClass)的那个类加载器加载了MyClass类,而是那个读取到了MyClass字节码并在调用defineClass的时候将这个字节码流作为参数传递,的ClassLoader加载了MyClass类,MyClass将保存在那个ClassLoader的已加载类列表中。
l 哪个ClassLoader会去主动加载一个类呢?Java规范规定,当执行代码段A的时候,如果需要加载一个类B,那么,就由加载A的ClassLoader去加载B。一段代码总要属于一个类吧,一个类总要被一个ClassLoader加载的吧,那么好了,加载关系弄清楚了^_^。
有几种情况下我们需要注意ClassLoader的作用:
l 一个典型的App Server会为每一个应用创建一个ClassLoader,这样,每个应用的ClassLoader是兄弟关系,那么他们彼此之间加载的类信息是不可共享的,也就避免了应用间造成类使用混乱(尤其是在不同应用要使用不同版本的jar包时)。
l 还有就是各种应用接口的使用。如果需要动态的从数据源(比如说数据库、本地磁盘、网络、内存等)加载一个类,最好的方法是让这个类实现一个接口,将这个接口的class文件放在classpath目录下(或者别的目录,但是一定要保证这个类对AppClassLoader是可见的,这点很重要)然后用这个接口的引用指向这个类创建的实例。为什么要这么做呢?如果不这么做的话,你在程序中就只能够通过反射来访问这个动态记载的类的各种方法和字段了!为什么呢?因为AppClassLoader及其父ClassLoader无法加载这个你从自定义数据源加载的类,也就是说,在主程序中,根本就不知道这个自定义加载的类是什么,那么,就算你通过一些方法使得类编译通过,那么在运行时也会报错(ClassNotFoundException)。
l 上面的问题还有一个问题没有解决,就是如何在程序中创建ClassLoader并指定让它加载我们自定义的类呢?这里牵扯到一个争论很多的问题:Class.forName(String classNmae)和Thread.currentThread().getContextClassLoader().loadClass(String classNmae)应该用哪个?哪个更好?关于这个,javaworld上有篇文章论述的非常好,叫做“Get a load of that name! ”,还有“Find a way out of the ClassLoader maze”对之也有很精妙的说明。在这里我说一下自己的认识。前者(Class.forName(String classNmae))其就是使用调用Class.forName 这个方法的类的ClassLoader去加载classNmae 这个类(这话说起来好别扭-_-!)。举例来说:如果A类在way方法中有一行是Class.forName(”XXXX”),那么,forName方法会通过一个本地方法(Native Method)获得加载其调用者(也就是A类)的类加载器,然后用这个类加载器去加载XXXX类。后者(Thread.currentThread().getContextClassLoader().loadClass(String classNmae))其实是使用当前线程使用的ClassLoader去装载类。这个ClassLoader是在线程被创建的时候设置进去的,默认是继承父线程的ContextClassLoader这个值。这个问题搞清楚以后,就简单了,你可以按照自己的实际情况使用两者之一在程序中加载类。
l 关于类的更新。其实这里才是我关心ClassLoader的最初原因。一个类在被一个ClassLoader加载后,是不能够被更新或者卸载的。在Tomcat中,更新一个Servlet是通过创建一个新的ClassLoader,然后加载来实现的。同时Tomcat对应用中自定义的类也可以更新,但是这种更新的实现机制我还没有搞清楚,期望有和人讨论一下Tomcat的这个实现,我的msn是DeepNightTwo@hotmail.com。这个问题欢迎大家来讨论http://www.jdon.com/jive/thread.jsp?forum=16&thread=27932,
总的感觉:类加载器很简单,就好像画个横线很简单一样。但是怎么画在哪里画用什么画,都是问题。
分享到:
相关推荐
这一周的实习让我对JAVA开发有了更深入的理解,特别是对Java虚拟机(JVM)和类加载器(ClassLoader)机制有了初步的认识。 Java虚拟机是Java语言运行的基础,它负责管理程序的内存空间,包括堆内存、栈内存、方法区...
这份PDF可能涵盖了预加载器的工作原理、如何创建自定义预加载器以及优化加载过程的策略等内容。预加载器的实现通常涉及到ActionScript编程,特别是ActionScript 2或3,这取决于 Flash的版本。 `classes`文件可能是...
类加载过程包括加载、验证、准备、解析、初始化等阶段,类加载器负责从文件系统或网络中加载Class文件到内存中。Java类加载器采用双亲委派模型,确保了Java核心库的类型安全。OSGi是一种基于Java的动态模块化系统,...
5. **理解类加载器**:OSGi的类加载机制与传统的Java类加载不同,它基于命名空间和bundle的隔离。源码中会包含如何管理类加载器和解决类冲突的实例。 6. **安全模型**:OSGi提供了细粒度的安全控制,每个bundle都...
JVM篇开始讨论了类加载器的双亲委派模型机制,这是一种类加载机制,保证了Java平台的安全性。破坏双亲委派模型的例子包括JDK1.0时就存在的DriverManager加载Driver的情况。 #### JVM运行时数据区分配内存 接着文档...
源码中展示了如何加载、验证、准备、解析和初始化类的过程,以及类加载器之间的关系。 5. **性能监控和调试工具**: Hotspot源码包含了丰富的性能监控和调试工具,如JConsole、VisualVM等,它们提供CPU、内存、...
4. 类加载系统:Java的类加载是动态的,源码中可以学习到类加载器如何工作,以及类加载的双亲委托模型。 5. 锁优化:HotSpot对锁进行了许多优化,如偏向锁、轻量级锁和重量级锁,以提升多线程环境下的性能。 通过对...
在技术学习方面,工程师特别提到了Java虚拟机(JVM)和类加载器(ClassLoader)机制的重要性。Java虚拟机是Java程序运行的基础,它负责管理内存和执行字节码。ClassLoader机制则确保在程序运行时,根据需要动态加载...
2. **选择器的使用**:选择器是CSS的核心,包括元素选择器(如`p`)、类选择器(如`.myClass`)、ID选择器(如`#myID`)以及更复杂的选择器组合,如后代选择器(`div p`)、相邻兄弟选择器(`h1 + p`)等。...
- 控制器类(Controller):处理用户的搜索请求,调用模型并更新视图。 - 模型类(Model):执行数据库查询或其他数据获取操作,返回搜索建议。 - 视图(View):HTML模板文件,显示搜索框和搜索建议列表。 - 脚本...
- **动态加载类**:在编译时无法确定类名的情况下,可以通过字符串形式的类名动态加载类。 - **运行时检查**:可以在运行时检查类的结构,包括方法、字段、构造器等信息。 - **运行时动态调用方法**:即使在编写...
4. **`ProgressDialog`或`ProgressFragment`**:在Activity切换或加载数据时,可以使用`ProgressDialog`显示一个模态对话框,或者在Material Design风格的应用中使用`ProgressFragment`,来提供一个加载指示器,增强...
8. **类加载器**:Tomcat有自己独特的类加载机制,以解决不同应用之间的类冲突。源码中的`classloader`目录揭示了这一机制。 9. **错误处理与日志系统**:Tomcat使用自定义的日志框架,源码中`logging`目录下的类...
环境变量是操作系统中存储信息的一种方式,这些信息可以被进程访问,如路径(PATH)、库加载器(LD_PRELOAD)等。实验中,学生通过`printenv`和`env`命令查看环境变量,然后通过`export`和`unset`来设置和删除它们。...
在PyTorch中,你可以通过定义`nn.Module`类来创建自定义的神经网络结构,而`autograd`模块则负责计算梯度,实现自动微分。 接着,我们将深入迁移学习,讲解预训练模型的工作原理和如何在PyTorch中加载和使用这些...
10. **JVM优化**:了解JVM的内存结构,理解如何进行性能调优,包括JVM参数设置、类加载机制、垃圾回收策略等。 11. **设计模式**:了解并能应用单例、工厂、观察者、装饰者、适配器、代理、模板等常见设计模式。 ...
1. **Action类与控制器**:`indexAction.class`是ThinkPHP中的一个默认控制器类,通常用于定义页面的操作方法。每个方法对应一个页面,通过URL访问时,方法名即为请求的ACTION。例如,`/index.php?m=Index&a=index`...
19. **Java虚拟机(JVM)**:概述JVM的工作原理,类加载机制,以及JVM调优的方法。 通过学习这些内容,你可以掌握Java编程的基础,为进一步学习Java高级特性、框架(如Spring、Hibernate)以及分布式开发(如微服务...
8. **资源管理**:游戏可能包含大量的图片、声音和其他资源,ActionScript中的Loader类可以帮助加载和管理这些资源。 9. **错误处理**:良好的代码应该包含适当的错误处理机制,如try-catch语句,以确保程序在遇到...
在编程领域,设计模式是一种被广泛认可的解决特定软件设计问题的最佳实践。它们是经过验证的、可重用的解决方案,适用于在...记得实践是检验真理的唯一标准,动手尝试并结合自己的项目去应用这些模式,你会收获更多。