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