Tomcat从零开始(十)Loader
第十课:
不知不觉就10篇blog了,说实话,我是第一次更这么长时间的Blog。
嗯,今天说说Loader,在以前的课程中,也就是内个能使用最初级的servlet的那一节,我们使用了URLClassLoader加载Servlet,但是这是不科学的,因为如果用系统自带的Loader加载,servlet能访问类库太多就太不安全了。所以我们需要实现自己的一个加载器,那我们首先看看Java的Loader。
JVM在运行的时候,会产生3个classLoader,分别是Boostrap,ClassLoader,Extension Classloader、AppClassLoader。
首先第一个Bootstrap,根据他的意思就知道是启动用的,它是用C++编写的,而且实际上不是classLoader的子类,而是JVM自身实现的。在JVM源码中,我们可以看到用static const char classpathFormat [] 数组来存储 所需加载的jar之后就是extension classLoader这个类了,他是负责加载/lib/ext这个文件夹下的类的,或者java.ext.dirs这个系统属性指定(别说不知道是什么,我们在以前的课程中,经常使用的user.dir也是系统属性),因为默认的Ext.dirs对所有从同一个JRE中启动的JVM都是通用的,所以放入这个目录的JAR类包对所有的JVM和system classloader都是可见的。剩下的一个就是AppClassLoader了,我们用的url内个也是它的儿子,用来加载classpath。ClassLoader加载类用的是靠上级的方式(这个名字有点忘了 AppClassLoader->ExtClassLoader->好像是全局委托吧),就是加载类的时候,上级先找,找不到下级来。所以就是 bootstrap。我们需要思考一下为什么要采用这种模式来处理,因为如果我们编写一个具有危险性的类,注意这个类要和系统存在的类重名,比如java.lang.math,那么当加载的时候这个有危险的类就不会加载到用户,因为bootstrap就不会加载这个类,因为那时候已经有原有的java.lang.Math了。如果不采用,那就直接在用户机器上运行,破坏安全。
这里举一个例子,比如你有两个类,一个放到了ext.dirs中 这个类引用了另外一个类,另外一个放到classpath中,那么 就会报错了。因为第二个类默认用Extloader来搜索,他不会让appLoader去查找。
妥了,那现在说说Tomcat为什么要使用自己的加载器,一个原因在上面已经说了,另外就是需要缓存以前的类,和预先加载一些类做预备。当然,说这么多J2SE的loader是为了让大家不与tomcat的loader混淆, j2se是用来加载类的,而tomcat实际上是一个webApp的Loader,Loader组件必须要实现org.apache.catalina.Loader接口。
Tomcat的Loader其实也是像J2SE中那样的。
首先是Commonclass Loader,主要是加载tomcat 的common下的所有jar和类。他的上级是appclassloader
之后就是server和shared Class Loader,两只个的区别是,前者是加载tomcat的核心类,主要是tomcat的server目录。而后者是加载 web app的类(公共类)。他们的上级是common class loader
再之后就是 webappclass loader了,这个是用来加载每个app的WEB-INF/ classes和lib的。他的上级是shared class loader。但是它的加载 和 之前的不一样,刚才说了Tomcat的loader是有缓存的,如果之前的类没加载,那么就给它 上级来加载(这里就是j2se的加载了),之后,如果加载失败了,那就查找WEB-INF/classes 和 lib下,这个是怎么实现的,我下面就会说。如果再没找到,就给shared class loader。 如果以前加载过,直接从缓存取就行了。
其实这里没什么说的,其实主要理解一下Java的loader 的委托模式。
我们先来看看Loader这个接口,其中我们注意与Repository有关的方法,Repository这个单词的意思是仓库。那么思考一下,这里的repository就是代表类库的意思,add就是添加,find就是查找。那么,我们来看看
Loader的实现类,是如何实现的。这个类在org.apache.catalina.loader.WebappLoader中。
public void addRepository(String repository) { if (debug >= 1)
log(sm.getString("webappLoader.addRepository", repository)); for (int i = 0; i < repositories.length; i++) {
if (repository.equals(repositories[i]))
return;
}
String results[] = new String[repositories.length + 1];
for (int i = 0; i < repositories.length; i++)
results[i] = repositories[i];
results[repositories.length] = repository;
repositories = results; if (started && (classLoader != null)) {
classLoader.addRepository(repository);
setClassPath();
}
//我们可以看到,这里就是一个数组的操作
}
之后我们看看他的Start()方法,这个方法在Lifecycle中说过了。那么,在运行的初期,系统就会默认调用一个方法setRepositories(),这个在start()方法可以自己找到,那我贴一段setRepositories方法。
// 加载Context的工作目录
File workDir =
(File) servletContext.getAttribute(Globals.WORK_DIR_ATTR);
if (workDir == null)
return;
log(sm.getString("webappLoader.deploy", workDir.getAbsolutePath())); DirContext resources = container.getResources(); //这里,就是将这个 classes目录设置到repository中,所以不用看了,我们的apploader
//一定默认加载了 /WEB-INF/classes目录的实现。
String classesPath = "/WEB-INF/classes";
DirContext classes = null;
看到了么,这里就是默认加载classes的地方,其实/lib目录也是开始的时候就被加到repositories中了,这个希望可以自己找到。毕竟读代码也是需要多多练习的~。
我们都知道,这个东西是要跟一个容器关联的,Engine,host,Context,Wrapper这四个容器中,他关联的是context。也不是说必须关联,只是context必须要有这个加载器。另外,我们在用tomcat的时候,会发现另外一个功能,就是当我们更改完servlet之后一般都不需要重启服务器,因为tomcat存在一种reloader机制。这个reloader也是一个接口,每个加载器都必须实现这个,其实就是实现以下reloader接口的 modified方法,来看 是否被更改,更改了就重新加载。
今天先说这么多,明天我会具体的分析一下这个appclassloader这个类。其实我觉得讲了这么多了,这个类其实大家也都能看懂了吧。另外说一下,用下面这段代码,可以看bootstrap在启动的时候到底加载了什么jar。注意! 这里不能用Eclipse去用这段代码。因为eclipse的Access Rule的问题。具体的设置,我会在下面贴图。
public class Test {
public static void main(String args[]){
URL[] urls=sun.misc.Launcher.getBootstrapClassPath().getURLs();
for (int i = 0; i < urls.length; i++) {
System.out.println(urls[i].toString());
} }
}
首先看一下运行截图。
Tomcat从零开始(十)Loader的更多相关文章
- Tomcat从零开始(十一)WebappLoader概述
好的,我们先看看这个WebappLoader到底在开始的时候做了什么,先看看他的start()方法. public void start() throws LifecycleException { / ...
- Tomcat从零开始(十七)——StandardWrapper
第十七课:StandardWrapper 课前复习: 不知道大家是否还有印象,就是在6.7节课说的4种container,粗略的从大到小来说就是engine,host,context,和wrapper ...
- solr4.10.3部署到tomcat——(十)
0. 准备环境:
- Linux搭建JavaEE开发环境与Tomcat——(十)
服务器通过ip地址访问是不需要备案的,如果通过域名访问的话才需要备案. 1.安装Mysql 在CentOS7上安装MySQL时,出现了以下的提示: 原因是: CentOS7带有MariaDB而不是my ...
- tomcat在linux下自启动
Linux下设置tomcat开机自启动 一.以root用户登录系统: 二.进入init.d文件夹 cd /etc/init.d/ 三.创建并打开tomcat文件 vi tomcat 四.tomcat ...
- 从零开始学 Java - 我放弃了 .NET ?
这不是一篇引起战争的文章 毫无疑问,我之前是一名在微软温暖怀抱下干了近三年的 .NET 开发者,为什么要牛(sha)X一样去搞 Java 呢?因为我喜欢 iOS 阿!哈哈,开个玩笑.其实,开始学 Ja ...
- Eclipse的Tomcat热部署,免重启的方法
背景与目标: 最好使用MyEclipse部署Web应用,在开发调试时,非常方式.资源文件修改可以自动的同步.修改Java文件,除非改变类的结构定义,也可以实现热部署的效果. 后来使用Eclipse J ...
- tomcat使用详解(week4_day2)--技术流ken
tomcat简介 Tomcat是Apache软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,由Apache.Sun和其他一些公司及个人共同开发 ...
- linux下部署tomcat 上线jpress博客系统
tomcat Tomcat服务器是一个免费的开放源代码的Web应用服务器,属于轻量级应用服务器. tomcat有三个端口 开始部署 安装tomcat 第一步:下载tomcat 安装包 tomcat官网 ...
随机推荐
- silverlight imagesource赋值与转换
介绍几种常用的Image source 赋值方式: this.abc.Source = new BitmapImage(new Uri("/1.jpg", UriKind.Rela ...
- C#控件、窗体置顶
//控件置于顶层和底层 panel.BringToFront();//置于顶层 panel.SendToBack();//置于底层 //窗体置顶 TopMost = true;
- 【转】IOS开发小技巧
1,Search Bar 怎样去掉背景的颜色(storyboard里只能设置background颜色,可是发现clear Color无法使用). 其实在代码里还是可以设置的,那就是删除背景view [ ...
- PhotoShop-CS4使用-----如何对psd进行简单切图
一.如何快速截图 1.如果图片为psd样式 2.要用放大器放大该图,选择放大器,放大后如图 3.开始切图 以其中一个为例,选中你所要选择切的图片 4. 选中后 5.选择文件---新建 6.此 ...
- J2SE知识点摘记(九)
1. 线程操作的一些方法 方法名称 方法说明 public static int activeCount() 返回线程组中目前活动的线 ...
- libcurl编译
下载: git://github.com/bagder/curl.git openssl: openssl编译 for linux or mingw:./buildconf./configure ...
- mongodb的 或 查询,实践总结
PostcardRecord.findOne({user:userid, $or : [ { at:{$gte:start.valueOf(), $lte:end.valueOf()} } , { i ...
- [Java 8 Lambda] java.util.stream 简单介绍
包结构例如以下所看到的: 这个包的结构非常easy,类型也不多. BaseStream接口 全部Stream接口类型的父接口,它继承自AutoClosable接口,定义了一些全部Stream都具备的行 ...
- Swift学习笔记:类和结构
一.类和结构的异同 类和结构有一些相似的地方.它们都能够: 1. 定义一些能够赋值的属性: 2. 定义具有功能性的方法 3. 定义下标.使用下标语法 4. 定义初始化方法来设置初始状态 5. 在原实现 ...
- 遍历文件夹及其子文件夹下的.pdf文件,并解压文件夹下所有的压缩包
List<PDFPATH> pdfpath = new List<PDFPATH>(); List<string> ziplist = new List<st ...