All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.alibaba.jvm.sandbox.agent.AgentLauncher Maven / Gradle / Ivy

There is a newer version: 1.4.0
Show newest version
package com.alibaba.jvm.sandbox.agent;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.instrument.Instrumentation;
import java.net.InetSocketAddress;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.jar.JarFile;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static java.lang.String.format;

/**
 * SandboxAgent启动器
 * 
    *
  • 这个类的所有静态属性都必须和版本、环境无关
  • *
  • 这个类删除、修改方法时必须考虑多版本情况下,兼容性问题!
  • *
* * @author [email protected] */ public class AgentLauncher { private static String getSandboxCfgPath(String sandboxHome) { return sandboxHome + File.separatorChar + "cfg"; } private static String getSandboxModulePath(String sandboxHome) { return sandboxHome + File.separatorChar + "module"; } private static String getSandboxCoreJarPath(String sandboxHome) { return sandboxHome + File.separatorChar + "lib" + File.separator + "sandbox-core.jar"; } private static String getSandboxSpyJarPath(String sandboxHome) { return sandboxHome + File.separatorChar + "lib" + File.separator + "sandbox-spy.jar"; } private static String getSandboxPropertiesPath(String sandboxHome) { return getSandboxCfgPath(sandboxHome) + File.separator + "sandbox.properties"; } private static String getSandboxProviderPath(String sandboxHome) { return sandboxHome + File.separatorChar + "provider"; } // sandbox默认主目录 private static final String DEFAULT_SANDBOX_HOME = new File(AgentLauncher.class.getProtectionDomain().getCodeSource().getLocation().getFile()) .getParentFile() .getParent(); private static final String SANDBOX_USER_MODULE_PATH = DEFAULT_SANDBOX_HOME + File.separator + "sandbox-module"; // 启动模式: agent方式加载 private static final String LAUNCH_MODE_AGENT = "agent"; // 启动模式: attach方式加载 private static final String LAUNCH_MODE_ATTACH = "attach"; // 启动默认 private static String LAUNCH_MODE; // agentmain上来的结果输出到文件${HOME}/.sandbox.token private static final String RESULT_FILE_PATH = System.getProperties().getProperty("user.home") + File.separator + ".sandbox.token"; // 全局持有ClassLoader用于隔离sandbox实现 private static volatile Map sandboxClassLoaderMap = new ConcurrentHashMap(); private static final String CLASS_OF_CORE_CONFIGURE = "com.alibaba.jvm.sandbox.core.CoreConfigure"; // private static final String CLASS_OF_JETTY_CORE_SERVER = "com.alibaba.jvm.sandbox.core.server.jetty.JettyCoreServer"; private static final String CLASS_OF_PROXY_CORE_SERVER = "com.alibaba.jvm.sandbox.core.server.ProxyCoreServer"; /** * 启动加载 * * @param featureString 启动参数 * [namespace,prop] * @param inst inst */ public static void premain(String featureString, Instrumentation inst) { LAUNCH_MODE = LAUNCH_MODE_AGENT; install(toFeatureMap(featureString), inst); } /** * 动态加载 * * @param featureString 启动参数 * [namespace,token,ip,port,prop] * @param inst inst */ public static void agentmain(String featureString, Instrumentation inst) { LAUNCH_MODE = LAUNCH_MODE_ATTACH; final Map featureMap = toFeatureMap(featureString); writeAttachResult( getNamespace(featureMap), getToken(featureMap), install(featureMap, inst) ); } /** * 写入本次attach的结果 *

* NAMESPACE;TOKEN;IP;PORT *

* * @param namespace 命名空间 * @param token 操作TOKEN * @param local 服务器监听[IP:PORT] */ private static synchronized void writeAttachResult(final String namespace, final String token, final InetSocketAddress local) { final File file = new File(RESULT_FILE_PATH); if (file.exists() && (!file.isFile() || !file.canWrite())) { throw new RuntimeException("write to result file : " + file + " failed."); } else { FileWriter fw = null; try { fw = new FileWriter(file, true); fw.append( format("%s;%s;%s;%s\n", namespace, token, local.getHostName(), local.getPort() ) ); fw.flush(); } catch (IOException e) { throw new RuntimeException(e); } finally { if (null != fw) { try { fw.close(); } catch (IOException e) { // ignore } } } } } private static synchronized ClassLoader loadOrDefineClassLoader(final String namespace, final String coreJar) throws Throwable { final SandboxClassLoader classLoader; // 如果已经被启动则返回之前启动的ClassLoader if (sandboxClassLoaderMap.containsKey(namespace) && null != sandboxClassLoaderMap.get(namespace)) { classLoader = sandboxClassLoaderMap.get(namespace); } // 如果未启动则重新加载 else { classLoader = new SandboxClassLoader(namespace, coreJar); sandboxClassLoaderMap.put(namespace, classLoader); } return classLoader; } /** * 删除指定命名空间下的jvm-sandbox * * @param namespace 指定命名空间 * @throws Throwable 删除失败 */ @SuppressWarnings("unused") public static synchronized void uninstall(final String namespace) throws Throwable { final SandboxClassLoader sandboxClassLoader = sandboxClassLoaderMap.get(namespace); if (null == sandboxClassLoader) { return; } // 关闭服务器 final Class classOfProxyServer = sandboxClassLoader.loadClass(CLASS_OF_PROXY_CORE_SERVER); classOfProxyServer.getMethod("destroy") .invoke(classOfProxyServer.getMethod("getInstance").invoke(null)); // 关闭SandboxClassLoader sandboxClassLoader.closeIfPossible(); sandboxClassLoaderMap.remove(namespace); } /** * 在当前JVM安装jvm-sandbox * * @param featureMap 启动参数配置 * @param inst inst * @return 服务器IP:PORT */ private static synchronized InetSocketAddress install(final Map featureMap, final Instrumentation inst) { final String namespace = getNamespace(featureMap); final String propertiesFilePath = getPropertiesFilePath(featureMap); final String coreFeatureString = toFeatureString(featureMap); try { final String home = getSandboxHome(featureMap); // 将Spy注入到BootstrapClassLoader inst.appendToBootstrapClassLoaderSearch(new JarFile(new File( getSandboxSpyJarPath(home) // SANDBOX_SPY_JAR_PATH ))); // 构造自定义的类加载器,尽量减少Sandbox对现有工程的侵蚀 final ClassLoader sandboxClassLoader = loadOrDefineClassLoader( namespace, getSandboxCoreJarPath(home) // SANDBOX_CORE_JAR_PATH ); // CoreConfigure类定义 final Class classOfConfigure = sandboxClassLoader.loadClass(CLASS_OF_CORE_CONFIGURE); // 反序列化成CoreConfigure类实例 final Object objectOfCoreConfigure = classOfConfigure.getMethod("toConfigure", String.class, String.class) .invoke(null, coreFeatureString, propertiesFilePath); // CoreServer类定义 final Class classOfProxyServer = sandboxClassLoader.loadClass(CLASS_OF_PROXY_CORE_SERVER); // 获取CoreServer单例 final Object objectOfProxyServer = classOfProxyServer .getMethod("getInstance") .invoke(null); // CoreServer.isBind() final boolean isBind = (Boolean) classOfProxyServer.getMethod("isBind").invoke(objectOfProxyServer); // 如果未绑定,则需要绑定一个地址 if (!isBind) { try { classOfProxyServer .getMethod("bind", classOfConfigure, Instrumentation.class) .invoke(objectOfProxyServer, objectOfCoreConfigure, inst); } catch (Throwable t) { classOfProxyServer.getMethod("destroy").invoke(objectOfProxyServer); throw t; } } // 返回服务器绑定的地址 return (InetSocketAddress) classOfProxyServer .getMethod("getLocal") .invoke(objectOfProxyServer); } catch (Throwable cause) { throw new RuntimeException("sandbox attach failed.", cause); } } // ----------------------------------------------- 以下代码用于配置解析 ----------------------------------------------- private static final String EMPTY_STRING = ""; private static final String KEY_SANDBOX_HOME = "home"; private static final String KEY_NAMESPACE = "namespace"; private static final String DEFAULT_NAMESPACE = "default"; private static final String KEY_SERVER_IP = "server.ip"; private static final String DEFAULT_IP = "0.0.0.0"; private static final String KEY_SERVER_PORT = "server.port"; private static final String DEFAULT_PORT = "0"; private static final String KEY_TOKEN = "token"; private static final String DEFAULT_TOKEN = EMPTY_STRING; private static final String KEY_PROPERTIES_FILE_PATH = "prop"; private static boolean isNotBlankString(final String string) { return null != string && string.length() > 0 && !string.matches("^\\s*$"); } private static boolean isBlankString(final String string) { return !isNotBlankString(string); } private static String getDefaultString(final String string, final String defaultString) { return isNotBlankString(string) ? string : defaultString; } private static Map toFeatureMap(final String featureString) { final Map featureMap = new LinkedHashMap(); // 不对空字符串进行解析 if (isBlankString(featureString)) { return featureMap; } // KV对片段数组 final String[] kvPairSegmentArray = featureString.split(";"); if (kvPairSegmentArray.length <= 0) { return featureMap; } for (String kvPairSegmentString : kvPairSegmentArray) { if (isBlankString(kvPairSegmentString)) { continue; } final String[] kvSegmentArray = kvPairSegmentString.split("="); if (kvSegmentArray.length != 2 || isBlankString(kvSegmentArray[0]) || isBlankString(kvSegmentArray[1])) { continue; } featureMap.put(kvSegmentArray[0], kvSegmentArray[1]); } return featureMap; } private static String getDefault(final Map map, final String key, final String defaultValue) { return null != map && !map.isEmpty() ? getDefaultString(map.get(key), defaultValue) : defaultValue; } private static String OS = System.getProperty("os.name").toLowerCase(); private static boolean isWindows() { return OS.contains("win"); } // 获取主目录 private static String getSandboxHome(final Map featureMap) { String home = getDefault(featureMap, KEY_SANDBOX_HOME, DEFAULT_SANDBOX_HOME); if( isWindows() ){ Matcher m = Pattern.compile("(?i)^[/\\\\]([a-z])[/\\\\]").matcher(home); if( m.find() ){ home = m.replaceFirst("$1:/"); } } return home; } // 获取命名空间 private static String getNamespace(final Map featureMap) { return getDefault(featureMap, KEY_NAMESPACE, DEFAULT_NAMESPACE); } // 获取TOKEN private static String getToken(final Map featureMap) { return getDefault(featureMap, KEY_TOKEN, DEFAULT_TOKEN); } // 获取容器配置文件路径 private static String getPropertiesFilePath(final Map featureMap) { return getDefault( featureMap, KEY_PROPERTIES_FILE_PATH, getSandboxPropertiesPath(getSandboxHome(featureMap)) // SANDBOX_PROPERTIES_PATH ); } // 如果featureMap中有对应的key值,则将featureMap中的[K,V]对合并到featureSB中 private static void appendFromFeatureMap(final StringBuilder featureSB, final Map featureMap, final String key, final String defaultValue) { if (featureMap.containsKey(key)) { featureSB.append(format("%s=%s;", key, getDefault(featureMap, key, defaultValue))); } } // 将featureMap中的[K,V]对转换为featureString private static String toFeatureString(final Map featureMap) { final String sandboxHome = getSandboxHome(featureMap); final StringBuilder featureSB = new StringBuilder( format( ";cfg=%s;system_module=%s;mode=%s;sandbox_home=%s;user_module=%s;provider=%s;namespace=%s;", getSandboxCfgPath(sandboxHome), // SANDBOX_CFG_PATH, getSandboxModulePath(sandboxHome), // SANDBOX_MODULE_PATH, LAUNCH_MODE, sandboxHome, // SANDBOX_HOME, SANDBOX_USER_MODULE_PATH, getSandboxProviderPath(sandboxHome), // SANDBOX_PROVIDER_LIB_PATH, getNamespace(featureMap) ) ); // 合并IP(如有) appendFromFeatureMap(featureSB, featureMap, KEY_SERVER_IP, DEFAULT_IP); // 合并PORT(如有) appendFromFeatureMap(featureSB, featureMap, KEY_SERVER_PORT, DEFAULT_PORT); return featureSB.toString(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy