探索《How Tomcat Work》 心得(六) 加载器 下 Java中URL、tomcat加载器WebappLoader和WebappClassLoader
2016-07-08 16:38
811 查看
在上一篇文章中,主要介绍了jvm中类加载器的工作原理和小demo,在这篇文章中,介绍下Tomcat封装后的加载器。
Tomcat封装后的加载器,只能够加载指定库中的文件,这里,还拿第二章的程序中的加载器做个例子。
String to parse as a URL,它就表示一个URL,通过上面的代码片段,这个参数使用URL的另一个构造器URL(String protocol, String host, String file),这个构造器我之后再说,这个参数所表示的url就是我们的类加载器所加载的类的路径。最后一个参数streamHandler,官方解释:the stream handler for the URL。如果这个参数不为空的话,Check for permission to specify a handler,在构造器中就会检查处理程序的权限。这个处理中的代表类的实际路径的spec参数是非空的,其他两个参数是可以为空的,这个构造器被Tomcat看中的点,就在于那两个参数,可以添加上下文和权限控制。
下面介绍先刚刚提到的构造器URL(String protocol, String host, String file),第一个参数protocol,官方解释:the name of the protocol to use.第二个参数:the name of the host.,第三个参数:the file on the host.当我们使用这个构造器的时候,他会调取该对象内的另一构造器:代码片段如下
; 描述项目下的web_root文件夹的路径
这里的构造器URL(String protocol, String host, int port, String file,URLStreamHandler handler),这是一个最终的构造器。看了这个构造器,我就好奇了,这个东西已经很全了,这个方法不能给构造器添加上下文,其余的添加权限控制类似的东西,这里都可以搞定。通过最开始的demo可以看出,它使用两个url构造器构造一个url实例,为了后面的内容做铺垫呢,为url添加权限,和上下文。
在Tomcat中,加载器都需要实现Loader接口,回顾一下tomcat加载器的UML结构图:
从结构图中,可以看出,在Tomcat的加载器中生活在最底层的是WebappClassLoader,下面,介绍下WebappClassLoader对象与WebappLoader对象,WebappLoader可以控制WebAppClassLoader的生死。从上面的结构图中可以知道,它还继承了URLClassLoader类,从WebappLoader的start()方法的开始,Start this component, initializing our associated class loader.在开始的时候,日志组件和Lifecycle接口中做的事情就不累述了,我在后面的会把前面讲到的几个组件联合起来讲一遍,这里只说loader的事情了,看下面代码块:
1、为JNDI协议注册一个流管理工厂
4、组件一旦启动起来,下面这个方法可能会经常调用,重载。WebappLoader 支持自动重载,如果 WEB-INF/classes 或者 WEB-INF/lib 目录被重新编译过,在不重启 Tomcat 的情况下必须自动重新载入这些类。为了实现这个目的,WebappLoader 有一个单独的线程每个 x 秒会检查源的时间戳。x 的值由checkInterval 变量定义,它的默认值是 15,也就是每隔 15 秒会进行一次检查是否需要自动重载。
每一个可以被加载的类(放在 WEB-INF/classes 目录下的类文件或者 JAR 文件)都被当做一个源。一个源被 org.apache.catalina.loader.ResourceEntry 类表示。一个 ResourceEntry 实例保存一个 byte 类型的数组表示该类、最后修改的数据或者副本等等。所有缓存的源被存放在一个叫做 resourceEntries 的 HashMap 中(在WabappClassLoader中的元素),键值为源名,所有找不到的源都被放在一个名为 notFoundResources
的 HashMap 中。要注意,Tomcat没加载一个类,都会把它放到缓存中,加载器加载类的时候,也是首先在缓存中查找,找不到才会到库中去查找。
Tomcat封装后的加载器,只能够加载指定库中的文件,这里,还拿第二章的程序中的加载器做个例子。
URLClassLoader loader = null; try { URL[] urls = new URL[1]; URLStreamHandler streamHandler = null; File classPath = new File(Constants.WEB_ROOT); String repository = (new URL("file", null, classPath.getAbsolutePath() + File.separator)).toString(); urls[0] = new URL(null, repository, streamHandler); loader = new URLClassLoader(urls); } catch (MalformedURLException e) { e.printStackTrace(); }介绍下上面用到的URL的构造器, URL(URL context, String spec, URLStreamHandler handler),第一个参数,context,上下文,官方的注释:the context in which to parse the specification,从构造器中的代码的条件(((context != null) && ((newProtocol == null) || newProtocol.equalsIgnoreCase(context.protocol))))可以知道,当传入的上下文中的协议与传入参数中spec中的url协议一致的时候,构造器会使用我们传入的上下文(context)。下面介绍第二个参数,spec,官方的注释:the
String to parse as a URL,它就表示一个URL,通过上面的代码片段,这个参数使用URL的另一个构造器URL(String protocol, String host, String file),这个构造器我之后再说,这个参数所表示的url就是我们的类加载器所加载的类的路径。最后一个参数streamHandler,官方解释:the stream handler for the URL。如果这个参数不为空的话,Check for permission to specify a handler,在构造器中就会检查处理程序的权限。这个处理中的代表类的实际路径的spec参数是非空的,其他两个参数是可以为空的,这个构造器被Tomcat看中的点,就在于那两个参数,可以添加上下文和权限控制。
下面介绍先刚刚提到的构造器URL(String protocol, String host, String file),第一个参数protocol,官方解释:the name of the protocol to use.第二个参数:the name of the host.,第三个参数:the file on the host.当我们使用这个构造器的时候,他会调取该对象内的另一构造器:代码片段如下
public URL(String protocol, String host, String file) throws MalformedURLException { this(protocol, host, -1, file); }它又搞出来一个新的构造器URL(String protocol, String host, int port, String file),这个构造器比刚才的构造器多了一个端口的参数,当调用上面的构造器的方法的时候,他会使用传入的主机host在默认端口-1,中查找文件file。但是当我看这个构造器的源码的时候,这里并没有结束,它描述路径的方法:String file = (new File(Constants.WEB_ROOT)).getAbsolutePath() + File.separator
; 描述项目下的web_root文件夹的路径
public URL(String protocol, String host, int port, String file) throws MalformedURLException { this(protocol, host, port, file, null); }
这里的构造器URL(String protocol, String host, int port, String file,URLStreamHandler handler),这是一个最终的构造器。看了这个构造器,我就好奇了,这个东西已经很全了,这个方法不能给构造器添加上下文,其余的添加权限控制类似的东西,这里都可以搞定。通过最开始的demo可以看出,它使用两个url构造器构造一个url实例,为了后面的内容做铺垫呢,为url添加权限,和上下文。
在Tomcat中,加载器都需要实现Loader接口,回顾一下tomcat加载器的UML结构图:
从结构图中,可以看出,在Tomcat的加载器中生活在最底层的是WebappClassLoader,下面,介绍下WebappClassLoader对象与WebappLoader对象,WebappLoader可以控制WebAppClassLoader的生死。从上面的结构图中可以知道,它还继承了URLClassLoader类,从WebappLoader的start()方法的开始,Start this component, initializing our associated class loader.在开始的时候,日志组件和Lifecycle接口中做的事情就不累述了,我在后面的会把前面讲到的几个组件联合起来讲一遍,这里只说loader的事情了,看下面代码块:
1、为JNDI协议注册一个流管理工厂
if (container.getResources() == null) return; // Register a stream handler factory for the JNDI protocol URLStreamHandlerFactory streamHandlerFactory = new DirContextURLStreamHandlerFactory(); try { URL.setURLStreamHandlerFactory(streamHandlerFactory); } catch (Throwable t) { // Ignore the error here. }2、创建classloader加载器,运用java中的反射创建classloader加载器,其中在下面代码块中的变量 loaderClass,是定义好了的常量,Tomcat默认加载器的类名:“org.apache.catalina.loader.WebappClassLoader”
Class clazz = Class.forName(loaderClass); WebappClassLoader classLoader = null; if (parentClassLoader == null) { // Will cause a ClassCast is the class does not extend WCL, but // this is on purpose (the exception will be caught and rethrown) classLoader = (WebappClassLoader) clazz.newInstance(); } else { Class[] argTypes = { ClassLoader.class }; Object[] args = { parentClassLoader }; Constructor constr = clazz.getConstructor(argTypes); classLoader = (WebappClassLoader) constr.newInstance(args); }3、装载有特色的classLoader,下面的各种设置中最主要的就是设置类库列表 addRepository,为classloader指定库,不仅如此,在设置完库之后,他又设置权限相关内容,使classLoader加载各种url中,按照与url匹配的协议加载,这样设置之后,对于首先的classLoader,用起来是安全的。
classLoader.setResources(container.getResources()); classLoader.setDebug(this.debug); classLoader.setDelegate(this.delegate); for (int i = 0; i < repositories.length; i++) { classLoader.addRepository(repositories[i]); } // Configure our repositories setRepositories(); setClassPath(); setPermissions();
4、组件一旦启动起来,下面这个方法可能会经常调用,重载。WebappLoader 支持自动重载,如果 WEB-INF/classes 或者 WEB-INF/lib 目录被重新编译过,在不重启 Tomcat 的情况下必须自动重新载入这些类。为了实现这个目的,WebappLoader 有一个单独的线程每个 x 秒会检查源的时间戳。x 的值由checkInterval 变量定义,它的默认值是 15,也就是每隔 15 秒会进行一次检查是否需要自动重载。
if (reloadable) { log(sm.getString("webappLoader.reloading")); try { threadStart(); } catch (IllegalStateException e) { throw new LifecycleException(e); } }5、重载,下面就是重载线程所做的事情:检查classloader是否发生改变,如果发生改变了,这里会通知上下文,上下文会唤醒一个线程 WebappContextNotifier,这个线程运行,就是让容器重载: ((Context) container).reload();
try { // Perform our modification check if (!classLoader.modified()) continue; } catch (Exception e) { log(sm.getString("webappLoader.failModifiedCheck"), e); continue; } // Handle a need for reloading notifyContext();6、缓存。
每一个可以被加载的类(放在 WEB-INF/classes 目录下的类文件或者 JAR 文件)都被当做一个源。一个源被 org.apache.catalina.loader.ResourceEntry 类表示。一个 ResourceEntry 实例保存一个 byte 类型的数组表示该类、最后修改的数据或者副本等等。所有缓存的源被存放在一个叫做 resourceEntries 的 HashMap 中(在WabappClassLoader中的元素),键值为源名,所有找不到的源都被放在一个名为 notFoundResources
的 HashMap 中。要注意,Tomcat没加载一个类,都会把它放到缓存中,加载器加载类的时候,也是首先在缓存中查找,找不到才会到库中去查找。
相关文章推荐
- 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简单理解
- Linux部署Tomcat服务器
- c++11 + SDL2 + ffmpeg +OpenAL + java = Android播放器