设为首页 收藏本站
查看: 558|回复: 0

[经验分享] java与tomcat类加载机制

[复制链接]

尚未签到

发表于 2017-1-30 06:19:29 | 显示全部楼层 |阅读模式
  前言:
  类加载机制,听起来“高大上”的东西,其实不是很难。理解类加载机制,对我们日常的开发和对tomcat的理解会有一个提升。
  一  java的类加载机制。
  1, java中类加载器的种类以及作用。
  (1)bootstrap            启动类加载器  JVM实现的一部分,在JVM运行的时候就加载 JAVA的核心API(java.lang.* or java.io.*)
  (2)ExtClassLoder     扩展类加载器  用来加载 java扩展的API 也就<JRE>/lib/ext 下面的类
  (3)AppClassLoder   系统类加载器  加载CLASSPATH下面的类,也就是用户自己写的类
  2, java类加载器的层次关系 和 调用顺序
  加载顺序 :按照从上到下的顺序 加载 类
  bootstrap 类加载器是由C++代码实现的 位于顶层
  ExtClassLoder 类加载器 位于中层
  AppClassLoder 类加载器 位于底层   
  注意:(ExtClassLoder 是 AppClassLoder 的父类 两者由java代码实现)
  3, java类加载器的双亲委托模型
  
DSC0000.jpeg
 
  当一个类加载请求加载某个类的时候,首先检查是否已经加载过这个类,如果加载过直接返回。如果没有加载过,首先会委托父类加载器,父类加载器也会检查时候加载过这个类,如果还是没有则继续向上委托
  如果最后的父类加载器不能加载这个类。则调用 bootstrap 去加载这个类,如果还是找不到则会抛出ClassNotFoundException。
  这种模型的用途就是为了解决 类载入过程中的安全性问题。如果有恶意用户自定义了 一个类 如Object 类 去覆盖 java 关键类 则会有产生安全性问题。
  4,加载器的命名空间 
  每个加载器都有自己的命名空间,命名空间由该加载器以及父类所有的加载器所加载的类组成,当加载器加载一个雷的时候
  首先会去自己的命名空间中查找 是否 加载过这个类。
  在同一命名空间不会出现出现类的完整名字完全相同的两个类,在不同的命名空间中有可能出现类的完整名字完全相同的两个类。

类加载器命名空间
Loader1Class1
Loader2Class1Class2
Loader3Class1Class2Class3
Loader4Class1Class2Class3
  5, 运行时包
  由同一类加载器加载属于相同包的类,组成了运行时包。
  决定两个类是否属于同一运行时包,不仅要看包名是否相同,还要看是否由,同一个ClassLoader加载。只有属于同一运行时包的类,才能互相访问包可见的类和成员。
  这样的限制避免了用户自己的代码冒充核心类库的类访问核心类库包可见成员的情况。假设用户自己定义了一个类 java.lang.xxx ,并用自定义的 ClassLoader 装载,由于 Java.lang.* 和 java.lang.xxx 是由不同的装载器装载,属于不同的运行时包,所以 java.lang.xxx 不能访问核心类库 java.lang 中类的包可见成员。
  二  Tomcat 类加载机制。
  先上一张tomcat 5的类 tomcat类加载器的结构图,虽然东西老,但是原理相同。
  Bootstrap
                  |
              System
                  |
            Common
          /                \
 Catalina          Shared
                      /  ... ...    \
            webapp1        webappN 
  (1)Bootstrap:该加载器包含由JVM提供的基本的运行时类,加上放置在系统扩展目录(<JAVA_HOME/jre/lib/ext>)的JAR文件中的类。
  注意——有些Java虚拟器(JVMs)也许把它作为不止一个类装载器用,或者作为一个类装载器用。
  (2)System - 这个类装载器通常是以CLASSPATH环境变量的内容为基础来初始化的。在使用Tomcat作为Servlet/JSP容器的Web环境中,Tomcat在启动过程中清除了原有CLASSPATH的内容,并对其进行了重新定义。



  • $CATALINA_HOME/bin/bootstrap.jar - 包含用来初始化Tomcat 5服务器的main()方法,以及它所依赖的类装载器执行类。 


  • $JAVA_HOME/lib/tools.jar - 包含用来把JSP页面转换成servlet类的"javac"编译器。  


  • $CATALINA_HOME/bin/commons-logging-api.jar - Jakarta commons 记录应用程序界面。


  • $CATALINA_HOME/bin/commons-daemon.jar - Jakarta commons        daemon API.


  • jmx.jar - JMX 1.2 执行。

  (3)Common:该类加载器包含一些对Tomcat内部类和web应用可见的额外类。其中包括1jasper-compiler.jar:JSP 2.0编译器(2)jsp-api.jar:JSP 2.0 API(3)servlet-api.jar:servlet 2.4 API等等。
  (4)Catalina:该加载器初始化用来包含实现Tomcat 5本身所需要所有类和资源;
  (5)Shared:在所有的web应用程序间共享的类和资源;
  (6)WebappN:为每个部署在单个Tomcat 5实例上的Web应用创建的类加载器。加载/WEB-INF/classes和WEB-INF/lib下的类和资源
  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

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-335048-1-1.html 上篇帖子: (转)Tomcat 系统架构与设计模式 下篇帖子: Tomcat 8 部署项目时 报错
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表