《How Tomcat Works》读书笔记(八)Loader

Loader就是一个普通的Java类加载器。

Tomcat通过实现org.apache.catalina.Loader接口来定义Loader,一个servlet容器需要制定自己的 Loader
  1. servlet容器不应该信任servlet,如果容器使用系统类加载器,那么servlet可以"看见"CLASSPATH中的class.
  2. 在加载类时可以加入特定的规则
  3. 可以换成之前加载过的类
  4. 支持自动重加载(热部署):自定制的类加载器(S)使用另外一个线程一直检查servlet和它依赖的class(S负责加载的)的时间戳,当WEB-INF/classes或WEB-INF/lib目录中的类被改变时,重新加载之。只需实现org.apache.catalina.loader.Reloader接口

Java类加载器

jvm从java1.2开始使用3个类加载器:启动类加载器(祖父 GF)、扩展类加载器(父亲 F)、系统类加载器(儿子 S)。

  1. GF:由操作系统本地代码编写,负责加载JVM启动所需的类库,还负责加载Java核心类库(如java.lang.*、java.io.*)
  2. F:负责加载在标准扩展目录中的类(/jdk/jre/lib/ext)
  3. S:加载CLASSPATH中的类.

双亲委托模式

      当JVM要加载一个类时,S首先被调用,但S不会去直接加载这个类,他会委托给F,而F会委托给GF,如果GF没有找到这个类就让F去加载,如果F也没找到,就让S去加载。如果最后S也没找到,就会抛出java.lang.ClassNotFoundException异常。

双亲委托模式有效保证了类加载的安全性:
      有人恶意写了一个java.lang.String类,希望能够替代java核心同名类,当String在程序某处被调用时,S委托F,F委托GF,GF会找到真正的Java核心库中的String类并加载,而恶意的String不会获得被加载的机会。

Web应用在加载servlet和其他class是要遵守规则的:
      servlet只可以使用部署在WEB-INF/classes或其子目录下的class.
放在WEB-INF/lib下的jar.

一个Tomcat的Loader代表的是一个Web应用加载器而不是一个类加载器.它必须实现org.apache.catalina.Loader接口.一个Loader的实现拥有一个类加载器(org.apache.catalina.loader.WebappClassLoader)并可以通过Loader接口中定义的getClassLoader方法获得它。

Loader通常会和一个Context(代表一个Web应用,也是一个容器)绑定在一起通过Loader接口中定义的getContainer和setContainer方法,获得和设置Context.

重加载
      如果Conext中的class被改变了,Loader(如果支持的话)会调用Context接口中定义的reload方法重新加载它们,而不需要重启Tomcat。Loader中定义了setReloadable和getReloadable来决定是否支持重加载。
      默认的org.apache.catalina.core.StandardContext是不支持重加载的,如果想要支持,我们需要在server.xml添加一个Context元素:
      <Context path="/myApp" docBase="myApp" debug="0" reloadable="true"/>

Loader接口定义

public interface Loader {
    public ClassLoader getClassLoader();
    public Container getContainer();
    public void setContainer(Container container);
    public DefaultContext getDefaultContext();
    public void setDefaultContext(DefaultContext defaultContext);
    public boolean getDelegate();
    public void setDelegate(boolean delegate);
    public String getInfo();
    public boolean getReloadable();
    public void setReloadable(boolean reloadable);
    public void addPropertyChangeListener(PropertyChangeListener listener);
    public void addRepository(String repository);
    public String[] findRepositories();
    public boolean modified();
    public void removePropertyChangeListener(PropertyChangeListener listener);
}

Tomcat提供了一个Loader的实现:org.apache.catalina.loader.WebappLoader
并且提供了它的类加载器实现:org.apache.catalina.loader.WebappClassLoader(继承了java.net.URLClassLoader类)
《How Tomcat Works》读书笔记(八)Loader

Reloader接口

public interface Reloader {
    public void addRepository(String repository);
    public String[] findRepositories ();
    //true:支持重加载
    public boolean modified();
}
org.apache.catalina.loader.WebappLoader
  1. 创建一个类加载器
  2. 设置repositories仓库(可以理解为Loader去加载class的地方)
  3. 设置classpaht
  4. 设置权限
  5. 开启一个新线程来实现自动重加载(循环检查)

org.apache.catalina.loader.WebappClassLoader

缓存加载过的类

  1. local cache:WebappClassLoader实例自己来管理
  2. super cache:java.lang.ClassLoader管理了一个Vector(存之前加载过的类)来防止GC,由超类管理
加载类
  1. 检查local cache
  2. 检查super cache
  3. 检查repositories仓库 找到加载 找不到抛异常ClassNotFoundException

你可能感兴趣的:(tomcat)