您的位置:首页 > 运维架构 > Tomcat

java与tomcat类加载机制

2016-03-15 17:21 537 查看

java与tomcat类加载机制

标签(空格分隔): java

前言:类加载机制,听起来“高大上”的东西,其实不是很难。理解类加载机制,对我们日常的开发和对tomcat的理解会有一个提升。

java的类加载机制。

1.1 java中类加载器的种类以及作用。

bootstrap:启动类加载器 JVM实现的一部分,在JVM运行的时候就加载 JAVA的核心API(java.lang.* or java.io.*)

ExtClassLoder:扩展类加载器 用来加载 java扩展的API 也就/lib/ext 下面的类

AppClassLoder:系统类加载器 加载CLASSPATH下面的类,也就是用户自己写的类

1.2 java类加载器的层次关系和调用顺序

加载顺序 :按照从上到下的顺序加载类

bootstrap 类加载器是由C++代码实现的位于顶层

ExtClassLoder 类加载器位于中层

AppClassLoder 类加载器位于底层

注意:(ExtClassLoder 是 AppClassLoder 的父类 两者由java代码实现)

1.3 java类加载器的双亲委托模型



  当一个类加载请求加载某个类的时候,首先检查是否已经加载过这个类,如果加载过直接返回。如果没有加载过,首先会委托父类加载器,父类加载器也会检查时候加载过这个类,如果还是没有则继续向上委托如果最后的父类加载器不能加载这个类。则调用 bootstrap 去加载这个类,如果还是找不到则会抛出ClassNotFoundException。

这种模型的用途就是为了解决 类载入过程中的安全性问题。如果有恶意用户自定义了 一个类 如Object 类 去覆盖 java 关键类 则会有产生安全性问题


1.4 加载器的命名空间

  每个加载器都有自己的命名空间,命名空间由该加载器以及父类所有的加载器所加载的类组成,当加载器加载一个雷的时候首先会去自己的命名空间中查找 是否 加载过这个类。

  在同一命名空间不会出现出现类的完整名字完全相同的两个类,在不同的命名空间中有可能出现类的完整名字完全相同的两个类。

  

类加载器命名空间
Loader1Class1
Loader2Class1Class2
Loader3Class1Class2Class3
Loader4Class1Class2Class3

1.5 运行时包

由同一类加载器加载属于相同包的类,组成了运行时包。


  决定两个类是否属于同一运行时包,不仅要看包名是否相同,还要看是否由,同一个ClassLoader加载。只有属于同一运行时包的类,才能互相访问包可见的类和成员。

  这样的限制避免了用户自己的代码冒充核心类库的类访问核心类库包可见成员的情况。假设用户自己定义了一个类 java.lang.xxx ,并用自定义的 ClassLoader 装载,由于 Java.lang.* 和 java.lang.xxx 是由不同的装载器装载,属于不同的运行时包,所以 java.lang.xxx 不能访问核心类库 java.lang 中类的包可见成员。

  

Tomcat的类加载机制

2.1 Tomcat类加载器的层级结构

先上一张tomcat 5的类 tomcat类加载器的结构图,虽然东西老,但是原理相同。

Bootstrap
|
System
|
Common
/        \
Catalina     Shared
/... ...\
webapp1   webappN


2.2 每层加载器的作用

Bootstrap:该加载器包含由JVM提供的基本的运行时类,加上放置在系统扩展目录(

2.3 Tomcat加载机制原理

  tomcat的类加载机制与java的类加载委派模型不同之处就是,当WebappN被请求记载一个类的时候,并不一定完全会按照java类加载器的委托模式,WebappN首先会在本地库中查找而不是直接委托。但是也有例外作为 JRE一些基本类的一部分类不能被覆盖。下面附上tomcat的WebappClassLoader的load方法

public synchronized Class loadClass(String name, boolean resolve)
throws ClassNotFoundException {

Class clazz = null;

//首先检查已加载的类
// (0) Check our previously loaded local class cache
clazz = findLoadedClass0(name);
if (clazz != null) {
if (log.isDebugEnabled())
log.debug("  Returning class from cache");
if (resolve)
resolveClass(clazz);
return (clazz);
}

// (0.1) Check our previously loaded class cache
clazz = findLoadedClass(name);
if (clazz != null) {
if (log.isDebugEnabled())
log.debug("  Returning class from cache");
if (resolve)
resolveClass(clazz);
return (clazz);
}

// (0.2) Try loading the class with the system class loader, to prevent
//       the webapp from overriding J2SE classes
try {
clazz = system.loadClass(name);
if (clazz != null) {
if (resolve)
resolveClass(clazz);
return (clazz);
}
} catch (ClassNotFoundException e) {
// Ignore
}

// (0.5) Permission to access this class when using a SecurityManager
if (securityManager != null) {
int i = name.lastIndexOf('.');
if (i >= 0) {
try {
securityManager.checkPackageAccess(name.substring(0,i));
} catch (SecurityException se) {
String error = "Security Violation, attempt to use " +
"Restricted Class: " + name;
log.info(error, se);
throw new ClassNotFoundException(error, se);
}
}
}

boolean delegateLoad = delegate || filter(name);
//Tomcat允许按照配置来确定优先使用本Web应用的类加载器加载还是使用父类
//加载器来进行类加载,此处先使用父类加载器进行加载
// (1) Delegate to our parent if requested
if (delegateLoad) {
if (log.isDebugEnabled())
log.debug("  Delegating to parent classloader1 " + parent);
ClassLoader loader = parent;
if (loader == null)
loader = system;
try {
clazz = loader.loadClass(name);
if (clazz != null) {
if (log.isDebugEnabled())
log.debug("  Loading class from parent");
if (resolve)
resolveClass(clazz);
return (clazz);
}
} catch (ClassNotFoundException e) {
;
}
}
//使用本地的类加载器进行加载
// (2) Search local repositories
if (log.isDebugEnabled())
log.debug("  Searching local repositories");
try {
clazz = findClass(name);
if (clazz != null) {
if (log.isDebugEnabled())
log.debug("  Loading class from local repository");
if (resolve)
resolveClass(clazz);
return (clazz);
}
} catch (ClassNotFoundException e) {
;
}
//如果没有特殊配置的话,使用父类加载器加载类
// (3) Delegate to parent unconditionally
if (!delegateLoad) {
if (log.isDebugEnabled())
log.debug("  Delegating to parent classloader at end: " + parent);
ClassLoader loader = parent;
if (loader == null)
loader = system;
try {
clazz = loader.loadClass(name);
if (clazz != null) {
if (log.isDebugEnabled())
log.debug("  Loading class from parent");
if (resolve)
resolveClass(clazz);
return (clazz);
}
} catch (ClassNotFoundException e) {
;
}
}
//若最终类还是没有找到,抛出异常
throw new ClassNotFoundException(name);

}


从一个网络程序的角度来看,类和资源的装载以这样的顺序在下列贮藏室进行查找:

你的JVM的Bootstrap类
系统类装载器类(描述如上)
你的网络程序的/WEB-INF/classes
你的网络程序的/WEB-INF/lib/*.jar
$CATALINA_HOME/common/classes
$CATALINA_HOME/common/endorsed/*.jar
$CATALINA_HOME/common/lib/*.jar
$CATALINA_BASE/shared/classes
$CATALINA_BASE/shared/lib/*.jar
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息