package agent;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.instrument.Instrumentation;
import java.util.jar.JarFile;
import agent.listenersupport.ListenerSupport;
import agent.mxbean.ServerIpPortObject;
import agent.register.RegisterServer;
import agent.util.FileUtil;
import agent.util.StringUtil;
/**
*
* 描述:代理类(premain 方式修改FileEncodingApplicationListener)
* @author sakyoka
* @date 2022年9月4日 上午11:22:09
*/
public class IpPortPremainAgent {
/** springboot的监听类 class文件名字包含.class */
private static final String FILE_ENCODING_APPLICATION_LISTENER_CLASS = "FileEncodingApplicationListener.class";
/** springboot的监听类 类路径*/
private static final String FILE_ENCODING_APPLICATION_LISTENER_PACKAGE = "org/springframework/boot/context/FileEncodingApplicationListener";
/** listener 支撑包名字包含.jar*/
private static final String LISTENER_JAR= "springboot-listener-support.jar";
/** 代理包名字包含.jar*/
private static final String PREMAIN_JAR = "springboot-agent-premain.jar";
/** 缓存文件夹名字*/
private static final String CACHE_FOLDER = "cache";
/**
*
* 描述:main方法前
* @author sakyoka
* @date 2022年9月4日 上午11:22:24
* @param agrentsArgs
* @param instrumentation
*/
public static void premain(String agrentsArgs, Instrumentation instrumentation) {
System.out.println("获取到的参数:" + agrentsArgs);
if (!StringUtil.isBlank(agrentsArgs)){
System.out.println("选择直接执行注册对象...");
System.out.println("开始注册对象...");
ServerIpPortObject serverIpPortObject = RegisterServer.registerServerIpPortObject(null, agrentsArgs);
String ip = serverIpPortObject.getIp();
System.out.println(String.format("注册对象完毕。ip:%s,端口:%s", ip, agrentsArgs));
}else{
System.out.println("选择修改监听器形式注册对象...");
loadFileEncodingApplicationListenerSupportJar(instrumentation);
replaceFileEncodingApplicationListenerFile(instrumentation);
System.out.println("修改监听器完毕。");
}
}
/**
*
* 描述:加载FileEncodingApplicationListener所需要的支撑包
* @author sakyoka
* @date 2022年9月4日 上午11:22:40
* @param instrumentation
*/
private static void loadFileEncodingApplicationListenerSupportJar(Instrumentation instrumentation) {
System.out.println("开始加载jar包...");
String tempFilePath = generateTempSpringListenerSupportJarAbsolutePath();
System.out.println("缓存文件路径:" + tempFilePath);
File tempFile = new File(tempFilePath);
try (InputStream inputStream = ListenerSupport.getListenerSupportInputStream(LISTENER_JAR)){
if (!tempFile.exists()) {
//这里存在多应用执行问题,但是目前jar启动是顺序执行的
FileUtil.write(inputStream, tempFile);
System.out.println("缓存文件已生成");
}else {
System.out.println("缓存文件已存在,不需要再产生。");
}
System.out.println("开始添加jar包.");
instrumentation.appendToBootstrapClassLoaderSearch(new JarFile(tempFile));
} catch (IOException e) {
throw new RuntimeException("加载jar包失败, jarPath:" + LISTENER_JAR, e);
}
System.out.println("加载jar包结束。");
}
/**
*
* 描述:生成SpringListenerSupport缓存文件绝对路径
* @author sakyoka
* @date 2022年9月4日 上午11:22:51
* @return
*/
private static String generateTempSpringListenerSupportJarAbsolutePath() {
String agentInnerPath = ListenerSupport.PREMAIN_JAR_ABSOLUTE;
String folder = agentInnerPath.substring(0, agentInnerPath.lastIndexOf(PREMAIN_JAR))
+ File.separator + CACHE_FOLDER ;
FileUtil.folderCreateIfNotExists(folder);
String tempFilePath = folder + File.separator + LISTENER_JAR;
return tempFilePath;
}
/**
*
* 描述:替换FileEncodingApplicationListener
* @author sakyoka
* @date 2022年9月4日 上午11:23:14
* @param instrumentation
*/
private static void replaceFileEncodingApplicationListenerFile(Instrumentation instrumentation) {
System.out.println("开始替换class...");
instrumentation.addTransformer((loader, className, classBeingRedefined, protectionDomain, classfileBuffer) -> {
if (FILE_ENCODING_APPLICATION_LISTENER_PACKAGE.equals(className)){
return FileUtil.streamToByteArray(ListenerSupport
.getListenerSupportInputStream(FILE_ENCODING_APPLICATION_LISTENER_CLASS));
}
return classfileBuffer;
});
System.out.println("替换class完毕。");
}
}
评论0