现在的位置: 首页 > 综合 > 正文

How Tomcat Works 8

2018年05月22日 ⁄ 综合 ⁄ 共 3386字 ⁄ 字号 评论关闭

本章讲述tomcat中的classloader,为什么要用不同的classloader而不直接使用systemclassloader呢?因为如果那样,servlet将可以访问到系统classpath下的所有类,包括tomcat内部类,这样是违反安全的。servlet应该只可以访问放在WEB-INF/classes或WEB-INF/lib下的类。在tomcat中,org.apache.catalina.Loader表示一个loader。

另一个原因是,自己定制的loader需要完成reload的任务,也就是如果应用中WEB-INF/classes或WEB-INF/lib下的类改变了,这个loader需要在单独的线程中每隔一段时间检查一次,如果有变化,就从新load。这需要看org.apache.catalina.loader.Reloader。

 

 

一,java classloader

http://topic.csdn.net/u/20090323/23/bcb01967-571d-4427-9391-2895d02a60cd.html

使用自定义classloader的原因:

 To specify certain rules in loading classes.
 To cache the previously loaded classes.
 To pre-load classes so they are ready to use.

 

二,The Loader Interface

这个loader并不是classloader,而是web app loader,负责一个web应用的类加载。WebappClassLoader类时Loader接口的实现类,它其中包含了一个WebappClassClassLoader,这个才是具体负责加载类的classloader。

 

当WEB-INF/classes或WEB-INF/lib下的类重新编译了,那么loader要负责从新加载它们,而不用重启服务器。StandardContext里有setReloadable和getReloadable方法,来决定是否启用reload。默认情况下是不启用的,如果想改成reload,则要在server.xml中:<Context path="/myApp" docBase="myApp" debug="0" reloadable="true"/>

 

三,The Reloader Interface

为了实现reload,classloader必须要实现Reloader接口。

public void addRepository(String repository);

public String[] findRepositories ();
public boolean modified();

最重要的是modified方法,它返回一个bool值,web loader根据这个bool值来判定这个app里的类是否改变了。如果改变了,就单起一个线程去完成reload过程。

 

四,The WebappLoader Class

当WebappLoader的start方法调用时,会完成以下工作:

  •  Creating a class loader
  •  Setting repositories               //WEB-INF/classes and WEB-INF/lib
  •  Setting the class path            //在servlet context中设一个值
  •  Setting permissions                //use  security manager
  •  Starting a new thread for auto-reload.

在WebappLoader中,只有getClassLoader却没有setClassLoader,但并不是不让你改变classloader。它提供了setLoaderClass,你可以吧继承于WebappClassLoader的classloader的全限定名设置进去(必须继承WebappClassLoader,因为createClassLoader()方法的返回值是WebappClassLoader类型的)。

在start方法中会调用createClassLoader()方法,在createClassLoader()方法中,是用class.forname来加载classloader的:

Class clazz = Class.forName(loaderClass);

 

在start方法的最后,会启动一个单独的线程,专门用于reload。这个线程要看WebappLoader的run方法,在run方法中:

  • Sleep for the period specified by the checkInterval variable.
  • Check if any class it loaded has been modified by calling the modified method of the WebappLoader instance's class loader. If not, continue.
  • If a class has been modified, call the notifyContext private method to ask the Context associated with this WebappLoader to reload.

notifyContext并不直接调用context的reload方法,而是通过inner class   WebappContextNotifier,WebappContextNotifier会单起一个线程,来调用context的reload方法。

 

五,The WebappClassLoader Class

1,cache

WebappClassLoader会把已经加载过的类放在cache中,没有找到的类也放在cache中,这样下次访问时,就不用从新加载了。

每个类都被看做是一个resource,由ResourceEntry类表示它的字节码,最后更新日期和Manifest等信息。

被找到的resource放在一个叫resourceEntries.的hashmap里,没找到的类放在另一个hashmap里notFoundResources。

 

2,Loading Classes

  • All previously loaded classes are cached, so first check the local cache.
  • If not found in the local cache, check in the cache, i.e. by calling the findLoadedClass of the java.lang.ClassLoader class.
  • If not found in both caches, use the system's class loader to prevent the web application from overriding J2EE class.
  • If SecurityManager is used, check if the class is allowed to be loaded. If the class is not allowed, throw a ClassNotFoundException.
  • If the delegate flag is on or if the class to be loaded belongs to the package name in the package trigger, use the parent class loader to load the class. If the parent class loader is null, use the system class loader.
  • Load the class from the current repositories.
  • If the class is not found in the current repositories, and if the delegate flag is not on, use the parent class loader. If the parent class loader is null, use the system class loader.
  • If the class is still not found, throw a ClassNotFoundException.
【上篇】
【下篇】

抱歉!评论已关闭.