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 加载器的命名空间
每个加载器都有自己的命名空间,命名空间由该加载器以及父类所有的加载器所加载的类组成,当加载器加载一个雷的时候首先会去自己的命名空间中查找 是否 加载过这个类。在同一命名空间不会出现出现类的完整名字完全相同的两个类,在不同的命名空间中有可能出现类的完整名字完全相同的两个类。
类加载器 | 命名空间 |
---|---|
Loader1 | Class1 |
Loader2 | Class1Class2 |
Loader3 | Class1Class2Class3 |
Loader4 | Class1Class2Class3 |
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
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- i-jetty环境搭配与编译
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 实现单Tomcat多Server配置
- 生产环境下的Tomcat配置
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- bootstrap初试进度条
- Linux部署Tomcat服务器
- c++11 + SDL2 + ffmpeg +OpenAL + java = Android播放器