前言
tomcat之所以创造了一堆自己的classloader体系,其目的之一就是为了实现应用的相互隔离,而对于许多应用,需要有共享的lib以便不浪费资源。那么,tomcat是如何实现这些功能的呢?通过tomcat源码,我会为大家详细介绍
tomcat的classloader体系
tomcat的具体的classloader体系如下图
BootstrapClassLoader,ExtensionClassLoader,SystemClassLoader这三个类我就不多介绍了,具体可参考我的《tomcat类加载体系》这篇博客
从Bootstrap的init开始
commonLoader、catalinaLoader和sharedLoader是在Tomcat容器初始化的的过程刚刚开始(即调用Bootstrap的init方法时)创建的。catalinaLoader会被设置为Tomcat主线程的线程上下文类加载器,并且使用catalinaLoader加载Tomcat容器自身的class。Bootstrap的init方法代码如代码清单1:
代码清单1
/**
* Initialize daemon.
*/
public void init()
throws Exception
{
// Set Catalina path
setCatalinaHome();
setCatalinaBase();
//初始化commonLoader、catalinaLoader和sharedLoader;
initClassLoaders();
//将catalinaLoader设置为Tomcat主线程的线程上下文类加载器;
Thread.currentThread().setContextClassLoader(catalinaLoader);
//线程安全的加载class。
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;
}
其中有关类加载器的执行步骤如下:
- 初始化commonLoader、catalinaLoader和sharedLoader;
- 将catalinaLoader设置为Tomcat主线程的线程上下文类加载器;
- 线程安全的加载class。
再之后就是加载Catalina,设置catalinaDaemon参数
初始化类加载器initClassLoaders()
initClassLoaders方法的实现如代码清单2:
代码清单2
private void initClassLoaders() {
try {
commonLoader = createClassLoader("common", null);
if( commonLoader == null ) {
//no config file, default to thisloader- we might be in a 'single' env.
commonLoader=this.getClass().getClassLoader();
}
catalinaLoader = createClassLoader("server", commonLoader);
sharedLoader = createClassLoader("shared", commonLoader);
} catch (Throwable t) {
log.error("Class loader creation threw exception", t);
System.exit(1);
}
}
我们可以看到initClassLoaders调用createClassLoader方法来创建commonLoader、catalinaLoader和sharedLoader,我们来看看createClassLoader的实现,其代码清单3:
代码清单3
private ClassLoader createClassLoader(String name, ClassLoader parent)
throws Exception {
String value = CatalinaProperties.getProperty(name + ".loader");
if ((value == null) || (value.equals("")))
return parent;
ArrayList<String> repositoryLocations = new ArrayList<String>();
ArrayList<Integer> repositoryTypes = new ArrayList<Integer>();
int i;
StringTokenizer tokenizer = new StringTokenizer(value, ",");
while (tokenizer.hasMoreElements()) {
String repository = tokenizer.nextToken();
// Local repository
boolean replace = false;
String before = repository;
while ((i=repository.indexOf(CATALINA_HOME_TOKEN))>=0) {
replace=true;
if (i>0) {
repository = repository.substring(0,i) + getCatalinaHome()
+ repository.substring(i+CATALINA_HOME_TOKEN.length());