tomcat 学习笔记之 载入器

我只是一个虾纸丫 提交于 2019-12-02 06:04:58

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

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!