From f45b6d4e83902b3db445c9e81172ac0c1dbffa4c Mon Sep 17 00:00:00 2001 From: zhangshanxue Date: Wed, 9 Oct 2019 16:51:49 +0800 Subject: [PATCH] =?UTF-8?q?=E7=83=AD=E5=8A=A0=E8=BD=BD=E6=96=B0=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/ljsd/jieling/hotfix/JavaAgent.java | 116 ++++++++++++++---- 1 file changed, 94 insertions(+), 22 deletions(-) diff --git a/hotfix/src/main/java/com/ljsd/jieling/hotfix/JavaAgent.java b/hotfix/src/main/java/com/ljsd/jieling/hotfix/JavaAgent.java index 8414c37b2..de267336c 100644 --- a/hotfix/src/main/java/com/ljsd/jieling/hotfix/JavaAgent.java +++ b/hotfix/src/main/java/com/ljsd/jieling/hotfix/JavaAgent.java @@ -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 threadLocal = new ThreadLocal(); @@ -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; + } }