`
vanadiumlin
  • 浏览: 508595 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论
阅读更多

play! 最大的卖点就在于 hot swap,正如它自己宣称的:
reach your maximum productivity。play! 允许开发人员修改java文件,保存,然后刷新浏览器,立马可以看到效果。不需要编译,也不需要重启服务器。
Java 要想实现动态更新 class 文件,不外乎两种手段:替换 classloader、替换 JVM。因为替换 JVM 引起的开销更大,需要维护 JVM 的堆、栈等运行信息,所以 hot swap 通常是选择替换 classloader。比如 grails 里面就是选择替换 classloader,它会自己维护一个线程,定期轮询源文件是否发生修改,以替换原来的 classloader。那么 play! 宣称的 hot swap 又是怎么实现的呢?
让我们来看看play! 的内部流程:
1. play! 使用了 Apache Mina 作为底层的 http server,然后使用了自己关于 Mina IoHandler 接口的实现—— HttpHandler
2. 当浏览器发起一个 request:
2.1 Mina Server 生成一个 Mina Request,转发给 HttpHandler 的 messageReceived 方法
2.2 play! 解析 Mina Request 和 Mina Session,包装成自己的 Request 对象


Request request = parseRequest(minaRequest, session);
2.3 play! 检测 Route 文件修改情况,根据 Route 配置信息将 Route/Action 的信息赋给 Request 对象


Router.detectChanges();
Router.route(request);
2.4 play! 根据当前配置的开发模式来采用不同的策略调用 Action 来理 Request


if (Play.mode == Play.Mode.DEV) {
Invoker.invokeInThread(new MinaInvocation(session, minaRequest, minaResponse, request, response));
} else {
Invoker.invoke(new MinaInvocation(session, minaRequest, minaResponse, request, response));
}

2.5 如果 play! 当前是 DEV 模式,invokeInThread方法会让 invocation 对象代理 run() 方法


publicvoid run() {
try {
before();
execute();
after();
} catch (Throwable e) {
onException(e);
} finally {
_finally();
}
}
咱们来看看 before() 方法:

publicstaticvoid before() {
Thread.currentThread().setContextClassLoader(Play.classloader);
if(!Play.id.equals("test")) {
Play.detectChanges();
if (!Play.started) {
Play.start();
}
}
//
}

在 Play 类的 detectChanges() 方法里面,有这么一句:

classloader.detectChanges();

哈哈,play! 修改源文件后,刷新浏览器即见效的奥秘就在这里了。再进去看看 play! 自定义 classloader 的 detectChanges() 方法:


publicvoid detectChanges() {
// Now check for file modification
List<ApplicationClass> modifieds =new ArrayList<ApplicationClass>();
for (ApplicationClass applicationClass : Play.classes.all()) {
if (applicationClass.timestamp < applicationClass.javaFile.lastModified()) {
applicationClass.refresh();
modifieds.add(applicationClass);
}
}
List<ClassDefinition> newDefinitions =new ArrayList<ClassDefinition>();
Map<Class, Integer> annotationsHashes =

="color: rgb(0, 0, 255);">new HashMap < Class, Integer > ();
for (ApplicationClass applicationClass : modifieds) {
annotationsHashes.put(applicationClass.javaClass, computeAnnotationsHash(applicationClass.javaClass));
if (applicationClass.compile() == null ) {
Play.classes.classes.remove(applicationClass.name);
} else {
applicationClass.enhance();
BytecodeCache.cacheBytecode(applicationClass.enhancedByteCode, applicationClass.name, applicationClass.javaSource);
newDefinitions.add( new ClassDefinition(applicationClass.javaClass, applicationClass.enhancedByteCode));
}
}
try {
HotswapAgent.reload(newDefinitions.toArray( new ClassDefinition[newDefinitions.size()]));
} catch (ClassNotFoundException e) {
throw new UnexpectedException(e);
} catch (UnmodifiableClassException e) {
throw new UnexpectedException(e);
}
// Check new annotations
for (Class clazz : annotationsHashes.keySet()) {
if (annotationsHashes.get(clazz) != computeAnnotationsHash(clazz)) {
throw new RuntimeException( " Annotations change ! " );
}
}
// Now check if there is new classes or removed classes
int hash = computePathHash();
if (hash != this .pathHash) {
// Remove class for deleted files !!
for (ApplicationClass applicationClass : Play.classes.all()) {
if ( ! applicationClass.javaFile.exists()) {
Play.classes.classes.remove(applicationClass.name);
}
if (applicationClass.name.contains( " $ " )) {
Play.classes.classes.remove(applicationClass.name);
}
}
throw new RuntimeException( " Path has changed " );
}
}

HotswapAgent类的 reload 方法如下:

publicstaticvoid reload(ClassDefinition definitions) throws UnmodifiableClassException, ClassNotFoundException {
instrumentation.redefineClasses(definitions);
}
读到这里,也就弄清楚了 play! 怎么实现 hot swap 的原理了,还是调用java.lang.instrument目录下的类和方法来实现的 hot swap。不存在魔法,play! 还是选择了替换 classloader,只不过这个替换动作发生在处理 http request 的时候,于是开发人员用起来就是“刷新浏览器就可以看见效果了”。

文章出处:飞诺网(www.firnow.com):http://dev.firnow.com/course/3_program/java/javajs/20100630/279343.html

分享到:
评论

相关推荐

    play1的文档资料

    Hotswap功能是Play的一个亮点,它允许开发者在运行时修改代码并立即看到效果,无需重新启动服务器。这一特性显著提高了开发效率,减少了部署过程中的麻烦。文档中"play! framework hot swap 浅析"深入探讨了这一...

    USB的通讯协议.ppt

    USB的设计使得设备的即插即用(Plug-and-Play)和热插拔(Hot Swap)成为可能,极大地简化了用户和开发者的工作。随着技术的发展,USB标准也在不断进化,例如USB 3.0、USB 3.1、USB 4等,带来了更高的传输速度和额外...

    PCI.zip_pci_单片机PCI协议

    PCI总线由数据线、地址线和控制线组成,能够支持多种数据宽度,如32位和64位,并且提供了即插即用(Plug and Play)和热插拔(Hot Swap)功能。PCI接口标准定义了多个设备类,包括网络适配器、声卡、图形卡等,使得...

    jme-clj:Clojure 3D游戏引擎包装,由jMonkeyEngine提供支持

    通过简单地重新加载名称空间,您的代码将被注入到游戏中,而不受诸如HotSwap之类的工具所带来的限制。 此外,REPL允许您在运行时读取和修改游戏状态,从而可以快速进行实验和诊断问题。 Clojure还带来了函数式编程...

    android 3.0

    2. **Instant Run的替换:**Android Studio 3.0中移除了Instant Run功能,并引入了更快的热重载(Hot Swap)。这个新特性允许开发者在运行应用时快速看到代码变更的效果,而无需完全重新部署应用,大大提高了调试...

    pci总线协议

    8. **热插拔(Hot Swap)**:尽管不是所有PCI设备都支持,但一些高级版本的PCI标准(如PCI-X和PCI Express)提供了热插拔功能,允许在系统运行时安全地插入或移除设备。 9. **兼容性**:PCI总线协议设计时考虑了向...

    PCI协议中文翻译 PCI协议中文翻译

    PCI插槽设计为即插即用(Plug and Play)和热插拔(Hot Swap),便于用户安装和更换硬件。该协议定义了信号规范、电气特性、机械规格以及软件接口,确保不同厂商的设备能兼容并协同工作。 二、PCI协议的工作原理 1....

    组成原理知识点第6章第四节总线标准_四合一1

    其次,即插即用(Plug-and-Play)和热插拔(Hot Swap)功能是现代计算机的重要特性。即插即用允许系统自动识别并配置插入的设备,而无需手动设置,简化了用户的操作。热插拔则进一步提升了系统的灵活性,允许在系统...

    pci局部总线开发宝典

    PCI总线提供了较高的数据传输速率,同时具备即插即用(Plug and Play)和热插拔(Hot Swap)功能,极大地简化了系统集成和维护。 PCI总线的架构主要包括以下关键概念: 1. **总线主控器**:通常集成在主板的北桥...

    PCI.rar_pci

    PCI总线还支持即插即用(Plug and Play)和热插拔(Hot Swap)功能,方便用户添加或更换硬件设备。 PCI卡细节: PCI卡是基于PCI标准的扩展卡,它通过一个物理接口连接到主板上的PCI插槽。PCI卡通常包含一个控制芯片...

    PCI总线规范PPT学习教案.pptx

    3. **PCI总线特点**:32位或64位数据宽度,支持多种工作频率,具备即插即用(Plug and Play)和热插拔(Hot Swap)功能,可提供高带宽数据传输和低延迟。 4. **PCI总线定义**:PCI是Peripheral Component ...

    【eoeAndroid特刊】第1至22期

    13. **Android Studio IDE**:分享关于Android Studio的使用技巧,如热重载(Hot Swap)、调试技巧、插件推荐等。 14. **App发布与部署**:包括签名应用、打包APK、发布到Google Play商店的流程,以及第三方市场的...

    USB通讯若干问题探讨

    4. 插拔即用(Plug and Play)与热插拔(Hot Swap):USB设备无需安装额外驱动程序即可被识别和使用,即插即用功能简化了用户操作。同时,USB支持在系统运行时插入或拔出设备,实现了热插拔。 5. 功率供应:USB接口...

    Android Studio实战快速高效地构建Android应用

    3. **热修复与Instant Run**:了解如何使用Instant Run快速部署和调试应用,以及使用Hot Swap进行代码修改。 四、UI设计与动画 1. **Material Design**:遵循Material Design指南,创建符合现代审美的用户界面。 2...

    单片机面试题大公司的一些面试题

    PCI总线的含义是Peripheral Component Interconnect,PCI总线的主要特点包括插槽Hot-Swap、 Plug-and-Play和可扩展性强等。中断的概念是指CPU暂停当前任务,响应外部事件,执行相应的中断处理程序,然后返回到原来的...

    VB编程资源大全(英文源码 控件)

    &lt;END&gt;&lt;br&gt;45,PlayAVI.zip PlayAVI.ocx is an activeX control which allows you to play an AVI file on a form. A sample application is provided with the control. &lt;END&gt;&lt;br&gt;46,FldrView.zip The ...

Global site tag (gtag.js) - Google Analytics