如果你是单点部署的话,就用你找的这种方法。如果你是集群部署,就按照楼上说的,部署一台服务器启动一台,没有部署的可以一直处于运行状态。
大家线上Java应用的热更新都是怎么实现的?
热更新的时候需要注意哪些点呢?
下面是从网上找到的两种解决方法:
解决方案一 : 自定义类加载器。
首先需要明白一点,class相等的判断条件不仅仅是类名相同,还需要加载它的ClassLoader相同。JVM内部规定一个ClassLoader不可以重复定义类,也就是说想要重定义一个类,就必须使用一个全新的ClassLoader。
JVM内部class被卸载的条件及其苛刻,甚至没有明确的方法可以直接调用,只有当加载该类型的类加载器实例为unreachable状态时,也就是没有任何实例,class才有可能被卸载。(启动类加载器实例永远为reachable状态,由启动类加载器加载的类型可能永远不会被卸载)
public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
Class<?> clazz = null;
// 首先检查请求的类型是否已经被这个类装载器装载到命名空间中了,如果已经装载,直接返回;否则继续。
if (name.startsWith("com.wafer") || name.contains("Service")) {
if (resolve) {
resolveClass(clazz); // 链接指定的 Java 类
}
// 如果class类被修改过,则重新加载
MoeLoader hcl = new MoeLoader(url);
clazz = customLoad(name, hcl);
return (clazz);
}
// 如果类的包名为"java."开始,则有系统默认加载器加载
try {
// 得到系统默认的加载cl
ClassLoader system = ClassLoader.getSystemClassLoader();
clazz = system.loadClass(name); // 加载名称为 name的类
if (clazz != null) {
if (resolve)
resolveClass(clazz);
return (clazz);
}
} catch (ClassNotFoundException e) {
// Ignore
}
return customLoad(name, this);
}
此范例的核心在于缓存自己已经加载的class,当再次需要加载时,如果发生变更,则可以new一个ClassLoader,这样新的字节码便可以即时生效。
JRbel是一种热更新的方案,它实现的方式是通过在启动参数中添加javaagent,即JVM底层提供的Instrumentation技术,来改变生成对象的方式。
解决方法二:
java.lang.instrument这个类很早就出了,redefineClasses这个方法可以更新方法级别的代码,但是不会触发一个类的初始化方法。游戏服务器的bug基本上只需要方法级别的更新就可以了,因为很多重大的bug基本在测试阶段被修复了,少量偶线的bug出现之后有些时候仅仅只需要改动一行代码却有时不得不需要重启所有应用程序,代价都似乎有点大。
现在开始从instrument入手
public static void premain(String agentArgs, Instrumentation inst);
public static void agentmain(String agentArgs, Instrumentation inst);
这两个方法都可以获取到Instrumentation对象,通过redefineClasses方法就可以更新对应的方法了
如果是调用premain这个方法 则需要在程序启动的时候指定对应的jar 同时项目里必须引用这个jar 因为获取到这个引用
java -javaagent:agent.jar -jar xx.jar 例如这样 执行这条命令后程序会查找 agent.jar 里的MANIFEST.MF文件里的Premain-Class参数 设置对应的代理类路径就行。例如:Premain-Class: com.test.JavaAgent 还需要加上 Can-Redefine-Classes: true这个参数才能调用redefineClasses方法。同时 可以拦截对应的类添加标记 做性能分析
agentmain 是通过指定对应的进程pid来加载对应的agent.jar 很典型的jconsule jvisualvm都是通过选择java进程来做一个简单的内存 和cpu分析 ,线程dump .Agent-Class 和上面一样
package com.test;
import java.lang.instrument.Instrumentation;
public class JavaAgent {
public static Instrumentation INST = null;
public static void premain(String agentArgs, Instrumentation inst){
INST = inst;
}
}
这里保存下引用就可以了 ,单独打成agent.jar
package com.test;
import java.io.FileInputStream;
import java.lang.instrument.ClassDefinition;
public class Test {
public static void main(String[] args) {
getInfo();
testhot();
}
public final static void testhot(){
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
while(true){
try {
if(JavaAgent.INST != null){
FileInputStream is = new FileInputStream("/Users/xxxx/Downloads/Student.class");
byte[] array = new byte[is.available()];
is.read(array);
is.close();
Class cls = Class.forName("com.test.Student");
JavaAgent.INST.redefineClasses(new ClassDefinition(cls,array));
}
Thread.sleep(1000);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}).start();
}
public final static void getInfo(){
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
while(true){
//System.out.println("=============="+JavaAgent.INST);
new Student().getName();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}).start();
}
}
上面就是一个很简单的例子,一个线程在不停的循环检测更新这个类,另外的一个线程在不停的输出这个对象对应的方法输出信息。
测试之后可以发现 ,方法的输出信息已经改变了。
- 点赞
- 写回答
- 关注问题
- 收藏
- 复制链接分享
- 邀请回答
2条回答
为你推荐
- 各位tomcat作为线上服务器的时候怎么做的热部署?或者不影响网站的操作情况下更新代码?
- 为什么我用cookie保存的日期时间(Date)不对呢?
- 如何监听到部署在tomcat上的web项目?
- mysql 本地和线上数据库数据同步
- mysql
- 7个回答
- ConcurrenthashMap如何实现并发操作
- 多线程
- java
- concurrenthashmap
- 并发
- 0个回答
- 打包war包到线上更新项目,实际代码为更新
- war
- 服务器
- 代码更新
- tomcat
- 12个回答
- 【JAVA】关于一个jvm内存的问题?
- 【java】为什么我使用jmap结合jhat查出来的内存使用情况低于实际?
- 内存
- java
- 调试与优化
- jvm
- 对象
- 1个回答
- nodejs 线上应用问题 请求不到对应资源
- java如何保存聊天记录?
- java
- 聊天
- 数据库
- 3个回答
- 一般情况下,统计log日志中的某个关键字,一般都是用哪些方式?
- 网上商城用户的定位是怎样实现的
- 淘宝网
- 浏览器
- 对象
- 百度
- 商城
- 1个回答
- 求助:JAVA文件修改以后,Tomcat运行还是之前的代码
- 请问如何实现后台与前端的数据对接,让可视化页面实现动态更新?改采取什么方式呢?求大神支招
- 5个回答
- java考试在线阅卷 编程题阅卷思路
- 在线考试
- java
- 编程
- 自动阅卷
- 2个回答
- java合同系统的在线签署问题,
- java
- 2个回答
- java实现excel下载(服务器端不生成文件)
- excel
- java
- 下载
- 3个回答
- App Store 申请加速审核,除线上提交之外还有其他途径吗?
- 技术
- app store
- 2个回答
- 怎么在java项目运行时调试bug
- java
- 4个回答
- 怎么用Git Shell把线上fork的仓库下载到本地?
- shell
- 下载
- fork
- 1个回答