Chapter8 Loader
来源:互联网 发布:淘宝商品id批量导出 编辑:程序博客网 时间:2024/05/22 01:30
Chapter 8: Loader
Overview
You have seen a simple loader implementation in the previous chapters, which was
used for loading servlet classes. This chapter explains the standard web application
loader, or loader for short, in Catalina. A servlet container needs a customized
loader and cannot simply use the system's class loader because it should not trust
the servlets it is running. If it were to load all servlets and other classes needed by
the servlets using the system's class loader, as we did in the previous chapters, then
a servlet would be able to access any class and library included in the CLASSPATH
environment variable of the running Java Virtual Machine (JVM), This would be a
breach of security. A servlet is only allowed to load classes in the WEB-INF/classes
directory and its subdirectories and from the libraries deployed into the
WEB-INF/lib directory. That's why a servlet container requires a loader of its own.
Each web application (context) in a servlet container has its own loader. A loader
employs a class loader that applies certain rules to loading classes. In Catalina, a
loader is represented by the org.apache.catalina.Loader interface.
Another reason why Tomcat needs its own loader is to support automatic reloading
whenever a class in the WEB-INF/classes or WEB-INF/lib directories has been
modified. The class loader in the Tomcat loader implementation uses a separate
thread that keeps checking the time stamps of the servlet and supporting class files.
To support automatic reloading, a class loader must implement the
org.apache.catalina.loader.Reloader interface.
The first section of this chapter briefly reviews the class loading mechanism in Java.
Next, it covers the Loader interface, which all loaders must implement, followed by
the Reloader interface. After a look at the implementation of the loader and class
loader, the chapter presents an application that demonstrates how to use a Tomcat's
loader.
Two terms are used extensively in this chapter: repository and resources. A
repository is a place that will be searched by the class loader. The term resources
refers to a DirContext object in a class loader whose document base points to the
context's document base.
Java Class Loader
Every time you create an instance of a Java class, the class must first be loaded into
memory. The JVM uses a class loader to load classes. The class loader normally
searches some core Java libraries and all directories included in the CLASSPATH environment variable. If it does not find the required class, it throws a
java.lang.ClassNotFoundException.
Starting from J2SE 1.2, the JVM employs three class loaders: bootstrap class loader,
extension class loader, and system class loader. Each of the three class loaders has a
parent-child relationship with each other, in which the bootstrap class loader sits at
the top of the hierarchy and the system class loader at the bottom.
The bootstrap class loader is used to bootstrap the JVM. It starts working whenever
you call the java.exe program. As such, it must be implemented using the native code
because it is used to load the classes required for the JVM to function. Also, it is
responsible for loading all the core Java classes, such as those in java.lang and
java.io packages. The bootstrap class loader searches the core libraries such as rt.jar,
i18n.jar, etc. Which libraries are searched depends on the version of the JVM and
the operating system.
The extension class loader is responsible for loading classes in a standard extension
directory. This is to make the programmer's life easier because they can just copy
JAR files into this extension directory and the jar files will be searched automatically.
The extension library differs from one vendor to another. Sun's JVM's standard
extension directory is /jdk/jre/lib/ext.
The system class loader is the default class loader and searches the directories and
JAR files specified in the CLASSPATH environment variable.
So, which class loader does the JVM use? The answer lies in the delegation model,
which is there for security reasons. Every time a class needs to be loaded, the
system class loader is first called. However, it does not load the class right away.
Instead, it delegates the task to its parent, the extension class loader. The extension
class loader also delegates it to its parent, the bootstrap class loader. Therefore, the
bootstrap class loader is always given the first chance to load a class. If the bootstrap
class loader can't find the class needed, the extension class loader will try to load the
class. If the extension class loader also fails, the system class loader will perform the
task. If the system class loader can't find the class, a
java.lang.ClassNotFoundException is thrown. Why the round trip?
The delegation model is very important for security. As you know, you can use the
security manager to restrict access to a certain directory. Now, someone with
malicious intents can write a class called java.lang.Object that can be used to access
any directory in the hard disk. Because the JVM trusts the java.lang.Object class, it
will not watch its activity in this regard. As a result, if the custom java.lang.Object
was allowed to be loaded, the security manager would be easily paralyzed.
Fortunately, this will not happen because of the delegation model. Here is how it
works. When the custom java.lang.Object class is called somewhere in the program, the
system class loader delegates the request to the extension class loader, which
delegates to the bootstrap class loader. The bootstrap class loader searches its core
libraries, and finds the standard java.lang.Object and instantiates it. As a result, the
custom java.lang.Object will never be loaded.
The great thing about the class loading mechanism in Java is that you can write your
own class loader by extending the abstract java.lang.ClassLoader class. The reasons
why Tomcat needs a custom class loader include the following:
To specify certain rules in loading classes.
To cache the previously loaded classes.
To pre-load classes so they are ready to use.
The Loader Interface
There are rules in loading servlet and other classes in a web application. For example,
a servlet in an application can use classes deployed to the WEB-INF/classes
directory and any sub-directory under it. However, servlets do not have access to
other classes, even though those classes are included in the CLASSPATH of the
JVM running Tomcat. Also, a servlet can only access libraries deployed under the
WEB-INF/lib directory and not other directories.
A Tomcat loader represents a web application loader rather than a class loader. A
loader must implement the org.apache.catalina.Loader interface. The loader
implementation uses a custom class loader represented by the
org.apache.catalina.loader.WebappClassLoader class. You can obtain the
ClassLoader inside a web loader using the Loader interface's getClassLoader
method.
Among others, the Loader interface defines methods to work with a collection of
repositories. The WEB-INF/classes and WEB-INF/lib of a web application are
directories to be added as repositories. The Loader interface's addRepository
method is used to add a repository and its findRepositories method returns an array
of all repositories.
A Tomcat loader implementation is usually associated with a context, and the
getContainer and setContainer methods of the Loader interface are used for building
this association. A loader can also supports reloading, if one or more classes in a
context have been modified. This way, a servlet programmer can recompile a servlet
or a supporting class and the new class will be reloaded without restarting Tomcat.
For the reloading purpose, the Loader interface has the modified method. In a loader
implementation, the modified method must return true if one or more classes in its
repositories have been modified, and therefore reloading is required. A loader does not do the reloading itself, however. Instead, it calls the Context interface's reload
method. Two other methods, setReloadable and getReloadable, are used to
determine if reloading is enabled in the Loader. By default, in the standard
implementation of Context (the org.apache.catalina.core.StandardContext class,
which is discussed in Chapter 12), reloading is not enabled. Therefore, to enable
reloading of a context, you need to add a Context element for that context in your
server.xml file, such as the following:
<Context path="/myApp" docBase="myApp" debug="0" reloadable="true"/>
Also, a Loader implementation can be told whether or not to delegate to a parent
class loader. For this purpose, the Loader interface provides the getDelegate and
setDelegate methods.
The Loader interface is given in Listing 8.1.
Listing 8.1: The Loader interface
Catalina provides the org.apache.catalina.loader.WebappLoader as an
implementation of the Loader interface. For its class loader, the WebappLoader
object contains an instance of the org.apache.catalina.loader.WebappClassLoader
class, which extends the java.net.URLClassLoader class.
Note Whenever the container associated with a loader needs a servlet class, i.e.
when its invoke method is called, the container first calls the loader's
getClassLoader method to obtain the class loader. The container then calls the
loadClass method of the class loader to load the servlet class. More details on
this can be found in Chapter 11, "StandardWrapper".
The class diagram for the Loader interface and its implementation is given in Figure
8.1.
The most important method of the Reloader interface is modified, which returns true
if one of the servlet or supporting classes in a web application has been modified. The addRepository method is used to add a repository and the findRepositories method
returns a String array of all repositories in the class loader implementing Reloader.
The WebappLoader Class
The org.apache.catalina.loader.WebappLoader class is the implementation of the
Loader interface and represents a web application loader responsible for loading
classes for a web application. WebappLoader creates an instance of the
org.apache.catalina.loader.WebappClassLoader class as its class loader. Like other
Catalina components, WebappLoader implements org.apache.catalina.Lifecycle and
it is started and stopped by the associated container. The WebappLoader class also
implements the java.lang.Runnable interface so that it can dedicate a thread for
repeatedly calling the modified method of its class loader. If the modified method
returns true, the WebappLoader instance notifies its associated container (in this
case a context). The class reloading itself is performed by the Context, not by the
WebappLoader. How the Context does this is discussed in Chapter 12,
"StandardContext".
Important tasks are performed when the WebappLoader class's start method is
called:
Creating a class loader
Setting repositories
Setting the class path
Setting permissions
Starting a new thread for auto-reload.
Each of these tasks is discussed in the following sub-sections.
Creating A Class Loader
For loading classes, a WebappLoader instance employs an internal class loader. You
may recall from the discussion of the Loader interface that this interface provides the
getClassLoader method but there is no setClassLoader. Therefore, you cannot
instantiate a class loader and pass it to the WebappLoader. Does it mean that the
WebappLoader does not have the flexibility to work with a non-default class loader?
The answer is no. The WebappLoader provides the getLoaderClass and
setLoaderClass methods to obtain and change the value of its private variable
loaderClass. This variable is a String representing the name of the class of the class
loader. By default, the value of loaderClass is org.apache.catalina.loader.WebappClassLoader. If you wish, you can create your
own class loader that extends WebappClassLoader and call the setLoaderClass to
force your WebappLoader to use your custom class loader. Otherwise, when it is
started, the WebappLoader will create an instance of WebappClassLoader by calling
its private createClassLoader method. This method is given in Listing 8.3.
Listing 8.3: The createClassLoader method
It is possible to use a different class loader other than an instance of
WebappClassLoader. Note, however, that the createClassLoader method returns a
WebappClassLoader. Therefore, if your custom class loader does not extend
WebappClassLoader, this method will throw an exception.
Setting Repositories
The WebappLoader class's start method calls the setRepositories method to add
repositories to its class loader. The WEB-INF/classes directory is passed to the
class loader's addRepository method and the WEB-INF/lib directory is passed to the class loader's setJarPath method. This way, the class loader will be able to load
classes in the WEB-INF/classes directory and from any library deployed to the
WEB-INF/lib directory.
Setting the Class Path
This task is performed by the start method by calling the setClassPath method. The
setClassPath method assigns to an attribute in the servlet context a string
containing the class path information for the Jasper JSP compiler. It will not be
discussed here.
Setting Permissions
If the security manager is used when running Tomcat, the setPermissions method
adds the permissions to the class loader to access necessary directories, such as
WEB-INF/classes and WEB-INF/lib. If no security manager is used, this method
returns right away.
Starting a New Thread for Auto-Reload
WebappLoader supports auto-reload. If a class in the WEB-INF/classes or
WEB-INF/lib directories is re-compiled, the class must be reloaded automatically
without restarting Tomcat. For this purpose, WebappLoader has a thread that
continuously checks the date stamp of each resource every x seconds. The x here is
defined by the value of the checkInterval variable. By default its value is 15, meaning
that a check for auto-reload is performed every 15 seconds. The getCheckInterval
and setCheckInterval methods are used to access this variable.
In Tomcat 4 WebappLoader implements the java.lang.Runnable interface to support
auto-reload. The implementation of the run method in WebappLoader is given in
Listing 8.3.
Listing 8.3: The run method
Note In Tomcat 5 the task of checking for modified classes is performed by the
backgroundProcess method of the org.apache.catalina.core.StandardContext
object. This method is called periodically by a dedicated thread in the
org.apache.catalina.core.ContainerBase class, the parent class of
StandardContext. Check the ContainerBase class's
ContainerBackgroundProcessor inner class that implements Runnable.
At its core, the run method in Listing 8.3 contains a while loop that will run until the
started variable (used to indicate that the WebappLoader has been started) is set to
false. The while loop does the following:
Sleep for the period specified by the checkInterval variable.
Check if any class it loaded has been modified by calling the modified method
of the WebappLoader instance's class loader. If not, continue.
If a class has been modified, call the notifyContext private method to ask the
Context associated with this WebappLoader to reload.
The notifyContext method is given in Listing 8.4.
Listing 8.4: The notifyContext method
The notifyContext method does not call the Context interface's reload method
directly. Instead, it instantiates the inner class WebappContextNotifier and passes
the thread object and calls its start method. This way, the execution of reload will be
performed by a different thread. The WebappContextNotifier class is given in Listing
8.5.
Listing 8.5: The WebappContextNotifier inner class
When an instance of WebappContextNotifier is passed to a Thread and the Thread
object's start method is invoked, the run method of the WebappContextNotifier
instance will be executed. In turn, the run method calls the reload method of the
Context interface. You can see how the reload method is implemented in the
org.apache.catalina.core.StandardContext class in Chapter 12.
The WebappClassLoader Class
The org.apache.catalina.loader.WebappClassLoader class represents the class
loader responsible for loading the classes used in a web application.
WebappClassLoader extends the java.net.URLClassLoader class, the class we used
for loading Java classes in the applications in the previous chapters.
WebappClassLoader was designed for optimization and security in mind. For
example, it caches the previously loaded classes to enhance performance. It also
caches the names of classes it has failed to find, so that the next time the same
classes are requested to be loaded, the class loader can throw the
ClassNotFoundException without first trying to find them. WebappClassLoader
searches for classes in the list of repositories as well as the specified JAR files. With regard to security, the WebappClassLoader will not allow certain classes to be
loaded. These classes are stored in a String array triggers and currently has one
member:
Also, you are not allowed to load classes belonging to these packages and
subpackages under them, without first delegating to the system class loader:
Let's now look at how this class performs caching and class loading in the following
sub-sections.
Caching
For better performance, classes that are loaded are cached so that the next time a
class is required, it can be taken from the cache. Caching can be done locally,
meaning that the cache is managed by the WebappClassLoader instance. In addition,
the java.lang.ClassLoader maintains a Vector of previously loaded classes to prevent
those classes from being garbage-collected. In this case, caching is managed by the
super class.
Each class (either deployed as a class file under WEB-INF/classes or from a JAR file)
that may be loaded by WebappClassLoader is referred to as a resource. A resource
is represented by the org.apache.catalina.loader.ResourceEntry class. A
ResourceEntry instance holds the byte array representation of the class, the last
modified date, the Manifest (if the resource is from a JAR file), etc.
The ResourceEntry class is given in Listing 8.6.
Listing 8.6: The ResourceEntry class.
All cached resources are stored in a HashMap called resourceEntries. The keys are
the resource names. All resources that were not found are stored in another
HashMap called notFoundResources.
Loading Classes
When loading a class, the WebappClassLoader class applies these rules:
All previously loaded classes are cached, so first check the local cache.
If not found in the local cache, check in the cache, i.e. by calling the
findLoadedClass of the java.lang.ClassLoader class.
If not found in both caches, use the system's class loader to prevent the web
application from overriding J2EE class.
If SecurityManager is used, check if the class is allowed to be loaded. If the
class is not allowed, throw a ClassNotFoundException.
If the delegate flag is on or if the class to be loaded belongs to the package
name in the package trigger, use the parent class loader to load the class. If
the parent class loader is null, use the system class loader.
Load the class from the current repositories.
If the class is not found in the current repositories, and if the delegate flag is
not on, use the parent class loader. If the parent class loader is null, use the
system class loader.
If the class is still not found, throw a ClassNotFoundException. The Application
The application accompanying this chapter demonstrates how to use a
WebappLoader instance associated with a context. The standard implementation of
Context is the org.apache.catalina.core.StandardContext class, therefore this
application instantiates the StandardContext class. However, the discussion of
StandardContext itself will be deferred until Chapter 12. You do not need to
understand the details of this class at this stage. All you need to know about
StandardContext is that it works with a listener that listens to events it fires, such as
the START_EVENT and STOP_EVENT. The listener must implement the
org.apache.catalina.lifecycle.LifecycleListener interface and call the
StandardContext class's setConfigured method. For this application, the listener is
represented by the ex08.pyrmont.core.SimpleContextConfig class, which is given in
Listing 8.6.
Listing 8.6: The SimpleContextConfig class
All you need to do is instantiate both StandardContext and SimpleContextConfig and
then register the latter with StandardContext by calling the addLifecycleListener
method of the org.apache.catalina.Lifecycle interface. This interface was discussed
in detail in Chapter 6, "Lifecycles".
In addition, the application retains the following classes from the previous chapter:
SimplePipeline, SimpleWrapper, and SimpleWrapperValve.
The application can be tested using both PrimitiveServlet and ModernServlet, but
this time the use of StandardContext dictates the servlets be stored under the WEB-INF/classes of an application directory. The application directory is called
myApp and should have been created when you deployed the downloadable ZIP file
the first time. To tell the StandardContext instance where to find the application
directory, you set a system property called catalina.base with the value of the
user.dir property, as follows.
System.setProperty("catalina.base", System.getProperty("user.dir"));
In fact, that is the first line in the main method of the Bootstrap class. Afterwards,
the main method instantiates the default connector.
It then creates two wrappers for the two servlets and initialize them, just like the
application in the previous chapter.
It then creates an instance of StandardContext and set the path as well as the
document base of the context.
This is equivalent to having the following element in the server.xml file.
<Context path="/myApp" docBase="myApp"/>
Then, the two wrappers are added to the context, and it adds the mapping for both
so that the context can locate the wrappers.
The next step is to instantiate a listener and register it with the context.
Next, it instantiates the WebappLoader and associates it with the context.
Loader loader = new WebappLoader();
context.setLoader(loader);
Afterwards, the context is associated with the default connector, and the
connector's initialize and start methods are called, followed by the context's start
method. This puts the servlet container into service.
connector.setContainer(context);
try {
connector.initialize();
((Lifecycle) connector).start();
((Lifecycle) context).start();
The next lines simply display the value of the resources' docBase and all the
repositories in the class loader.
// now we want to know some details about WebappLoader
WebappClassLoader classLoader = (WebappClassLoader)
loader.getClassLoader();
System.out.println("Resources' docBase: " +
((ProxyDirContext)classLoader.getResources ()).getDocBase());
String[] repositories = classLoader.findRepositories();
for (int i=0; i<repositorles.length; i++) {
System.out.println(" repository: " + repositories[i]);
}
These lines will make docBase and the list of repositories displayed when you run the
application.
Resources' docBase: C:/HowTomcatWorks/myApp
repository: /WEB-INF/classes/
The value of docBase may be different on your machine, depending where you install
the application.
Finally, the application waits until the user presses Enter on the console to stop the
application.
// make the application wait until we press a key. System.in.read();
((Lifecycle) context).stop();
Running the Application
To run the application in Windows, from the working directory, type the following:
java -classpath ./lib/servlet.jar;./lib/commons-collections.jar;./
ex08.pyrmont.startup.Bootstrap
In Linux, you use a colon to separate two libraries.
java -classpath ./lib/servlet.jar:./lib/commons-collections.jar:./
ex08.pyrmont.startup.Bootstrap
To invoke PrimitiveServlet servlet, you use the following URL in your browser.
http://localhost:8080/Primitive
To invoke ModernServlet, you use the following URL.
http://localhost:8080/Modern
Summary
The web application loader, or simply a loader, is a most important component in
Catalina. A loader is responsible for loading classes and therefore employs an
internal class loader. This internal class loader is a customized class that is used by
Tomcat to apply certain rules to the class loading within an application context. Also,
the customized class loader supports caching and can check whether or not one or
more classes have been modified.
- Chapter8 Loader
- chapter8:ManagingSchemaObjects
- chapter8 other
- CCNA-Cisco-Chapter8
- CCNA2-Cisco-Chapter8
- 【C++】Chapter8:外观模式
- Qt 笔记 Chapter6-Chapter8
- Chapter8 Bit Manipulation
- Chapter6-Chapter8 Chapter 6
- ESL-chapter8-gibbs采样
- ESL-chapter8-bagging
- Chapter8 Data Binding
- 数据结构--Chapter8(外排序)
- Beginning Python Chapter8
- Cpp_Primer--Chapter8--IO库
- Algorithm Chapter8 Exicise
- CHAPTER8 SOFTWARE RNGINEERING
- algorithm chapter8 8.15
- Web Services类型请求中替换XML格式的节点值的方法
- NVRAM读写操作
- Android 网络编程---STRUTS2,JSON,HttpClient
- MyEclipse8.5安装jbpm4.3插件更新至Myeclipse8.6出错的解决办法
- 儒略日反推计算日期
- Chapter8 Loader
- with inner join & with outer join
- grep awk sed
- SQL Server 中对XML数据的五种基本操作【转】
- jsp连接数据库常见问题
- c++虚函数的实现机制
- 用powerbasic语言写的时钟程序代码
- [apple]UI和class的连接
- 单点登录(SSO)的技术