有个同事提高个jrebel的工具,提起tomcat的热部署方案。

jrebel是一款收费的JVM级的热部署工具包。

JVM级的热部署也就是说,可以不重启JVM,让修改或添加的类加载到JVM中。

加载器:启动类加载器-》扩展类加载器-》应用程序类加载器-》自定义类加载器。

对JVM来说只有一种启动类加载器(Bootstrap ClassLoader)是C++写的。

这个类加载器负责将存放在<JAVA_HOME>\lib目录中的,

或者被-Xbootclasspath参数所指定的路径中的,并且是虚拟机识别的(仅按照文件名识别,如rt.jar,名字不符合的类库即使放在lib目录中也不会被加载)类库加载到虚拟机内存中。启动类加载器无法被Java程序直接引用。

Java实现的加载器的:扩展类加载器,应用程序类加载器,自定义类加载器。

什么是双亲委派模型?

按这个顺序:启动类加载器-》扩展类加载器-》应用程序类加载器-》自定义类加载器。去加载类。也就是当你用自定义类加载器加载某类时,一定要从启动类加载器(<JAVA_HOME>\lib)这个目录中的jar中找先。例如类java.lang.Object,它存放在rt.jar之中,无论哪一个类加载器要加载这个类,最终都是委派给处于模型最顶端的启动类加载器进行加载,因此Object类在程序的各种类加载器环境中都是同一个类。

打破双亲委派模型

如果基础类又要调用回用户的代码,那该怎么办?这并非是不可能的事情,一个典型的例子便是JNDI服务,JNDI现在已经是Java的标准服务,它的代码由启动类加载器去加载(在JDK 1.3时放进去的rt.jar),但JNDI的目的就是对资源进行集中管理和查找,它需要调用由独立厂商实现并部署在应用程序的Class Path下的JNDI接口提供者(SPI,Service Provider Interface)的代码,但启动类加载器不可能“认识”这些代码,因为启动类加载器的搜索范围中找不到用户应用程序类,那该怎么办?为了解决这个问题,Java设计团队只好引入了一个不太优雅的设计:线程上下文类加载器(Thread Context ClassLoader)。这个类加载器可以通过java.lang.Thread类的setContextClassLoader()方法进行设置

Tomcat的类加载器架构

在Tomcat目录结构中,有3组目录(“/common/*”、“/server/*”和“/shared/*”)可以存放Java类库,另外还可以加上Web应用程序自身的目录“/WEB-INF/*”,一共4组,把Java类库放置在这些目录中的含义分别如下:

①放置在/common目录中:类库可被Tomcat和所有的Web应用程序共同使用。

②放置在/server目录中:类库可被Tomcat使用,对所有的Web应用程序都不可见。

③放置在/shared目录中:类库可被所有的Web应用程序共同使用,但对Tomcat自己不可见。

④放置在/WebApp/WEB-INF目录中:类库仅仅可以被此Web应用程序使用,对Tomcat和其他Web应用程序都不可见。

CommonClassLoader、CatalinaClassLoader、SharedClassLoader和WebappClassLoader则是Tomcat自己定义的类加载器,它们分别加载/common/*、/server/*、/shared/*和/WebApp/WEB-INF/*中的Java类库。其中WebApp类加载器和Jsp类加载器通常会存在多个实例,每一个Web应用程序对应一个WebApp类加载器,每一个JSP文件对应一个Jsp类加载器。Tomcat 6.x顺理成章地把/common、/server和/shared三个目录默认合并到一起变成一个/lib目录,这个目录里的类库相当于以前/common目录中类库的作用。

Tomcat和server.xml中的 reloadble=true时

<Context docBase="" path="" reloadable="true" source=""/></Host>

Tomcat的加载是怎样的呢?看看tomcaat源码。

public void backgroundProcess() {

if (reloadable && modified()) {

try {

Thread.currentThread().setContextClassLoader

(WebappLoader.class.getClassLoader());

if (context != null) {

context.reload();

}

} finally {

if (context != null && context.getLoader() != null) {

Thread.currentThread().setContextClassLoader

(context.getLoader().getClassLoader());

}

}

}

}

有个后台线程扫.class文件,如果有修改就使用(Appclassloader)应用程序类加载器去动态加载被修改过的class到JVM中:context.reload()重启上下文。也是就是重启当前的WEB应用程序;。而不是重启jvm去静态加载.class。

请看这个if:if (reloadable && modified()) ,如果reloadble=true而且有.class文件被修改过。就会重启上下文件。那么添加.class会不会也重启上下文呢?请看下面代码:

public boolean modified() {

if (log.isDebugEnabled())

log.debug("modified()");

for (Entry<String,ResourceEntry> entry : resourceEntries.entrySet()) {

long cachedLastModified = entry.getValue().lastModified;

long lastModified = resources.getClassLoaderResource(

entry.getKey()).getLastModified();

if (lastModified != cachedLastModified) {

if( log.isDebugEnabled() )

log.debug(sm.getString("webappClassLoader.resourceModified",

entry.getKey(),

new Date(cachedLastModified),

new Date(lastModified)));

return true;

}

}

// Check if JARs have been added or removed

WebResource[] jars = resources.listResources("/WEB-INF/lib");

// Filter out non-JAR resources

int jarCount = 0;

for (WebResource jar : jars) {

if (jar.getName().endsWith(".jar") && jar.isFile() && jar.canRead()) {

jarCount++;

Long recordedLastModified = jarModificationTimes.get(jar.getName());

if (recordedLastModified == null) {

// Jar has been added

log.info(sm.getString("webappClassLoader.jarsAdded",

resources.getContext().getName()));

return true;

}

if (recordedLastModified.longValue() != jar.getLastModified()) {

// Jar has been changed

log.info(sm.getString("webappClassLoader.jarsModified",

resources.getContext().getName()));

return true;

}

}

}

if (jarCount < jarModificationTimes.size()){

log.info(sm.getString("webappClassLoader.jarsRemoved",

resources.getContext().getName()));

return true;

}

// No classes have been modified

return false;

}

看到//jar has been added没有,所以肯定也会重启加载。

Jrebel热部署的原理就很清晰了,就是只加载调用appclassloader加载.class到jvm中,而不context.reload()重启上下文就行了。

浅谈jrebel的更多相关文章

  1. 浅谈 Fragment 生命周期

    版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/Fragment 文中如有纰漏,欢迎大家留言指出. Fragment 是在 Android 3.0 中 ...

  2. 浅谈 LayoutInflater

    浅谈 LayoutInflater 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/View 文中如有纰漏,欢迎大家留言指出. 在 Android 的 ...

  3. 浅谈Java的throw与throws

    转载:http://blog.csdn.net/luoweifu/article/details/10721543 我进行了一些加工,不是本人原创但比原博主要更完善~ 浅谈Java异常 以前虽然知道一 ...

  4. 浅谈SQL注入风险 - 一个Login拿下Server

    前两天,带着学生们学习了简单的ASP.NET MVC,通过ADO.NET方式连接数据库,实现增删改查. 可能有一部分学生提前预习过,在我写登录SQL的时候,他们鄙视我说:“老师你这SQL有注入,随便都 ...

  5. 浅谈WebService的版本兼容性设计

    在现在大型的项目或者软件开发中,一般都会有很多种终端, PC端比如Winform.WebForm,移动端,比如各种Native客户端(iOS, Android, WP),Html5等,我们要满足以上所 ...

  6. 浅谈angular2+ionic2

    浅谈angular2+ionic2   前言: 不要用angular的语法去写angular2,有人说二者就像Java和JavaScript的区别.   1. 项目所用:angular2+ionic2 ...

  7. iOS开发之浅谈MVVM的架构设计与团队协作

    今天写这篇博客是想达到抛砖引玉的作用,想与大家交流一下思想,相互学习,博文中有不足之处还望大家批评指正.本篇博客的内容沿袭以往博客的风格,也是以干货为主,偶尔扯扯咸蛋(哈哈~不好好工作又开始发表博客啦 ...

  8. Linux特殊符号浅谈

    Linux特殊字符浅谈 我们经常跟键盘上面那些特殊符号比如(?.!.~...)打交道,其实在Linux有其独特的含义,大致可以分为三类:Linux特殊符号.通配符.正则表达式. Linux特殊符号又可 ...

  9. 浅谈Angular的 $q, defer, promise

    浅谈Angular的 $q, defer, promise 时间 2016-01-13 00:28:00  博客园-原创精华区 原文  http://www.cnblogs.com/big-snow/ ...

随机推荐

  1. About English Web Site Font

    Which font will you choose when develop one website! Actually , I have no idea about this! If you ha ...

  2. JaVA web服务器配置

    1:第一是下载好Eclipse开发工具,这里不做叙述,自行下载安装. 2:使用Eclipse开发WEB项目,启动Eclipse,选择File--->new --->other---> ...

  3. Picasso VS Glide

    原文: Introduction to Glide, Image Loader Library for Android, recommended by Google 在泰国举行的谷歌开发者论坛上,谷歌 ...

  4. preventDefault()对象

    preventDefault() 方法 Event 对象 定义和用法 取消事件的默认动作. 语法 event.preventDefault() 说明 该方法将通知 Web 浏览器不要执行与事件关联的默 ...

  5. 通过委托更新UI(异步加载)

    来自:http://blog.csdn.net/gongzhe2011/article/details/27351853 using System.Windows.Forms; using Syste ...

  6. 生成全局唯一ID

    在实际业务处理中,有时需要生成全局唯一ID来区别同类型的不同事物,介绍一下几种方式及其C++实现 //获取全局唯一ID //server_id为服务的id,因当同一个服务部署在多个服务器上时,需要区别 ...

  7. JS控制A标记的href跳转

    var a = document.getElementById("aHref"); a.href = '/user'; //取消<a>标签原先的onclick事件,使& ...

  8. Binder学习笔记(二)——defaultServiceManager()返回了什么?

    不管是客户端还是服务端,头部都要先调用 sp < IServiceManager > sm = defaultServiceManager(); defaultServiceManager ...

  9. iOS模拟器录屏转gif神器

    我发现苹果的Quick Time Player用来录屏就挺好用的.打开后选择 文件 - 新建屏幕录制 - 点击录制按钮, 划出要录制的模拟器窗体 - 点击录制就可以了. 录制成mov格式还要再转成gi ...

  10. IOS中录音后再播放声音太小问题解决

    1.AVAudioSessionCategory说明 1.1 AVAudioSessionCategoryAmbient 或 kAudioSessionCategory_AmbientSound 用于 ...