- 浏览: 794177 次
- 性别:
- 来自: 上海
文章分类
- 全部博客 (651)
- Java (39)
- Java 初学者小问题 (66)
- 设计模式 (7)
- 项目管理 (3)
- 数据库 (1)
- 算法 (2)
- Java practices (6)
- Effective Java2读书笔记 (78)
- Linux (2)
- programming ruby 读书笔记 (5)
- Core Java Ninth Edition Volume I 读书笔记 (15)
- Pro Git 读书笔记 (12)
- Git (3)
- Maven in Action 读书笔记 (20)
- Web (12)
- 非技术类书籍 (11)
- 电影 (40)
- Web Cache (1)
- jquery (0)
- 历史 (4)
- Dive Into HTML5 读书笔记 (13)
- 三国演义小学毕业考 (79)
- 高效能人士的7个习惯 读书笔记 (12)
- Java Performance 读书笔记 (3)
- Protocol Buffer 学习笔记 (6)
- Mongo DB 学习笔记 (7)
- Morphia 学习笔记 (7)
- Algorithms -- Princeton 学习笔记 (13)
- String研究 (10)
- Hadoop: The Definitive Guide 读书笔记 (3)
- Java与模式读书笔记 (5)
- Date研究 (3)
- The Roman Empire 听课笔记 (4)
- Algorithms -- Standford 学习笔记 (16)
- Core Java Ninth Edition Volume II 读书笔记 (9)
- Thinking in Java 4th Edition 读书笔记 (21)
- Node : Up and Running 学习笔记 (5)
- Eloquent Javascript (8)
- Smashing Node.js 读书笔记 (1)
- Algorithms II -- Standford 学习笔记 (19)
- Algorithm II -- Princeton 学习笔记 (14)
- 网络安全 (2)
- Javascript (4)
- 正则表达式 (1)
- JAVA 7/8 (15)
- JVM (10)
- NodeJS (1)
- 鸟哥的linux私房菜读书笔记 (14)
- Web Service (1)
- The art of programming (9)
- Introduction to Algorithm 读书笔记 (4)
- Java 源码阅读 (0)
- Spring in Action 读书笔记 (2)
- Java Network Programming 读书笔记 (2)
最新评论
-
心存高远:
谢谢作者分享,刚好看到这里不太明白,现在茅塞顿开。不过runt ...
关于 Maven的传递依赖的理解 -
sxlkk:
851228082 写道甚至在某次技术会议现场遇到《Maven ...
关于 Maven的传递依赖的理解 -
851228082:
851228082 写道a----compile----b-- ...
第五章 坐标和依赖 -
851228082:
a----compile----b-----provided- ...
第五章 坐标和依赖 -
851228082:
甚至在某次技术会议现场遇到《Maven in action》的 ...
关于 Maven的传递依赖的理解
Qestion:
When should I use Thread.getContextClassLoader()?
Answer:
Although not frequently asked, this question is rather tough to correctly answer. It usually comes up during framework programming, when a good deal of dynamic class and resource loading goes on. In general, when loading a resource dynamically, you can choose from at least three classloaders: the system (also referred to as the application) classloader, the current classloader, and the current thread context classloader. The question above refers to the latter. Which classloader is the right one?
One choice I dismiss easily: the system classloader. This classloader handles -classpath and is programmatically accessible as ClassLoader.getSystemClassLoader(). All ClassLoader.getSystemXXX() API methods are also routed through this classloader. You should rarely write code that explicitly uses any of the previous methods and instead let other classloaders delegate to the system one. Otherwise, your code will only work in simple command-line applications, when the system classloader is the last classloader created in the JVM. As soon as you move your code into an Enterprise JavaBean, a Web application, or a Java Web Start application, things are guaranteed to break.
So, now we are down to two choices: current and context classloaders. By definition, a current classloader loads and defines the class to which your current method belongs. This classloader is implied when dynamic links between classes resolve at runtime, and when you use the one-argument version of Class.forName(), Class.getResource(), and similar methods. It is also used by syntactic constructs like X.class class literals (see "Get a Load of That Name!" for more details).
Thread context classloaders were introduced in Java 2 Platform, Standard Edition (J2SE). Every ThreadThread.setContextClassLoader() method. If you don't invoke this method following a Thread's construction, the thread will inherit its context classloader from its parent Thread. If you don't do anything at all in the entire application, all Threads will end up with the system classloader as their context classloader. It is important to understand that nowadays this is rarely the case since Web and Java 2 Platform, Enterprise Edition (J2EE) application servers utilize sophisticated classloader hierarchies for features like Java Naming and Directory Interface (JNDI), thread pooling, component hot redeployment, and so on. has a context classloader associated with it (unless it was created by native code). It is set via the
Why do thread context classloaders exist in the first place? They were introduced in J2SE without much fanfare. A certain lack of proper guidance and documentation from Sun Microsystems likely explains why many developers find them confusing.
In truth, context classloaders provide a back door around the classloading delegation scheme also introduced in J2SE. Normally, all classloaders in a JVM are organized in a hierarchy such that every classloader (except for the primordial classloader that bootstraps the entire JVM) has a single parent. When asked to load a class, every compliant classloader is expected to delegate loading to its parent first and attempt to define the class only if the parent fails
Sometimes this orderly arrangement does not work, usually when some JVM core
code must dynamically load resources provided by application developers. Take
JNDI for instance: its guts are implemented by bootstrap classes in
rt.jar
(starting with J2SE 1.3), but these core JNDI classes may
load JNDI providers implemented by independent vendors and potentially deployed
in the application's -classpath
. This scenario calls for a parent
classloader (the primordial one in this case) to load a class visible to one of
its child classloaders (the system one, for example). Normal J2SE delegation
does not work, and the workaround is to make the core JNDI classes use thread
context loaders, thus effectively "tunneling" through the classloader hierarchy
in the direction opposite to the proper delegation.
By the way, the previous paragraph may have reminded you of something else: Java API for XML Parsing (JAXP). Yes, when JAXP was just a J2SE extension, the XML parser factories used the current classloader approach for bootstrapping parser implementations. When JAXP was made part of the J2SE 1.4 core, the classloading changed to use thread context classloaders, in complete analogy with JNDI (and confusing many programmers along the way). See what I mean by lack of guidance from Sun?
After this introduction, I have come to the crux of the matter: neither of
the remaining two choices is the right one under all circumstances. Some believe
that thread context classloaders should become the new standard strategy. This,
however, creates a very messy classloading picture if various JVM threads
communicate via shared data, unless all of them use the same context loader
instance. Furthermore, delegating to the current classloader is already a legacy
rule in some existing situations like class literals or explicit calls to
Class.forName()
(which is why, by the way, I recommend (again, see
"Get
a Load of That Name!
") avoiding the one-argument version of this method).
Even if you make an explicit effort to use only context loaders whenever you
can, there will always be some code not under your control that delegates to the
current loader. This uncontrolled mixing of delegation strategies sounds rather
dangerous.
To make matters worse, certain application servers set context and current
classloaders to different
ClassLoader
instances that have
the same
classpaths and yet are not related as a delegation parent
and child
. Take a second to think about why this is particularly
horrendous. Remember that the classloader that loads and defines a class is part
of the internal JVM's ID for that class. If the current classloader loads a
class X
that subsequently executes, say, a JNDI lookup for some
data of type Y
, the context loader could load and define
Y
. This Y
definition will differ from the one by the
same name but seen by the current loader. Enter obscure class cast and loader
constraint violation exceptions.
This confusion will probably stay with Java for some time. Take any J2SE API with dynamic resource loading of any kind and try to guess which loading strategy it uses. Here is a sampling:
- JNDI uses context classloaders
-
Class.getResource()
andClass.forName()
use the current classloader - JAXP uses context classloaders (as of J2SE 1.4)
-
java.util.ResourceBundle
uses the caller's current classloader -
URL protocol handlers specified via
java.protocol.handler.pkgs
system property are looked up in the bootstrap and system classloaders only - Java Serialization API uses the caller's current classloader by default
Those class and resource loading strategies must be the most poorly documented and least specified area of J2SE.
What is a Java programmer to do?
If your implementation is confined to a certain framework with articulated
resource loading rules, stick to them. Hopefully, the burden of making them work
will be on whoever has to implement the framework (such as an application server
vendor, although they don't always get it right either). For example, always use
Class.getResource()
in a Web application or an Enterprise JavaBean.
In other situations, you might consider using a solution I have found useful in personal work. The following class serves as a global decision point for acquiring the best classloader to use at any given time in the application (all classes shown in this article are available with the download ):
public abstract class ClassLoaderResolver
{
/**
* This method selects the best classloader instance to be used for
* class/resource loading by whoever calls this method. The decision
* typically involves choosing between the caller's current, thread context,
* system, and other classloaders in the JVM and is made by the {@link IClassLoadStrategy}
* instance established by the last call to {@link #setStrategy}.
*
* @return classloader to be used by the caller ['null' indicates the
* primordial loader]
*/
public static synchronized ClassLoader getClassLoader ()
{
final Class caller = getCallerClass (0);
final ClassLoadContext ctx = new ClassLoadContext (caller);
return s_strategy.getClassLoader (ctx);
}
public static synchronized IClassLoadStrategy getStrategy ()
{
return s_strategy;
}
public static synchronized IClassLoadStrategy setStrategy (final IClassLoadStrategy strategy)
{
final IClassLoadStrategy old = s_strategy;
s_strategy = strategy;
return old;
}
/**
* A helper class to get the call context. It subclasses SecurityManager
* to make getClassContext() accessible. An instance of CallerResolver
* only needs to be created, not installed as an actual security
* manager.
*/
private static final class CallerResolver extends SecurityManager
{
protected Class [] getClassContext ()
{
return super.getClassContext ();
}
} // End of nested class
/*
* Indexes into the current method call context with a given
* offset.
*/
private static Class getCallerClass (final int callerOffset)
{
return CALLER_RESOLVER.getClassContext () [CALL_CONTEXT_OFFSET +
callerOffset];
}
private static IClassLoadStrategy s_strategy; // initialized in <clinit>
private static final int CALL_CONTEXT_OFFSET = 3; // may need to change if this class is redesigned
private static final CallerResolver CALLER_RESOLVER; // set in <clinit>
static
{
try
{
// This can fail if the current SecurityManager does not allow
// RuntimePermission ("createSecurityManager"):
CALLER_RESOLVER = new CallerResolver ();
}
catch (SecurityException se)
{
throw new RuntimeException ("ClassLoaderResolver: could not create CallerResolver: " + se);
}
s_strategy = new DefaultClassLoadStrategy ();
}
} // End of class.
You acquire a classloader reference by calling the
ClassLoaderResolver.getClassLoader()
static method and use the
result to load classes and resources via the normal
java.lang.ClassLoader
API. Alternatively, you can use this
ResourceLoader
API as a drop-in replacement for
java.lang.ClassLoader
:
public abstract class ResourceLoader
{
/**
* @see java.lang.ClassLoader#loadClass(java.lang.String)
*/
public static Class loadClass (final String name)
throws ClassNotFoundException
{
final ClassLoader loader = ClassLoaderResolver.getClassLoader (1);
return Class.forName (name, false, loader);
}
/**
* @see java.lang.ClassLoader#getResource(java.lang.String)
*/
public static URL getResource (final String name)
{
final ClassLoader loader = ClassLoaderResolver.getClassLoader (1);
if (loader != null)
return loader.getResource (name);
else
return ClassLoader.getSystemResource (name);
}
... more methods ...
} // End of class
The decision of what constitutes the best classloader to use is factored out
into a pluggable component implementing the IClassLoadStrategy
interface:
public interface IClassLoadStrategy
{
ClassLoader getClassLoader (ClassLoadContext ctx);
} // End of interface
To help IClassLoadStrategy
make its decision, it is given a
ClassLoadContext
object:
public class ClassLoadContext
{
public final Class getCallerClass ()
{
return m_caller;
}
ClassLoadContext (final Class caller)
{
m_caller = caller;
}
private final Class m_caller;
} // End of class
ClassLoadContext.getCallerClass()
returns the class whose code
calls into ClassLoaderResolver
or ResourceLoader
. This
is so that the strategy implementation can figure out the caller's classloader
(the context loader is always available as
Thread.currentThread().getContextClassLoader()
). Note that the
caller is determined statically; thus, my API does not require existing business
methods to be augmented with extra Class
parameters and is suitable
for static methods and initializers as well. You can augment this context object
with other attributes that make sense in your deployment situation.
All of this should look like a familiar Strategy design pattern to you. The idea is that decisions like "always context loader" or "always current loader" get separated from the rest of your implementation logic. It is hard to know ahead of time which strategy will be the right one, and with this design, you can always change the decision later.
I have a default strategy implementation that should work correctly in 95 percent of real-life situations:
public class DefaultClassLoadStrategy implements IClassLoadStrategy
{
public ClassLoader getClassLoader (final ClassLoadContext ctx)
{
final ClassLoader callerLoader = ctx.getCallerClass ().getClassLoader ();
final ClassLoader contextLoader = Thread.currentThread ().getContextClassLoader ();
ClassLoader result;
// If 'callerLoader' and 'contextLoader' are in a parent-child
// relationship, always choose the child:
if (isChild (contextLoader, callerLoader))
result = callerLoader;
else if (isChild (callerLoader, contextLoader))
result = contextLoader;
else
{
// This else branch could be merged into the previous one,
// but I show it here to emphasize the ambiguous case:
result = contextLoader;
}
final ClassLoader systemLoader = ClassLoader.getSystemClassLoader ();
// Precaution for when deployed as a bootstrap or extension class:
if (isChild (result, systemLoader))
result = systemLoader;
return result;
}
... more methods ...
} // End of class
The logic above should be easy to follow. If the caller's current and context classloaders are in a parent-child relationship, I always choose the child. The set of resources visible to a child loader is normally a superset of classes visible to its parent, so this feels like the right decision as long as everybody plays by J2SE delegation rules.
It is when the current and the context classloaders are siblings that the right decision is impossible. Ideally, no Java runtime should ever create this ambiguity. When it happens, my code chooses the context loader: a decision based on personal experience of when things work correctly most of the time. Feel free to change that code branch to suit your taste. It is possible that the context loader is a better choice for framework components, and the current loader is better for business logic.
Finally, a simple check ensures that the selected classloader is not a parent of the system classloader. This is a good thing to do if you are developing code that might be deployed as an extension library.
Note that I intentionally do not look at the name of resources or classes that will be loaded. If nothing else, the experience with Java XML APIs becoming part of the J2SE core should have taught you that filtering by class names is a bad idea. Nor do I trial load classes to see which classloader succeeds first. Examining classloader parent-child relationships is a fundamentally better and more predictable approach.
Although Java resource loading remains an esoteric topic, J2SE relies on various load strategies more and more with every major platform upgrade. Java will be in serious trouble if this area is not given some significantly better design considerations. Whether you agree or not, I would appreciate your feedback and any interesting pointers from your personal design experience.
This article originates from http://www.javaworld.com/javaworld/javaqa/2003-06/01-qa-0606-load.html?page=1
发表评论
-
Zz The java.lang.LinkageError: loader constraint violation" demystified
2014-05-13 19:24 1508http://frankkieviet.blogspot.c ... -
zz Java NIO 系列教程
2014-05-09 22:38 1159http://www.iteye.com/magazines ... -
Zz Java NIO Tutorial
2014-05-09 22:34 1775http://tutorials.jenkov.com/ja ... -
Zz Spring IOC 好处和劣势
2014-03-28 18:06 1069IoC是什么? Inversion of Contro ... -
Zz ConcurrentHashMap源码解析
2014-03-16 17:29 664ConcurrentHashMap是Java 5中支持高并发 ... -
Zz Java多线程之ConcurrentHashMap深入分析
2014-03-16 14:50 1180一、Map体系 Hashtable是JDK ... -
Zz ConcurrentHashMap原理分析
2014-03-16 14:03 1125集合是编程中最常用的数据结构。而谈到并发,几乎总是离不开集合 ... -
Zz Java并发编程之ConcurrentHashMap
2014-03-16 13:40 2065ConcurrentHashMap Concurrent ... -
关于ConcurrentHashMap 中位移的问题
2014-03-16 14:33 1260拜读了GoldenDoc的大作:《Java并发编程之Con ... -
ConcurrentHashMap 详解
2014-03-15 21:19 01. ConcurrentHashMap 可以做到读取数 ... -
Why java Arrays use two different sort algorithms for different types?
2014-02-25 22:09 1298Java 7 uses Dual-Pivot Quicks ... -
深入探讨 java.lang.ref 包
2014-02-25 19:58 1090回顾了一下三年多前写的文章https://www.i ... -
Zz Java 中使用内存映射文件需要考虑的 10 个问题
2014-02-09 17:18 944java中的内存映射IO和内存映射文件是什么? 内存 ... -
Zz 10 Things to Know about Memory Mapped File in Java
2014-02-09 17:16 628What is Memory Mapped File ... -
Zz Direct vs non-direct ByteBuffer
2014-02-08 12:46 846先解释一下两者的区 ... -
Zz direct buffer VS non-direct buffer
2014-02-08 10:55 864在java NIO中,有两种不同的buffer:direct ... -
Java Generics 小结
2013-03-07 14:12 01. 泛型类型或泛型类 ... -
关于 Java正则表达式中的Possessive数量修饰词的理解
2013-02-26 21:14 1283正则表达式对于数量限定符如 ?, + , *, {n, m ... -
Run Application in debug mode
2013-01-23 13:59 1308Q: I use the Eclipse IDE to de ... -
一个 Dynamic Proxy 的例子
2012-11-22 11:18 1231最近翻出了两年前老吴让我写的一个MockFacotry , ...
相关推荐
- **加载类**:编译完成后,使用自定义ClassLoader的findClass方法加载编译后的类。 **3. 示例代码框架** ```java public class AutoCompileClassLoader extends ClassLoader { // 定义加载类的方法 @Override ...
创建自定义Classloader需要继承java.lang.ClassLoader类,并重写其关键方法,如`findClass(String name)`或`loadClass(String name)`。这两个方法分别用于查找指定类的字节码和实际加载类。在`findClass`中,我们...
1. 如果WebApp ClassLoader的缓存中没有类A,则会查找System ClassPath,未找到A。 2. 接下来查找Application Class Path,如果在其中找到了A(如在wsdl4j.jar中),则加载该类。 3. 如果Application Class Path也...
### Java虚拟机中ClassLoader概述与双亲委托机制详解 #### 一、ClassLoader概念与作用 在Java编程语言中,`ClassLoader`是一个非常重要的组件,它负责加载程序运行所需的类文件到Java虚拟机(JVM)中。`ClassLoader`...
- 自定义ClassLoader通常需要重写`loadClass()`方法,该方法在找不到类时调用`findClass()`进行实际的加载操作。 - 在`ClassLoaderDemo`这个例子中,可能就展示了如何创建一个自定义的ClassLoader,从非标准位置...
Java ClassLoader是Java运行时系统的关键但经常被忽视的组件,负责在运行时查找和加载类文件。通过创建自定义ClassLoader,你可以定制JVM,使类文件的引入方式完全重新定义,这提供了很多实用和有趣的可能。这篇教程...
在自定义ClassLoader时,主要需要覆写两个关键方法:`findClass()` 和 `loadClass()`。`loadClass()` 方法通常用于委托父类加载器加载类,如果父类加载器无法加载,再由当前类加载器尝试加载。`findClass()` 方法则...
在Java编程语言中,ClassLoader是一个至关重要的组成部分,它负责加载类到JVM(Java虚拟机)中。理解ClassLoader的工作原理以及如何定制它,对于深入学习Java的运行机制和进行高级应用开发具有重要意义。本篇文章将...
自定义ClassLoader通常需要重写findClass()或loadClass()方法,以控制类的加载行为。 理解ClassLoader的工作原理对于排查类冲突、处理依赖关系以及优化大型J2EE应用的性能具有重要意义。开发者可以通过日志输出、...
本文档提到的“编译时类加载器”(The Compiling ClassLoader)实际上是指在加载类的同时执行编译操作的类加载器。这种类型的类加载器可以实现在运行时自动编译源代码,并将生成的字节码加载到JVM中。这种能力对于...
自定义ClassLoader需要继承`java.lang.ClassLoader`类,并重写`findClass()`或`loadClass()`方法。通过这两个方法,你可以控制类的加载来源和方式。 在实际开发中,理解ClassLoader机制可以帮助解决一些问题,例如...
java虚拟机的运行机理的详细介绍 Inside the Java Virtual Machine Bill Venners $39.95 0-07-913248-0 Inside the Java Virtual ... Slices of Pi: A Simulation of the Java Virtual Machine Index About the Author
《深入理解ClassLoader工作机制》 Java虚拟机(JVM)中的ClassLoader是负责加载类到内存中的核心组件。它不仅承担着将字节码转换为可执行对象的重任,还参与了类生命周期的各个阶段,包括加载、验证、准备、解析、...
首先,ClassLoader可以分为三种基本类型:Bootstrap ClassLoader、Extension ClassLoader和Application ClassLoader。Bootstrap ClassLoader是JVM启动时的第一个ClassLoader,负责加载JDK的`<JAVA_HOME>\lib`目录下...
Java ClassLoader机制是Java虚拟机(JVM)中一个至关重要的组成部分,它的主要任务是将类的.class文件加载到JVM中,使得程序能够运行。ClassLoader不仅负责类的加载,还涉及类的验证、初始化等一系列过程。理解...
在Java编程语言中,ClassLoader是核心组件之一,它负责加载类到JVM(Java虚拟机)中执行。本文将深入探讨ClassLoader的工作原理和类加载机制,帮助开发者理解这个至关重要的概念。 1. 类加载机制概述 Java的类加载...