Tomcat ClassLoader研究 收藏
<script type="text/javascript"></script><script type="text/javascript"></script> http://tomcat.apache.org/tomcat-4.1-doc/class-loader-howto.html
Tomcat的ClassLoader层次结构:
源代码如下:
org.apache.catalina.startup.Bootstrap类(tomcat主类)
view plain copy to clipboard print ?
public final class Bootstrap {
// ------------------------------------------------------- Static Variables
/**
* Debugging detail level for processing the startup.
*/
private static int debug = 0 ;
// ----------------------------------------------------------- Main Program
/**
* The main program for the bootstrap.
*
* @param args Command line arguments to be processed
*/
public static void main(String args[]) {
// Set the debug flag appropriately
for (int i = 0 ; i < args.length; i++) {
if ("-debug" .equals(args))
debug = 1 ;
}
// Configure catalina.base from catalina.home if not yet set
if (System.getProperty("catalina.base" ) == null )
System.setProperty("catalina.base" , getCatalinaHome());
// Construct the class loaders we will need
ClassLoader commonLoader = null ;
ClassLoader catalinaLoader = null ;
ClassLoader sharedLoader = null ;
try {
File unpacked[] = new File[1 ];
File packed[] = new File[1 ];
File packed2[] = new File[2 ];
ClassLoaderFactory.setDebug(debug);
unpacked[0 ] = new File(getCatalinaHome(),
"common" + File.separator + "classes" );
packed2[0 ] = new File(getCatalinaHome(),
"common" + File.separator + "endorsed" );
packed2[1 ] = new File(getCatalinaHome(),
"common" + File.separator + "lib" );
commonLoader =
ClassLoaderFactory.createClassLoader(unpacked, packed2, null );
unpacked[0 ] = new File(getCatalinaHome(),
"server" + File.separator + "classes" );
packed[0 ] = new File(getCatalinaHome(),
"server" + File.separator + "lib" );
catalinaLoader =
ClassLoaderFactory.createClassLoader(unpacked, packed,
commonLoader);
unpacked[0 ] = new File(getCatalinaBase(),
"shared" + File.separator + "classes" );
packed[0 ] = new File(getCatalinaBase(),
"shared" + File.separator + "lib" );
sharedLoader =
ClassLoaderFactory.createClassLoader(unpacked, packed,
commonLoader);
} catch (Throwable t) {
log("Class loader creation threw exception" , t);
System.exit(1 );
}
Thread.currentThread().setContextClassLoader(catalinaLoader);
// Load our startup class and call its process() method
try {
SecurityClassLoad.securityClassLoad(catalinaLoader);
// Instantiate a startup class instance
if (debug >= 1 )
log("Loading startup class" );
Class startupClass =
catalinaLoader.loadClass
("org.apache.catalina.startup.Catalina" );
Object startupInstance = startupClass.newInstance();
// Set the shared extensions class loader
if (debug >= 1 )
log("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);
// Call the process() method
if (debug >= 1 )
log("Calling startup class process() method" );
methodName = "process" ;
paramTypes = new Class[1 ];
paramTypes[0 ] = args.getClass();
paramValues = new Object[1 ];
paramValues[0 ] = args;
method =
startupInstance.getClass().getMethod(methodName, paramTypes);
method.invoke(startupInstance, paramValues);
} catch (Exception e) {
System.out.println("Exception during startup processing" );
e.printStackTrace(System.out);
System.exit(2 );
}
}
其中:
commonLoader =
ClassLoaderFactory.createClassLoader(unpacked, packed2, null);
创建common classloader,以AppClassLoader为父ClassLoader
catalinaLoader =
ClassLoaderFactory.createClassLoader(unpacked, packed,
commonLoader);
创建catalina classloader,以common classloader为父classloader
sharedLoader =
ClassLoaderFactory.createClassLoader(unpacked, packed,
commonLoader);
创建share classloader,以common classloader为父classloader
Thread.currentThread().setContextClassLoader(catalinaLoader);
设置ContextClassLoader为catalina classloader
org.apache.catalina.startup.ClassLoaderFactory类
view plain copy to clipboard print ?
public static ClassLoader createClassLoader(File unpacked[],
File packed[],
ClassLoader parent)
throws Exception {
if (debug >= 1 )
log("Creating new class loader" );
// Construct the "class path" for this class loader
ArrayList list = new ArrayList();
// Add unpacked directories
if (unpacked != null ) {
for (int i = 0 ; i < unpacked.length; i++) {
File file = unpacked;
if (!file.isDirectory() || !file.exists() || !file.canRead())
continue ;
if (debug >= 1 )
log(" Including directory " + file.getAbsolutePath());
URL url = new URL("file" , null ,
file.getCanonicalPath() + File.separator);
list.add(url.toString());
}
}
// Add packed directory JAR files
if (packed != null ) {
for (int i = 0 ; i < packed.length; i++) {
File directory = packed;
if (!directory.isDirectory() || !directory.exists() ||
!directory.canRead())
continue ;
String filenames[] = directory.list();
for (int j = 0 ; j < filenames.length; j++) {
String filename = filenames[j].toLowerCase();
if (!filename.endsWith(".jar" ))
continue ;
File file = new File(directory, filenames[j]);
if (debug >= 1 )
log(" Including jar file " + file.getAbsolutePath());
URL url = new URL("file" , null ,
file.getCanonicalPath());
list.add(url.toString());
}
}
}
// Construct the class loader itself
String array[] = (String[]) list.toArray(new String[list.size()]);
StandardClassLoader classLoader = null ;
if (parent == null )
classLoader = new StandardClassLoader(array);
else
classLoader = new StandardClassLoader(array, parent);
classLoader.setDelegate(true );
return (classLoader);
}
ClassLoaderFactory创建的是StandardClassLoader(org.apache.catalina.loader包中)
由Bootstrap类调用Catalina类的process()方法,再调用execute()方法,再调用start()来启动Server实例。
当Tomcat开启每个Context时,是调用的StandardContext的start()方法,其中:
设置Loader为WebappLoader
view plain copy to clipboard print ?
if (getLoader() == null ) { // (2) Required by Manager
if (getPrivileged()) {
if (debug >= 1 )
log("Configuring privileged default Loader" );
setLoader(new WebappLoader(this .getClass().getClassLoader()));
} else {
if (debug >= 1 )
log("Configuring non-privileged default Loader" );
setLoader(new WebappLoader(getParentClassLoader()));
}
}
然后调用:bindThread(),设置当前线程的ClassLoader为WebappLoader的ClassLoader,即为WebappClassLoader
view plain copy to clipboard print ?
private ClassLoader bindThread() {
ClassLoader oldContextClassLoader =
Thread.currentThread().getContextClassLoader();
if (getResources() == null )
return oldContextClassLoader;
Thread.currentThread().setContextClassLoader
(getLoader().getClassLoader());
DirContextURLStreamHandler.bind(getResources());
if (isUseNaming()) {
try {
ContextBindings.bindThread(this , this );
} catch (NamingException e) {
// Silent catch, as this is a normal case during the early
// startup stages
}
}
return oldContextClassLoader;
}
WebappLoader的ClassLoader的赋值如下:
view plain copy to clipboard print ?
private String loaderClass =
"org.apache.catalina.loader.WebappClassLoader" ;
......
public void start() throws LifecycleException {
// Validate and update our current component state
if (started)
throw new LifecycleException
(sm.getString("webappLoader.alreadyStarted" ));
if (debug >= 1 )
log(sm.getString("webappLoader.starting" ));
lifecycle.fireLifecycleEvent(START_EVENT, null );
started = true ;
if (container.getResources() == null )
return ;
// Register a stream handler factory for the JNDI protocol
URLStreamHandlerFactory streamHandlerFactory =
new DirContextURLStreamHandlerFactory();
try {
URL.setURLStreamHandlerFactory(streamHandlerFactory);
} catch (Throwable t) {
// Ignore the error here.
}
// Construct a class loader based on our current repositories list
try {
classLoader = createClassLoader();
classLoader.setResources(container.getResources());
classLoader.setDebug(this .debug);
classLoader.setDelegate(this .delegate);
if (container instanceof StandardContext)
classLoader.setAntiJARLocking(((StandardContext) container).getAntiJARLocking());
for (int i = 0 ; i < repositories.length; i++) {
classLoader.addRepository(repositories);
}
// Configure our repositories
setRepositories();
setClassPath();
setPermissions();
if (classLoader instanceof Lifecycle)
((Lifecycle) classLoader).start();
// Binding the Webapp class loader to the directory context
DirContextURLStreamHandler.bind
((ClassLoader) classLoader, this .container.getResources());
} catch (Throwable t) {
throw new LifecycleException("start: " , t);
}
// Validate that all required packages are actually available
validatePackages();
// Start our background thread if we are reloadable
if (reloadable) {
log(sm.getString("webappLoader.reloading" ));
try {
threadStart();
} catch (IllegalStateException e) {
throw new LifecycleException(e);
}
}
}
......
private WebappClassLoader createClassLoader()
throws Exception {
Class clazz = Class.forName(loaderClass);
WebappClassLoader classLoader = null ;
if (parentClassLoader == null ) {
// Will cause a ClassCast is the class does not extend WCL, but
// this is on purpose (the exception will be caught and rethrown)
classLoader = (WebappClassLoader) clazz.newInstance();
} else {
Class[] argTypes = { ClassLoader.class };
Object[] args = { parentClassLoader };
Constructor constr = clazz.getConstructor(argTypes);
classLoader = (WebappClassLoader) constr.newInstance(args);
}
return classLoader;
}
在WebappClassLoader中,其findClass的搜索顺序与一般的ClassLoader的搜索顺序不同。
一般的ClassLoader的搜索顺序为:
将其委托给父ClassLoader,如果父ClassLoader不能载入相应类,则才交给自己处理
但是WebappClassLoader中,其是先由自己来处理,如果不行再委托给父ClassLoader
相关源代码如下:
view plain copy to clipboard print ?
Class clazz = null ;
try {
if (debug >= 4 )
log(" findClassInternal(" + name + ")" );
try {
clazz = findClassInternal(name);
} catch (ClassNotFoundException cnfe) {
if (!hasExternalRepositories) {
throw cnfe;
}
} catch (AccessControlException ace) {
ace.printStackTrace();
throw new ClassNotFoundException(name);
} catch (RuntimeException e) {
if (debug >= 4 )
log(" -->RuntimeException Rethrown" , e);
throw e;
}
if ((clazz == null ) && hasExternalRepositories) {
try {
clazz = super .findClass(name);
} catch (AccessControlException ace) {
throw new ClassNotFoundException(name);
} catch (RuntimeException e) {
if (debug >= 4 )
log(" -->RuntimeException Rethrown" , e);
throw e;
}
}
if (clazz == null ) {
if (debug >= 3 )
log(" --> Returning ClassNotFoundException" );
throw new ClassNotFoundException(name);
}
} catch (ClassNotFoundException e) {
if (debug >= 3 )
log(" --> Passing on ClassNotFoundException" , e);
throw e;
}
以下引自tomcat的说明文档,说明了加载类的顺序
Therefore, from the perspective of a web application, class or resource loading looks in the following repositories, in this order:
/WEB-INF/classes of your web application
/WEB-INF/lib/*.jar of your web application
Bootstrap classes of your JVM
System class loader classses (described above)
$CATALINA_HOME/common/classes
$CATALINA_HOME/common/endorsed/*.jar
$CATALINA_HOME/common/lib/*.jar
$CATALINA_BASE/shared/classes
$CATALINA_BASE/shared/lib/*.jar
运维网声明
1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网 享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com