热加载新类
parent
f47b80ea14
commit
f45b6d4e83
|
@ -3,8 +3,10 @@ package com.ljsd.jieling.hotfix;
|
|||
import java.io.*;
|
||||
import java.lang.instrument.ClassDefinition;
|
||||
import java.lang.instrument.Instrumentation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class JavaAgent {
|
||||
private static final ThreadLocal<SimpleDateFormat> threadLocal = new ThreadLocal<SimpleDateFormat>();
|
||||
|
@ -39,59 +41,129 @@ public class JavaAgent {
|
|||
return dateString;
|
||||
}
|
||||
|
||||
private static void writeLog(Exception e){
|
||||
private static void writeLog(Exception e) {
|
||||
try {
|
||||
String fname = "../logs/" + getStrDateYMD() + "_" + logFileName;
|
||||
File file = new File(fname);
|
||||
OutputStream fos=new FileOutputStream(file, true);
|
||||
OutputStream fos = new FileOutputStream(file, true);
|
||||
PrintStream out = new PrintStream(fos);
|
||||
writeLog(e.getMessage());
|
||||
e.printStackTrace(out);
|
||||
out.close();
|
||||
} catch(Exception e1){
|
||||
} catch (Exception e1) {
|
||||
e.printStackTrace();
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
private static void writeLog(String line){
|
||||
|
||||
private static void writeLog(String line) {
|
||||
try {
|
||||
String fname = "../logs/" + getStrDateYMD() + "_" + logFileName;
|
||||
File file = new File(fname);
|
||||
OutputStream fos=new FileOutputStream(file, true);
|
||||
OutputStream fos = new FileOutputStream(file, true);
|
||||
PrintStream out = new PrintStream(fos);
|
||||
line = "[" + getStrDateYMDHMS() + "][" + Thread.currentThread().getId() + "]:" + line + "\n";
|
||||
System.out.print(line);
|
||||
out.print(line);
|
||||
out.close();
|
||||
} catch(Exception e){
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
//该方法支持在JVM 启动后再启动代理,对应清单的Agent-Class:属性
|
||||
public static void agentmain(String args,Instrumentation inst){
|
||||
try{
|
||||
public static void agentmain(String args, Instrumentation inst) {
|
||||
try {
|
||||
writeLog("argsxxxxxxxxxx=:[" + args + "]");
|
||||
writeLog("argsxxxxxxxxxxyyy=:[" + JavaAgent.class.getResource("").getPath() + "]");
|
||||
File f = new File(args);
|
||||
byte[] targetClassFile = new byte[(int)f.length()];
|
||||
String[] paths = args.split("#");
|
||||
File f = new File(paths[0]);
|
||||
byte[] targetClassFile = new byte[(int) f.length()];
|
||||
DataInputStream dis = new DataInputStream(new FileInputStream(f));
|
||||
dis.readFully(targetClassFile);
|
||||
dis.close();
|
||||
|
||||
DynamicClassLoader myLoader = new DynamicClassLoader();
|
||||
Class targetClazz = myLoader.findClass(targetClassFile);
|
||||
writeLog("class namexxxxx is:["+targetClazz.getName() + "]");
|
||||
writeLog("class path is:["+targetClazz.getResource("").getPath() + "]");
|
||||
Class<?> clz = Class.forName(targetClazz.getName());
|
||||
writeLog("clz-->Class.forName:(\""+targetClazz.getName() + "\")");
|
||||
Class<?> loads = null;
|
||||
try {
|
||||
loads = Class.forName(paths[1]);
|
||||
} catch (Exception var18) {
|
||||
}
|
||||
if (null != loads ) {
|
||||
try {
|
||||
ClassDefinition clazzDef = new ClassDefinition(loads, targetClassFile);
|
||||
inst.redefineClasses(clazzDef);
|
||||
writeLog("热加载(旧)"+loads.getName()+"成功"+"\r\n");
|
||||
}catch (Exception oldVarErr){
|
||||
writeLog("热加载(旧)"+loads.getName()+"失败"+"\r\n"+oldVarErr);
|
||||
}
|
||||
}else {
|
||||
|
||||
ClassDefinition clazzDef = new ClassDefinition(clz, targetClassFile);
|
||||
writeLog("ClassDefinition");
|
||||
JavaAgent agent = new JavaAgent();
|
||||
if(!defineNewClass(paths[1],agent.getClass().getClassLoader(),targetClassFile)){
|
||||
writeLog("热加载(新类)"+paths[0]+"失败"+"\r\n");
|
||||
}
|
||||
|
||||
inst.redefineClasses(clazzDef);
|
||||
writeLog("redefineClasses "+args+" finish!");
|
||||
Class cls=null;
|
||||
try {
|
||||
cls = Class.forName(paths[1]);
|
||||
} catch (ClassNotFoundException newVarErr) {
|
||||
writeLog("热加载(新类)"+paths[0]+"失败—ClassNotFoundException"+"\r\n"+newVarErr);
|
||||
}
|
||||
|
||||
}catch(Exception e){
|
||||
writeLog(e);
|
||||
if (null == cls) {
|
||||
writeLog("热加载(新类)"+paths[0]+"失败—null"+"\r\n");
|
||||
}
|
||||
|
||||
writeLog("热加载(新类)"+paths[0]+"成功"+"\r\n");
|
||||
}
|
||||
|
||||
// DynamicClassLoader myLoader = new DynamicClassLoader();
|
||||
// Class targetClazz = myLoader.findClass(targetClassFile);
|
||||
// writeLog("class namexxxxx is:[" + targetClazz.getName() + "]");
|
||||
// writeLog("class path is:[" + targetClazz.getResource("").getPath() + "]");
|
||||
// Class<?> clz = Class.forName(targetClazz.getName());
|
||||
// writeLog("clz-->Class.forName:(\"" + targetClazz.getName() + "\")");
|
||||
//
|
||||
// String names2= targetClazz.getName();
|
||||
//
|
||||
//
|
||||
//
|
||||
// writeLog("redefineClasses " + paths[0] + " finish!");
|
||||
|
||||
} catch (Exception e) {
|
||||
writeLog("热加载"+"失败"+"\r\n"+e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static boolean defineNewClass(String classname, ClassLoader classLoader, byte[] bs) {
|
||||
|
||||
Method method = getMethod(classLoader.getClass(), "defineClass", new Class[]{String.class, byte[].class, Integer.TYPE, Integer.TYPE});
|
||||
if (method == null) {
|
||||
return false;
|
||||
} else {
|
||||
method.setAccessible(true);
|
||||
try {
|
||||
method.invoke(classLoader, classname, bs, 0, bs.length);
|
||||
return true;
|
||||
} catch (Throwable var6) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Method getMethod(Class<?> cls, String methodName, Class... classes) {
|
||||
Method method = null;
|
||||
Class clazz = cls;
|
||||
|
||||
while(clazz != Object.class) {
|
||||
try {
|
||||
method = clazz.getDeclaredMethod(methodName, classes);
|
||||
break;
|
||||
} catch (NoSuchMethodException var6) {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
return method;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue