文档章节

Tomcat类加载

小菜鸡1
 小菜鸡1
发布于 2016/08/03 15:21
字数 2061
阅读 47
收藏 1

一、类加载器实例之——Tomcat

主流的Java Web服务器,如Tomcat、Jetty、WebLogic、WebSphere,都实现了自己定义的类加载器(一般都不止一个)。因为一个功能健全的Web服务器,要解决如下问题:

  • 部署在同一个服务器上的两个Web应用程序所使用的Java类库可以使用相互隔离。这是最基本的要求,因为不同应用可能依赖同一个类库的不同版本,不能要求每个类库在一个服务器只有一个版本,应当保证两个应用程序的类库可以互相独立使用
  • 部署在同一个服务器上的两个Web应用程序所使用的Java类库可以互相共享。这个也很正常,比如我有10个应用程序,都用到Spring,那么我不可能放10份Spring相关的类库吧。
  • 服务器需要尽可能地保证自身的安全不受部署的Web应用程序影响。目前很多Java Web服务器也是Java实现的,因此肯定有库依赖问题。一般来说,基于安全考虑,服务器所使用的类库应该和应用程序的类库相互独立
  • 支持Jsp应用的Web服务器,十有八九都需要支持HotSwap功能。因为Jsp本质上还是需要被编译成.class文件才能被JVM执行,但Jsp在运行时被修改的概率比较大。因此主流Web服务器都会支持Jsp生成类的热替换

由于以上几个要求,如果只有一个CLASSPATH就很难实现了。所以各种Web服务器都会提供好几个CLASSPATH路径供用 户存放第三方类库,这些路径一般都以lib或者classes命名。被放置在不同目录的类库,具备不同的访问范围和服务对象。通常而言,每一个目录都会有 一个对应的自定义类加载器去加载设置在里面的Java类库。那么我们就以Tomcat为例来看一下。

1. Tomcat目录结构

在Tomcat目录结构中,有三组目录可以存放Java类库,另外加上应用程序自身的目录,一共四组:

  1. 放置在/common目录中:类库可被Tomcat和所有Web应用程序共同使用
  2. 放置在/server目录中:类库只能被Tomcat使用
  3. 放置在/shared目录中:类库可以Web应用程序共同使用,但是Tomcat不能使用
  4. 放置在/webapp/WEB-INF目录中:仅仅可以被这个Web应用程序使用,Tomcat和其它Web应用程序不能使用

为了支持这套目录,并对目录内的类库进行加载和隔离,Tomcat自定义了几个类加载器,这些类加载器按照经典的双亲委派模型来实现,如下图所示:

img

  • 其中最上层的3个是JVM的类加载器(因为Tomcat也相当于一个Java程序,它只是将程序员写的Java程序做了一个封装)
  • CommonClassLoader:对应/common目录
  • CatalinaClassLoader:对应/server目录
  • SharedClassLoader:对应/shared目录
  • WebAppClassLoader:对应/webapp/WEB-INF目录

其中WebAppClassLoader和JsperClassLoader会存在多个实例,每一个WebApp对应一个WebApp类加载器,每一个Jsp文件对应一个Jsp类加载器。

上面的图我们也能看出它们之间的隔离性:

  • Common类加载器加载的类可以被Catalina类加载器和Shared类加载器使用
  • Catalina类加载器和Shared类加载器相互隔离
  • WebApp类加载器可以使用Shared类加载器加载的类
  • 各个WebApp类加载器之间加载的类相互隔离
  • 各个Jsp类加载器加载的仅仅是这个Jsp文件编译出来的那个.class文件,它出现的目的就是被丢弃,如果修改,就会新建一个Jsp类加载器替换原来的那个,实现HotSwap

2. Tomcat版本升级

对于Tomcat的6.x版本,只有指定了conf/catalina.properties配置文件中的server.loader和 share.loader才会真正建立CatalinaClassLoader和SharedClassLoader的实例,否则会以 CommonClassLoader代替。而默认的配置里面是没有设置这两个loader的,所以Tomcat 6.x顺理成章的把/commmon、/server、/shared这三个目录合并为一个/lib目录。这是Tomcat团队为了简化大多数部署场景所 做的一项改进,如果默认设置不能满足需求,再通过修改配置完成3种类加载器的协同分工。

二、OSGi:灵活的类加载器结构

传说Java社区流传这样一句话:学习JEE规范,去看JBoss源码;学习类加载器,去看OSGi源码。可见,OSGi的类加载器机制确实值得学习。

OSGi(Open Service Gateway Initiative)是OSGi联盟制定的一个基于Java语言的动态模块化规范,最初是Sun、IBM、爱立信等公司联合发起,目的是使服务提供商通过住宅网关为各种家用智能设备提供各种服务,后来这个规范在Java其他技术领域都有不错的发展,现在已经成为Java世界中“事实上”的模块化标准。OSGi在程序员中最著名的应用案例Eclipse。你对Eclipse进行设置后,不需要重启就可以完成某个功能的开启或关闭,这就是OSGi的功劳。

看了之后,给我的感觉就是这东西非常灵活。OSGi的基本单位是Bundle,每个Bundle都可以有自己的类加载器和父加载器。而Bundle 和类也差不多,内部也是package和class组成。但是一个Bundle可以声明它依赖的Java Packeage(通过Import-Package描述),也可以声明它允许导出发布的Java Package(通过Export-Package描述)。在OSGi中,Bundle之间的依赖关系从传统的上层模块依赖叠层模块转变为平级模块之间的依赖,而且类库的可见性得到了非常精确的控制,一个模块里只有被Export过的Package才能被外界访问,其他的Package和class会被隐藏。所以,OSGi才能支持热插拔技术。

而OSGi拥有这么诱人特性的原因就是它的类加载器架构。举一个简单的例子:

  • Bundle A:声明发布了packageA,依赖了java.*的包
  • Bundle B:声明依赖了packageA和packageC,同时也依赖了java.*的包
  • Bundle C:声明发布了packageC,依赖了packageA

那么,三者之间的关系可以用下图表示:

img

从上图可以看出来,OSGi里面的加载器不再是双亲委派模型的树形结构,而是进一步发展成了一种运行时才能确定的网状结构。更灵活的同时肯定带来了更复杂的使用方法,这点在实际应用中确实值得权衡。

一般来说,在OSGi中,加载一个类可能发生的查找行为和委派关系会比上图复杂的多,大体规则可以总结为:

  1. 以java.*开头的类,委派给父类加载器加载
  2. 委派列表名单内的类,委派给父类加载器加载
  3. Import列表中的类,委派给Export这个类的Bundle的类加载器加载
  4. 查找当前Bundle的CLASSPATH,使用自己的类加载器加载
  5. 否则,查找是否在自己的Fragment Bundle中,如果是则委派给Fragment Bundle的类加载器加载
  6. 否则,查找Dynamic Import列表的Bundle,委派给对应Bundle的类加载器加载
  7. 否则,类查找失败

本文转载自:

小菜鸡1
粉丝 10
博文 59
码字总数 16851
作品 0
深圳
程序员
私信 提问
Tomcat7.0源码分析——类加载体系

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/beliefer/article/details/50995516 前言Tomcat遵循J2EE规范,实现了Web容器。很多有关web的书籍和文章都离不...

泰山不老生
2016/03/28
0
0
【死磕 Tomcat】—关于tomcat热加载的一些思考

原文作者:黄晓峰 原文链接:https://blog.csdn.net/dwademia/article/details/80512916 在前面的文章中,我们分析了 tomcat 类加载器的相关源码,也了解了 tomcat 支持类的热加载,意味着 ...

黄晓峰
2018/09/08
0
0
【死磕 Tomcat】—类加载器

原文作者:黄晓峰 原文链接:https://blog.csdn.net/dwademia/article/details/80140585 在分析 tomcat 类加载之前,我们简单的回顾下 java 体系的类加载器 启动类加载器(Bootstrap ClassLo...

黄晓峰
2018/09/08
0
0
图解Tomcat类加载机制(阿里面试题)

Tomcat的类加载机制是违反了双亲委托原则的,对于一些未加载的非基础类(Object,String等),各个web应用自己的类加载器(WebAppClassLoader)会优先加载,加载不到时再交给commonClassLoader走双...

群星纪元
04/22
0
0
The method getJspApplicationContext(ServletContext

The method getJspApplicationContext(ServletContext) is undefined for the typ 搜索了半天,原来是类加载机制的问题,在tomcat的conf下的context.xml里面加上一句 <Loader delegate="true......

土鳖的弟弟
2015/06/11
0
0

没有更多内容

加载失败,请刷新页面

加载更多

跨域的理解,以及解决方案!

/*什么是跨域? * 跨域的主要原因是浏览器的同源策略。 * =>>所谓的同源策略就是A网页设置的 Cookie,B网页不能打开,除非这两个网页"同源"。 * 什么是同源? * =>>同源就是协议相同、域名相同...

流年那么伤
7分钟前
1
0
Nginx配置try_fiels,php无法获取$_GET参数

平时开发都是用LNMP,新安装的虚拟机在配置nginx的rewrite的时候使用try_files命令。但是在写的时候配置成“try_files $uri $uri/ /index.php?q=args;”, 在PHP的web程序中,打印$_GET为空。...

叫我哀木涕
8分钟前
0
0
【原创】Microsoft Edge可以用localhost访问但无法用IP访问

Microsoft Edge可以用localhost和127.0.0.1访问但无法用本机IP访问, chrome ie都可以推测是edge的问题,网络是专用网络,防火墙也关了: 在edge里 按F12 以在控制台里看到这句 CONSOLE21301...

shzwork
8分钟前
0
0
Python利用数学方程式画4种不一样的心型图案

前言 下面这四个心型图案,是通过科学地计算,根据数学方程式生成的,虽然做的不是特别完美,但是基本的还是能实现的 第一个心型 结果图 第二心型 结果图 学习从来不是一个人的事情,要有个相互监...

A_裙232550246
9分钟前
0
0
微信带场景参数的二维码生成与使用?

微信公众号推广时,用户通过扫二维码关注公众号,需要统计用户是通过谁的二维码进行关注。 在用户扫码关注公众号时,二维码带上推广者的参数,在关注公众号后,获取到该推广者的参数。 目前有...

wxgzhgncj
9分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部