1、标准web 应用程序的载入器,tomcat 中的载入器
- servlet 容器需要实现一个自定义的载入器
- 由于servlet 容器不能完全信任运行的servlet 程序
- 使用系统类的载入器,则该类可以访问任何程序,包括本地虚拟机中环境变量classpath 指明的所有类,非常危险
- servlet 应该只允许载入WEB-INF/classes 目录和WEB-INF/lib 目录
- 在 Catalina 中,载入器是 org.apache.catalina.Loader 接口的实例
实现一个自定义的载入器另一个原因
- 提供自动重载功能
- WEB-INF/classes 目录和WEB-INF/lib 目录发生变化时,重新加载这些类
- 自动重载功能 实现org.apache.catalina.loader.Reloader 接口
2、java 的类载入器
- 每次创建类实例,先将类加载到内存中
- 会在java核心类库,以及classpath 变量中指明的目录中扫描相关类
- 找不到抛异常:ClassNotFoundException
3、JVM 三种类载入器
- 引导类载入器(bootstrap class loader)
- 扩展类载入器(extension class loader)
- 系统类载入器(system class loader)
- --------------三个类是父子继承关系,从上到下的顺序
引导类载入器(bootstrap class loader)
- 引导启动java 虚拟机
扩展类载入器(extension class loader)
- 载入标准扩展类目录中的类(jdk/jre/lib/ext)
系统类载入器(system class loader)
- 默认类载入器,搜索classpath指明的 路径和jar文件
类载入器代理模型
- 按照从上到下的顺序载入,优先级递减
- 主要是为了解决类载入过程中的安全性问题
- 可以使用安全管理器来限制某个类或路径的访问
- 举例:某人在硬盘上写上java.lang.Object 会被忽略,而不是覆盖系统的Object类
继承java.lang.ClassLoader 可以实现自己的类载入器
tomcat之所以使用自定义类载入器原因:
- 为了在载入类中指定某些规则
- 为了缓存已经载入的类
- 为了实现类的预载入,方便使用
4、Loader 接口
在载入web应用程序中需要servlet 类及其相关类时,需要遵守一些明确规则
- 应用程序的servlet 类只能部署在WEB-INF/classes 目录下
- servlet 类不能访问其他路径的类,即使这些类包含在当前tomcat jvm的classpath 路径下
- servlet 类只能访问 WEB-INF/lib 目录下
tomcat 载入器指的是web 应用程序载入器
- 必须实现 org.apache.catalina.Loader 接口
- 实现中会使用 org.apache.catalina.WebappClassLoader
WEB-INF/classes 和WEB-INF/lib 作为仓库被添加到载入器中的
- addRepository 添加一个仓库
- getRepository 获取所有已添加仓库数组对象
tomcat 载入器会和一个Context 级别容器关联
- Context 中一个或多个类被修改了,loader 接口支持自动重载(程序员不需要重启tomcat)
- loader 接口使用 modified方法自动重载
- 配置自动重载
载入器实现会指明,是否委托给一个父类载入器
具体实现中使用了org.apache.catalina.WebappClassLoader 继承自 java.net.URLClassLoader
5、Reloader 接口
- 为了支持类的自动加载
6、WebappLoader 类
- org.apache.catalina.WebappLoader 实现了 Loader 接口
- 其实例就是web 应用程序中的载入器
- 也实现了LifeCycle 接口,其相关联的容器启动和关闭
- 实现了 RunnerAble 接口
调用WebappLoader 的start 方法,会完成以下几项重要工作:
- 创建一个类载入器
- 设置仓库
- 设置类路径
- 设置访问权限
- 启动一个新线程支持自我重载
(1)创建一个类载入器
- 私有字符串变量loaderClass 默认保存的是org.apache.catalina.WebappClassLoader
- 也可以继承WebappClassLoader,实现自定义类加载器(不继承,会抛异常)
(2)设置仓库
- 调用 setRepository 将WEB-INF/classes 目录传入类加载器addRepository
- WEB-INF/lib 目录传入类加载器 setJarPath
(3)设置类路径
(4)设置访问权限
- 启用了安全管理器,使用setPermission 设置相关目录访问权限
(5)开启新线程开启类的重新载入
- WebappLoader 使用一个线程周期性扫描资源的时间戳(时间间隔是变量checkInterval 默认15秒)
7、WebappClassLoader 类(载入器类)
该类设计考虑了优化和安全两个方案
- 缓存之前已经载入的类来提升性能(缓存加载失败的类,下次访问直接抛异常)
安全性
- 不允许载入某些类,写入triggers 变量
- 委托给系统类载入器
(1)类缓存
- 为了达到更好的性能,会缓存已载入的类
可以是本地缓存
- ClassLoader 维护一个Vector 对象,保存已载入的类,防止其被当垃圾回收
WebAppClassLoader 载入的类都是为资源(org.apache.catalina.ResourceEntry的实例)
该实例会保存
- class文件字节流
- 最后修改时间
- Manifest信息(如果来自 jar文件的话)
- 已缓存类会存储在一个叫resourceEntries的hashMap 中,key为载入资源名称
(2)载入类
遵守以下规则
- 由于所有类都已缓存,先检查本地缓存
- 本地缓存没有检查上一层缓存(即ClassLoader 类的 findLoadedClass 方法)
- 二者都没有使用系统类载入器载入(防止web应用程序的类覆盖javaee的类)
- 若启用了SecurityManager ,检查是否允许载入该类;如果不允许,抛出 ClassNotFoundException
- 打开delegate 标志位,或者带载入的类属于包触发器的包名,使用父载入器载入,(父为空,使用系统载入器)
- 从当前仓库中载入相关类
- 当前仓库没有,且标志位delegate 关闭,使用父载入器载入,(父为空,使用系统载入器)
- 仍未找到抛出ClassNotFoundException
来源:oschina
链接:https://my.oschina.net/u/3847203/blog/1837885