有个同事提高个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. 小组作业wordCountPro·

    基本任务:代码编写+单元测试 (1) Github地址: https://github.com/LongtermPartner/ExtendWordCount (2) PSP表格:   psp 2.1 ...

  2. LeetCode第21题:合并两个有序链表

    题目描述: 将两个有序链表合并为一个新的有序链表并返回.新链表是通过拼接给定的两个链表的所有节点组成的. 示例: 输入:1->2->4, 1->3->4 输出:1->1- ...

  3. C++面试笔记--STL模板与容器

    1.C++ STL 之所以得到广泛的赞誉,也被很多人使用,不只是提供了像vector, string, list等方便的容器,更重要的是STL封装了许多复杂的数据结构算法和大量常用数据结构操作.vec ...

  4. 《Effective Java》第3章 对于所有对象都通用的方法

    第8条:覆盖equals时请遵守通用约定 覆盖equals方法看起来似乎很简单,但是有许多覆盖方式会导致错误,并且后果非常严重.最容易避免这类问题的办法就是不覆盖equals方法,在这种情况下,类的每 ...

  5. 【C#】 通过http webRequest方式调用webservice

    上一篇文章写了关于webservice的调用部署等内容,在上一篇文章中,我们通过微软给的方式--添加[WebReference服务引用]来进行调用如下图 那今天,我们说的是通过webrequest的方 ...

  6. w2008 R2 401 - 未授权: 由于凭据无效,访问被拒绝。

    1.打开服务器的"IIS信息服务管理器"-->选择你发布的网站-->选择功能视图中的"身份验证"-->右键匿名身份验证,选择"编辑& ...

  7. SQLServer数据库,表内存,实例名分析SQL语句

    --数据库内存分析 USE master go DECLARE @insSize TABLE(dbName sysname,checkTime VARCHAR(19),dbSize VARCHAR(5 ...

  8. 自定义等高 Cell

    1.介绍 1.1 代码自定义 cell(使用 frame) 创建一个继承自 UITableViewCell 的子类,比如 BookCell1. 在 initWithStyle:reuseIdentif ...

  9. Hyperledger Fabric java chaincode 编译部署(1.4V)

    前提条件: 构建好了一个拥有四个peer 一个Order 的1.4版本的Fabric网络. 证书通过Cryptogen生成,没有使用CA服务. 开启TLS. 网络中的peer都加入了一个 名为mych ...

  10. 51nod1040最大公约数之和(欧拉函数)

    题面 传送门 题解 这种题目就是推倒推倒 \[\sum_{i=1}^n \gcd(i,n)=\sum_{i|n}i\sum_{j=1}^n[\gcd(j,n)=i]\] \[\sum_{i=1}^n ...