`

tomcat热部署的实现原理

 
阅读更多

一.             概述

名词解释:所谓热部署,就是在应用正在运行的时候升级软件,却不需要重新启动应用。

对于Java应用程序来说,热部署就是在运行时更新Java类文件。在基于Java的应用服务器实现热部署的过程中,类装入器扮演着重要的角色。大多数基于Java的应用服务器,包括EJB服务器和Servlet容器,都支持热部署。类装入器不能重新装入一个已经装入的类,但只要使用一个新的类装入器实例,就可以将类再次装入一个正在运行的应用程序。

我们知道,现在大多数的web服务器都支持热部署,而对于热部署的实现机制,网上讲的却不够完善,下面我们就tomcat的热部署实现机制,讲解一下它是如何实现的:

Tomcat的容器实现热部署使用了两种机制:

1.  Classloader重写,通过自定义classloader加载相应的jsp编译后的classJVM中。

2.  通过动态修改内存中的字节码,将修改过的class再次装载到JVM中。

 

二.             Classloader实现jsp的重新加载

Tomcat通过org.apache.jasper.servlet.JasperLoader实现了对jsp的加载,下面做个测试:

1. 新建一个web工程,并编写一个jsp页面,在jsp页面中输出该页面的classloader,<%System.out.print(this.getClass().getClassLoader());%>.

2.  启动web服务器,打开jsp页面,我们可以看到后台输出,该jspclassloaderJasperLoader的一个实例。

3.  修改jsp,保存并刷新jsp页面,再次查看后台输出,此classloader实例已经不是刚才那个了,也就是说tomcat通过一个新的classloader再次装载了该jsp

4.  其实,对于每个jsp页面tomcat都使用了一个独立的classloader来装载,每次修改完jsp后,tomcat都将使用一个新的classloader来装载它。

 

关于如何使用自定义classloader来装载一个class这里就不说了,相信网上都能找到,JSP属于一次性消费,每次调用容器将创建一个新的实例,属于用完就扔的那种,但是对于这种实现方式却很难用于其它情况下,如现在我们工程中很多都使用了单例,尤其是spring工程,在这种情况下使用新的classloader来加载修改后的类是不现实的,单例类将在内存中产生多个实例,而且这种方式无法改变当前内存中已有实例的行为,当然,tomcat也没通过该方式实现class文件的重新加载。

 

三.             通过代理修改内存中class的字节码

Tomcat中的class文件是通过org.apache.catalina.loader. WebappClassLoader装载的,同样我们可以做个测试,测试过程与jsp测试类似,测试步骤就不说了,只说一下结果:

         在热部署的情况下,对于被该classloader 加载的class文件,它的classloader始终是同一个WebappClassLoader,除非容器重启了,相信做完这个实验你就不会再认为tomcat是使用一个新的classloader来加载修改过的class了,而且对于有状态的实例,之前该实例拥有的属性和状态都将保存,并在下次执行时拥有了新的class的逻辑,这就是热部署的神秘之处(其实每个实例只是保存了该实例的状态属性,我们通过序列化对象就能看到对象中包含的状态,最终的逻辑还是存在于class文件中)。

下面的class重定义是通过:java.lang.instrument实现的,具体可参考相关文档。

         下面我们看一下如何通过代理修改内存中的class字节码:

以下是一个简单的热部署代理实现类(代码比较粗糙,也没什么判断):

package agent;

 

import java.lang.instrument.ClassFileTransformer;

import java.lang.instrument.Instrumentation;

import java.util.Set;

import java.util.Timer;

import java.util.TreeSet;

 

 

public  class  HotAgent {

    protected  static  Set<String>  clsnames=new TreeSet<String>();

   

    public  static  void  premain(String  agentArgs, Instrumentation  inst)  throws Exception {

       ClassFileTransformer  transformer =new ClassTransform(inst);

       inst.addTransformer(transformer);

       System.out.println("是否支持类的重定义:"+inst.isRedefineClassesSupported());

       Timer  timer=new  Timer();

      timer.schedule(new ReloadTask(inst),2000,2000);

    }

}

 

package agent;

 

import java.lang.instrument.ClassFileTransformer;

importjava.lang.instrument.IllegalClassFormatException;

import java.lang.instrument.Instrumentation;

import java.security.ProtectionDomain;

 

public  class  ClassTransform.  implements ClassFileTransformer {

    private  Instrumentation  inst;

    protected  ClassTransform(Instrumentation  inst){

       this.inst=inst;

    }

    /**

     * 此方法在redefineClasses时或者初次加载时会被调用,也就是说在class被再次加载时会被调用,

     * 并且我们通过此方法可以动态修改class字节码,实现类似代理之类的功能,具体方法可使用ASM或者javasist

     * 如果对字节码很熟悉的话可以直接修改字节码。

     */

    public  byte[]  transform(ClassLoader  loader, String  className,

           Class<?>  classBeingRedefined, ProtectionDomain  protectionDomain,

           byte[]  classfileBuffer)throws IllegalClassFormatException {

       byte[]  transformed = null;

       HotAgent.clsnames.add(className);

        return  null;

    }

}

 

package agent;

 

import java.io.InputStream;

import java.lang.instrument.ClassDefinition;

import java.lang.instrument.Instrumentation;

import java.util.TimerTask;

 

public  class  ReloadTask  extends  TimerTask {

   

    private  Instrumentation  inst;

    protected  ReloadTask(Instrumentation  inst){

       this.inst=inst;

    }

   

    @Override

    public  void  run() {

       try{

           ClassDefinition[]  cd=new ClassDefinition[1];

           Class[]  classes=inst.getAllLoadedClasses();

           for(Class  cls:classes){

          if(cls.getClassLoader()==null||!cls.getClassLoader().getClass().getName().equals("sun.misc.Launcher$AppClassLoader"))

                  continue;

              String  name=cls.getName().replaceAll("\\.","/");

             cd[0]=new ClassDefinition(cls,loadClassBytes(cls,name+".class"));

              inst.redefineClasses(cd);

           }

          

       }catch(Exception ex){

           ex.printStackTrace();

       }

    }

   

    private  byte[]  loadClassBytes(Class  cls,String  clsname) throws  Exception{

       System.out.println(clsname+":"+cls);

       InputStream  is=cls.getClassLoader().getSystemClassLoader().getResourceAsStream(clsname);

       if(is==null)return  null;

       byte[]  bt=new  byte[is.available()];

       is.read(bt);

       is.close();

       return  bt;

    }

}

 

以上是基本实现代码,需要组件为:

1.  HotAgent(预加载)

2.  ClassTransform(在加载class的时候可以修改class的字节码),本例中没用到

3.  ReloadTaskclass定时加载器,以上代码仅供参考)

4.  META-INF/MANIFEST.MF内容为:(参数一:支持class重定义;参数二:预加载类)

Can-Redefine-Classes: true

Premain-Class: agent.HotAgent

5.  将以上组件打包成jar文件(到此,组件已经完成,下面为编写测试类文件)。

6.  新建一个java工程,编写一个java逻辑类,并编写一个Test类,在该测试类中调用逻辑类的方法,下面看下测试类代码:

package test.redefine;

 

public  class  Bean1 {

    public  void  test1(){

      System.out.println("============================");

    }

}

 

package test.redefine;

 

public  class  Test {

    public  static  void  main(String[] args)throws  InterruptedException {

       Bean1  c1=new  Bean1();

       while(true){

           c1.test1();

           Thread.sleep(5000);

       }

    }

}

 

运行测试类:

java –javaagent:agent.jar test.redefine.Test

在测试类中,我们使用了一个死循环,定时调用逻辑类的方法。我们可以修改Bean1中的方法实现,将在不同时间看到不同的输出结果,关于技术细节也没什么好讲的了,相信大家都能明白。

分享到:
评论

相关推荐

    Tomcat 热部署的实现原理详解

    热部署的核心原理是利用Java的类加载机制和字节码操作来实现。 首先,对于Java的类加载器(Classloader),其设计遵循“双亲委派模型”,但当涉及到热部署时,Tomcat使用了一种特殊的方式。在Tomcat中,每个Web应用...

    Maven工程Tomcat热部署详解.pdf

    热部署实现原理是基于Tomcat的类加载机制。Tomcat启动时会启动一个检测线程,该线程会定时检查应用中的类是否有变化,比如类的数量变化或类的修改。一旦检测到变化,Tomcat会停止应用的启动线程,清除引用,并将加载...

    springMVC样例、jreloader实现tomcat热部署

    接着,我们要介绍jreloader如何实现Tomcat的热部署。jreloader通过监听文件系统,一旦发现被监控的类文件发生变化,就会触发类的重新加载。它的工作原理是在Tomcat的生命周期中插入一个监听器,当检测到应用中的类...

    Jrebel 基于TOMCAT实现项目修改热部署

    下面将详细介绍 JRebel 如何与 Tomcat 集成,实现项目修改后的热部署。 **1. JRebel 的工作原理** JRebel 是通过动态类加载技术,实现在运行时替换已经加载的类,以达到热部署的效果。它拦截了 JVM 的类加载过程,...

    apache-tomcat-8.5.12-直接热部署版本

    这个版本是特别为热部署设计的,这意味着开发者可以在应用程序运行时无需重启Tomcat就能更新Web应用,极大地提高了开发效率。 首先,我们来看一下提供的压缩包文件的组成部分: 1. **LICENSE** 和 **NOTICE**:这...

    实现tomcat热更新class文件.docx

    为了解决这个问题,可以配置Tomcat实现热更新class文件,使得修改后的Java类在不重启服务器的情况下就能立即生效。下面将详细介绍如何实现这一功能。 首先,我们需要理解Tomcat的工作原理。当一个Web应用被部署到...

    eclipse上如何进行热部署

    热部署需要服务器支持热部署机制,否则将无法实现热部署。同时,热部署也需要正确地配置服务器和项目的部署方式。 结论 eclipse热部署配置可以提高开发和测试效率,减少重启服务器的次数。但是,需要正确地配置...

    Tomcat深入剖析pdf+源码(Tomcat运行原理)

    7. **部署与热部署**:Tomcat支持自动部署和热部署,只需将WAR文件放入webapps目录,Tomcat会自动解压并部署应用。修改应用后,无需重启服务器,Tomcat可以检测到变化并自动更新。 8. **安全性**:Tomcat提供多种...

    热部署工具

    **实现Tomcat热部署的方法** 1. **自动检测**: Tomcat默认开启对Web应用目录的监控,如果检测到修改,就会自动重新加载。但是,如果修改频繁,可能导致性能下降,因为每次更新都需要解析和验证整个应用。 2. **...

    jboss热部署配置

    首先,理解热部署的基本原理是至关重要的。热部署允许开发者在运行时更改或替换已部署的应用程序,而无需重启服务器。在JBoss中,这主要通过监视特定目录的变化来实现,当检测到新的或更新的类文件时,服务器会自动...

    tomcat服务器工作原理

    Tomcat支持集群部署,通过复制Session数据和负载均衡,实现高可用性和水平扩展。 理解Tomcat的工作原理有助于我们更好地管理和优化Java Web应用,提升服务器性能,解决运行中可能出现的问题。通过深入学习,我们...

    java热部署工具

    通常,Java应用服务器如Tomcat、Jetty、JBoss等都提供了一定程度的热部署支持。以标题中的"jbos热部署"为例,JBoss是Red Hat公司的一个开源企业级应用服务器,它包含了对热部署的支持。 JBoss的热部署机制主要通过...

    原创-tomcat快速开发调试-类修改热部署

    【热部署原理与实现】 在Java开发中,由于其编译执行的特点,相较于动态语言如PHP,进行快速迭代和调试通常需要重启应用服务器,这在Web应用开发中尤其不便。然而,通过使用像DCE VM(Dynamic Code Evolution ...

    Eclipse配置Tomcat的方法[图解

    - **Sysdeo Eclipse Tomcat插件**:这个插件极大地简化了Eclipse与Tomcat的集成,允许用户在Eclipse内部启动和管理Tomcat服务器,从而实现无缝的Web项目开发流程。 ### 2. 安装与配置 #### 安装步骤 1. **解压...

    Tomcat热加载Jrebel

    【描述】:Tomcat热加载Jrebel是通过Jrebel插件与Tomcat服务器的集成,实现Java应用的热部署。这意味着开发者在编码过程中可以实时看到代码更改的效果,无需每次都停止、重新启动服务器,极大地提高了开发迭代的速度...

    springloaded-1.2.6实现spring热部署,最全的教程

    本教程将详细介绍如何利用SpringLoaded实现Spring应用的热部署。 1. **SpringLoaded简介** SpringLoaded是一个JVM插件,它在运行时动态地重新加载类,使得在修改了源代码后,无需重启服务器就能观察到改动。这对于...

    myeclipse热部署

    2. **Tomcat配置**:Tomcat作为常用的Java Web服务器,其配置也会影响热部署。在`conf/server.xml`文件中,找到`&lt;Host&gt;`标签,添加或修改`reloadable="true"`属性,使得服务器能够自动检测应用的改动并重新加载。 3...

    idea热部署文件.rar

    本篇文章将详细探讨热部署的概念、原理以及如何在IntelliJ IDEA(简称idea)中实现热部署。 **热部署概念** 热部署,也被称为热更新或热替换,是指在应用程序运行时,能够自动检测到代码的变更并即时更新到运行中的...

    简单的Tomcat源码实现

    9. **热部署与监控**:Tomcat支持热部署,允许在不重启服务器的情况下更新Web应用。同时,`Manager`应用可以用来监控和管理部署在Tomcat上的应用。 通过深入研究这些核心组件和概念,开发者可以更好地定制Tomcat,...

    修改java代码以及js无需重启tomcat

    #### 二、Tomcat热部署原理概述 热部署(Hot Deployment)是指在不重启服务器的情况下更新应用程序。Apache Tomcat支持一定程度上的热部署功能,主要通过检测类文件的变化并在运行时自动加载新版本的类来实现。然而...

Global site tag (gtag.js) - Google Analytics