初始化之ClassLoader
初始化第2步就是ClassLoader,调用的initClassLoaders()
:
private void initClassLoaders() {
try {
commonLoader = createClassLoader("common", null);
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);
sharedLoader = createClassLoader("shared", commonLoader);
} catch (Throwable t) {
handleThrowable(t);
log.error("Class loader creation threw exception", t);
System.exit(1);
}
}
一共有3个ClassLoader,分别为commonLoader
,catalinaLoader
,sharedLoader
,都是通过调用createClassLoader
来获取。
private ClassLoader createClassLoader(String name, ClassLoader parent)
throws Exception {
String value = CatalinaProperties.getProperty(name + ".loader");
if ((value == null) || (value.equals("")))
return parent;
value = replace(value);
List<Repository> repositories = new ArrayList<Repository>();
StringTokenizer tokenizer = new StringTokenizer(value, ",");
while (tokenizer.hasMoreElements()) {
String repository = tokenizer.nextToken().trim();
if (repository.length() == 0) {
continue;
}
// Check for a JAR URL repository
try {
@SuppressWarnings("unused")
URL url = new URL(repository);
repositories.add(
new Repository(repository, RepositoryType.URL));
continue;
} catch (MalformedURLException e) {
// Ignore
}
// Local repository
if (repository.endsWith("*.jar")) {
repository = repository.substring
(0, repository.length() - "*.jar".length());
repositories.add(
new Repository(repository, RepositoryType.GLOB));
} else if (repository.endsWith(".jar")) {
repositories.add(
new Repository(repository, RepositoryType.JAR));
} else {
repositories.add(
new Repository(repository, RepositoryType.DIR));
}
}
ClassLoader classLoader = ClassLoaderFactory.createClassLoader
(repositories, parent);
// Retrieving MBean server
MBeanServer mBeanServer = null;
if (MBeanServerFactory.findMBeanServer(null).size() > 0) {
mBeanServer = MBeanServerFactory.findMBeanServer(null).get(0);
} else {
mBeanServer = ManagementFactory.getPlatformMBeanServer();
}
// Register the server classloader
ObjectName objectName =
new ObjectName("Catalina:type=ServerClassLoader,name=" + name);
mBeanServer.registerMBean(classLoader, objectName);
return classLoader;
}
###createClassLoader
###
1.首先从配置文件中取出相应的loader,如果没有就返回父Loader,取配置文件的优先级为(参考类CatalinaProperties
):
1.从System中获取catalina.config
2.从catalina.base下面的conf文件夹里面获取catalina.properties文件(一般情况下默认的就为这个)
3.包路径/org/apache/catalina/startup/catalina.properties
2.一般情况下在我们的${catalina.base}/conf/catalina.properties中默认都有配置
common.loader=${catalina.base}/lib,${catalina.base}/lib/*.jar,${catalina.home}/lib,${catalina.home}/lib/*.jar
server.loader
和shared.loader
都为空,所以默认情况下这两个loader都为common.loader
3.把从配置中取出的路径全部加到一个List<Repository>
,每一个Repository
都包含一个路径,并且会指明其类型,类型包括有:
public static enum RepositoryType {
DIR,
GLOB,
JAR,
URL
}
4.在取出所有路径后,通过ClassLoaderFactory.createClassLoader
来获取classLoader,在ClassLoaderFactory.createClassLoader
中解析完所有路径后,通过
return AccessController.doPrivileged(
new PrivilegedAction<StandardClassLoader>() {
@Override
public StandardClassLoader run() {
if (parent == null)
return new StandardClassLoader(array);
else
return new StandardClassLoader(array, parent);
}
});
返回ClassLoader,所以tomcat里面的ClassLoader就为StandardClassLoader
,这个又继承的URLClassLoader
5.把ClassLoader注册到MBeanServer
中
###总结###
1.tomcat中默认加载jar的顺序为${catalina.base}/lib,${catalina.base}/lib/*.jar,${catalina.home}/lib,${catalina.home}/lib/*.jar
,并且里面用的LinkedHashSet
来保存的这些路径,所以当我们有多个instance的时候,${catalina.base}
应该会覆盖${catalina.home}
里面同样的,以及如果有些公共的jar,需要提前加载的也应该可以配置到这里
2.看了StandardClassLoader
,在开发过程中我们应该也可以动态加载jar。直接使用URLClassLoader
加载