From e764621790919ea948492817138faa9d34ca9974 Mon Sep 17 00:00:00 2001 From: dukun Date: Sun, 3 Dec 2017 11:38:11 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E9=97=AE=E9=A2=98=20#3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/server/jetty/servlet/ModuleHttpServlet.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/server/jetty/servlet/ModuleHttpServlet.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/server/jetty/servlet/ModuleHttpServlet.java index 8cf07b7b..4b7b6c75 100755 --- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/server/jetty/servlet/ModuleHttpServlet.java +++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/server/jetty/servlet/ModuleHttpServlet.java @@ -4,6 +4,7 @@ import com.alibaba.jvm.sandbox.core.domain.CoreModule; import com.alibaba.jvm.sandbox.core.manager.CoreModuleManager; import com.alibaba.jvm.sandbox.core.manager.ModuleResourceManager; +import com.alibaba.jvm.sandbox.util.SandboxStringUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; @@ -174,8 +175,12 @@ private Method matchingModuleMethod(final String path, for (final Method method : MethodUtils.getMethodsListWithAnnotation(classOfModule, Http.class)) { final Http httpAnnotation = method.getAnnotation(Http.class); + if(null == httpAnnotation) { + continue; + } + final String pathPattern = "/"+uniqueId+httpAnnotation.value(); if (ArrayUtils.contains(httpAnnotation.method(), httpMethod) - && StringUtils.equals(path, URI.create("/" + uniqueId + httpAnnotation.value()).getPath())) { + && SandboxStringUtils.matching(path, pathPattern)) { return method; } } From edbb19e182d860a25c85ede5f9b4bbe4971a523e Mon Sep 17 00:00:00 2001 From: dukun Date: Sun, 3 Dec 2017 18:38:28 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E9=97=AE=E9=A2=98=20#4?= =?UTF-8?q?=20=E5=AE=9E=E7=8E=B0=E5=91=BD=E5=90=8D=E7=A9=BA=E9=97=B4?= =?UTF-8?q?=E9=9A=94=E7=A6=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bin/sandbox.sh | 43 ++- pom.xml | 2 +- .../jvm/sandbox/agent/AgentLauncher.java | 264 +++++++++++++----- .../jvm/sandbox/agent/SandboxClassLoader.java | 12 +- .../jvm/sandbox/api/resource/ConfigInfo.java | 8 + .../jvm/sandbox/core/CoreConfigure.java | 15 +- .../core/manager/impl/DefaultConfigInfo.java | 5 + .../core/server/jetty/JettyCoreServer.java | 6 +- .../resources/com/alibaba/jvm/sandbox/version | 2 +- .../jvm/sandbox/module/mgr/ControlModule.java | 42 +-- .../jvm/sandbox/module/mgr/InfoModule.java | 3 +- 11 files changed, 295 insertions(+), 107 deletions(-) diff --git a/bin/sandbox.sh b/bin/sandbox.sh index 716fcd28..dfc64203 100755 --- a/bin/sandbox.sh +++ b/bin/sandbox.sh @@ -7,12 +7,12 @@ # define sandbox's home # will be replace by install-local.sh -typeset SANDBOX_HOME_DIR; +typeset SANDBOX_HOME_DIR [[ -z ${SANDBOX_HOME_DIR} ]] \ && SANDBOX_HOME_DIR=$(cd `dirname $0`; pwd)/.. # define sandbox's network -typeset SANDBOX_SERVER_NETWORK; +typeset SANDBOX_SERVER_NETWORK # define sandbox's lib typeset SANDBOX_LIB_DIR=${SANDBOX_HOME_DIR}/lib @@ -24,13 +24,18 @@ typeset SANDBOX_TOKEN_FILE=${HOME}/.sandbox.token typeset SANDBOX_JVM_OPS="-Xms128M -Xmx128M -Xnoclassgc -ea"; # define target JVM Process ID -typeset TARGET_JVM_PID; +typeset TARGET_JVM_PID # define target SERVER network interface -typeset TARGET_SERVER_IP; +typeset TARGET_SERVER_IP +typeset DEFAULT_TARGET_SERVER_IP="0.0.0.0" # define target SERVER network port -typeset TARGET_SERVER_PORT; +typeset TARGET_SERVER_PORT + +# define target NAMESPACE +typeset TARGET_NAMESPACE +typeset DEFAULT_NAMESPACE="default" # exit shell with err_code @@ -44,7 +49,7 @@ exit_on_err() # display usage function usage() { -echo ' +echo " usage: ${0} [h] [ [vlRFfu:a:A:d:m:I:P:C:]] -h : help @@ -130,7 +135,7 @@ usage: ${0} [h] [ [vlRFfu:a:A:d:m:I:P:C:]] -I : IP address Appoint the network interface (bind ip address) - when default, use localhost + when default, use \"${DEFAULT_TARGET_SERVER_IP}\" EXAMPLE: ${0} -p -I 192.168.0.1 -v @@ -153,7 +158,11 @@ usage: ${0} [h] [ [vlRFfu:a:A:d:m:I:P:C:]] -S : Shutdown server Shutdown jvm-sandbox\` server -' + -n : Namespace + Appoint the jvm-sandbox\` namespace + when default, use \"${DEFAULT_NAMESPACE}\" + +" } # check sandbox permission @@ -208,11 +217,11 @@ function attach_jvm() { -jar ${SANDBOX_LIB_DIR}/sandbox-core.jar \ ${TARGET_JVM_PID} \ "${SANDBOX_LIB_DIR}/sandbox-agent.jar" \ - "${token};${TARGET_SERVER_IP};${TARGET_SERVER_PORT}" \ + "token=${token};ip=${TARGET_SERVER_IP};port=${TARGET_SERVER_PORT};namespace=${TARGET_NAMESPACE}" \ || exit_on_err 1 "attach JVM ${TARGET_JVM_PID} fail." # get network from attach result - SANDBOX_SERVER_NETWORK=$(grep ${token} ${SANDBOX_TOKEN_FILE}|tail -1|awk -F ";" '{print $2";"$3}'); + SANDBOX_SERVER_NETWORK=$(grep ${token} ${SANDBOX_TOKEN_FILE}|grep ${TARGET_NAMESPACE}|tail -1|awk -F ";" '{print $3";"$4}'); [[ -z ${SANDBOX_SERVER_NETWORK} ]] \ && exit_on_err 1 "attach JVM ${TARGET_JVM_PID} fail, attach lose response." @@ -234,7 +243,7 @@ function sandbox_curl_with_exit() { function sandbox_debug_curl() { local host=$(echo "${SANDBOX_SERVER_NETWORK}"|awk -F ";" '{print $1}') local port=$(echo "${SANDBOX_SERVER_NETWORK}"|awk -F ";" '{print $2}') - curl -N -s "http://${host}:${port}/sandbox/${1}" \ + curl -N -s "http://${host}:${port}/sandbox/${TARGET_NAMESPACE}/${1}" \ || exit_on_err 1 "target JVM ${TARGET_JVM_PID} lose response." } @@ -243,7 +252,7 @@ function main() { check_permission - while getopts "hp:vFfRu:a:A:d:m:I:P:ClS" ARG + while getopts "hp:vFfRu:a:A:d:m:I:P:ClSn:" ARG do case ${ARG} in h) usage;exit;; @@ -262,6 +271,7 @@ function main() { P) TARGET_SERVER_PORT=${OPTARG};; C) OP_CONNECT_ONLY=1;; S) OP_SHUTDOWN=1;; + n) OP_NAMESPACE=1;ARG_NAMESPACE=${OPTARG};; ?) usage;exit_on_err 1;; esac done @@ -269,11 +279,17 @@ function main() { reset_for_env # reset IP - [ -z ${TARGET_SERVER_IP} ] && TARGET_SERVER_IP="0.0.0.0"; + [ -z ${TARGET_SERVER_IP} ] && TARGET_SERVER_IP="${DEFAULT_TARGET_SERVER_IP}"; # reset PORT [ -z ${TARGET_SERVER_PORT} ] && TARGET_SERVER_PORT=0; + # reset NAMESPACE + [[ ${OP_NAMESPACE} ]] \ + && TARGET_NAMESPACE=${ARG_NAMESPACE} + [[ -z ${TARGET_NAMESPACE} ]] \ + && TARGET_NAMESPACE=${DEFAULT_NAMESPACE} + if [[ ${OP_CONNECT_ONLY} ]]; then [[ 0 -eq ${TARGET_SERVER_PORT} ]] \ && exit_on_err 1 "server appoint PORT (-P) was missing" @@ -282,7 +298,6 @@ function main() { # -p was missing [[ -z ${TARGET_JVM_PID} ]] \ && exit_on_err 1 "PID (-p) was missing."; - attach_jvm fi diff --git a/pom.xml b/pom.xml index f6230cdc..59bda87e 100755 --- a/pom.xml +++ b/pom.xml @@ -14,7 +14,7 @@ UTF-8 1.0.9 1.0.1 - 1.0.1 + 1.0.2 diff --git a/sandbox-agent/src/main/java/com/alibaba/jvm/sandbox/agent/AgentLauncher.java b/sandbox-agent/src/main/java/com/alibaba/jvm/sandbox/agent/AgentLauncher.java index 7e1a6c96..04f31ede 100755 --- a/sandbox-agent/src/main/java/com/alibaba/jvm/sandbox/agent/AgentLauncher.java +++ b/sandbox-agent/src/main/java/com/alibaba/jvm/sandbox/agent/AgentLauncher.java @@ -5,6 +5,9 @@ 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; /** @@ -55,86 +58,63 @@ private static String substringBeforeLast(String str, String separator) { // 启动模式: 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"; - 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"; - // 全局持有ClassLoader用于隔离sandbox实现 - private static volatile ClassLoader sandboxClassLoader; - + private static volatile Map sandboxClassLoaderMap + = new ConcurrentHashMap(); - private static boolean isNotBlankString(final String string) { - return null != string - && string.length() > 0 - && !string.matches("^\\s*$"); - } + 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 String getDefaultString(final String string, final String defaultString) { - return isNotBlankString(string) - ? string - : defaultString; - } /** * 启动加载 * - * @param propertiesFilePath 配置文件路径 - * @param inst inst + * @param featureString 启动参数 + * [namespace,prop] + * @param inst inst */ - public static void premain(String propertiesFilePath, Instrumentation inst) { - main( - SANDBOX_CORE_JAR_PATH, - String.format(";cfg=%s;system_module=%s;mode=%s;sandbox_home=%s;user_module=%s;provider=%s;", - SANDBOX_CFG_PATH, SANDBOX_MODULE_PATH, LAUNCH_MODE_AGENT, SANDBOX_HOME, SANDBOX_USER_MODULE_PATH, SANDBOX_PROVIDER_LIB_PATH), - getDefaultString(propertiesFilePath, SANDBOX_PROPERTIES_PATH), - inst - ); + public static void premain(String featureString, Instrumentation inst) { + LAUNCH_MODE = LAUNCH_MODE_AGENT; + main(toFeatureMap(featureString), inst); } /** * 动态加载 * - * @param cfg config of this attach - * @param inst inst + * @param featureString 启动参数 + * [namespace,token,ip,port,prop] + * @param inst inst */ - public static void agentmain(String cfg, Instrumentation inst) { - - - final String[] cfgSegmentArray = cfg.split(";"); - - // token - final String token = cfgSegmentArray.length >= 1 - ? cfgSegmentArray[0] - : ""; - - // server ip - final String ip = cfgSegmentArray.length >= 2 - ? cfgSegmentArray[1] - : "127.0.0.1"; - - // server port - final String port = cfgSegmentArray.length >= 3 - ? cfgSegmentArray[2] - : "0"; - - if (token.matches("^\\s*$")) { - throw new IllegalArgumentException("sandbox attach token was blank."); - } - - final InetSocketAddress local = main( - SANDBOX_CORE_JAR_PATH, - String.format(";cfg=%s;system_module=%s;mode=%s;sandbox_home=%s;user_module=%s;provider=%s;server.ip=%s;server.port=%s;", - SANDBOX_CFG_PATH, SANDBOX_MODULE_PATH, LAUNCH_MODE_ATTACH, SANDBOX_HOME, SANDBOX_USER_MODULE_PATH, SANDBOX_PROVIDER_LIB_PATH, ip, port), - SANDBOX_PROPERTIES_PATH, - inst + public static void agentmain(String featureString, Instrumentation inst) { + LAUNCH_MODE = LAUNCH_MODE_ATTACH; + final Map featureMap = toFeatureMap(featureString); + writeAttachResult( + getNamespace(featureMap), + getToken(featureMap), + main(featureMap, inst) ); - writeTokenResult(token, local); } - private static synchronized void writeTokenResult(final String token, final InetSocketAddress local) { + /** + * 写入本次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() @@ -145,7 +125,14 @@ private static synchronized void writeTokenResult(final String token, final Inet FileWriter fw = null; try { fw = new FileWriter(file, true); - fw.append(String.format("%s;%s;%s;\n", token, local.getHostName(), local.getPort())); + fw.append( + String.format("%s;%s;%s;%s\n", + namespace, + token, + local.getHostName(), + local.getPort() + ) + ); fw.flush(); } catch (IOException e) { throw new RuntimeException(e); @@ -162,35 +149,50 @@ private static synchronized void writeTokenResult(final String token, final Inet } - private static ClassLoader loadOrDefineClassLoader(String coreJar) throws Throwable { + private static synchronized ClassLoader loadOrDefineClassLoader(final String namespace, + final String coreJar) throws Throwable { final ClassLoader classLoader; // 如果已经被启动则返回之前启动的ClassLoader - if (null != sandboxClassLoader) { - classLoader = sandboxClassLoader; + if (sandboxClassLoaderMap.containsKey(namespace) + && null != sandboxClassLoaderMap.get(namespace)) { + classLoader = sandboxClassLoaderMap.get(namespace); } // 如果未启动则重新加载 else { - classLoader = new SandboxClassLoader(coreJar); + classLoader = new SandboxClassLoader(namespace, coreJar); + sandboxClassLoaderMap.put(namespace, classLoader); } - return sandboxClassLoader = classLoader; + return classLoader; } - private static synchronized InetSocketAddress main(final String coreJarPath, - final String coreFeatureString, - final String propertiesFilePath, + /** + * 清理namespace所指定的ClassLoader + * + * @param namespace 命名空间 + * @return 被清理的ClassLoader + */ + public static synchronized ClassLoader cleanClassLoader(final String namespace) { + return sandboxClassLoaderMap.remove(namespace); + } + + private static synchronized InetSocketAddress main(final Map featureMap, final Instrumentation inst) { + final String namespace = getNamespace(featureMap); + final String propertiesFilePath = getPropertiesFilePath(featureMap); + final String coreFeatureString = toFeatureString(featureMap); + try { // 将Spy注入到BootstrapClassLoader inst.appendToBootstrapClassLoaderSearch(new JarFile(new File(SANDBOX_SPY_JAR_PATH))); // 构造自定义的类加载器,尽量减少Sandbox对现有工程的侵蚀 - final ClassLoader agentLoader = loadOrDefineClassLoader(coreJarPath); + final ClassLoader agentLoader = loadOrDefineClassLoader(namespace, SANDBOX_CORE_JAR_PATH); // CoreConfigure类定义 final Class classOfConfigure = agentLoader.loadClass(CLASS_OF_CORE_CONFIGURE); @@ -236,4 +238,128 @@ private static synchronized InetSocketAddress main(final String coreJarPath, } + + // ----------------------------------------------- 以下代码用于配置解析 ----------------------------------------------- + + private static final String EMPTY_STRING = ""; + + private static final String KEY_NAMESPACE = "namespace"; + private static final String DEFAULT_NAMESPACE = "default"; + + private static final String KEY_SERVER_IP = "ip"; + private static final String DEFAULT_IP = "0.0.0.0"; + + private static final String KEY_SERVER_PORT = "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 (null == kvPairSegmentArray + || kvPairSegmentArray.length <= 0) { + return featureMap; + } + + for (String kvPairSegmentString : kvPairSegmentArray) { + if (isBlankString(kvPairSegmentString)) { + continue; + } + final String[] kvSegmentArray = kvPairSegmentString.split("="); + if (null == kvSegmentArray + || 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 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, 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(String.format("%s=%s;", key, getDefault(featureMap, key, defaultValue))); + } + } + + // 将featureMap中的[K,V]对转换为featureString + private static String toFeatureString(final Map featureMap) { + final StringBuilder featureSB = new StringBuilder( + String.format( + ";cfg=%s;system_module=%s;mode=%s;sandbox_home=%s;user_module=%s;provider=%s;namespace=%s;", + SANDBOX_CFG_PATH, + SANDBOX_MODULE_PATH, + LAUNCH_MODE, + SANDBOX_HOME, + SANDBOX_USER_MODULE_PATH, + 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(); + } + + } diff --git a/sandbox-agent/src/main/java/com/alibaba/jvm/sandbox/agent/SandboxClassLoader.java b/sandbox-agent/src/main/java/com/alibaba/jvm/sandbox/agent/SandboxClassLoader.java index ac4356d6..294a30fe 100755 --- a/sandbox-agent/src/main/java/com/alibaba/jvm/sandbox/agent/SandboxClassLoader.java +++ b/sandbox-agent/src/main/java/com/alibaba/jvm/sandbox/agent/SandboxClassLoader.java @@ -10,8 +10,14 @@ */ class SandboxClassLoader extends URLClassLoader { - SandboxClassLoader(final String sandboxCoreJarFilePath) throws MalformedURLException { + private final String namespace; + private final String path; + + SandboxClassLoader(final String namespace, + final String sandboxCoreJarFilePath) throws MalformedURLException { super(new URL[]{new URL("file:" + sandboxCoreJarFilePath)}); + this.namespace = namespace; + this.path = sandboxCoreJarFilePath; } @Override @@ -37,4 +43,8 @@ protected synchronized Class loadClass(String name, boolean resolve) throws C } } + @Override + public String toString() { + return String.format("SandboxClassLoader[namespace=%s;path=%s;]", namespace, path); + } } diff --git a/sandbox-common-api/src/main/java/com/alibaba/jvm/sandbox/api/resource/ConfigInfo.java b/sandbox-common-api/src/main/java/com/alibaba/jvm/sandbox/api/resource/ConfigInfo.java index a1b4b1b7..8df7453b 100755 --- a/sandbox-common-api/src/main/java/com/alibaba/jvm/sandbox/api/resource/ConfigInfo.java +++ b/sandbox-common-api/src/main/java/com/alibaba/jvm/sandbox/api/resource/ConfigInfo.java @@ -11,6 +11,14 @@ */ public interface ConfigInfo { + /** + * 获取沙箱的命名空间 + * + * @return 沙箱的命名空间 + * @since {@code sandbox-common-api:1.0.2} + */ + String getNamespace(); + /** * 获取沙箱的加载模式 * diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/CoreConfigure.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/CoreConfigure.java index d74f011d..cfc2c6ee 100755 --- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/CoreConfigure.java +++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/CoreConfigure.java @@ -23,6 +23,9 @@ */ public class CoreConfigure { + private static final String KEY_NAMESPACE="namespace"; + private static final String DEFAULT_VAL_NAMESPACE="default"; + private static final String KEY_SANDBOX_HOME = "sandbox_home"; private static final String KEY_LAUNCH_MODE = "mode"; private static final String KEY_SERVER_IP = "server.ip"; @@ -48,7 +51,7 @@ public class CoreConfigure { private static final String KEY_UNSAFE_ENABLE = "unsafe.enable"; // 受保护key数组,在保护key范围之内,如果前端已经传递过参数了,只能认前端,后端无法修改 - private static final String[] PROTECT_KEY_ARRAY = {KEY_SANDBOX_HOME, KEY_LAUNCH_MODE, KEY_SERVER_IP, KEY_SERVER_PORT}; + private static final String[] PROTECT_KEY_ARRAY = {KEY_NAMESPACE, KEY_SANDBOX_HOME, KEY_LAUNCH_MODE, KEY_SERVER_IP, KEY_SERVER_PORT}; private static final FeatureCodec codec = new FeatureCodec(';', '='); @@ -105,6 +108,16 @@ public static CoreConfigure getInstance() { return instance; } + /** + * 获取容器的命名空间 + * @return 容器的命名空间 + */ + public String getNamespace() { + final String namespace = featureMap.get(KEY_NAMESPACE); + return StringUtils.isNotBlank(namespace) + ? namespace + : DEFAULT_VAL_NAMESPACE; + } /** * 获取系统模块加载路径 diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/DefaultConfigInfo.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/DefaultConfigInfo.java index 5691c73e..d5c45aa1 100755 --- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/DefaultConfigInfo.java +++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/DefaultConfigInfo.java @@ -22,6 +22,11 @@ public DefaultConfigInfo(CoreConfigure cfg) { this.cfg = cfg; } + @Override + public String getNamespace() { + return cfg.getNamespace(); + } + @Override public Information.Mode getMode() { return cfg.getLaunchMode(); diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/server/jetty/JettyCoreServer.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/server/jetty/JettyCoreServer.java index aa3d37bf..9a566e02 100755 --- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/server/jetty/JettyCoreServer.java +++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/server/jetty/JettyCoreServer.java @@ -133,7 +133,7 @@ public InetSocketAddress getLocal() throws IOException { /* * 初始化Jetty's ContextHandler */ - private void initJettyContextHandler() { + private void initJettyContextHandler(final CoreConfigure cfg) { final ServletContextHandler context = new ServletContextHandler(SESSIONS); // websocket-servlet @@ -142,7 +142,7 @@ private void initJettyContextHandler() { // module-http-servlet context.addServlet(new ServletHolder(new ModuleHttpServlet(coreModuleManager, moduleResourceManager)), "/module/http/*"); - context.setContextPath("/sandbox"); + context.setContextPath("/sandbox/" + cfg.getNamespace()); context.setClassLoader(getClass().getClassLoader()); httpServer.setHandler(context); } @@ -224,7 +224,7 @@ public void process() throws Throwable { initHttpServer(cfg); logger.debug("init http-server finished."); - initJettyContextHandler(); + initJettyContextHandler(cfg); logger.debug("init servlet finished."); httpServer.start(); diff --git a/sandbox-core/src/main/resources/com/alibaba/jvm/sandbox/version b/sandbox-core/src/main/resources/com/alibaba/jvm/sandbox/version index f0fafe2a..726017f9 100755 --- a/sandbox-core/src/main/resources/com/alibaba/jvm/sandbox/version +++ b/sandbox-core/src/main/resources/com/alibaba/jvm/sandbox/version @@ -1 +1 @@ -0.0.1.c \ No newline at end of file +0.1.0.0 \ No newline at end of file diff --git a/sandbox-mgr-module/src/main/java/com/albaba/jvm/sandbox/module/mgr/ControlModule.java b/sandbox-mgr-module/src/main/java/com/albaba/jvm/sandbox/module/mgr/ControlModule.java index 624f184c..7625deae 100644 --- a/sandbox-mgr-module/src/main/java/com/albaba/jvm/sandbox/module/mgr/ControlModule.java +++ b/sandbox-mgr-module/src/main/java/com/albaba/jvm/sandbox/module/mgr/ControlModule.java @@ -4,9 +4,11 @@ import com.alibaba.jvm.sandbox.api.Module; import com.alibaba.jvm.sandbox.api.ModuleException; import com.alibaba.jvm.sandbox.api.http.Http; +import com.alibaba.jvm.sandbox.api.resource.ConfigInfo; import com.alibaba.jvm.sandbox.api.resource.ModuleManager; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.reflect.FieldUtils; +import org.apache.commons.lang3.reflect.MethodUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -23,20 +25,27 @@ public class ControlModule implements Module { private final Logger logger = LoggerFactory.getLogger(getClass()); @Resource - private ModuleManager moduleManager; + private ConfigInfo configInfo; - // 清道夫,清理SandboxClassLoader和Spy中对Method的引用 - private void cleanRef(final Class classOfAgentLauncher) throws IllegalAccessException, ClassNotFoundException { + @Resource + private ModuleManager moduleManager; - // 清理AgentLauncher.sandboxClassLoader - FieldUtils.writeDeclaredStaticField( + // 清理命名空间所对应的SandboxClassLoader + private ClassLoader cleanSandboxClassLoader(final Class classOfAgentLauncher) + throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { + // 清理AgentLauncher.sandboxClassLoaderMap + final ClassLoader sandboxClassLoader = (ClassLoader) MethodUtils.invokeStaticMethod( classOfAgentLauncher, - "sandboxClassLoader", - null, - true + "cleanClassLoader", + configInfo.getNamespace() ); - logger.info("clean jvm-sandbox ClassLoader success, for jvm-sandbox shutdown."); + logger.info("clean jvm-sandbox ClassLoader[namespace={}] success, for jvm-sandbox shutdown.", + configInfo.getNamespace()); + return sandboxClassLoader; + } + // 清理Spy中对Method的引用 + private void cleanSpy() throws ClassNotFoundException, IllegalAccessException { // 清理Spy中的所有方法 final Class classOfSpy = getClass().getClassLoader() .loadClass("java.com.alibaba.jvm.sandbox.spy.Spy"); @@ -85,6 +94,12 @@ private void unloadSelf() throws ModuleException { private void shutdownServer(final ClassLoader sandboxClassLoader) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { + if (null == sandboxClassLoader) { + logger.warn("detection an warning, target SandboxClassLoader[namespace={}] is null, shutdown server will be ignore", + configInfo.getNamespace()); + return; + } + final Class classOfJettyCoreServer = sandboxClassLoader .loadClass("com.alibaba.jvm.sandbox.core.server.jetty.JettyCoreServer"); final Object objectOfJettyCoreServer = classOfJettyCoreServer.getMethod("getInstance").invoke(null); @@ -101,14 +116,9 @@ public void shutdown(final HttpServletResponse resp) throws Exception { final Class classOfAgentLauncher = getClass().getClassLoader() .loadClass("com.alibaba.jvm.sandbox.agent.AgentLauncher"); - final ClassLoader sandboxClassLoader = (ClassLoader) FieldUtils.getDeclaredField( - classOfAgentLauncher, - "sandboxClassLoader", - true - ).get(null); - // 清理引用 - cleanRef(classOfAgentLauncher); + final ClassLoader sandboxClassLoader = cleanSandboxClassLoader(classOfAgentLauncher); + cleanSpy(); // 卸载模块 unloadModules(); diff --git a/sandbox-mgr-module/src/main/java/com/albaba/jvm/sandbox/module/mgr/InfoModule.java b/sandbox-mgr-module/src/main/java/com/albaba/jvm/sandbox/module/mgr/InfoModule.java index 6eff6dea..89bfa47a 100755 --- a/sandbox-mgr-module/src/main/java/com/albaba/jvm/sandbox/module/mgr/InfoModule.java +++ b/sandbox-mgr-module/src/main/java/com/albaba/jvm/sandbox/module/mgr/InfoModule.java @@ -16,7 +16,7 @@ * * @author luanjia@taobao.com */ -@Information(id = "info", version = "0.0.2", author = "luanjia@taobao.com") +@Information(id = "info", version = "0.0.3", author = "luanjia@taobao.com") public class InfoModule implements Module { @Resource @@ -29,6 +29,7 @@ public class InfoModule implements Module { public void version(final HttpServletResponse resp) throws IOException { final StringBuilder versionSB = new StringBuilder() + .append(" NAMESPACE : ").append(configInfo.getNamespace()).append("\n") .append(" VERSION : ").append(configInfo.getVersion()).append("\n") .append(" MODE : ").append(configInfo.getMode()).append("\n") .append(" SERVER_ADDR : ").append(configInfo.getServerAddress().getHostName()).append("\n") From fb72a8bf6232ff07d2e4ee16954cd836126c7001 Mon Sep 17 00:00:00 2001 From: dukun Date: Sun, 3 Dec 2017 23:57:18 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E9=97=AE=E9=A2=98=20#5?= =?UTF-8?q?=20=E6=94=AF=E6=8C=81JDK9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- doc/JVM-SANDBOX-ReadMe-Chineies.md | 2 +- doc/JVM-SANDBOX-ReadMe-English.md | 2 +- pom.xml | 12 +++++++++--- sandbox-core/pom.xml | 4 ++++ .../sandbox/core/classloader/ModuleClassLoader.java | 3 ++- sandbox-debug-module/pom.xml | 5 +++++ sandbox-mgr-module/pom.xml | 5 +++++ 8 files changed, 28 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index bca11d87..061eef8b 100755 --- a/README.md +++ b/README.md @@ -132,7 +132,7 @@ Based on this I am through the JDK6 provided Instrumentation-API implementation #### Provides a plug-and-play module management container -In order to realize the dynamic hot-swapping of the sandbox module, the container client and the sandbox dynamic pluggable container communicate with the HTTP protocol. The bottom layer uses Jetty6 as the HTTP server. +In order to realize the dynamic hot-swapping of the sandbox module, the container client and the sandbox dynamic pluggable container communicate with the HTTP protocol. The bottom layer uses Jetty8 as the HTTP server. ### What can the JVM-SANDBOX do? diff --git a/doc/JVM-SANDBOX-ReadMe-Chineies.md b/doc/JVM-SANDBOX-ReadMe-Chineies.md index fc26d4c9..ee9e800b 100644 --- a/doc/JVM-SANDBOX-ReadMe-Chineies.md +++ b/doc/JVM-SANDBOX-ReadMe-Chineies.md @@ -29,7 +29,7 @@ 基于此我通过JDK6所提供的Instrumentation-API实现了利用HotSwap技术在不重启JVM的情况下实现对任意方法的AOP增强。而且性能开销还在可以接受的范围之内。 #####2. 动态可插拔容器 -为了实现沙箱模块的动态热插拔,容器客户端和沙箱动态可插拔容器采用HTTP协议进行通讯,底层用Jetty6作为HTTP服务器。 +为了实现沙箱模块的动态热插拔,容器客户端和沙箱动态可插拔容器采用HTTP协议进行通讯,底层用Jetty8作为HTTP服务器。 #### What can the JVM-SANDBOX do? diff --git a/doc/JVM-SANDBOX-ReadMe-English.md b/doc/JVM-SANDBOX-ReadMe-English.md index 4fc0ed3f..39b6f36c 100644 --- a/doc/JVM-SANDBOX-ReadMe-English.md +++ b/doc/JVM-SANDBOX-ReadMe-English.md @@ -38,7 +38,7 @@ Based on this I am through the JDK6 provided Instrumentation-API implementation ##### Provides a plug-and-play module management container -In order to realize the dynamic hot-swapping of the sandbox module, the container client and the sandbox dynamic pluggable container communicate with the HTTP protocol. The bottom layer uses Jetty6 as the HTTP server. +In order to realize the dynamic hot-swapping of the sandbox module, the container client and the sandbox dynamic pluggable container communicate with the HTTP protocol. The bottom layer uses Jetty8 as the HTTP server. #### What can the JVM-SANDBOX do? diff --git a/pom.xml b/pom.xml index 59bda87e..e5e1da73 100755 --- a/pom.xml +++ b/pom.xml @@ -177,17 +177,17 @@ org.ow2.asm asm - 5.0.3 + 6.0 org.ow2.asm asm-commons - 5.0.3 + 6.0 org.ow2.asm asm-util - 5.0.3 + 6.0 org.apache.commons @@ -202,6 +202,12 @@ 1.7.0 + + javax.annotation + javax.annotation-api + 1.3.1 + + diff --git a/sandbox-core/pom.xml b/sandbox-core/pom.xml index fbe21eb8..82f6c2bc 100755 --- a/sandbox-core/pom.xml +++ b/sandbox-core/pom.xml @@ -123,5 +123,9 @@ ant ant + + javax.annotation + javax.annotation-api + diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/classloader/ModuleClassLoader.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/classloader/ModuleClassLoader.java index 2dc2ef52..4d35353c 100755 --- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/classloader/ModuleClassLoader.java +++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/classloader/ModuleClassLoader.java @@ -52,7 +52,8 @@ private ModuleClassLoader(final File moduleJarFile, new Routing( sandboxClassLoader, "^com\\.alibaba\\.jvm\\.sandbox\\.api\\..*", - "^javax\\.servlet\\..*" + "^javax\\.servlet\\..*", + "^javax\\.annotation\\.Resource*$" ) ); this.checksumCRC32 = FileUtils.checksumCRC32(moduleJarFile); diff --git a/sandbox-debug-module/pom.xml b/sandbox-debug-module/pom.xml index 86d30439..5dc0179e 100755 --- a/sandbox-debug-module/pom.xml +++ b/sandbox-debug-module/pom.xml @@ -73,6 +73,11 @@ commons-collections commons-collections + + javax.annotation + javax.annotation-api + provided + diff --git a/sandbox-mgr-module/pom.xml b/sandbox-mgr-module/pom.xml index 6e824936..f4c1667f 100755 --- a/sandbox-mgr-module/pom.xml +++ b/sandbox-mgr-module/pom.xml @@ -61,6 +61,11 @@ org.apache.commons commons-lang3 + + javax.annotation + javax.annotation-api + provided +