Classloader
参考:http://www.iteye.com/topic/83978
http://longdick.iteye.com/blog/442213
1,作用:
它就是用来加载Class文件到JVM,以供程序使用。所有java class 加载过程从此开始。
2,实现:
最上级的Classloader是由C++编写,名叫:bootstrap classloader。jvm运行后,bootstrap classloader被启动,驻留在内存中,供程序调用,进行类加载。
这个ClassLoader在JVM运行的时候加载java核心的API以满足java程序最基本的需求。
3,应用程序中ClassLoader层级关系
jvm默认ClassLoader分3个:
Bootstrap ClassLoader:负责加载java基础类,主要是 %JRE_HOME/lib/ 目录下的rt.jar、resources.jar、harsets.jar和class等
Extension ClassLoader:负责加载java扩展类,主要是 %JRE_HOME/lib/ext 目录下的jar和class
App ClassLoader :负责加载当前java应用的classpath中的所有类。
ClassLoader调用顺序如下:
注意:这里的层级并不是基础关系。
一、ClassLoader具体实现机制:双亲委托模式
ClassLoader这个抽象类中有一个getParent()方法,并且有一个parent 变量。
看代码如下:
protected synchronized Class loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
// 首先检查该name指定的class是否有被加载
Class c = findLoadedClass(name);
if (c == null) {
try {
if (parent != null) {
//如果parent不为null,则调用parent的loadClass进行加载
= parent.loadClass(name, false);
} else {
//parent为null,则调用BootstrapClassLoader进行加载
c = findBootstrapClass0(name);
}
} catch (ClassNotFoundException e) {
//如果仍然无法加载成功,则调用自身的findClass进行加载
c = findClass(name);
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
Tomcat ClassLoader实现:
每个运行中的线程都有一个成员contextClassLoader,用来在运行时动态地载入其它类。系统默认的contextClassLoader是systemClassLoader,所以一般而言java程序在执行时可以使用JVM自带的类、$JAVA_HOME/jre/lib/ext/中的类和$CLASSPATH/中的类。可以使用Thread.currentThread().setContextClassLoader(...);更改当前线程的contextClassLoader,来改变其载入类的行为,但是最终都会调用systemClassLoader。
现在看Tomcat 启动过程:
在startup.bat调用catalina.bat ,bat文件中找到启动类:
set _EXECJAVA=%_RUNJAVA%
set MAINCLASS=org.apache.catalina.startup.Bootstrap
1,初始化函数:init()
public void init()
throws Exception
{
// Set Catalina path
setCatalinaHome();
setCatalinaBase();
initClassLoaders();//初始化ClassLoader
Thread.currentThread().setContextClassLoader(catalinaLoader);设置当前线程ClassLoader
SecurityClassLoad.securityClassLoad(catalinaLoader);
// Load our startup class and call its process() method
if (log.isDebugEnabled())
log.debug("Loading startup class");
Class startupClass =
catalinaLoader.loadClass
("org.apache.catalina.startup.Catalina");
Object startupInstance = startupClass.newInstance();
// Set the shared extensions class loader
if (log.isDebugEnabled())
log.debug("Setting startup class properties");
String methodName = "setParentClassLoader";
Class paramTypes[] = new Class[1];
paramTypes[0] = Class.forName("java.lang.ClassLoader");
Object paramValues[] = new Object[1];
paramValues[0] = sharedLoader;
Method method =
startupInstance.getClass().getMethod(methodName, paramTypes);
method.invoke(startupInstance, paramValues);
catalinaDaemon = startupInstance;
}
其中initClassLoader()函数如下:
private void initClassLoaders() {
try {
commonLoader = createClassLoader("common", null); //common ---system loader
if( commonLoader == null ) {
// no config file, default to this loader - we might be in a 'single' env.
commonLoader=this.getClass().getClassLoader();
}
catalinaLoader = createClassLoader("server", commonLoader); //Tomcat classLoader
sharedLoader = createClassLoader("shared", commonLoader);//Webapp classloader
} catch (Throwable t) {
log.error("Class loader creation threw exception", t);
System.exit(1);
}
}
1,当前线程设置的ClassLoader 是 CatalinaLoader。
2,初始化了3个classloader:commonloader、catalinaloader、sharedloader
其中catalinaloader、sharedloader的parent loader 是commonloader。
它们作用如下:
--commonloader
这个目录下的类虽然对TOMCAT和所有的WEB APP都可见.但是Web App的类不应该 放在这个目录下,所有未打包的Class都在$CATALINA_HOME/common/classes下,所 有打包的jar都在 $CATALINA_HOME/commons/endorsed $CATALINA_HOME/common/lib下。
默认情况包含如下几个包(现在版本已不是这样,学习用):
1. naming-common.jar JNDI接口实现类,Tomcat用这些类在内存中使用Context.
2. naming-resources.jar JNDI实现,Tomcat用它们定位Web App的静态资源.
3. servlet.jar Servlet,Jsp API
4. xerces.jar XML解析器,特定的Web App可以在自己的/WEB-INF/lib 中覆盖.
-catalinaloader
默认包含下面几个包(现在版本已不是这样,学习用):
1. catalina.jar Servlet容器的Tomcat实现包
2. jakarta-regexp-X.Y.jar 正则表达式,请求过滤时使用
3. servlets-xxxxx.jar Servlet支持包
4. tomcat-coyote.jar Tomcat的Coyote连接实现包
5. tomcat-jk.jar Web Server绑定包,允许Tomcat绑定Apache等作为Web Server
6. tomcat-jk2.jar 功能同上
7. tomcat-util.jar Tomcat工具类,可能被一些Connector用到
8. tomcat-warp.jar 用于Apache Server包
装入Tomcat实现所有接口的类。这些类对Web App是完全不可见的,所有未打包的类在 $CATALINA_HOME/server/classes所有jar包在$CATALINA_HOME/server/lib下。
-sharedloader
默认包含下面几个包(现在版本已不是这样,学习用):
1. jasper-compiler.jar Jsp编译器,编译Jsp为Servlet
2. jasper-runtime.jar Jsp(已编译成Servlet)运行支持包
3. naming-factory.jar 支持Web App使用JNDI的封装包
载入所有WEB APP都可见的类,对TOMCAT不可见. 所有未打包的类在 $CATALINA_HOME/shared/classes,所有jar包在$CATALINA_HOME /lib下。
再看上面调用的createClassLoader函数:
private ClassLoader createClassLoader(String name, ClassLoader parent)
throws Exception {
。。。。。
ClassLoader classLoader = ClassLoaderFactory.createClassLoader
(locations, types, parent);
。。。。。
return classLoader;
}
调用了ClassLoaderFactory 工厂类来创建ClassLoader。
在ClassLoaderFactory 的createClassLoader()函数中:
StandardClassLoader classLoader = null;
if (parent == null)
classLoader = new StandardClassLoader(array);
else
classLoader = new StandardClassLoader(array, parent);
return (classLoader);
standardClassLoader是URLClassloader的子类
(URLClassloader是java.security.SecureClassLoader的子类,java.security.SecureClassLoader
是Classloader的子类 java.security.SecureClassLoader扩展了Classloader,他还可以支持使用相关的代码源和权限定义类) 。