1
0

Added tech guide. This provides introductions to subjects such as classloading for expert users and developers.

git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/logging/trunk@157339 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Robert Burrell Donkin
2005-03-13 16:21:42 +00:00
parent 0721445959
commit 80ed7615b6
3 changed files with 586 additions and 0 deletions

579
xdocs/tech.xml Normal file
View File

@@ -0,0 +1,579 @@
<?xml version="1.0"?>
<!--
Copyright 2001-2004 The Apache Software Foundation.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<document>
<properties>
<title>JCL Technology Guide</title>
<author email="commons-dev@jakarta.apache.org">Commons Documentation Team</author>
</properties>
<body>
<section name='Overview'>
<subsection name='Contents'>
<ul>
<li>
Overview
<ul>
<li>
Contents
</li>
<li>
<a href='#Introduction'>Introduction</a>
</li>
</ul>
</li>
<li>
<a href='#A Short Introduction to Class Loading and Class Loaders'>
A Short Introduction to Class Loading and Class Loaders
</a>
<ul>
<li>
<a href='#Preamble'>
Preamble
</a>
</li>
<li>
<a href='#Resolution Of Symbolic References'>
Resolution Of Symbolic References
</a>
</li>
<li>
<a href='#Loading'>
Loading
</a>
</li>
<li>
<a href='#Linking'>
Linking
</a>
</li>
<li>
<a href='#Loading Classes'>
Loading Classes
</a>
</li>
<li>
<a href='#Bootstrap Classloader'>
Bootstrap Classloader
</a>
</li>
<li>
<a href='#Runtime Package'>
Runtime Package
</a>
</li>
<li>
<a href='#Loader Used To Resolve A Symbolic Reference'>
Loader Used To Resolve A Symbolic Reference
</a>
</li>
<li>
<a href='#Bibliography'>
Bibliography
</a>
</li>
</ul>
</li>
<li>
<a href='#A Short Guide To Hierarchical Class Loading'>
A Short Guide To Hierarchical Class Loading
</a>
<ul>
<li>
<a href='#Delegating Class Loaders'>
Delegating Class Loaders
</a>
</li>
<li>
<a href='#Parent-First And Child-First Class Loaders'>
Parent-First And Child-First Class Loaders
</a>
</li>
<li>
<a href='#Class ClassLoader'>
Class ClassLoader
</a>
</li>
<li>
<a href='#Context ClassLoader'>
Context ClassLoader
</a>
</li>
<li>
<a href='#Issues with Context ClassLoaders'>
Issues with Context ClassLoaders
</a>
</li>
<li>
<a href='#J2EE Context Classloaders'>
J2EE Context Classloaders
</a>
</li>
<li>
<a href='#Reflection And The Context ClassLoader'>
Reflection And The Context ClassLoader
</a>
</li>
<li>
<a href='#More Information'>
More Information
</a>
</li>
</ul>
</li>
<li>
<a href='#A Short Theory Guide To JCL'>
A Short Theory Guide To JCL
</a>
<ul>
<li>
<a href='#Isolation And The Context Class Loader'>
Isolation And The Context Class Loader
</a>
</li>
<li>
<a href='#Log And LogFactory'>
Log And LogFactory
</a>
</li>
<li>
<a href='#Log Implementations'>
Log Implementations
</a>
</li>
<li>
<a href='#Using Reflection To Load Log Implementations'>
Using Reflection To Load Log Implementations
</a>
</li>
</ul>
</li>
</ul>
</subsection>
<subsection name='Introduction'>
<p>
This guide is aimed at describing the technologies that JCL developers and expert users
(and users who need to become experts)
should be familiar with. The aim is to give an understanding whilst being precise but brief.
Details which are not relevent for JCL have been suppressed.
References have been included.
</p>
<p>
These topics are a little difficult and it's easy for even experience developers to make
mistakea. We need you to help us get it right! Please submit corrections, comments, additional references
and requests for clarification
by either:
</p>
<ul>
<li>
posting to the <a href='http://jakarta.apache.org/site/mail.html'>jakarta commons-dev mailing list</a> or
</li>
<li>
creating an issue in <a href='http://issues.apache.org/bugzilla'>Bugzilla</a>.
</li>
</ul>
<p>
TIA
</p>
</subsection>
</section>
<section name='A Short Introduction to Class Loading and Class Loaders'>
<subsection name='Preamble'>
<p>
This is intended to present a guide to the process by which Java bytecode uses bytecode in other classes
from the perspective of the language and virtual machine specifications. The focus will be on deciding
which bytecode will be used (rather than the mechanics of the usage). It focusses on facts and terminology.
</p>
<p>
The process is recursive: it is therefore difficult to pick a starting point.
Sun's documentation starts from the persective of the startup of a new application.
This guide starts from the perspective of an executing application.
</p>
<p>
During this discussion, please assume that each time that <em>class</em> is mentioned,
the comments applied equally well to interfaces.
</p>
<p>
This document is targeted at Java 1.2 and above.
</p>
</subsection>
<subsection name='Resolution Of Symbolic References'>
<p>
(<a href='http://java.sun.com/docs/books/jls/second_edition/html/execution.doc.html#44524'>LangSpec 12.3.3</a>)
The bytecode representation of a class contains symbolic names for other classes referenced.
</p>
<p>
<em>
In practical development terms: If a class is imported (either explicitly in the list of imports at the top of
the source file or implicitly through a fully qualified name in the source code) it is referenced symbolically.
</em>
</p>
<p>
(<a href='http://java.sun.com/docs/books/vmspec/2nd-edition/html/ConstantPool.doc.html#73492'>VMSpec 5.4.3</a>)
Resolution of a symbolic reference occurs dymanically at runtime and is carried out by
the Java Vitual Machine. Resolution of a symbolic reference requires loading and linking of the new class.
</p>
<p>
<em>
Note: references are not statically resolved at compile time.
</em>
</p>
</subsection>
<subsection name='Loading'>
<p>
(<a href='http://java.sun.com/docs/books/vmspec/2nd-edition/html/Concepts.doc.html#19175'>VMSpec 2.17.2</a>)
Loading is the name given process by which a binary form of a class is obtained
by the Java Virutal Machine.
Java classes are always loaded and linked dynamically by the Java Virtual Machine
(rather than statically by the compiler).
</p>
<p>
<em>
In practical development terms:
This means that the developer has no certain knowledge about the actual
bytecode that will be used to execute any external call (one made outside the class). This is determined only
at execution time and is effected by the way that the code is deployed.
</em>
</p>
</subsection>
<subsection name='Linking'>
<p>
(<a href='http://java.sun.com/docs/books/vmspec/2nd-edition/html/Concepts.doc.html#22574'>VMSpec 2.17.3</a>)
Linking is the name used for combining the
binary form of a class into the Java Virtual Machine. This must happen before the class can be used.
</p>
<p>
(<a href='http://java.sun.com/docs/books/vmspec/2nd-edition/html/Concepts.doc.html#22574'>VMSpec 2.17.3</a>)
Linking is composed of verification, preparation and resolution (of symbolic references).
Flexibility is allowed over the timing of resolution. (Within limit) this may happen at any time after
preparation and before that reference is used.
</p>
<p>
<em>
In practical development terms: This means that different JVMs may realize that a reference cannot be
resolved at different times during execution. Consequently, the actual behaviour cannot be precisely predicted
without intimate knowledge of the JVM (on which the bytecode will be executed).
This makes it hard to give universal guildance to users.
</em>
</p>
</subsection>
<subsection name='Loading Classes'>
<p>
(<a href='http://java.sun.com/docs/books/vmspec/2nd-edition/html/Concepts.doc.html#19175'>VMSpec 2.17.2</a>)
The loading process is performed by a <code>ClassLoader</code>.
</p>
<p>
(<a href='http://java.sun.com/docs/books/vmspec/2nd-edition/html/ConstantPool.doc.html#72007'>VMSpec 5.3</a>)
A classloader may create a class either by delegation or by defining it directly.
The classloader that initiates loading of a class is known as the initiating loader.
The classloader that defines the class is known as the defining loader.
</p>
<p>
<em>
In practical terms: understanding and appreciating this distinction is crucial when debugging issues
concerning classloaders.
</em>
</p>
</subsection>
<subsection name='Bootstrap Classloader'>
<p>
(<a href='http://java.sun.com/docs/books/vmspec/2nd-edition/html/ConstantPool.doc.html#72007'>VMSPEC 5.3</a>)
The bootstrap is the base <code>ClassLoader</code> supplied by the Java Virtual Machine.
All others are user (also known as application) <code>ClassLoader</code>'s.
</p>
<p>
<em>
In practical development terms: The System classloader returned by <code>Classloader.getSystemClassLoader()</code>
will be either the bootstrap classloader or a direct descendent of the bootstrap classloader.
Only when debugging issues concerning the system classloader should there be any need to consider the detailed
differences between the bootstrap classloader and the system classloader.
</em>
</p>
</subsection>
<subsection name='Runtime Package'>
<p>
(<a href='http://java.sun.com/docs/books/vmspec/2nd-edition/html/ConstantPool.doc.html#72007'>VMSpec 5.3</a>)
At runtime, a class (or interface) is determined by it's fully qualified name
and by the classloader that defines it. This is known as the class's runtime package.
</p>
<p>
(<a href='http://java.sun.com/docs/books/vmspec/2nd-edition/html/ConstantPool.doc.html#75929'>VMSpec 5.4.4</a>)
Only classes in the same runtime package are mutually accessible.
</p>
<p>
<em>
In practical development terms: two classes with the same symbolic name can only be used interchangably
if they are defined by the same classloader. A classic symptom indicative of a classloader issue is that
two classes with the same fully qualified name are found to be incompatible during a method call.
This may happen when a member is expecting an interface which is (seemingly) implemented by a class
but the class is in a different runtime package after being defined by a different classloader. This is a
fundemental java language security feature.
</em>
</p>
</subsection>
<subsection name='Loader Used To Resolve A Symbolic Reference'>
<p>
(<a href='http://java.sun.com/docs/books/vmspec/2nd-edition/html/ConstantPool.doc.html#72007'>VMSpec 5.3</a>)
The classloader which defines the class (whose reference is being resolved) is the one
used to initiate loading of the class referred to.
</p>
<p>
<em>
In practial development terms: This is very important to bear in mind when trying to solve classloader issues.
A classic misunderstanding is this: suppose class A defined by classloader C has a symbolic reference to
class B and further that when C initiates loading of B, this is delegated to classloader D which defines B.
Class B can now only resolve symbols that can be loaded by D, rather than all those which can be loaded by C.
This is a classic recipe for classloader problems.
</em>
</p>
</subsection>
<subsection name='Bibliography'>
<ul>
<li>
<a href='http://java.sun.com/docs/books/vmspec/'>VMSpec</a> <em>The Java Virtual Machine Specification, Second Edition</em>
</li>
<li>
<a href='http://java.sun.com/docs/books/jls/'>LangSpec</a> <em>The Java Language Specification Second Edition</em>
</li>
</ul>
</subsection>
</section>
<section name='A Short Guide To Hierarchical Class Loading'>
<subsection name='Delegating Class Loaders'>
<p>
When asked to load a class, a class loader may either define the class itself or delegate.
The base <code>ClassLoader</code> class insists that every implementation has a parent class loader.
This delegation model therefore naturally forms a tree structure rooted in the bootstrap classloader.
</p>
<p>
Containers often use complex trees to allow isolation of different applications
running within the container.
This is particularly true of J2EE containers
</p>
</subsection>
<subsection name='Parent-First And Child-First Class Loaders'>
<p>
When a classloader is asked to load a class, a question presents itself: should it immediately
delegate the loading to it's parent (and thus only define those classes not defined by it's parent)
or should it try to define it first itself (and only delegate to it's parent those classes it does
not itself define). Classloaders which universally adopt the first approach are termed parent-first
and the second child-first.
</p>
<p>
Though child-first and parent-first are not the only strategies possible,
they are by far the most common.
All other strategies are rare.
However, it is not uncommon to be faced with a mixture of parent-first and child-first
classloaders within the same hierarchy.
</p>
</subsection>
<subsection name='Class ClassLoader'>
<p>
The class loader used to define the class is available programmatically by calling
the <code>getClassLoader</code> method
on the class in question. This is often known as the class classloader.
</p>
</subsection>
<subsection name='Context ClassLoader'>
<p>
Java 1.2 introduces a mechanism which allows code to access classloaders
which are not parents of the class classloader.
A thread may have a class loader associated to it by it's creator for use
by code running in this thread when loading resources and classes.
This is accessed by the <code>getContextClassLoader</code> method on <code>Thread</code>.
This is therefore often known as the context classloader.
</p>
<p>
Note that the quality and appropriateness of the context classloader depends on the
care with which the thread is created.
</p>
</subsection>
<subsection name='Issues with Context ClassLoaders'>
<p>
In practice, context classloaders vary in quality and issues sometimes arise
when using them.
The creator of the thread is responsible for setting the classloader.
If the context clasloader is not set then it will default to the system
classloader.
Any container doing so will cause difficulties for any code using the context classloader.
</p>
<p>
The creator is also at liberty to set the classloader as they wish.
Containers may set the context classloader so that it is nether a child nor a parent
of the classloader that defines the class using that loader.
Again, this will cause difficulties.
</p>
</subsection>
<subsection name='J2EE Context Classloaders'>
<p>
Introduced in <a href='http://java.sun.com/j2ee/j2ee-1_3-fr-spec.pdf'>Java J2EE 1.3</a>
is a requirement for vendors to appropriately set the context classloader.
Section 6.2.4.8 (1.4 text):
</p>
<source>
This specification requires that J2EE containers provide a per thread
context class loader for the use of system or library classes in
dynamicly loading classes provided by the application. The EJB
specification requires that all EJB client containers provide a per
thread context class loader for dynamicly loading system value classes.
The per thread context class loader is accessed using the Thread method
getContextClassLoader.
The classes used by an application will typically be loaded by a
hierarchy of class loaders. There may be a top level application class
loader, an extension class loader, and so on, down to a system class
loader. The top level application class loader delegates to the lower
class loaders as needed. Classes loaded by lower class loaders, such as
portable EJB system value classes, need to be able to discover the top
level application class loader used to dynamicly load application
classes.
We require that containers provide a per thread context class loader
that can be used to load top level application classes as described
above.
</source>
<p>
This specification leaves quite a lot of freedom for vendors.
(As well as using unconventional terminology and containing the odd typo.)
It is a difficult passage (to say the least).
</p>
</subsection>
<subsection name='Reflection And The Context ClassLoader'>
<p>
Reflection cannot bypass restrictions imposed by the java langauge security model but by avoiding symbolic
references, reflection can be used to load classes which could not otherwise be loaded. Another <code>ClassLoader</code>
can be used to load a class and then reflection used to create an instance.
</p>
<p>
Recall that the runtime packaging is used to determine accessibility.
Reflection cannot be used to avoid basic java security.
Therefore, the runtime packaging becomes an issue when attempting to cast classes
created by reflection using other class loaders.
When using this strategy, various modes of failure are possible
when common class references are defined by the different class loaders.
</p>
<p>
Reflection is often used with the context classloader. In theory, this allows a class defined in
a parent classloader to load any class that is loadable by the application.
In practice, this only works well when the context classloader is set carefully.
</p>
</subsection>
<subsection name='More Information'>
<ul>
<li>
Articles On Class Loaders And Class Loading
<ul>
<li>
<a
href='http://www.onjava.com/pub/a/onjava/2001/07/25/ejb.html'>
Article on J2EE class loading
</a>
</li>
<li>
<a
href='http://www.onjava.com/pub/a/onjava/2003/11/12/classloader.html'>
Article on class loading
</a>
</li>
<li>
<a
href='http://www.javaworld.com/javaworld/javaqa/2003-06/01-qa-0606-load.html'>
Article on context class loaders
</a>
</li>
</ul>
</li>
<li>Specific Containers
<ul>
<li>
<a
href='http://jakarta.apache.org/tomcat/tomcat-4.1-doc/class-loader-howto.html'>
Tomcat 4.1 ClassLoader Guide
</a>
</li>
<li>
<a
href='http://jakarta.apache.org/tomcat/tomcat-5.0-doc/class-loader-howto.html'>
Tomcat 5.0 ClassLoader Guide
</a>
</li>
<li>
<a
href='http://publib.boulder.ibm.com/infocenter/ws60help/index.jsp?topic=/com.ibm.websphere.express.doc/info/exp/ae/trun_classload_web.html'>
Classloading In WebSphere
</a>
</li>
</ul>
</li>
</ul>
</subsection>
</section>
<section name='A Short Theory Guide To JCL'>
<subsection name='Isolation And The Context Class Loader'>
<p>
JCL takes the view that different context class loader indicate boundaries between applications
running in a container environment. Isolation requires that JCL honours these boundaries
and therefore allows different isolated applications to configure their logging systems
independently.
</p>
</subsection>
<subsection name='Log And LogFactory'>
<p>
Performance dictates that symbolic references to these classes are present in the calling application code
(reflection would simply be too slow). Therefore, these classes must be loadable by the classloader
that loads the application code.
</p>
</subsection>
<subsection name='Log Implementations'>
<p>
Performance dictates that symbolic references to the logging systems are present in the implementation
classes (again, reflection would simply be too slow). So, for an implementation to be able to function,
it is neccessary for the logging system to be loadable by the classloader that defines the implementing class.
</p>
</subsection>
<subsection name='Using Reflection To Load Log Implementations'>
<p>
However, there is actually no reason why <code>LogFactory</code> requires symbolic references to particular <code>Log</code>
implementations. Reflection can be used to load these from an appropriate classloader
without unacceptable performance degradation.
This is the strategy adopted by JCL.
</p>
<p>
JCL uses the context classloader to use the <code>Log</code> implementation.
</p>
</subsection>
</section>
</body>
</document>