From 1e73ca9dc997b865680585261e4b7f7ef68263b9 Mon Sep 17 00:00:00 2001 From: dongchenxu Date: Sun, 6 Jan 2019 14:00:51 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=E6=A8=A1=E5=9D=97=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E5=86=85=E6=A0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jvm/sandbox/agent/AgentLauncher.java | 98 +-- .../api/spi/ModuleJarLifeCycleProvider.java | 8 + .../alibaba/jvm/sandbox/core/CoreModule.java | 276 ++++++++ .../alibaba/jvm/sandbox/core/JvmSandbox.java | 61 ++ .../core/classloader/ModuleClassLoader.java | 10 +- .../jvm/sandbox/core/domain/CoreModule.java | 119 ---- .../sandbox/core/enhance/EventEnhancer.java | 55 +- .../manager/CoreLoadedClassDataSource.java | 14 +- .../core/manager/CoreModuleManager.java | 9 +- .../manager/LoadedClassLoaderListener.java | 7 + .../core/manager/ModuleLifeCycleEventBus.java | 75 -- .../core/manager/ModuleResourceManager.java | 62 -- .../core/manager/impl/DefaultConfigInfo.java | 5 +- .../impl/DefaultCoreModuleManager.java | 183 +++-- .../manager/impl/DefaultEventMonitor.java | 36 - .../impl/DefaultLoadedClassDataSource.java | 64 +- .../manager/impl/DefaultModuleController.java | 2 +- .../impl/DefaultModuleEventWatcher.java | 34 +- .../impl/DefaultModuleLifeCycleEventBus.java | 57 -- .../manager/impl/DefaultModuleManager.java | 2 +- .../impl/DefaultModuleResourceManager.java | 115 ---- .../manager/impl/DefaultProviderManager.java | 10 +- .../core/manager/impl/ModuleJarLoader.java | 35 +- .../core/manager/impl/ModuleLibLoader.java | 34 +- .../core/server/jetty/JettyCoreServer.java | 154 ++--- .../jetty/servlet/ModuleHttpServlet.java | 27 +- .../servlet/WebSocketAcceptorServlet.java | 56 +- .../jvm/sandbox/core/util/LogbackUtils.java | 60 ++ .../jvm/sandbox/core/util/SpyUtils.java | 14 +- .../core/util/matcher/ExtFilterMatcher.java | 2 +- .../listener/LineNumTracingEventListener.java | 7 +- .../listener/TracingAdviceListener.java | 8 +- .../listener/TracingEventListener.java | 8 +- .../CoreLoadedClassDataSourceTestCase.java | 74 +- .../manager/CoreModuleManagerTestCase.java | 651 ++++++------------ .../core/manager/ModuleLifeCycleAdapter.java | 30 - .../core/manager/TracingLifeCycleModule.java | 62 ++ .../mock/EmptyCoreLoadedClassDataSource.java | 54 ++ .../core/mock/EmptyInstrumentation.java | 84 +++ .../core/mock/EmptyProviderManager.java | 18 + .../sandbox/qatest/core/util/AssertUtils.java | 25 + .../qatest/core/util/CalculatorHelper.java | 2 - .../module/debug/OnJarUnLoadCompleted.java | 5 + .../jvm/sandbox/module/mgr/ControlModule.java | 114 +-- .../module/mgr/OnJarUnLoadCompleted.java | 5 + 45 files changed, 1291 insertions(+), 1540 deletions(-) create mode 100755 sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/CoreModule.java create mode 100644 sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/JvmSandbox.java delete mode 100755 sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/domain/CoreModule.java create mode 100644 sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/LoadedClassLoaderListener.java delete mode 100755 sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/ModuleLifeCycleEventBus.java delete mode 100755 sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/ModuleResourceManager.java delete mode 100644 sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/DefaultEventMonitor.java delete mode 100755 sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/DefaultModuleLifeCycleEventBus.java delete mode 100755 sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/DefaultModuleResourceManager.java create mode 100644 sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/LogbackUtils.java delete mode 100644 sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/manager/ModuleLifeCycleAdapter.java create mode 100644 sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/manager/TracingLifeCycleModule.java create mode 100644 sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/mock/EmptyCoreLoadedClassDataSource.java create mode 100644 sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/mock/EmptyInstrumentation.java create mode 100644 sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/mock/EmptyProviderManager.java create mode 100644 sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/AssertUtils.java 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 3b331223..d14db8c5 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 @@ -15,39 +15,14 @@ /** * SandboxAgent启动器 * * * @author luanjia@taobao.com */ public class AgentLauncher { -// // sandbox配置文件目录 -// private static final String SANDBOX_CFG_PATH -// = SANDBOX_HOME + File.separatorChar + "cfg"; -// -// // 模块目录 -// private static final String SANDBOX_MODULE_PATH -// = SANDBOX_HOME + File.separatorChar + "module"; -// -// -// // sandbox核心工程文件 -// private static final String SANDBOX_CORE_JAR_PATH -// = SANDBOX_HOME + File.separatorChar + "lib" + File.separator + "sandbox-core.jar"; -// -// // sandbox-spy工程文件 -// private static final String SANDBOX_SPY_JAR_PATH -// = SANDBOX_HOME + File.separatorChar + "lib" + File.separator + "sandbox-spy.jar"; -// -// private static final String SANDBOX_PROPERTIES_PATH -// = SANDBOX_CFG_PATH + File.separator + "sandbox.properties"; -// -// // sandbox-provider库目录 -// private static final String SANDBOX_PROVIDER_LIB_PATH -// = SANDBOX_HOME + File.separatorChar + "provider"; - - private static String getSandboxCfgPath(String sandboxHome) { return sandboxHome + File.separatorChar + "cfg"; } @@ -114,7 +89,7 @@ private static String getSandboxProviderPath(String sandboxHome) { */ public static void premain(String featureString, Instrumentation inst) { LAUNCH_MODE = LAUNCH_MODE_AGENT; - main(toFeatureMap(featureString), inst); + install(toFeatureMap(featureString), inst); } /** @@ -130,7 +105,7 @@ public static void agentmain(String featureString, Instrumentation inst) { writeAttachResult( getNamespace(featureMap), getToken(featureMap), - main(featureMap, inst) + install(featureMap, inst) ); } @@ -202,40 +177,37 @@ private static synchronized ClassLoader loadOrDefineClassLoader(final String nam } /** - * 获取当前命名空间下的ClassLoader - *

- * 该方法将会被{@code ControlModule#shutdown}通过反射调用, - * 请保持方法声明一致 + * 删除指定命名空间下的jvm-sandbox * - * @param namespace 命名空间 - * @return 当前的ClassLoader - * @since {@code sandbox-api:1.0.15} + * @param namespace 指定命名空间 + * @throws Throwable 删除失败 */ @SuppressWarnings("unused") - public static ClassLoader getClassLoader(final String namespace) { - return sandboxClassLoaderMap.get(namespace); + 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); } /** - * 清理namespace所指定的ClassLoader - *

- * 该方法将会被{@code ControlModule#shutdown}通过反射调用, - * 请保持方法声明一致 + * 在当前JVM安装jvm-sandbox * - * @param namespace 命名空间 - * @return 被清理的ClassLoader + * @param featureMap 启动参数配置 + * @param inst inst + * @return 服务器IP:PORT */ - @SuppressWarnings("unused") - public static synchronized ClassLoader cleanClassLoader(final String namespace) { - final SandboxClassLoader sandboxClassLoader = sandboxClassLoaderMap.remove(namespace); - if (null != sandboxClassLoader) { - sandboxClassLoader.closeIfPossible(); - } - return sandboxClassLoader; - } - - private static synchronized InetSocketAddress main(final Map featureMap, - final Instrumentation inst) { + private static synchronized InetSocketAddress install(final Map featureMap, + final Instrumentation inst) { final String namespace = getNamespace(featureMap); final String propertiesFilePath = getPropertiesFilePath(featureMap); @@ -250,29 +222,29 @@ private static synchronized InetSocketAddress main(final Map fea ))); // 构造自定义的类加载器,尽量减少Sandbox对现有工程的侵蚀 - final ClassLoader agentLoader = loadOrDefineClassLoader( + final ClassLoader sandboxClassLoader = loadOrDefineClassLoader( namespace, getSandboxCoreJarPath(getSandboxHome(featureMap)) // SANDBOX_CORE_JAR_PATH ); // CoreConfigure类定义 - final Class classOfConfigure = agentLoader.loadClass(CLASS_OF_CORE_CONFIGURE); + 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 = agentLoader.loadClass(CLASS_OF_PROXY_CORE_SERVER); + final Class classOfProxyServer = sandboxClassLoader.loadClass(CLASS_OF_PROXY_CORE_SERVER); // 获取CoreServer单例 - final Object objectOfCoreServer = classOfProxyServer + final Object objectOfProxyServer = classOfProxyServer .getMethod("getInstance") .invoke(null); // CoreServer.isBind() - final boolean isBind = (Boolean) classOfProxyServer.getMethod("isBind").invoke(objectOfCoreServer); + final boolean isBind = (Boolean) classOfProxyServer.getMethod("isBind").invoke(objectOfProxyServer); // 如果未绑定,则需要绑定一个地址 @@ -280,9 +252,9 @@ private static synchronized InetSocketAddress main(final Map fea try { classOfProxyServer .getMethod("bind", classOfConfigure, Instrumentation.class) - .invoke(objectOfCoreServer, objectOfCoreConfigure, inst); + .invoke(objectOfProxyServer, objectOfCoreConfigure, inst); } catch (Throwable t) { - classOfProxyServer.getMethod("destroy").invoke(objectOfCoreServer); + classOfProxyServer.getMethod("destroy").invoke(objectOfProxyServer); throw t; } @@ -291,7 +263,7 @@ private static synchronized InetSocketAddress main(final Map fea // 返回服务器绑定的地址 return (InetSocketAddress) classOfProxyServer .getMethod("getLocal") - .invoke(objectOfCoreServer); + .invoke(objectOfProxyServer); } catch (Throwable cause) { diff --git a/sandbox-api/src/main/java/com/alibaba/jvm/sandbox/api/spi/ModuleJarLifeCycleProvider.java b/sandbox-api/src/main/java/com/alibaba/jvm/sandbox/api/spi/ModuleJarLifeCycleProvider.java index 1d14985b..c271d27f 100644 --- a/sandbox-api/src/main/java/com/alibaba/jvm/sandbox/api/spi/ModuleJarLifeCycleProvider.java +++ b/sandbox-api/src/main/java/com/alibaba/jvm/sandbox/api/spi/ModuleJarLifeCycleProvider.java @@ -8,6 +8,14 @@ */ public interface ModuleJarLifeCycleProvider { + /** + * 等待 + * @param loaded + * @param inComing + * @return + */ + ClassLoader waitingFor(ClassLoader[] loaded, ClassLoader inComing); + /** * 模块Jar文件卸载完所有模块后,正式卸载Jar文件之前之后调用! */ diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/CoreModule.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/CoreModule.java new file mode 100755 index 00000000..594d4c5b --- /dev/null +++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/CoreModule.java @@ -0,0 +1,276 @@ +package com.alibaba.jvm.sandbox.core; + +import com.alibaba.jvm.sandbox.api.Module; +import com.alibaba.jvm.sandbox.core.classloader.ModuleClassLoader; +import com.alibaba.jvm.sandbox.core.manager.impl.SandboxClassFileTransformer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.lang.ref.WeakReference; +import java.util.*; + +/** + * 沙箱模块内核封装对象 + * + * @author luanjia@taobao.com + */ +public class CoreModule { + + private final Logger logger = LoggerFactory.getLogger(getClass()); + + // 全局唯一编号 + private final String uniqueId; + + // 模块归属Jar文件 + private final File jarFile; + + // 模块加载的ClassLoader + private final ModuleClassLoader loader; + + // 模块 + private final Module module; + + // 模块的类转换器 + private final Set sandboxClassFileTransformers + = new LinkedHashSet(); + + // 模块所持有的可释放资源 + private final List> releaseResources + = new ArrayList>(); + + // 是否已经激活 + private boolean isActivated; + + // 是否已被加载 + private boolean isLoaded; + + /** + * 模块业务对象 + * + * @param uniqueId 模块ID + * @param jarFile 模块归属Jar文件 + * @param loader 模块加载ClassLoader + * @param module 模块 + */ + public CoreModule(final String uniqueId, + final File jarFile, + final ModuleClassLoader loader, + final Module module) { + this.uniqueId = uniqueId; + this.jarFile = jarFile; + this.loader = loader; + this.module = module; + } + + /** + * 判断模块是否已被激活 + * + * @return TRUE:已激活;FALSE:未激活 + */ + public boolean isActivated() { + return isActivated; + } + + /** + * 标记模块激活状态 + * + * @param isActivated 模块激活状态 + * @return this + */ + public CoreModule markActivated(boolean isActivated) { + this.isActivated = isActivated; + return this; + } + + /** + * 判断模块是否已经被加载 + * + * @return TRUE:被加载;FALSE:未被加载 + */ + public boolean isLoaded() { + return isLoaded; + } + + + /** + * 标记模块加载状态 + * + * @param isLoaded 模块加载状态 + * @return this + */ + public CoreModule markLoaded(boolean isLoaded) { + this.isLoaded = isLoaded; + return this; + } + + /** + * 获取ModuleJar文件 + * + * @return ModuleJar文件 + */ + public File getJarFile() { + return jarFile; + } + + /** + * 获取对应的ModuleClassLoader + * + * @return ModuleClassLoader + */ + public ModuleClassLoader getLoader() { + return loader; + } + + /** + * 获取模块ID + * + * @return 模块ID + */ + public String getUniqueId() { + return uniqueId; + } + + /** + * 获取模块实例 + * + * @return 模块实例 + */ + public Module getModule() { + return module; + } + + /** + * 获取模块所创建的SandboxClassFileTransformer集合 + * + * @return 模块所创建的SandboxClassFileTransformer集合 + */ + public Set getSandboxClassFileTransformers() { + return sandboxClassFileTransformers; + } + + /** + * 获取模块所编织的类个数 + * + * @return 模块所编织的类个数 + */ + public int cCnt() { + int cCnt = 0; + for (final SandboxClassFileTransformer sandboxClassFileTransformer : sandboxClassFileTransformers) { + cCnt += sandboxClassFileTransformer.getAffectStatistic().cCnt(); + } + return cCnt; + } + + /** + * 获取模块所编织的方法个数 + * + * @return 模块所编织的方法个数 + */ + public int mCnt() { + int mCnt = 0; + for (final SandboxClassFileTransformer sandboxClassFileTransformer : sandboxClassFileTransformers) { + mCnt += sandboxClassFileTransformer.getAffectStatistic().mCnt(); + } + return mCnt; + } + + @Override + public String toString() { + return String.format( + "module[id=%s;class=%s;]", + uniqueId, + module.getClass() + ); + } + + + /** + * 在模块下追加一个可释放资源 + * + * @param resource 可释放资源封装 + * @param 资源实体 + * @return 资源实体本身 + */ + public T append(ReleaseResource resource) { + if (null == resource + || null == resource.get()) { + return null; + } + releaseResources.add(resource); + logger.debug("append resource={} in module[id={};]", resource.get(), uniqueId); + return resource.get(); + } + + /** + * 在当前模块下移除一个可释放资源 + * + * @param target 待释放的资源实体 + */ + public void remove(Object target) { + final Iterator> resourceRefIt = releaseResources.iterator(); + while (resourceRefIt.hasNext()) { + final ReleaseResource resourceRef = resourceRefIt.next(); + + // 删除掉无效的资源 + if (null == resourceRef) { + resourceRefIt.remove(); + logger.info("remove null resource in module={}", uniqueId); + continue; + } + + // 删除掉已经被GC掉的资源 + if (null == resourceRef.get()) { + resourceRefIt.remove(); + logger.info("remove empty resource in module={}", uniqueId); + continue; + } + + if (target.equals(resourceRef.get())) { + resourceRefIt.remove(); + logger.info("remove resource={} in module={}", resourceRef.get(), uniqueId); + try { + resourceRef.release(); + } catch (Exception cause) { + logger.warn("release resource occur error in module={};", uniqueId, cause); + } + } + } + } + + /** + * 可释放资源 + * + * @param 资源类型 + */ + public static abstract class ReleaseResource { + + // 资源弱引用,允许被GC回收 + private final WeakReference reference; + + /** + * 构造释放资源 + * + * @param resource 资源目标 + */ + public ReleaseResource(T resource) { + this.reference = new WeakReference(resource); + } + + /** + * 释放资源 + */ + public abstract void release(); + + /** + * 获取资源实体 + * + * @return 资源实体 + */ + public T get() { + return reference.get(); + } + + } + +} diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/JvmSandbox.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/JvmSandbox.java new file mode 100644 index 00000000..cd09d539 --- /dev/null +++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/JvmSandbox.java @@ -0,0 +1,61 @@ +package com.alibaba.jvm.sandbox.core; + +import com.alibaba.jvm.sandbox.core.enhance.weaver.EventListenerHandlers; +import com.alibaba.jvm.sandbox.core.manager.CoreLoadedClassDataSource; +import com.alibaba.jvm.sandbox.core.manager.CoreModuleManager; +import com.alibaba.jvm.sandbox.core.manager.impl.DefaultCoreModuleManager; +import com.alibaba.jvm.sandbox.core.manager.impl.DefaultLoadedClassDataSource; +import com.alibaba.jvm.sandbox.core.manager.impl.DefaultProviderManager; +import com.alibaba.jvm.sandbox.core.util.SpyUtils; + +import java.lang.instrument.Instrumentation; + +public class JvmSandbox { + + private final CoreConfigure cfg; + private final Instrumentation inst; + private final CoreLoadedClassDataSource loadedClassDataSource; + private final CoreModuleManager coreModuleManager; + + public JvmSandbox(final CoreConfigure cfg, + final Instrumentation inst) { + EventListenerHandlers.getSingleton(); + this.cfg = cfg; + this.coreModuleManager = new DefaultCoreModuleManager( + cfg, + this.inst = inst, + this.loadedClassDataSource = new DefaultLoadedClassDataSource(inst, cfg.isEnableUnsafe()), + new DefaultProviderManager(cfg) + ); + + init(); + } + + private void init() { + SpyUtils.init(cfg.getNamespace()); + inst.addTransformer(this.loadedClassDataSource); + } + + + /** + * 获取模块管理器 + * + * @return + */ + public CoreModuleManager getCoreModuleManager() { + return coreModuleManager; + } + + public void destroy() { + + inst.removeTransformer(loadedClassDataSource); + + // 卸载所有的模块 + coreModuleManager.unloadAll(); + + // 清理Spy + SpyUtils.clean(cfg.getNamespace()); + + } + +} 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 54a06db0..df905bf8 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 @@ -45,18 +45,16 @@ private static File copyToTempFile(final File moduleJarFile) throws IOException return tempFile; } - public ModuleClassLoader(final File moduleJarFile, - final ClassLoader sandboxClassLoader) throws IOException { - this(moduleJarFile, copyToTempFile(moduleJarFile), sandboxClassLoader); + public ModuleClassLoader(final File moduleJarFile) throws IOException { + this(moduleJarFile, copyToTempFile(moduleJarFile)); } private ModuleClassLoader(final File moduleJarFile, - final File tempModuleJarFile, - final ClassLoader sandboxClassLoader) throws IOException { + final File tempModuleJarFile) throws IOException { super( new URL[]{new URL("file:" + tempModuleJarFile.getPath())}, new Routing( - sandboxClassLoader, + ModuleClassLoader.class.getClassLoader(), "^com\\.alibaba\\.jvm\\.sandbox\\.api\\..*", "^javax\\.servlet\\..*", "^javax\\.annotation\\.Resource.*$" diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/domain/CoreModule.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/domain/CoreModule.java deleted file mode 100755 index 3d198460..00000000 --- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/domain/CoreModule.java +++ /dev/null @@ -1,119 +0,0 @@ -package com.alibaba.jvm.sandbox.core.domain; - -import com.alibaba.jvm.sandbox.api.Module; -import com.alibaba.jvm.sandbox.core.classloader.ModuleClassLoader; -import com.alibaba.jvm.sandbox.core.manager.impl.SandboxClassFileTransformer; - -import java.io.File; -import java.util.LinkedHashSet; -import java.util.Set; - -/** - * 沙箱模块内核封装对象 - * Created by luanjia on 16/10/4. - */ -public class CoreModule { - - // 全局唯一编号 - private final String uniqueId; - - // 模块归属Jar文件 - private final File jarFile; - - // 模块加载的ClassLoader - private final ModuleClassLoader loader; - - // 模块 - private final Module module; - - // 模块的类转换器 - private final Set sandboxClassFileTransformers - = new LinkedHashSet(); - - // 是否已经激活 - private boolean activated; - - // 是否已被加载 - private boolean loaded; - - /** - * 模块业务对象 - * - * @param uniqueId 模块ID - * @param jarFile 模块归属Jar文件 - * @param loader 模块加载ClassLoader - * @param module 模块 - */ - public CoreModule(final String uniqueId, - final File jarFile, - final ModuleClassLoader loader, - final Module module) { - this.uniqueId = uniqueId; - this.jarFile = jarFile; - this.loader = loader; - this.module = module; - } - - public boolean isActivated() { - return activated; - } - - public CoreModule setActivated(boolean activated) { - this.activated = activated; - return this; - } - - public boolean isLoaded() { - return loaded; - } - - public CoreModule setLoaded(boolean loaded) { - this.loaded = loaded; - return this; - } - - public File getJarFile() { - return jarFile; - } - - public ModuleClassLoader getLoader() { - return loader; - } - - public Module getModule() { - return module; - } - - public Set getSandboxClassFileTransformers() { - return sandboxClassFileTransformers; - } - - public String getUniqueId() { - return uniqueId; - } - - public int cCnt() { - int cCnt = 0; - for (final SandboxClassFileTransformer sandboxClassFileTransformer : sandboxClassFileTransformers) { - cCnt += sandboxClassFileTransformer.getAffectStatistic().cCnt(); - } - return cCnt; - } - - public int mCnt() { - int mCnt = 0; - for (final SandboxClassFileTransformer sandboxClassFileTransformer : sandboxClassFileTransformers) { - mCnt += sandboxClassFileTransformer.getAffectStatistic().mCnt(); - } - return mCnt; - } - - @Override - public String toString() { - return String.format( - "module[id:%s;class:%s;]", - uniqueId, - module.getClass() - ); - } -} diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/enhance/EventEnhancer.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/enhance/EventEnhancer.java index 84343980..91773f51 100755 --- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/enhance/EventEnhancer.java +++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/enhance/EventEnhancer.java @@ -3,7 +3,6 @@ import com.alibaba.jvm.sandbox.api.event.Event; import com.alibaba.jvm.sandbox.core.enhance.weaver.asm.EventWeaver; import com.alibaba.jvm.sandbox.core.util.ObjectIDs; -import com.alibaba.jvm.sandbox.core.util.SpyUtils; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; import org.slf4j.Logger; @@ -73,36 +72,6 @@ protected String getCommonSuperClass(String type1, String type2) { }; } - /** - * 编织事件方法 - * - * @param sourceByteCodeArray 原始字节码数组 - * @return 编织后的字节码数组 - */ - private byte[] weavingEvent(final ClassLoader targetClassLoader, - final byte[] sourceByteCodeArray, - final Set signCodes, - final String namespace, - final int listenerId, - final Event.Type[] eventTypeArray) { - final ClassReader cr = new ClassReader(sourceByteCodeArray); - final ClassWriter cw = createClassWriter(targetClassLoader, cr); - final int targetClassLoaderObjectID = ObjectIDs.instance.identity(targetClassLoader); - cr.accept( - new EventWeaver( - ASM7, cw, namespace, listenerId, - targetClassLoaderObjectID, - cr.getClassName(), - signCodes, - eventTypeArray - ), - EXPAND_FRAMES - ); - return cw.toByteArray(); - // return dumpClassIfNecessary(SandboxStringUtils.toJavaClassName(cr.getClassName()), cw.toByteArray()); - } - - // /* // * dump class to file // * 用于代码调试 @@ -136,17 +105,21 @@ public byte[] toByteCodeArray(final ClassLoader targetClassLoader, final String namespace, final int listenerId, final Event.Type[] eventTypeArray) { - // 如果定义间谍类失败了,则后续不需要增强 - try { - SpyUtils.init(namespace); - // defineSpyIfNecessary(targetClassLoader); - } catch (Throwable cause) { - logger.warn("define Spy to target ClassLoader={} failed.", targetClassLoader, cause); - return byteCodeArray; - } - // 返回增强后字节码 - return weavingEvent(targetClassLoader, byteCodeArray, signCodes, namespace, listenerId, eventTypeArray); + final ClassReader cr = new ClassReader(byteCodeArray); + final ClassWriter cw = createClassWriter(targetClassLoader, cr); + final int targetClassLoaderObjectID = ObjectIDs.instance.identity(targetClassLoader); + cr.accept( + new EventWeaver( + ASM7, cw, namespace, listenerId, + targetClassLoaderObjectID, + cr.getClassName(), + signCodes, + eventTypeArray + ), + EXPAND_FRAMES + ); + return cw.toByteArray(); } } diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/CoreLoadedClassDataSource.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/CoreLoadedClassDataSource.java index d2f52e25..d3ae6f56 100644 --- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/CoreLoadedClassDataSource.java +++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/CoreLoadedClassDataSource.java @@ -3,6 +3,7 @@ import com.alibaba.jvm.sandbox.api.resource.LoadedClassDataSource; import com.alibaba.jvm.sandbox.core.util.matcher.Matcher; +import java.lang.instrument.ClassFileTransformer; import java.util.List; /** @@ -10,7 +11,7 @@ * * @author luanjia@taobao.com */ -public interface CoreLoadedClassDataSource extends LoadedClassDataSource { +public interface CoreLoadedClassDataSource extends LoadedClassDataSource, ClassFileTransformer { /** * 使用{@link Matcher}来完成类的检索 @@ -23,4 +24,15 @@ public interface CoreLoadedClassDataSource extends LoadedClassDataSource { */ List> findForReTransform(Matcher matcher); + /** + * 列出所有已经加载的ClassLoader + * + * @return 已经加载的ClassLoader + */ + ClassLoader[] listLoadedClassLoader(); + + void appendLoadedClassLoaderListener(LoadedClassLoaderListener listener); + + void removeLoadedClassLoaderListener(LoadedClassLoaderListener listener); + } diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/CoreModuleManager.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/CoreModuleManager.java index 68b2a09b..6048ce80 100755 --- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/CoreModuleManager.java +++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/CoreModuleManager.java @@ -1,7 +1,7 @@ package com.alibaba.jvm.sandbox.core.manager; import com.alibaba.jvm.sandbox.api.ModuleException; -import com.alibaba.jvm.sandbox.core.domain.CoreModule; +import com.alibaba.jvm.sandbox.core.CoreModule; import java.util.Collection; @@ -22,9 +22,10 @@ public interface CoreModuleManager { /** * 沙箱重置 * + * @return this * @throws ModuleException 沙箱重置失败 */ - void reset() throws ModuleException; + CoreModuleManager reset() throws ModuleException; /** * 激活模块 @@ -79,5 +80,9 @@ public interface CoreModuleManager { */ CoreModule unload(CoreModule coreModule, boolean isIgnoreModuleException) throws ModuleException; + /** + * 卸载所有模块 + */ + void unloadAll(); } diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/LoadedClassLoaderListener.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/LoadedClassLoaderListener.java new file mode 100644 index 00000000..c00ce74c --- /dev/null +++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/LoadedClassLoaderListener.java @@ -0,0 +1,7 @@ +package com.alibaba.jvm.sandbox.core.manager; + +public interface LoadedClassLoaderListener { + + void onLoaded(ClassLoader loader); + +} diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/ModuleLifeCycleEventBus.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/ModuleLifeCycleEventBus.java deleted file mode 100755 index af3940b0..00000000 --- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/ModuleLifeCycleEventBus.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.alibaba.jvm.sandbox.core.manager; - -import com.alibaba.jvm.sandbox.core.domain.CoreModule; - -/** - * 模块生命周期事件总线 - * Created by luanjia@taobao.com on 2017/2/3. - */ -public interface ModuleLifeCycleEventBus { - - /** - * 添加模块生命周期监听器 - *

被添加的监听器将按顺序完成生命周期的通知

- * - * @param lifeCycleEventListener 模块生命周期监听 - */ - void append(ModuleLifeCycleEventListener lifeCycleEventListener); - - /** - * 通知事件 - * - * @param coreModule 被通知的沙箱模块 - * @param event 通知事件类型 - */ - void fire(CoreModule coreModule, Event event); - - /** - * 模块事件类型 - */ - enum Event { - - /** - * 模块加载 - */ - LOAD, - - /** - * 模块加载完成 - */ - LOAD_COMPLETED, - - /** - * 模块卸载 - */ - UNLOAD, - - /** - * 模块激活 - */ - ACTIVE, - - /** - * 模块冻结 - */ - FROZE - } - - /** - * 模块生命周期事件监听器 - */ - interface ModuleLifeCycleEventListener { - - /** - * 模块生命周期事件到达 - * - * @param coreModule 被通知的沙箱模块 - * @param event 通知事件类型 - * @return TRUE : 继续保持监听,下次有事件通知时继续接收消息 - * FALSE : 放弃后续的监听 - */ - boolean onFire(CoreModule coreModule, Event event); - - } - -} diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/ModuleResourceManager.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/ModuleResourceManager.java deleted file mode 100755 index 60d6002a..00000000 --- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/ModuleResourceManager.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.alibaba.jvm.sandbox.core.manager; - -import com.alibaba.jvm.sandbox.core.manager.ModuleLifeCycleEventBus.ModuleLifeCycleEventListener; - -import java.lang.ref.WeakReference; - -/** - * 模块可释放资源管理 - * 通常用来管理围绕Module所展开的http/websocket连接 - * Created by luanjia@taobao.com on 2017/2/4. - */ -public interface ModuleResourceManager extends ModuleLifeCycleEventListener { - - /** - * 在模块下追加一个可释放资源 - * - * @param uniqueId 模块ID - * @param resource 可释放资源封装 - * @param 资源实体 - * @return 资源实体本身 - */ - T append(String uniqueId, WeakResource resource); - - /** - * 在当前模块下移除一个可释放资源 - * - * @param uniqueId 模块ID - * @param target 待释放的资源实体 - * @param 资源实体 - */ - void remove(String uniqueId, T target); - - /** - * 弱引用资源 - * - * @param 资源类型 - */ - abstract class WeakResource { - - private final WeakReference weakReference; - - public WeakResource(T resource) { - this.weakReference = new WeakReference(resource); - } - - /** - * 释放资源 - */ - public abstract void release(); - - /** - * 获取资源实体 - * - * @return 资源实体 - */ - public T get() { - return weakReference.get(); - } - - } - -} 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 730870ee..04f347bf 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 @@ -12,9 +12,10 @@ /** * 默认配置信息实现 - * Created by luanjia@taobao.com on 2017/2/9. + * + * @author luanjia@taobao.com */ -public class DefaultConfigInfo implements ConfigInfo { +class DefaultConfigInfo implements ConfigInfo { private final CoreConfigure cfg; diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/DefaultCoreModuleManager.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/DefaultCoreModuleManager.java index 1e0d680a..26aeb9fe 100755 --- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/DefaultCoreModuleManager.java +++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/DefaultCoreModuleManager.java @@ -1,15 +1,16 @@ package com.alibaba.jvm.sandbox.core.manager.impl; import com.alibaba.jvm.sandbox.api.*; +import com.alibaba.jvm.sandbox.api.event.Event; import com.alibaba.jvm.sandbox.api.resource.*; import com.alibaba.jvm.sandbox.core.CoreConfigure; +import com.alibaba.jvm.sandbox.core.CoreModule; import com.alibaba.jvm.sandbox.core.classloader.ModuleClassLoader; -import com.alibaba.jvm.sandbox.core.domain.CoreModule; import com.alibaba.jvm.sandbox.core.enhance.weaver.EventListenerHandlers; import com.alibaba.jvm.sandbox.core.manager.CoreLoadedClassDataSource; import com.alibaba.jvm.sandbox.core.manager.CoreModuleManager; -import com.alibaba.jvm.sandbox.core.manager.ModuleLifeCycleEventBus; import com.alibaba.jvm.sandbox.core.manager.ProviderManager; +import com.alibaba.jvm.sandbox.core.manager.impl.ModuleLibLoader.ModuleJarLoadCallback; import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.reflect.FieldUtils; import org.slf4j.Logger; @@ -24,7 +25,7 @@ import java.util.concurrent.ConcurrentHashMap; import static com.alibaba.jvm.sandbox.api.ModuleException.ErrorCode.*; -import static com.alibaba.jvm.sandbox.core.manager.ModuleLifeCycleEventBus.Event.LOAD_COMPLETED; +import static com.alibaba.jvm.sandbox.core.manager.impl.DefaultCoreModuleManager.ModuleLifeCycleType.*; import static org.apache.commons.lang3.reflect.FieldUtils.writeField; /** @@ -37,9 +38,7 @@ public class DefaultCoreModuleManager implements CoreModuleManager { private final CoreConfigure cfg; private final Instrumentation inst; - private final ClassLoader sandboxClassLoader; private final CoreLoadedClassDataSource classDataSource; - private final ModuleLifeCycleEventBus moduleLifeCycleEventBus; private final ProviderManager providerManager; // 模块目录&文件集合 @@ -51,24 +50,18 @@ public class DefaultCoreModuleManager implements CoreModuleManager { /** * 模块模块管理 * - * @param cfg 模块核心配置 - * @param inst inst - * @param sandboxClassLoader 沙箱加载ClassLoader - * @param classDataSource 已加载类数据源 - * @param moduleLifeCycleEventBus 模块生命周期通知总线 - * @param providerManager 服务提供者管理器 + * @param cfg 模块核心配置 + * @param inst inst + * @param classDataSource 已加载类数据源 + * @param providerManager 服务提供者管理器 */ public DefaultCoreModuleManager(final CoreConfigure cfg, final Instrumentation inst, - final ClassLoader sandboxClassLoader, final CoreLoadedClassDataSource classDataSource, - final ModuleLifeCycleEventBus moduleLifeCycleEventBus, final ProviderManager providerManager) { this.cfg = cfg; this.inst = inst; - this.sandboxClassLoader = sandboxClassLoader; this.classDataSource = classDataSource; - this.moduleLifeCycleEventBus = moduleLifeCycleEventBus; this.providerManager = providerManager; // 初始化模块目录 @@ -76,13 +69,6 @@ public DefaultCoreModuleManager(final CoreConfigure cfg, new File[]{new File(cfg.getSystemModuleLibPath())}, cfg.getUserModuleLibFilesWithCache() ); - -// // 初始化加载所有的模块 -// try { -// reset(); -// } catch (Throwable cause) { -// logger.warn("reset occur error when initializing.", cause); -// } } private File[] mergeFileArray(File[] aFileArray, File[] bFileArray) { @@ -95,13 +81,13 @@ private File[] mergeFileArray(File[] aFileArray, File[] bFileArray) { /* * 通知模块生命周期 */ - private void callAndFireModuleLifeCycle(final CoreModule coreModule, final ModuleLifeCycleEventBus.Event e) throws ModuleException { + private void callAndFireModuleLifeCycle(final CoreModule coreModule, final ModuleLifeCycleType type) throws ModuleException { if (coreModule.getModule() instanceof ModuleLifecycle) { final ModuleLifecycle moduleLifecycle = (ModuleLifecycle) coreModule.getModule(); final String uniqueId = coreModule.getUniqueId(); - switch (e) { + switch (type) { - case LOAD: { + case MODULE_LOAD: { try { moduleLifecycle.onLoad(); } catch (Throwable throwable) { @@ -110,7 +96,7 @@ private void callAndFireModuleLifeCycle(final CoreModule coreModule, final Modul break; } - case UNLOAD: { + case MODULE_UNLOAD: { try { moduleLifecycle.onUnload(); } catch (Throwable throwable) { @@ -119,7 +105,7 @@ private void callAndFireModuleLifeCycle(final CoreModule coreModule, final Modul break; } - case ACTIVE: { + case MODULE_ACTIVE: { try { moduleLifecycle.onActive(); } catch (Throwable throwable) { @@ -128,7 +114,7 @@ private void callAndFireModuleLifeCycle(final CoreModule coreModule, final Modul break; } - case FROZE: { + case MODULE_FROZEN: { try { moduleLifecycle.onFrozen(); } catch (Throwable throwable) { @@ -142,7 +128,7 @@ private void callAndFireModuleLifeCycle(final CoreModule coreModule, final Modul // 这里要对LOAD_COMPLETED事件做特殊处理 // 因为这个事件处理失败不会影响模块变更行为,只做简单的日志处理 - if (e == LOAD_COMPLETED + if (type == MODULE_LOAD_COMPLETED && coreModule.getModule() instanceof LoadCompleted) { try { ((LoadCompleted) coreModule.getModule()).loadCompleted(); @@ -151,8 +137,6 @@ private void callAndFireModuleLifeCycle(final CoreModule coreModule, final Modul } } - // fire the bus - moduleLifeCycleEventBus.fire(coreModule, e); } /** @@ -189,11 +173,10 @@ private synchronized void load(final String uniqueId, // 注入@Resource资源 injectResourceOnLoadIfNecessary(coreModule); - // 通知生命周期:模块加载开始 - callAndFireModuleLifeCycle(coreModule, ModuleLifeCycleEventBus.Event.LOAD); + callAndFireModuleLifeCycle(coreModule, MODULE_LOAD); // 设置为已经加载 - coreModule.setLoaded(true); + coreModule.markLoaded(true); // 如果模块标记了加载时自动激活,则需要在加载完成之后激活模块 markActiveOnLoadIfNecessary(coreModule); @@ -202,7 +185,7 @@ private synchronized void load(final String uniqueId, loadedModuleBOMap.put(uniqueId, coreModule); // 通知生命周期,模块加载完成 - callAndFireModuleLifeCycle(coreModule, LOAD_COMPLETED); + callAndFireModuleLifeCycle(coreModule, MODULE_LOAD_COMPLETED); } @@ -231,7 +214,19 @@ else if (ModuleEventWatcher.class.isAssignableFrom(fieldType)) { cfg.isEnableUnsafe(), cfg.getNamespace() ); - moduleLifeCycleEventBus.append((DefaultModuleEventWatcher) moduleEventWatcher); + coreModule.append(new CoreModule.ReleaseResource(moduleEventWatcher) { + + @Override + public void release() { + for (final SandboxClassFileTransformer transformer + : new ArrayList(coreModule.getSandboxClassFileTransformers())) { + logger.info("delete watch[id={}] by module[id={};] unload.", + transformer.getWatchId(), coreModule.getUniqueId()); + moduleEventWatcher.delete(transformer.getWatchId()); + } + } + + }); writeField( resourceField, module, @@ -275,7 +270,32 @@ else if (EventMonitor.class.isAssignableFrom(fieldType)) { writeField( resourceField, module, - new DefaultEventMonitor(), + new EventMonitor() { + @Override + public EventPoolInfo getEventPoolInfo() { + return new EventPoolInfo() { + @Override + public int getNumActive() { + return 0; + } + + @Override + public int getNumActive(Event.Type type) { + return 0; + } + + @Override + public int getNumIdle() { + return 0; + } + + @Override + public int getNumIdle(Event.Type type) { + return 0; + } + }; + } + }, true ); } @@ -284,9 +304,9 @@ else if (EventMonitor.class.isAssignableFrom(fieldType)) { else { logger.warn("module inject @Resource ignored: field not found. module={};class={};type={};field={};", coreModule.getUniqueId(), - resourceField.getName(), coreModule.getModule().getClass().getName(), - fieldType.getName() + fieldType.getName(), + resourceField.getName() ); } @@ -333,7 +353,7 @@ public synchronized CoreModule unload(final CoreModule coreModule, // 通知生命周期 try { - callAndFireModuleLifeCycle(coreModule, ModuleLifeCycleEventBus.Event.UNLOAD); + callAndFireModuleLifeCycle(coreModule, MODULE_UNLOAD); } catch (ModuleException meCause) { if (isIgnoreModuleException) { logger.warn("unload module occur error, ignored. module={};class={};code={};", @@ -351,7 +371,7 @@ public synchronized CoreModule unload(final CoreModule coreModule, loadedModuleBOMap.remove(coreModule.getUniqueId()); // 标记模块为:已卸载 - coreModule.setLoaded(false); + coreModule.markLoaded(false); // 尝试关闭ClassLoader closeModuleClassLoaderIfNecessary(coreModule.getLoader()); @@ -359,6 +379,23 @@ public synchronized CoreModule unload(final CoreModule coreModule, return coreModule; } + @Override + public void unloadAll() { + + logger.info("force unloading all loaded modules:{}", loadedModuleBOMap.keySet()); + + // 强制卸载所有模块 + for (final CoreModule coreModule : new ArrayList(loadedModuleBOMap.values())) { + try { + unload(coreModule, true); + } catch (ModuleException cause) { + // 强制卸载不可能出错,这里不对外继续抛出任何异常 + logger.warn("force unloading module occur error! module={};", coreModule.getUniqueId(), cause); + } + } + + } + @Override public synchronized void active(final CoreModule coreModule) throws ModuleException { @@ -375,7 +412,7 @@ public synchronized void active(final CoreModule coreModule) throws ModuleExcept ); // 通知生命周期 - callAndFireModuleLifeCycle(coreModule, ModuleLifeCycleEventBus.Event.ACTIVE); + callAndFireModuleLifeCycle(coreModule, MODULE_ACTIVE); // 激活所有监听器 for (final SandboxClassFileTransformer sandboxClassFileTransformer : coreModule.getSandboxClassFileTransformers()) { @@ -387,7 +424,7 @@ public synchronized void active(final CoreModule coreModule) throws ModuleExcept } // 标记模块为:已激活 - coreModule.setActivated(true); + coreModule.markActivated(true); } @Override @@ -408,7 +445,7 @@ public synchronized void frozen(final CoreModule coreModule, // 通知生命周期 try { - callAndFireModuleLifeCycle(coreModule, ModuleLifeCycleEventBus.Event.FROZE); + callAndFireModuleLifeCycle(coreModule, MODULE_FROZEN); } catch (ModuleException meCause) { if (isIgnoreModuleException) { logger.warn("frozen module occur error, ignored. module={};class={};code={};", @@ -429,7 +466,7 @@ public synchronized void frozen(final CoreModule coreModule, } // 标记模块为:已冻结 - coreModule.setActivated(false); + coreModule.markActivated(false); } @Override @@ -472,7 +509,7 @@ private boolean isSystemModule(final File child) { /** * 用户模块文件加载回调 */ - final private class InnerModuleJarLoadCallback implements ModuleJarLoader.ModuleJarLoadCallback { + final private class InnerModuleJarLoadCallback implements ModuleJarLoadCallback { @Override public void onLoad(File moduleJarFile) throws Throwable { providerManager.loading(moduleJarFile); @@ -517,6 +554,8 @@ public void onLoad(final String uniqueId, moduleClass, moduleClassLoader ); + + // 这里进行真正的模块加载 load(uniqueId, module, moduleJarFile, moduleClassLoader); } } @@ -531,28 +570,29 @@ public synchronized void flush(final boolean isForce) throws ModuleException { } @Override - public synchronized void reset() throws ModuleException { + public synchronized CoreModuleManager reset() throws ModuleException { logger.info("resetting all loaded modules:{}", loadedModuleBOMap.keySet()); // 1. 强制卸载所有模块 - for (final CoreModule coreModule : new ArrayList(loadedModuleBOMap.values())) { - unload(coreModule, true); - } + unloadAll(); // 2. 加载所有模块 for (final File moduleLibDir : moduleLibDirArray) { // 用户模块加载目录,加载用户模块目录下的所有模块 // 对模块访问权限进行校验 - if (moduleLibDir.exists() - && moduleLibDir.canRead()) { - new ModuleLibLoader(moduleLibDir, cfg.getLaunchMode(), sandboxClassLoader) - .load(new InnerModuleJarLoadCallback(), new InnerModuleLoadCallback()); + if (moduleLibDir.exists() && moduleLibDir.canRead()) { + new ModuleLibLoader(moduleLibDir, cfg.getLaunchMode()) + .load( + new InnerModuleJarLoadCallback(), + new InnerModuleLoadCallback() + ); } else { logger.warn("module-lib not access, ignore flush load this lib. path={}", moduleLibDir); } } + return this; } /** @@ -662,7 +702,7 @@ private void softFlush() { // 4. 加载add for (final File jarFile : appendJarFiles) { - new ModuleLibLoader(jarFile, cfg.getLaunchMode(), sandboxClassLoader) + new ModuleLibLoader(jarFile, cfg.getLaunchMode()) .load(new InnerModuleJarLoadCallback(), new InnerModuleLoadCallback()); } } catch (Throwable cause) { @@ -716,7 +756,7 @@ private void forceFlush() throws ModuleException { if (userModuleLibDir.exists() && userModuleLibDir.canRead()) { logger.info("force-flush modules: module-lib={}", userModuleLibDir); - new ModuleLibLoader(userModuleLibDir, cfg.getLaunchMode(), sandboxClassLoader) + new ModuleLibLoader(userModuleLibDir, cfg.getLaunchMode()) .load(new InnerModuleJarLoadCallback(), new InnerModuleLoadCallback()); } else { logger.warn("force-flush modules: module-lib can not access, will be ignored. module-lib={}", userModuleLibDir); @@ -725,4 +765,35 @@ private void forceFlush() throws ModuleException { } + /** + * 模块生命周期类型 + */ + enum ModuleLifeCycleType { + + /** + * 模块加载 + */ + MODULE_LOAD, + + /** + * 模块卸载 + */ + MODULE_UNLOAD, + + /** + * 模块激活 + */ + MODULE_ACTIVE, + + /** + * 模块冻结 + */ + MODULE_FROZEN, + + /** + * 模块加载完成 + */ + MODULE_LOAD_COMPLETED + } + } diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/DefaultEventMonitor.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/DefaultEventMonitor.java deleted file mode 100644 index da411a7a..00000000 --- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/DefaultEventMonitor.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.alibaba.jvm.sandbox.core.manager.impl; - -import com.alibaba.jvm.sandbox.api.event.Event; -import com.alibaba.jvm.sandbox.api.resource.EventMonitor; - -/** - * 事件监控器实现 - */ -class DefaultEventMonitor implements EventMonitor { - - @Override - public EventPoolInfo getEventPoolInfo() { - return new EventPoolInfo() { - @Override - public int getNumActive() { - return 0; - } - - @Override - public int getNumActive(Event.Type type) { - return 0; - } - - @Override - public int getNumIdle() { - return 0; - } - - @Override - public int getNumIdle(Event.Type type) { - return 0; - } - }; - } - -} diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/DefaultLoadedClassDataSource.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/DefaultLoadedClassDataSource.java index b9b542dc..7b24b251 100644 --- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/DefaultLoadedClassDataSource.java +++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/DefaultLoadedClassDataSource.java @@ -1,8 +1,8 @@ package com.alibaba.jvm.sandbox.core.manager.impl; import com.alibaba.jvm.sandbox.api.filter.Filter; -import com.alibaba.jvm.sandbox.core.CoreConfigure; import com.alibaba.jvm.sandbox.core.manager.CoreLoadedClassDataSource; +import com.alibaba.jvm.sandbox.core.manager.LoadedClassLoaderListener; import com.alibaba.jvm.sandbox.core.util.matcher.ExtFilterMatcher; import com.alibaba.jvm.sandbox.core.util.matcher.Matcher; import com.alibaba.jvm.sandbox.core.util.matcher.UnsupportedMatcher; @@ -11,6 +11,7 @@ import org.slf4j.LoggerFactory; import java.lang.instrument.Instrumentation; +import java.security.ProtectionDomain; import java.util.*; import static com.alibaba.jvm.sandbox.api.filter.ExtFilter.ExtFilterFactory.make; @@ -24,12 +25,14 @@ public class DefaultLoadedClassDataSource implements CoreLoadedClassDataSource { private final Logger logger = LoggerFactory.getLogger(getClass()); private final Instrumentation inst; - private final CoreConfigure cfg; + private final boolean isEnableUnsafe; + private final List loadedClassLoaderListeners + = new ArrayList(); public DefaultLoadedClassDataSource(final Instrumentation inst, - final CoreConfigure cfg) { + final boolean isEnableUnsafe) { this.inst = inst; - this.cfg = cfg; + this.isEnableUnsafe = isEnableUnsafe; } @Override @@ -89,7 +92,7 @@ private List> find(final Matcher matcher, } try { if (isRemoveUnsupported) { - if (new UnsupportedMatcher(clazz.getClassLoader(), cfg.isEnableUnsafe()) + if (new UnsupportedMatcher(clazz.getClassLoader(), isEnableUnsafe) .and(matcher) .matching(ClassStructureFactory.createClassStructure(clazz)) .isMatched()) { @@ -125,4 +128,55 @@ public Set> find(Filter filter) { return new LinkedHashSet>(find(new ExtFilterMatcher(make(filter)), false)); } + private void appendClassLoader(final ClassLoader loader, + final Set loadedClassLoaderSet) { + if (null == loader) { + return; + } + loadedClassLoaderSet.add(loader); + loadedClassLoaderSet.add(loader.getParent()); + } + + @Override + public ClassLoader[] listLoadedClassLoader() { + final Set loadedClassLoaderSet = new LinkedHashSet(); + for (Class loadedClass : list()) { + if (null == loadedClass) { + continue; + } + appendClassLoader(loadedClass.getClassLoader(), loadedClassLoaderSet); + + } + return loadedClassLoaderSet.toArray(new ClassLoader[]{}); + } + + @Override + public void appendLoadedClassLoaderListener(LoadedClassLoaderListener listener) { + synchronized (loadedClassLoaderListeners) { + loadedClassLoaderListeners.add(listener); + } + } + + @Override + public void removeLoadedClassLoaderListener(LoadedClassLoaderListener listener) { + synchronized (loadedClassLoaderListeners) { + loadedClassLoaderListeners.remove(listener); + } + } + + @Override + public byte[] transform(final ClassLoader loader, + final String className, + final Class classBeingRedefined, + final ProtectionDomain protectionDomain, + final byte[] classfileBuffer) { + final List cloneLoadedClassLoaderListener + = new ArrayList(loadedClassLoaderListeners); + if (null != loader) { + for (final LoadedClassLoaderListener listener : cloneLoadedClassLoaderListener) { + listener.onLoaded(loader); + } + } + return classfileBuffer; + } } diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/DefaultModuleController.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/DefaultModuleController.java index bd6c26b0..725f0148 100755 --- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/DefaultModuleController.java +++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/DefaultModuleController.java @@ -2,7 +2,7 @@ import com.alibaba.jvm.sandbox.api.ModuleException; import com.alibaba.jvm.sandbox.api.resource.ModuleController; -import com.alibaba.jvm.sandbox.core.domain.CoreModule; +import com.alibaba.jvm.sandbox.core.CoreModule; import com.alibaba.jvm.sandbox.core.manager.CoreModuleManager; /** diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/DefaultModuleEventWatcher.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/DefaultModuleEventWatcher.java index cedc58a3..3f03e11d 100755 --- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/DefaultModuleEventWatcher.java +++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/DefaultModuleEventWatcher.java @@ -5,10 +5,9 @@ import com.alibaba.jvm.sandbox.api.listener.EventListener; import com.alibaba.jvm.sandbox.api.listener.ext.EventWatchCondition; import com.alibaba.jvm.sandbox.api.resource.ModuleEventWatcher; -import com.alibaba.jvm.sandbox.core.domain.CoreModule; +import com.alibaba.jvm.sandbox.core.CoreModule; import com.alibaba.jvm.sandbox.core.enhance.weaver.EventListenerHandlers; import com.alibaba.jvm.sandbox.core.manager.CoreLoadedClassDataSource; -import com.alibaba.jvm.sandbox.core.manager.ModuleLifeCycleEventBus; import com.alibaba.jvm.sandbox.core.util.Sequencer; import com.alibaba.jvm.sandbox.core.util.matcher.ExtFilterMatcher; import com.alibaba.jvm.sandbox.core.util.matcher.GroupMatcher; @@ -18,16 +17,20 @@ import org.slf4j.LoggerFactory; import java.lang.instrument.Instrumentation; -import java.util.*; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; import static com.alibaba.jvm.sandbox.api.filter.ExtFilter.ExtFilterFactory.make; import static com.alibaba.jvm.sandbox.core.util.matcher.ExtFilterMatcher.toOrGroupMatcher; /** * 默认事件观察者实现 - * Created by luanjia@taobao.com on 2017/2/23. + * + * @author luanjia@taobao.com */ -public class DefaultModuleEventWatcher implements ModuleEventWatcher, ModuleLifeCycleEventBus.ModuleLifeCycleEventListener { +public class DefaultModuleEventWatcher implements ModuleEventWatcher { private final Logger logger = LoggerFactory.getLogger(getClass()); @@ -101,7 +104,7 @@ private void reTransformClasses(final int watchId, boolean batchReTransformSuccess = true; if (null == progress) { try { - inst.retransformClasses(waitingReTransformClasses.toArray(new Class[waitingReTransformClasses.size()])); + inst.retransformClasses(waitingReTransformClasses.toArray(new Class[0])); logger.info("module[id:{}] watch[id:{}] batch reTransform classes[count:{}] success.", coreModule.getUniqueId(), watchId, waitingReTransformClasses.size()); } catch (Throwable e) { @@ -307,23 +310,4 @@ public void watching(final Filter filter, } } - @Override - public boolean onFire(final CoreModule coreModule, - final ModuleLifeCycleEventBus.Event event) { - - if (this.coreModule == coreModule - && event == ModuleLifeCycleEventBus.Event.UNLOAD) { - // 是当前模块的卸载事件,需要主动清理掉之前的埋点 - for (final SandboxClassFileTransformer transformer : new ArrayList(coreModule.getSandboxClassFileTransformers())) { - logger.info("delete watch[id={}] by module[id={};] unload.", - transformer.getWatchId(), coreModule.getUniqueId()); - delete(transformer.getWatchId()); - } - // 当前模块都卸载了,我还留着做啥... - return false; - } - - // 不是当前模块的卸载事件,继续保持监听 - return true; - } } diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/DefaultModuleLifeCycleEventBus.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/DefaultModuleLifeCycleEventBus.java deleted file mode 100755 index bc17b6c0..00000000 --- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/DefaultModuleLifeCycleEventBus.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.alibaba.jvm.sandbox.core.manager.impl; - -import com.alibaba.jvm.sandbox.core.domain.CoreModule; -import com.alibaba.jvm.sandbox.core.manager.ModuleLifeCycleEventBus; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Iterator; -import java.util.LinkedList; - -/** - * 默认模块生命周期实现 - * Created by luanjia@taobao.com on 2017/2/3. - */ -public class DefaultModuleLifeCycleEventBus implements ModuleLifeCycleEventBus { - - private final Logger logger = LoggerFactory.getLogger(getClass()); - private final LinkedList moduleLifeCycleEventListeners - = new LinkedList(); - - @Override - public void append(ModuleLifeCycleEventListener lifeCycleEventListener) { - moduleLifeCycleEventListeners.add(lifeCycleEventListener); - } - - @Override - public void fire(CoreModule coreModule, Event event) { - - logger.info("firing module-event: event={};module={};", event, coreModule.getUniqueId()); - final Iterator listenerIt = moduleLifeCycleEventListeners.iterator(); - while (listenerIt.hasNext()) { - - final ModuleLifeCycleEventListener moduleLifeCycleEventListener = listenerIt.next(); - try { - if (!moduleLifeCycleEventListener.onFire(coreModule, event)) { - // 监听器返回FALSE,说明监听器主动放弃后续的消息监听 - listenerIt.remove(); - logger.debug("fired module-event by once. event={};module={};listener={};", - event, - coreModule.getUniqueId(), - moduleLifeCycleEventListener - ); - } - } catch (Throwable cause) { - logger.warn("fire module-event failed, event={};module={};listener={};", - event, - coreModule.getUniqueId(), - moduleLifeCycleEventListener, - cause - ); - } - - } - - } - -} diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/DefaultModuleManager.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/DefaultModuleManager.java index b953e153..f37eaf29 100755 --- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/DefaultModuleManager.java +++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/DefaultModuleManager.java @@ -3,7 +3,7 @@ import com.alibaba.jvm.sandbox.api.Module; import com.alibaba.jvm.sandbox.api.ModuleException; import com.alibaba.jvm.sandbox.api.resource.ModuleManager; -import com.alibaba.jvm.sandbox.core.domain.CoreModule; +import com.alibaba.jvm.sandbox.core.CoreModule; import com.alibaba.jvm.sandbox.core.manager.CoreModuleManager; import java.io.File; diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/DefaultModuleResourceManager.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/DefaultModuleResourceManager.java deleted file mode 100755 index 73dfd915..00000000 --- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/DefaultModuleResourceManager.java +++ /dev/null @@ -1,115 +0,0 @@ -package com.alibaba.jvm.sandbox.core.manager.impl; - -import com.alibaba.jvm.sandbox.core.domain.CoreModule; -import com.alibaba.jvm.sandbox.core.manager.ModuleLifeCycleEventBus; -import com.alibaba.jvm.sandbox.core.manager.ModuleLifeCycleEventBus.ModuleLifeCycleEventListener; -import com.alibaba.jvm.sandbox.core.manager.ModuleResourceManager; -import org.apache.commons.collections.CollectionUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.*; - -/** - * 默认实现自动释放连接释放管理 - * Created by luanjia@taobao.com on 2017/2/4. - */ -public class DefaultModuleResourceManager implements ModuleResourceManager, ModuleLifeCycleEventListener { - - private final Logger logger = LoggerFactory.getLogger(getClass()); - - private final Map>> moduleResourceListMapping - = new HashMap>>(); - - @Override - public synchronized T append(String uniqueId, WeakResource resource) { - if (null == resource - || null == resource.get()) { - return null; - } - final List> moduleResourceList; - if (moduleResourceListMapping.containsKey(uniqueId)) { - moduleResourceList = moduleResourceListMapping.get(uniqueId); - } else { - moduleResourceListMapping.put(uniqueId, moduleResourceList - = new ArrayList>()); - } - moduleResourceList.add(resource); - logger.debug("append resource={} in module[id={};]", resource.get(), uniqueId); - return resource.get(); - } - - @Override - public void remove(String uniqueId, T target) { - if (null == target) { - return; - } - synchronized (this) { - final List> moduleResourceList = moduleResourceListMapping.get(uniqueId); - if (null == moduleResourceList) { - return; - } - final Iterator> resourceRefIt = moduleResourceList.iterator(); - while (resourceRefIt.hasNext()) { - final WeakResource resourceRef = resourceRefIt.next(); - - // 删除掉无效的资源 - if (null == resourceRef) { - resourceRefIt.remove(); - logger.debug("remove illegal resource in module[id={};]", uniqueId); - continue; - } - - // 删除掉已经被GC掉的资源 - if (null == resourceRef.get()) { - resourceRefIt.remove(); - logger.debug("remove empty resource in module[id={};]", uniqueId); - continue; - } - - if (target.equals(resourceRef.get())) { - resourceRefIt.remove(); - logger.debug("remove resource={} in module[id={};]", resourceRef.get(), uniqueId); - } - }//while - }//sync - } - - @Override - public boolean onFire(CoreModule coreModule, ModuleLifeCycleEventBus.Event event) { - - // 只有模块卸载的时候才需要关注处理 - if (event != ModuleLifeCycleEventBus.Event.UNLOAD) { - return true; - } - - final String uniqueId = coreModule.getUniqueId(); - final List> moduleResourceList; - synchronized (this) { - moduleResourceList = moduleResourceListMapping.remove(uniqueId); - } - if (CollectionUtils.isEmpty(moduleResourceList)) { - logger.debug("module[id={};] mapping resources was empty.", uniqueId); - return true; - } else { - logger.info("module[id={};] is unloading, will release {} resources.", uniqueId, moduleResourceList.size()); - } - - for (final WeakResource resource : moduleResourceList) { - if (null == resource - || null == resource.get()) { - continue; - } - try { - resource.release(); - logger.info("module[id={};] is unloading, resource={} was closed.", uniqueId, resource); - } catch (Throwable cause) { - logger.warn("module[id={};] is unloading, resource={} closing failed.", - uniqueId, resource, cause); - } - } - return true; - - } - -} diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/DefaultProviderManager.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/DefaultProviderManager.java index 98d57f80..645bf616 100644 --- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/DefaultProviderManager.java +++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/DefaultProviderManager.java @@ -33,18 +33,16 @@ public class DefaultProviderManager implements ProviderManager { private final Collection moduleLoadingChains = new ArrayList(); private final CoreConfigure cfg; - public DefaultProviderManager(final CoreConfigure cfg, - final ClassLoader sandboxClassLoader) { + public DefaultProviderManager(final CoreConfigure cfg) { this.cfg = cfg; try { - init(cfg, sandboxClassLoader); + init(cfg); } catch (Throwable cause) { logger.warn("loading sandbox's provider-lib[{}] failed.", cfg.getProviderLibPath(), cause); } } - private void init(final CoreConfigure cfg, - final ClassLoader sandboxClassLoader) { + private void init(final CoreConfigure cfg) { final File providerLibDir = new File(cfg.getProviderLibPath()); if (!providerLibDir.exists() || !providerLibDir.canRead()) { @@ -55,7 +53,7 @@ private void init(final CoreConfigure cfg, for (final File providerJarFile : FileUtils.listFiles(providerLibDir, new String[]{"jar"}, false)) { try { - final ProviderClassLoader providerClassLoader = new ProviderClassLoader(providerJarFile, sandboxClassLoader); + final ProviderClassLoader providerClassLoader = new ProviderClassLoader(providerJarFile, getClass().getClassLoader()); // load ModuleJarLoadingChain inject(moduleJarLoadingChains, ModuleJarLoadingChain.class, providerClassLoader, providerJarFile); diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/ModuleJarLoader.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/ModuleJarLoader.java index ebd76607..7f3292a0 100644 --- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/ModuleJarLoader.java +++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/ModuleJarLoader.java @@ -25,20 +25,14 @@ class ModuleJarLoader { // 沙箱加载模式 private final Information.Mode mode; - // 沙箱加载ClassLoader - private final ClassLoader sandboxClassLoader; - ModuleJarLoader(final File moduleJarFile, - final Information.Mode mode, - final ClassLoader sandboxClassLoader) { + final Information.Mode mode) { this.moduleJarFile = moduleJarFile; this.mode = mode; - this.sandboxClassLoader = sandboxClassLoader; } private boolean loadingModules(final ModuleClassLoader moduleClassLoader, - final ModuleJarLoadCallback mjCb, final ModuleLoadCallback mCb) { final Set loadedModuleUniqueIds = new LinkedHashSet(); @@ -117,20 +111,19 @@ private boolean loadingModules(final ModuleClassLoader moduleClassLoader, } - public void load(final ModuleJarLoadCallback mjCb, - final ModuleLoadCallback mCb) throws IOException { + void load(final ModuleLoadCallback mCb) throws IOException { boolean hasModuleLoadedSuccessFlag = false; ModuleClassLoader moduleClassLoader = null; logger.info("prepare loading module-jar={};", moduleJarFile); try { - moduleClassLoader = new ModuleClassLoader(moduleJarFile, sandboxClassLoader); + moduleClassLoader = new ModuleClassLoader(moduleJarFile); final ClassLoader preTCL = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(moduleClassLoader); try { - hasModuleLoadedSuccessFlag = loadingModules(moduleClassLoader, mjCb, mCb); + hasModuleLoadedSuccessFlag = loadingModules(moduleClassLoader, mCb); } finally { Thread.currentThread().setContextClassLoader(preTCL); } @@ -139,30 +132,12 @@ public void load(final ModuleJarLoadCallback mjCb, if (!hasModuleLoadedSuccessFlag && null != moduleClassLoader) { logger.warn("loading module-jar completed, but NONE module loaded, will be close ModuleClassLoader. module-jar={};", moduleJarFile); - if (null != moduleClassLoader) { - moduleClassLoader.closeIfPossible(); - } + moduleClassLoader.closeIfPossible(); } } } - - /** - * 模块文件加载回调 - */ - public interface ModuleJarLoadCallback { - - /** - * 模块文件加载回调 - * - * @param moduleJarFile 模块文件 - * @throws Throwable 加载回调异常 - */ - void onLoad(File moduleJarFile) throws Throwable; - - } - /** * 模块加载回调 */ diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/ModuleLibLoader.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/ModuleLibLoader.java index 530b0743..2a43c891 100755 --- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/ModuleLibLoader.java +++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/ModuleLibLoader.java @@ -7,10 +7,7 @@ import java.io.File; import java.util.Arrays; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.ThreadFactory; -import static java.util.concurrent.Executors.newCachedThreadPool; import static org.apache.commons.io.FileUtils.convertFileCollectionToFileArray; import static org.apache.commons.io.FileUtils.listFiles; import static org.apache.commons.lang3.StringUtils.join; @@ -30,15 +27,10 @@ class ModuleLibLoader { // 沙箱加载模式 private final Information.Mode mode; - // 沙箱加载ClassLoader - private final ClassLoader sandboxClassLoader; - ModuleLibLoader(final File moduleLibDir, - final Information.Mode mode, - final ClassLoader sandboxClassLoader) { + final Information.Mode mode) { this.moduleLibDir = moduleLibDir; this.mode = mode; - this.sandboxClassLoader = sandboxClassLoader; } private File[] toModuleJarFileArray() { @@ -74,7 +66,7 @@ private File[] listModuleJarFileInLib() { * @param mjCb 模块文件加载回调 * @param mCb 模块加载回掉 */ - void load(final ModuleJarLoader.ModuleJarLoadCallback mjCb, + void load(final ModuleJarLoadCallback mjCb, final ModuleJarLoader.ModuleLoadCallback mCb) { // 开始逐条加载 @@ -94,11 +86,7 @@ void load(final ModuleJarLoader.ModuleJarLoadCallback mjCb, // } // }); try { - new ModuleJarLoader( - moduleJarFile, - mode, - sandboxClassLoader - ).load(mjCb, mCb); + new ModuleJarLoader(moduleJarFile, mode).load(mCb); } catch (Exception cause) { logger.warn("loading module-jar occur error! module-jar={};", moduleJarFile, cause); } @@ -119,4 +107,20 @@ void load(final ModuleJarLoader.ModuleJarLoadCallback mjCb, // static void shutdown() { // moduleJarLoaderExecutor.shutdown(); // } + + /** + * 模块文件加载回调 + */ + public interface ModuleJarLoadCallback { + + /** + * 模块文件加载回调 + * + * @param moduleJarFile 模块文件 + * @throws Throwable 加载回调异常 + */ + void onLoad(File moduleJarFile) throws Throwable; + + } + } 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 c65f33ae..7cdc51e0 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 @@ -1,20 +1,12 @@ package com.alibaba.jvm.sandbox.core.server.jetty; -import ch.qos.logback.classic.LoggerContext; -import ch.qos.logback.classic.joran.JoranConfigurator; import com.alibaba.jvm.sandbox.core.CoreConfigure; -import com.alibaba.jvm.sandbox.core.enhance.weaver.EventListenerHandlers; -import com.alibaba.jvm.sandbox.core.manager.CoreModuleManager; -import com.alibaba.jvm.sandbox.core.manager.ModuleLifeCycleEventBus; -import com.alibaba.jvm.sandbox.core.manager.ModuleResourceManager; -import com.alibaba.jvm.sandbox.core.manager.ProviderManager; -import com.alibaba.jvm.sandbox.core.manager.impl.*; +import com.alibaba.jvm.sandbox.core.JvmSandbox; import com.alibaba.jvm.sandbox.core.server.CoreServer; import com.alibaba.jvm.sandbox.core.server.jetty.servlet.ModuleHttpServlet; import com.alibaba.jvm.sandbox.core.server.jetty.servlet.WebSocketAcceptorServlet; import com.alibaba.jvm.sandbox.core.util.Initializer; -import com.alibaba.jvm.sandbox.core.util.SandboxStringUtils; -import org.apache.commons.io.IOUtils; +import com.alibaba.jvm.sandbox.core.util.LogbackUtils; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.nio.SelectChannelConnector; @@ -25,13 +17,10 @@ import org.slf4j.LoggerFactory; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; -import java.io.InputStream; import java.lang.instrument.Instrumentation; import java.net.InetSocketAddress; -import static com.alibaba.jvm.sandbox.core.util.NamespaceConvert.initNamespaceConvert; import static com.alibaba.jvm.sandbox.core.util.NetworkUtils.isPortInUsing; import static java.lang.String.format; import static org.eclipse.jetty.servlet.ServletContextHandler.NO_SESSIONS; @@ -49,8 +38,7 @@ public class JettyCoreServer implements CoreServer { private Server httpServer; private CoreConfigure cfg; - private ModuleResourceManager moduleResourceManager; - private CoreModuleManager coreModuleManager; + private JvmSandbox jvmSandbox; /** * 单例 @@ -79,6 +67,7 @@ public void unbind() throws IOException { initializer.destroyProcess(new Initializer.Processor() { @Override public void process() throws Throwable { + if (null != httpServer) { // stop http server @@ -86,6 +75,7 @@ public void process() throws Throwable { httpServer.stop(); } + } }); @@ -130,143 +120,95 @@ public InetSocketAddress getLocal() throws IOException { /* * 初始化Jetty's ContextHandler */ - private void initJettyContextHandler(final CoreConfigure cfg) { + private void initJettyContextHandler() { + final String namespace = cfg.getNamespace(); final ServletContextHandler context = new ServletContextHandler(NO_SESSIONS); - final String contextPath = "/sandbox/" + cfg.getNamespace(); + final String contextPath = "/sandbox/" + namespace; context.setContextPath(contextPath); context.setClassLoader(getClass().getClassLoader()); // web-socket-servlet final String wsPathSpec = "/module/websocket/*"; logger.info("initializing ws-http-handler. path={}", contextPath + wsPathSpec); - context.addServlet(new ServletHolder(new WebSocketAcceptorServlet(coreModuleManager, moduleResourceManager)), wsPathSpec); + //noinspection deprecation + context.addServlet( + new ServletHolder(new WebSocketAcceptorServlet(jvmSandbox.getCoreModuleManager())), + wsPathSpec + ); // module-http-servlet final String pathSpec = "/module/http/*"; logger.info("initializing http-handler. path={}", contextPath + pathSpec); - context.addServlet(new ServletHolder(new ModuleHttpServlet(coreModuleManager, moduleResourceManager)), pathSpec); + context.addServlet( + new ServletHolder(new ModuleHttpServlet(jvmSandbox.getCoreModuleManager())), + pathSpec + ); httpServer.setHandler(context); } - // 初始化Logback日志配置 - private void initLogback(final CoreConfigure cfg) { - final LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory(); - final JoranConfigurator configurator = new JoranConfigurator(); - final File configureFile = new File(cfg.getCfgLibPath() + File.separator + "sandbox-logback.xml"); - configurator.setContext(loggerContext); - loggerContext.reset(); - InputStream is = null; - try { - is = new FileInputStream(configureFile); - initNamespaceConvert(cfg.getNamespace()); - configurator.doConfigure(is); - logger.info(SandboxStringUtils.getLogo()); - logger.info("initializing logback success. file={};", configureFile); - } catch (Throwable cause) { - logger.warn("initialize logback failed. file={};", configureFile, cause); - } finally { - IOUtils.closeQuietly(is); - } - } + private void initHttpServer() { - // 关闭Logback日志框架 - private void closeLogback() { - try { - ((LoggerContext) LoggerFactory.getILoggerFactory()).stop(); - } catch (Throwable cause) { - cause.printStackTrace(); - } - } - - private void initHttpServer(final CoreConfigure cfg) { + final String serverIp = cfg.getServerIp(); + final int serverPort = cfg.getServerPort(); // 如果IP:PORT已经被占用,则无法继续被绑定 // 这里说明下为什么要这么无聊加个这个判断,让Jetty的Server.bind()抛出异常不是更好么? // 比较郁闷的是,如果这个端口的绑定是"SO_REUSEADDR"端口可重用的模式,那么这个server是能正常启动,但无法正常工作的 // 所以这里必须先主动检查一次端口占用情况,当然了,这里也会存在一定的并发问题,BUT,我认为这种概率事件我可以选择暂时忽略 - if (isPortInUsing(cfg.getServerIp(), cfg.getServerPort())) { + if (isPortInUsing(serverIp, serverPort)) { throw new IllegalStateException(format("address[%s:%s] already in using, server bind failed.", - cfg.getServerIp(), - cfg.getServerPort()) - ); + serverIp, + serverPort + )); } - httpServer = new Server(new InetSocketAddress(cfg.getServerIp(), cfg.getServerPort())); + httpServer = new Server(new InetSocketAddress(serverIp, serverPort)); if (httpServer.getThreadPool() instanceof QueuedThreadPool) { final QueuedThreadPool qtp = (QueuedThreadPool) httpServer.getThreadPool(); qtp.setName("sandbox-jetty-qtp-" + qtp.hashCode()); } } - // 关闭HTTP服务器 - private void closeHttpServer() { - if (null != httpServer) { - httpServer.destroy(); - } - } - - // 初始化各种manager - private void initManager(final Instrumentation inst, - final CoreConfigure cfg) { - - final ClassLoader sandboxClassLoader = getClass().getClassLoader(); - - // 初始化事件处理总线 - logger.info("initializing manager : EventListenerHandlers"); - EventListenerHandlers.getSingleton(); - - // 初始化模块生命周期事件总线 - logger.info("initializing manager : ModuleLifeCycleEventBus"); - final ModuleLifeCycleEventBus moduleLifeCycleEventBus = new DefaultModuleLifeCycleEventBus(); - - // 初始化模块资源管理器 - logger.info("initializing manager : ModuleResourceManager"); - moduleLifeCycleEventBus.append(moduleResourceManager = new DefaultModuleResourceManager()); - - // 初始化服务管理器 - logger.info("initializing manager : ProviderManager"); - final ProviderManager providerManager = new DefaultProviderManager(cfg, sandboxClassLoader); - - // 初始化模块管理器 - logger.info("initializing manager : CoreModuleManager"); - coreModuleManager = new DefaultCoreModuleManager( - cfg, inst, - sandboxClassLoader, new DefaultLoadedClassDataSource(inst, cfg), - moduleLifeCycleEventBus, - providerManager - ); - - } - @Override public synchronized void bind(final CoreConfigure cfg, final Instrumentation inst) throws IOException { + this.cfg = cfg; try { initializer.initProcess(new Initializer.Processor() { @Override public void process() throws Throwable { - JettyCoreServer.this.cfg = cfg; - initLogback(cfg); + LogbackUtils.init( + cfg.getNamespace(), + cfg.getCfgLibPath() + File.separator + "sandbox-logback.xml" + ); logger.info("initializing server. cfg={}", cfg); - initManager(inst, cfg); - initHttpServer(cfg); - initJettyContextHandler(cfg); + jvmSandbox = new JvmSandbox(cfg, inst); + initHttpServer(); + initJettyContextHandler(); httpServer.start(); } }); // 初始化加载所有的模块 try { - coreModuleManager.reset(); + jvmSandbox.getCoreModuleManager().reset(); } catch (Throwable cause) { logger.warn("reset occur error when initializing.", cause); } final InetSocketAddress local = getLocal(); - logger.info("initialized server. actual bind to {}:{}", local.getHostName(), local.getPort()); + logger.info("initialized server. actual bind to {}:{}", + local.getHostName(), + local.getPort() + ); + } catch (Throwable cause) { + + // 这里会抛出到目标应用层,所以在这里留下错误信息 logger.warn("initialize server failed.", cause); + + // 对外抛出到目标应用中 throw new IOException("server bind failed.", cause); } @@ -275,6 +217,8 @@ public void process() throws Throwable { @Override public void destroy() { + + // 关闭HTTP服务器 if (isBind()) { try { unbind(); @@ -283,11 +227,11 @@ public void destroy() { } } - // STOP HTTP-SERVER - closeHttpServer(); + // 关闭JVM-SANDBOX + jvmSandbox.destroy(); - // STOP LOGBACK - closeLogback(); + // 关闭LOGBACK + LogbackUtils.destroy(); } @Override 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 d6b6b6d6..ef1a4bc6 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 @@ -2,9 +2,9 @@ import com.alibaba.jvm.sandbox.api.annotation.Command; import com.alibaba.jvm.sandbox.api.http.Http; -import com.alibaba.jvm.sandbox.core.domain.CoreModule; +import com.alibaba.jvm.sandbox.core.CoreModule; +import com.alibaba.jvm.sandbox.core.CoreModule.ReleaseResource; import com.alibaba.jvm.sandbox.core.manager.CoreModuleManager; -import com.alibaba.jvm.sandbox.core.manager.ModuleResourceManager; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; @@ -36,12 +36,9 @@ public class ModuleHttpServlet extends HttpServlet { private final Logger logger = LoggerFactory.getLogger(getClass()); private final CoreModuleManager coreModuleManager; - private final ModuleResourceManager moduleResourceManager; - public ModuleHttpServlet(final CoreModuleManager coreModuleManager, - final ModuleResourceManager moduleResourceManager) { + public ModuleHttpServlet(final CoreModuleManager coreModuleManager) { this.coreModuleManager = coreModuleManager; - this.moduleResourceManager = moduleResourceManager; } @Override @@ -104,18 +101,16 @@ private void doMethod(final HttpServletRequest req, // 生成方法调用参数 final Object[] parameterObjectArray = generateParameterObjectArray(method, req, resp); - final PrintWriter writer = resp.getWriter(); + final PrintWriter writer = coreModule.append(new ReleaseResource(resp.getWriter()) { - // 调用方法 - moduleResourceManager.append(uniqueId, - new ModuleResourceManager.WeakResource(writer) { + @Override + public void release() { + IOUtils.closeQuietly(get()); + } + + }); - @Override - public void release() { - IOUtils.closeQuietly(get()); - } - }); final boolean isAccessible = method.isAccessible(); final ClassLoader oriThreadContextClassLoader = Thread.currentThread().getContextClassLoader(); try { @@ -142,7 +137,7 @@ public void release() { } finally { Thread.currentThread().setContextClassLoader(oriThreadContextClassLoader); method.setAccessible(isAccessible); - moduleResourceManager.remove(uniqueId, writer); + coreModule.remove(writer); } } diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/server/jetty/servlet/WebSocketAcceptorServlet.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/server/jetty/servlet/WebSocketAcceptorServlet.java index fb931a45..e342b0c6 100755 --- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/server/jetty/servlet/WebSocketAcceptorServlet.java +++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/server/jetty/servlet/WebSocketAcceptorServlet.java @@ -4,9 +4,8 @@ import com.alibaba.jvm.sandbox.api.http.websocket.WebSocketAcceptor; import com.alibaba.jvm.sandbox.api.http.websocket.WebSocketConnection; import com.alibaba.jvm.sandbox.api.http.websocket.WebSocketConnectionListener; -import com.alibaba.jvm.sandbox.core.domain.CoreModule; +import com.alibaba.jvm.sandbox.core.CoreModule; import com.alibaba.jvm.sandbox.core.manager.CoreModuleManager; -import com.alibaba.jvm.sandbox.core.manager.ModuleResourceManager; import org.apache.commons.lang3.StringUtils; import org.eclipse.jetty.websocket.WebSocket; import org.eclipse.jetty.websocket.WebSocket.OnTextMessage; @@ -28,15 +27,10 @@ public class WebSocketAcceptorServlet extends WebSocketServlet { private final Logger logger = LoggerFactory.getLogger(getClass()); - // WebSocket Connection auto release Map - private final ModuleResourceManager moduleResourceManager; - private final CoreModuleManager coreModuleManager; - public WebSocketAcceptorServlet(final CoreModuleManager coreModuleManager, - final ModuleResourceManager moduleResourceManager) { + public WebSocketAcceptorServlet(final CoreModuleManager coreModuleManager) { this.coreModuleManager = coreModuleManager; - this.moduleResourceManager = moduleResourceManager; } @@ -77,9 +71,9 @@ public WebSocket doWebSocketConnect(final HttpServletRequest req, uniqueId, coreModule.getModule().getClass().getName(), req.getPathInfo()); if (listener instanceof TextMessageListener) { - return new InnerOnTextMessage(uniqueId, (TextMessageListener) listener); + return new InnerOnTextMessage(coreModule, (TextMessageListener) listener); } else { - return new InnerWebSocket(uniqueId, listener); + return new InnerWebSocket(coreModule, listener); } } @@ -96,42 +90,27 @@ private String parseUniqueId(final String pathInfo) { return null; } - private class WebSocketConnectionResource extends ModuleResourceManager.WeakResource { - - final WebSocketConnection conn; - - WebSocketConnectionResource(WebSocketConnection conn) { - super(conn); - this.conn = conn; - } - - @Override - public void release() { - if (null != conn) { - conn.disconnect(); - } - } - - } - private class InnerWebSocket implements WebSocket { - final String uniqueId; + final CoreModule coreModule; final WebSocketConnectionListener listener; private WebSocketConnection conn = null; - InnerWebSocket(String uniqueId, WebSocketConnectionListener listener) { - this.uniqueId = uniqueId; + InnerWebSocket(final CoreModule coreModule, + final WebSocketConnectionListener listener) { + this.coreModule = coreModule; this.listener = listener; } @Override public void onOpen(Connection connection) { - conn = moduleResourceManager.append( - uniqueId, - new WebSocketConnectionResource(toWebSocketConnection(connection)) - ); + conn = coreModule.append(new CoreModule.ReleaseResource(toWebSocketConnection(connection)) { + @Override + public void release() { + get().disconnect(); + } + }); listener.onOpen(conn); } @@ -164,7 +143,7 @@ public void onClose(int closeCode, String message) { try { listener.onClose(closeCode, message); } finally { - moduleResourceManager.remove(uniqueId, conn); + coreModule.remove(conn); } } @@ -174,8 +153,9 @@ private class InnerOnTextMessage extends InnerWebSocket implements OnTextMessage private final TextMessageListener textMessageListener; - InnerOnTextMessage(String uniqueId, TextMessageListener listener) { - super(uniqueId, listener); + InnerOnTextMessage(final CoreModule coreModule, + final TextMessageListener listener) { + super(coreModule, listener); this.textMessageListener = listener; } diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/LogbackUtils.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/LogbackUtils.java new file mode 100644 index 00000000..6493ca8a --- /dev/null +++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/LogbackUtils.java @@ -0,0 +1,60 @@ +package com.alibaba.jvm.sandbox.core.util; + +import ch.qos.logback.classic.LoggerContext; +import ch.qos.logback.classic.joran.JoranConfigurator; +import org.apache.commons.io.IOUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; + +import static com.alibaba.jvm.sandbox.core.util.NamespaceConvert.initNamespaceConvert; + +/** + * Logback日志框架工具类 + */ +public class LogbackUtils { + + + /** + * 初始化Logback日志框架 + * + * @param namespace 命名空间 + * @param logbackCfgFilePath logback配置文件路径 + */ + public static void init(final String namespace, + final String logbackCfgFilePath) { + final LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory(); + final JoranConfigurator configurator = new JoranConfigurator(); + final File configureFile = new File(logbackCfgFilePath); + configurator.setContext(loggerContext); + loggerContext.reset(); + InputStream is = null; + final Logger logger = LoggerFactory.getLogger(LoggerFactory.class); + try { + is = new FileInputStream(configureFile); + initNamespaceConvert(namespace); + configurator.doConfigure(is); + logger.info(SandboxStringUtils.getLogo()); + logger.info("initializing logback success. file={};", configureFile); + } catch (Throwable cause) { + logger.warn("initialize logback failed. file={};", configureFile, cause); + } finally { + IOUtils.closeQuietly(is); + } + } + + /** + * 销毁Logback日志框架 + */ + public static void destroy() { + try { + ((LoggerContext) LoggerFactory.getILoggerFactory()).stop(); + } catch (Throwable cause) { + cause.printStackTrace(); + } + } + +} diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/SpyUtils.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/SpyUtils.java index cdb0d407..9d6a32db 100644 --- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/SpyUtils.java +++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/SpyUtils.java @@ -13,14 +13,13 @@ */ public class SpyUtils { - private static final Initializer isSpyInit = new Initializer(); /** * 初始化Spy类 * - * @throws Throwable 初始化失败 + * @param namespace 命名空间 */ - public synchronized static void init(final String namespace) throws Throwable { + public synchronized static void init(final String namespace) { if (Spy.isInit(namespace)) { return; @@ -70,4 +69,13 @@ public synchronized static void init(final String namespace) throws Throwable { } + /** + * 清理Spy中的命名空间 + * + * @param namespace 命名空间 + */ + public synchronized static void clean(final String namespace) { + Spy.clean(namespace); + } + } diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/ExtFilterMatcher.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/ExtFilterMatcher.java index 15fc99fc..4a657daf 100644 --- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/ExtFilterMatcher.java +++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/ExtFilterMatcher.java @@ -126,7 +126,7 @@ private static int toFilterAccess(final Access access) { * 兼容{@code sandbox-api:1.0.10}时 * 在{@link EventWatchCondition#getOrFilterArray()}中将{@link Filter}直接暴露出来的问题, * 所以这里做一个兼容性的强制转换 - *

+ * *

    *
  • 如果filterArray[index]是一个{@link ExtFilter},则不需要再次转换
  • *
  • 如果filterArray[index]是一个{@link Filter},则需要进行{@link ExtFilterFactory#make(Filter)}的转换
  • diff --git a/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/enhance/listener/LineNumTracingEventListener.java b/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/enhance/listener/LineNumTracingEventListener.java index 0d38ab1d..5d09316e 100644 --- a/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/enhance/listener/LineNumTracingEventListener.java +++ b/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/enhance/listener/LineNumTracingEventListener.java @@ -8,6 +8,7 @@ import java.util.ArrayList; import java.util.List; +import static com.alibaba.jvm.sandbox.qatest.core.util.AssertUtils.assertArrayEquals; import static org.apache.commons.lang3.ArrayUtils.getLength; import static org.junit.Assert.assertEquals; @@ -52,10 +53,4 @@ private void assertEventProcessor() { .checkEventProcessor(ObjectIDs.instance.identity(this)); } - private void assertArrayEquals(E[] exceptArray, E[] actualArray) { - assertEquals("except size not matched!", getLength(exceptArray), getLength(actualArray)); - for (int index = 0; index < exceptArray.length; index++) { - assertEquals("[" + index + "] not matched", exceptArray[index], actualArray[index]); - } - } } diff --git a/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/enhance/listener/TracingAdviceListener.java b/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/enhance/listener/TracingAdviceListener.java index 8277c569..00ade620 100644 --- a/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/enhance/listener/TracingAdviceListener.java +++ b/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/enhance/listener/TracingAdviceListener.java @@ -14,6 +14,7 @@ import static com.alibaba.jvm.sandbox.api.util.GaStringUtils.getJavaClassName; import static com.alibaba.jvm.sandbox.api.util.GaStringUtils.getJavaClassNameArray; import static com.alibaba.jvm.sandbox.core.util.SandboxStringUtils.toJavaClassNameArray; +import static com.alibaba.jvm.sandbox.qatest.core.util.AssertUtils.assertArrayEquals; import static com.sun.tools.javac.util.StringUtils.toUpperCase; import static org.apache.commons.lang3.ArrayUtils.getLength; import static org.apache.commons.lang3.StringUtils.join; @@ -235,11 +236,4 @@ private void assertEventProcessor() { .checkEventProcessor(ObjectIDs.instance.identity(eventListener)); } - private void assertArrayEquals(E[] exceptArray, E[] actualArray) { - assertEquals("except size not matched!", getLength(exceptArray), getLength(actualArray)); - for (int index = 0; index < exceptArray.length; index++) { - assertEquals("[" + index + "] not matched", exceptArray[index], actualArray[index]); - } - } - } diff --git a/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/enhance/listener/TracingEventListener.java b/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/enhance/listener/TracingEventListener.java index 3c631e59..e636d67c 100644 --- a/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/enhance/listener/TracingEventListener.java +++ b/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/enhance/listener/TracingEventListener.java @@ -8,6 +8,7 @@ import java.util.ArrayList; import java.util.List; +import static com.alibaba.jvm.sandbox.qatest.core.util.AssertUtils.assertArrayEquals; import static org.apache.commons.lang3.ArrayUtils.getLength; import static org.junit.Assert.assertEquals; @@ -52,12 +53,5 @@ private void assertEventProcessor() { .checkEventProcessor(ObjectIDs.instance.identity(this)); } - private void assertArrayEquals(E[] exceptArray, E[] actualArray) { - assertEquals("except size not matched!", getLength(exceptArray), getLength(actualArray)); - for (int index = 0; index < exceptArray.length; index++) { - assertEquals("[" + index + "] not matched", exceptArray[index], actualArray[index]); - } - } - } diff --git a/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/manager/CoreLoadedClassDataSourceTestCase.java b/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/manager/CoreLoadedClassDataSourceTestCase.java index 467650da..abdcc961 100644 --- a/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/manager/CoreLoadedClassDataSourceTestCase.java +++ b/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/manager/CoreLoadedClassDataSourceTestCase.java @@ -5,6 +5,7 @@ import com.alibaba.jvm.sandbox.core.CoreConfigure; import com.alibaba.jvm.sandbox.core.manager.CoreLoadedClassDataSource; import com.alibaba.jvm.sandbox.core.manager.impl.DefaultLoadedClassDataSource; +import com.alibaba.jvm.sandbox.qatest.core.mock.EmptyInstrumentation; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; @@ -17,7 +18,7 @@ import java.util.Set; import java.util.jar.JarFile; -class MockLoadedClassesOnlyInstrumentation implements Instrumentation { +class MockLoadedClassesOnlyInstrumentation extends EmptyInstrumentation { final Set> loadedClasses = new LinkedHashSet>(); @@ -25,80 +26,11 @@ void regLoadedClass(Class clazz) { loadedClasses.add(clazz); } - @Override - public void addTransformer(ClassFileTransformer transformer, boolean canRetransform) { - - } - - @Override - public void addTransformer(ClassFileTransformer transformer) { - - } - - @Override - public boolean removeTransformer(ClassFileTransformer transformer) { - return false; - } - - @Override - public boolean isRetransformClassesSupported() { - return false; - } - - @Override - public void retransformClasses(Class... classes) throws UnmodifiableClassException { - - } - - @Override - public boolean isRedefineClassesSupported() { - return false; - } - - @Override - public void redefineClasses(ClassDefinition... definitions) throws ClassNotFoundException, UnmodifiableClassException { - - } - - @Override - public boolean isModifiableClass(Class theClass) { - return false; - } - @Override public Class[] getAllLoadedClasses() { return loadedClasses.toArray(new Class[]{}); } - @Override - public Class[] getInitiatedClasses(ClassLoader loader) { - return new Class[0]; - } - - @Override - public long getObjectSize(Object objectToSize) { - return 0; - } - - @Override - public void appendToBootstrapClassLoaderSearch(JarFile jarfile) { - - } - - @Override - public void appendToSystemClassLoaderSearch(JarFile jarfile) { - - } - - @Override - public boolean isNativeMethodPrefixSupported() { - return false; - } - - @Override - public void setNativeMethodPrefix(ClassFileTransformer transformer, String prefix) { - - } } public class CoreLoadedClassDataSourceTestCase { @@ -208,7 +140,7 @@ public void methodOfHuman() { } private final CoreLoadedClassDataSource coreLoadedClassDataSource - = new DefaultLoadedClassDataSource(mockInstrumentation, CoreConfigure.toConfigure("", null)); + = new DefaultLoadedClassDataSource(mockInstrumentation, false); @Test diff --git a/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/manager/CoreModuleManagerTestCase.java b/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/manager/CoreModuleManagerTestCase.java index bf409d17..4678026b 100644 --- a/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/manager/CoreModuleManagerTestCase.java +++ b/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/manager/CoreModuleManagerTestCase.java @@ -3,18 +3,14 @@ import com.alibaba.jvm.sandbox.api.Information; import com.alibaba.jvm.sandbox.api.Module; import com.alibaba.jvm.sandbox.api.ModuleException; -import com.alibaba.jvm.sandbox.api.filter.Filter; import com.alibaba.jvm.sandbox.core.CoreConfigure; -import com.alibaba.jvm.sandbox.core.domain.CoreModule; -import com.alibaba.jvm.sandbox.core.manager.CoreLoadedClassDataSource; +import com.alibaba.jvm.sandbox.core.CoreModule; import com.alibaba.jvm.sandbox.core.manager.CoreModuleManager; -import com.alibaba.jvm.sandbox.core.manager.ModuleLifeCycleEventBus; -import com.alibaba.jvm.sandbox.core.manager.ModuleLifeCycleEventBus.Event; -import com.alibaba.jvm.sandbox.core.manager.ProviderManager; import com.alibaba.jvm.sandbox.core.manager.impl.DefaultCoreModuleManager; -import com.alibaba.jvm.sandbox.core.manager.impl.DefaultModuleLifeCycleEventBus; import com.alibaba.jvm.sandbox.core.util.FeatureCodec; -import com.alibaba.jvm.sandbox.core.util.matcher.Matcher; +import com.alibaba.jvm.sandbox.qatest.core.mock.EmptyCoreLoadedClassDataSource; +import com.alibaba.jvm.sandbox.qatest.core.mock.EmptyInstrumentation; +import com.alibaba.jvm.sandbox.qatest.core.mock.EmptyProviderManager; import com.alibaba.jvm.sandbox.qatest.core.util.SandboxModuleJarBuilder; import org.apache.commons.lang3.StringUtils; import org.junit.Assert; @@ -24,15 +20,13 @@ import java.io.File; import java.io.IOException; -import java.lang.instrument.ClassDefinition; -import java.lang.instrument.ClassFileTransformer; -import java.lang.instrument.Instrumentation; -import java.lang.instrument.UnmodifiableClassException; import java.util.*; -import java.util.jar.JarFile; import static com.alibaba.jvm.sandbox.api.ModuleException.ErrorCode.MODULE_ACTIVE_ERROR; +import static com.alibaba.jvm.sandbox.qatest.core.manager.TracingLifeCycleModule.LifeCycleType.*; import static java.io.File.createTempFile; +import static org.apache.commons.lang3.ArrayUtils.getLength; +import static org.junit.Assert.assertEquals; public class CoreModuleManagerTestCase { @@ -48,177 +42,69 @@ public static class BrokenOnCInitModule implements Module { } @Information(id = "broken-on-load") - public static class BrokenOnLoadModule extends ModuleLifeCycleAdapter implements Module { + public static class BrokenOnLoadModule extends TracingLifeCycleModule implements Module { @Override public void onLoad() throws Throwable { + super.onLoad(); throw new IllegalAccessException("BROKEN-ON-LOAD"); } } @Information(id = "broken-on-unload") - public static class BrokenOnUnLoadModule extends ModuleLifeCycleAdapter implements Module { + public static class BrokenOnUnLoadModule extends TracingLifeCycleModule implements Module { @Override public void onUnload() { + super.onUnload(); throw new RuntimeException("BROKEN-ON-UNLOAD"); } } @Information(id = "broken-on-active") - public static class BrokenOnActiveModule extends ModuleLifeCycleAdapter implements Module { + public static class BrokenOnActiveModule extends TracingLifeCycleModule implements Module { @Override public void onActive() { + super.onActive(); throw new RuntimeException("BROKEN-ON-ACTIVE"); } } @Information(id = "broken-on-lazy-active", isActiveOnLoad = false) - public static class BrokenOnLazyActiveModule extends ModuleLifeCycleAdapter implements Module { + public static class BrokenOnLazyActiveModule extends TracingLifeCycleModule implements Module { @Override public void onActive() { + super.onActive(); throw new RuntimeException("BROKEN-ON-LAZY-ACTIVE"); } } @Information(id = "broken-on-frozen") - public static class BrokenOnFrozenModule extends ModuleLifeCycleAdapter implements Module { + public static class BrokenOnFrozenModule extends TracingLifeCycleModule implements Module { @Override public void onFrozen() { + super.onFrozen(); throw new RuntimeException("BROKEN-ON-FROZEN"); } } @Information(id = "broken-on-load-completed") - public static class BrokenOnLoadCompletedModule extends ModuleLifeCycleAdapter implements Module { + public static class BrokenOnLoadCompletedModule extends TracingLifeCycleModule implements Module { @Override public void loadCompleted() { + super.loadCompleted(); throw new RuntimeException("BROKEN-ON-LOAD-COMPLETED"); } } @Information(id = "normal-module") - public static class NormalModule extends ModuleLifeCycleAdapter implements Module { + public static class NormalModule extends TracingLifeCycleModule implements Module { } @Information(id = "normal-no-lazy-active-module", isActiveOnLoad = false) - public static class NormalOnLazyActiveModule extends ModuleLifeCycleAdapter implements Module { + public static class NormalOnLazyActiveModule extends TracingLifeCycleModule implements Module { } - final class EmptyInstrumentation implements Instrumentation { - - @Override - public void addTransformer(ClassFileTransformer transformer, boolean canRetransform) { - - } - - @Override - public void addTransformer(ClassFileTransformer transformer) { - - } - - @Override - public boolean removeTransformer(ClassFileTransformer transformer) { - return false; - } - - @Override - public boolean isRetransformClassesSupported() { - return false; - } - - @Override - public void retransformClasses(Class... classes) throws UnmodifiableClassException { - - } - - @Override - public boolean isRedefineClassesSupported() { - return false; - } - - @Override - public void redefineClasses(ClassDefinition... definitions) throws ClassNotFoundException, UnmodifiableClassException { - - } - - @Override - public boolean isModifiableClass(Class theClass) { - return false; - } - - @Override - public Class[] getAllLoadedClasses() { - return new Class[0]; - } - - @Override - public Class[] getInitiatedClasses(ClassLoader loader) { - return new Class[0]; - } - - @Override - public long getObjectSize(Object objectToSize) { - return 0; - } - - @Override - public void appendToBootstrapClassLoaderSearch(JarFile jarfile) { - - } - - @Override - public void appendToSystemClassLoaderSearch(JarFile jarfile) { - - } - - @Override - public boolean isNativeMethodPrefixSupported() { - return false; - } - - @Override - public void setNativeMethodPrefix(ClassFileTransformer transformer, String prefix) { - - } - } - - final class EmptyCoreLoadedClassDataSource implements CoreLoadedClassDataSource { - - @Override - public List> findForReTransform(Matcher matcher) { - return null; - } - - @Override - public Set> list() { - return null; - } - - @Override - public Set> find(Filter filter) { - return null; - } - - @Override - public Iterator> iteratorForLoadedClasses() { - return null; - } - } - - final class EmptyProviderManager implements ProviderManager { - - @Override - public void loading(File moduleJarFile) throws Throwable { - - } - - @Override - public void loading(String uniqueId, Class moduleClass, Module module, File moduleJarFile, ClassLoader moduleClassLoader) throws Throwable { - - } - } - private CoreConfigure buildingCoreConfigureWithUserModuleLib(final File... moduleJarFileArray) { final Set moduleJarFilePathSet = new LinkedHashSet(); @@ -245,126 +131,113 @@ private File buildingModuleJarFileWithModuleClass(final File targetModuleJarFile } - @Test - public void test$$CoreModuleManager$$ModuleLifeCycle() throws IOException, ModuleException { - final File moduleJarFile = buildingModuleJarFileWithModuleClass( - createTempFile("test-", ".jar"), - NormalModule.class - ); + private void assertLoadedModule(final CoreModuleManager coreModuleManager, + final String... exceptUniqueIds) { + assertEquals(getLength(exceptUniqueIds), coreModuleManager.list().size()); + final Set actualUniqueIdSet = new LinkedHashSet(); + for (final CoreModule coreModule : coreModuleManager.list()) { + actualUniqueIdSet.add(coreModule.getUniqueId()); + } - final Queue eventQueue = new LinkedList(); - eventQueue.offer(Event.LOAD); - eventQueue.offer(Event.ACTIVE); - eventQueue.offer(Event.LOAD_COMPLETED); - - final ModuleLifeCycleEventBus moduleLifeCycleEventBus = new DefaultModuleLifeCycleEventBus(); - moduleLifeCycleEventBus.append(new ModuleLifeCycleEventBus.ModuleLifeCycleEventListener() { - @Override - public boolean onFire(CoreModule coreModule, Event event) { - Assert.assertEquals("normal-module", coreModule.getUniqueId()); - Assert.assertTrue(coreModule.getModule() instanceof Module); - Assert.assertEquals(moduleJarFile, coreModule.getJarFile()); - if (eventQueue.peek() == event) { - eventQueue.poll(); - } else { - logger.warn("expect-event={} but actual-event={}", eventQueue.peek(), event); - } - return true; - } - }); + assertEquals( + new HashSet(Arrays.asList(exceptUniqueIds)), + actualUniqueIdSet + ); + } - final CoreModuleManager coreModuleManager = new DefaultCoreModuleManager( - buildingCoreConfigureWithUserModuleLib(moduleJarFile), + private CoreModuleManager buildingCoreModuleManager(final File... moduleJarFiles) throws ModuleException { + return new DefaultCoreModuleManager( + buildingCoreConfigureWithUserModuleLib(moduleJarFiles), new EmptyInstrumentation(), - this.getClass().getClassLoader(), new EmptyCoreLoadedClassDataSource(), - moduleLifeCycleEventBus, new EmptyProviderManager() - ); - coreModuleManager.reset(); + ).reset(); + } + private void assertTracingLifeCycle(final CoreModuleManager coreModuleManager, + final String uniqueId, + final TracingLifeCycleModule.LifeCycleType... exceptLifeCycleTypes) { + final TracingLifeCycleModule module = (TracingLifeCycleModule) coreModuleManager.get(uniqueId).getModule(); + module.assertTracing(exceptLifeCycleTypes); + } - // 刚完成初始化,注册好的事件应该消化完成 - { - Assert.assertEquals(1, coreModuleManager.list().size()); - Assert.assertEquals("normal-module", coreModuleManager.list().iterator().next().getUniqueId()); - Assert.assertTrue(eventQueue.isEmpty()); - } + private void assertTracingLifeCycle(final CoreModule coreModule, + final TracingLifeCycleModule.LifeCycleType... exceptLifeCycleTypes) { + final TracingLifeCycleModule module = (TracingLifeCycleModule) coreModule.getModule(); + module.assertTracing(exceptLifeCycleTypes); + } + + @Test + public void test$$CoreModuleManager$$ModuleLifeCycle() throws IOException, ModuleException { + final CoreModuleManager coreModuleManager + = buildingCoreModuleManager( + buildingModuleJarFileWithModuleClass( + createTempFile("test-", ".jar"), + NormalModule.class + )); + + assertLoadedModule(coreModuleManager, "normal-module"); + assertTracingLifeCycle( + coreModuleManager, + "normal-module", + LOAD, ACTIVE, LOAD_COMPLETED + ); // 卸载模块 - { - eventQueue.offer(Event.FROZE); - eventQueue.offer(Event.UNLOAD); - coreModuleManager.unload(coreModuleManager.get("normal-module"), false); - Assert.assertEquals(0, coreModuleManager.list().size()); - Assert.assertTrue(eventQueue.isEmpty()); - } + assertTracingLifeCycle( + coreModuleManager.unload(coreModuleManager.get("normal-module"), false), + LOAD, ACTIVE, LOAD_COMPLETED, FROZEN, UNLOAD + ); - // 重新刷新 - { - eventQueue.offer(Event.LOAD); - eventQueue.offer(Event.ACTIVE); - eventQueue.offer(Event.LOAD_COMPLETED); - coreModuleManager.flush(false); - Assert.assertEquals(1, coreModuleManager.list().size()); - Assert.assertEquals("normal-module", coreModuleManager.list().iterator().next().getUniqueId()); - Assert.assertTrue(eventQueue.isEmpty()); - } - // 冻结-激活-冻结 - { - eventQueue.offer(Event.FROZE); - eventQueue.offer(Event.ACTIVE); - eventQueue.offer(Event.FROZE); - coreModuleManager.frozen(coreModuleManager.get("normal-module"), false); - coreModuleManager.active(coreModuleManager.get("normal-module")); - coreModuleManager.frozen(coreModuleManager.get("normal-module"), false); - Assert.assertEquals(1, coreModuleManager.list().size()); - Assert.assertEquals("normal-module", coreModuleManager.list().iterator().next().getUniqueId()); - Assert.assertTrue(eventQueue.isEmpty()); - } + // 重新刷新 + coreModuleManager.flush(false); + assertLoadedModule(coreModuleManager, "normal-module"); + assertTracingLifeCycle( + coreModuleManager, + "normal-module", + LOAD, ACTIVE, LOAD_COMPLETED + ); + // 冻结-冻结-激活-激活-冻结 + coreModuleManager.frozen(coreModuleManager.get("normal-module"), false); + coreModuleManager.active(coreModuleManager.get("normal-module")); + coreModuleManager.frozen(coreModuleManager.get("normal-module"), false); + assertTracingLifeCycle( + coreModuleManager, + "normal-module", + LOAD, ACTIVE, LOAD_COMPLETED, FROZEN, ACTIVE, FROZEN + ); } @Test public void test$$CoreModuleManager$$loading() throws IOException, ModuleException { - final File moduleJarFile = buildingModuleJarFileWithModuleClass( - createTempFile("test-", ".jar"), - NormalModule.class, - BrokenOnCInitModule.class, - BrokenOnLazyActiveModule.class, - BrokenOnActiveModule.class, - BrokenOnFrozenModule.class, - BrokenOnLoadModule.class, - BrokenOnUnLoadModule.class, - BrokenOnLoadCompletedModule.class + final CoreModuleManager coreModuleManager + = buildingCoreModuleManager( + buildingModuleJarFileWithModuleClass( + createTempFile("test-", ".jar"), + NormalModule.class, + BrokenOnCInitModule.class, + BrokenOnLazyActiveModule.class, + BrokenOnActiveModule.class, + BrokenOnFrozenModule.class, + BrokenOnLoadModule.class, + BrokenOnUnLoadModule.class, + BrokenOnLoadCompletedModule.class + )); + + assertLoadedModule( + coreModuleManager, + "normal-module", + "broken-on-lazy-active", + "broken-on-unload", + "broken-on-frozen", + "broken-on-load-completed" ); - final CoreModuleManager coreModuleManager = new DefaultCoreModuleManager( - buildingCoreConfigureWithUserModuleLib(moduleJarFile), - new EmptyInstrumentation(), - this.getClass().getClassLoader(), - new EmptyCoreLoadedClassDataSource(), - new DefaultModuleLifeCycleEventBus(), - new EmptyProviderManager() - ); - coreModuleManager.reset(); - - final Set uniqueIds = new LinkedHashSet(); - for (final CoreModule coreModule : coreModuleManager.list()) { - uniqueIds.add(coreModule.getUniqueId()); - } - - Assert.assertTrue(uniqueIds.contains("normal-module")); - Assert.assertTrue(uniqueIds.contains("broken-on-unload")); - Assert.assertTrue(uniqueIds.contains("broken-on-lazy-active")); - Assert.assertTrue(uniqueIds.contains("broken-on-frozen")); - Assert.assertTrue(uniqueIds.contains("broken-on-load-completed")); - Assert.assertEquals(5, uniqueIds.size()); - } @@ -381,84 +254,65 @@ public static class ModifyAnotherNormalModule implements Module { @Test public void test$$CoreModuleManager$$forceFlush() throws IOException, ModuleException { - final File normalModuleJarFile = buildingModuleJarFileWithModuleClass( - createTempFile("test-", ".jar"), - NormalModule.class - ); - final File anotherNormalModuleJarFile = buildingModuleJarFileWithModuleClass( createTempFile("test-", ".jar"), AnotherNormalModule.class ); - final CoreModuleManager coreModuleManager = new DefaultCoreModuleManager( - buildingCoreConfigureWithUserModuleLib( - normalModuleJarFile, - anotherNormalModuleJarFile + final CoreModuleManager coreModuleManager + = buildingCoreModuleManager( + buildingModuleJarFileWithModuleClass( + createTempFile("test-", ".jar"), + NormalModule.class ), - new EmptyInstrumentation(), - this.getClass().getClassLoader(), - new EmptyCoreLoadedClassDataSource(), - new DefaultModuleLifeCycleEventBus(), - new EmptyProviderManager() + anotherNormalModuleJarFile ); - coreModuleManager.reset(); - final Set uniqueIds = new LinkedHashSet(); - for (final CoreModule coreModule : coreModuleManager.list()) { - uniqueIds.add(coreModule.getUniqueId()); - } - - Assert.assertTrue(uniqueIds.contains("normal-module")); - Assert.assertTrue(uniqueIds.contains("another-normal-module")); - Assert.assertEquals(2, uniqueIds.size()); + assertLoadedModule( + coreModuleManager, + "normal-module", + "another-normal-module" + ); Assert.assertTrue(anotherNormalModuleJarFile.delete()); coreModuleManager.flush(true); - Assert.assertEquals(1, coreModuleManager.list().size()); - Assert.assertEquals("normal-module", coreModuleManager.list().iterator().next().getUniqueId()); + + assertLoadedModule( + coreModuleManager, + "normal-module" + ); } @Test public void test$$CoreModuleManager$$softFlush$$delete() throws IOException, ModuleException { - final File normalModuleJarFile = buildingModuleJarFileWithModuleClass( - createTempFile("test-", ".jar"), - NormalModule.class - ); - final File anotherNormalModuleJarFile = buildingModuleJarFileWithModuleClass( createTempFile("test-", ".jar"), AnotherNormalModule.class ); - final CoreModuleManager coreModuleManager = new DefaultCoreModuleManager( - buildingCoreConfigureWithUserModuleLib( - normalModuleJarFile, - anotherNormalModuleJarFile + final CoreModuleManager coreModuleManager + = buildingCoreModuleManager( + buildingModuleJarFileWithModuleClass( + createTempFile("test-", ".jar"), + NormalModule.class ), - new EmptyInstrumentation(), - this.getClass().getClassLoader(), - new EmptyCoreLoadedClassDataSource(), - new DefaultModuleLifeCycleEventBus(), - new EmptyProviderManager() + anotherNormalModuleJarFile ); - coreModuleManager.reset(); - final Set uniqueIds = new LinkedHashSet(); - for (final CoreModule coreModule : coreModuleManager.list()) { - uniqueIds.add(coreModule.getUniqueId()); - } - - Assert.assertTrue(uniqueIds.contains("normal-module")); - Assert.assertTrue(uniqueIds.contains("another-normal-module")); - Assert.assertEquals(2, uniqueIds.size()); + assertLoadedModule( + coreModuleManager, + "normal-module", + "another-normal-module" + ); Assert.assertTrue(anotherNormalModuleJarFile.delete()); coreModuleManager.flush(false); - Assert.assertEquals(1, coreModuleManager.list().size()); - Assert.assertEquals("normal-module", coreModuleManager.list().iterator().next().getUniqueId()); + assertLoadedModule( + coreModuleManager, + "normal-module" + ); } @@ -466,60 +320,42 @@ public static class ModifyAnotherNormalModule implements Module { @Test public void test$$CoreModuleManager$$softFlush$$modify() throws IOException, ModuleException { - final File normalModuleJarFile = buildingModuleJarFileWithModuleClass( - createTempFile("test-", ".jar"), - NormalModule.class - ); - final File anotherNormalModuleJarFile = buildingModuleJarFileWithModuleClass( createTempFile("test-", ".jar"), AnotherNormalModule.class ); - final CoreModuleManager coreModuleManager = new DefaultCoreModuleManager( - buildingCoreConfigureWithUserModuleLib( - normalModuleJarFile, - anotherNormalModuleJarFile + final CoreModuleManager coreModuleManager + = buildingCoreModuleManager( + buildingModuleJarFileWithModuleClass( + createTempFile("test-", ".jar"), + NormalModule.class ), - new EmptyInstrumentation(), - this.getClass().getClassLoader(), - new EmptyCoreLoadedClassDataSource(), - new DefaultModuleLifeCycleEventBus(), - new EmptyProviderManager() + anotherNormalModuleJarFile ); - coreModuleManager.reset(); - { - final Set uniqueIds = new LinkedHashSet(); - for (final CoreModule coreModule : coreModuleManager.list()) { - uniqueIds.add(coreModule.getUniqueId()); - } - - Assert.assertTrue(uniqueIds.contains("normal-module")); - Assert.assertTrue(uniqueIds.contains("another-normal-module")); - Assert.assertEquals(2, uniqueIds.size()); - } + assertLoadedModule( + coreModuleManager, + "normal-module", + "another-normal-module" + ); - { - buildingModuleJarFileWithModuleClass( - anotherNormalModuleJarFile, - ModifyAnotherNormalModule.class - ); - coreModuleManager.flush(false); + buildingModuleJarFileWithModuleClass( + anotherNormalModuleJarFile, + ModifyAnotherNormalModule.class + ); + coreModuleManager.flush(false); - final Set uniqueIds = new LinkedHashSet(); - for (final CoreModule coreModule : coreModuleManager.list()) { - uniqueIds.add(coreModule.getUniqueId()); - } + assertLoadedModule( + coreModuleManager, + "normal-module", + "another-normal-module" + ); - Assert.assertTrue(uniqueIds.contains("normal-module")); - Assert.assertTrue(uniqueIds.contains("another-normal-module")); - Assert.assertEquals(2, coreModuleManager.list().size()); - Assert.assertEquals( - ModifyAnotherNormalModule.class.getName(), - coreModuleManager.get("another-normal-module").getModule().getClass().getName() - ); - } + Assert.assertEquals( + ModifyAnotherNormalModule.class.getName(), + coreModuleManager.get("another-normal-module").getModule().getClass().getName() + ); } @@ -527,141 +363,94 @@ public static class ModifyAnotherNormalModule implements Module { @Test(expected = ModuleException.class) public void test$$CoreModuleManager$$getThrowsExceptionIfNull() throws IOException, ModuleException { - final File moduleJarFile = buildingModuleJarFileWithModuleClass( - createTempFile("test-", ".jar"), - NormalModule.class, - BrokenOnCInitModule.class, - BrokenOnLazyActiveModule.class, - BrokenOnActiveModule.class, - BrokenOnFrozenModule.class, - BrokenOnLoadModule.class, - BrokenOnUnLoadModule.class, - BrokenOnLoadCompletedModule.class + final CoreModuleManager coreModuleManager + = buildingCoreModuleManager( + buildingModuleJarFileWithModuleClass( + createTempFile("test-", ".jar"), + NormalModule.class, + BrokenOnCInitModule.class, + BrokenOnLazyActiveModule.class, + BrokenOnActiveModule.class, + BrokenOnFrozenModule.class, + BrokenOnLoadModule.class, + BrokenOnUnLoadModule.class, + BrokenOnLoadCompletedModule.class + ) ); - final CoreModuleManager coreModuleManager = new DefaultCoreModuleManager( - buildingCoreConfigureWithUserModuleLib(moduleJarFile), - new EmptyInstrumentation(), - this.getClass().getClassLoader(), - new EmptyCoreLoadedClassDataSource(), - new DefaultModuleLifeCycleEventBus(), - new EmptyProviderManager() - ); - coreModuleManager.reset(); - coreModuleManager.getThrowsExceptionIfNull("not-existed-module"); } @Test public void test$$CoreModuleManager$$activeOnSuccess() throws IOException, ModuleException { - final File moduleJarFile = buildingModuleJarFileWithModuleClass( - createTempFile("test-", ".jar"), - NormalOnLazyActiveModule.class + final CoreModuleManager coreModuleManager + = buildingCoreModuleManager( + buildingModuleJarFileWithModuleClass( + createTempFile("test-", ".jar"), + NormalOnLazyActiveModule.class + ) ); - - final Queue eventQueue = new LinkedList(); - eventQueue.offer(Event.LOAD); - eventQueue.offer(Event.LOAD_COMPLETED); - - final ModuleLifeCycleEventBus moduleLifeCycleEventBus = new DefaultModuleLifeCycleEventBus(); - moduleLifeCycleEventBus.append(new ModuleLifeCycleEventBus.ModuleLifeCycleEventListener() { - @Override - public boolean onFire(CoreModule coreModule, Event event) { - Assert.assertEquals("normal-no-lazy-active-module", coreModule.getUniqueId()); - Assert.assertTrue(coreModule.getModule() instanceof Module); - Assert.assertEquals(moduleJarFile, coreModule.getJarFile()); - if (eventQueue.peek() == event) { - eventQueue.poll(); - } else { - logger.warn("expect-event={} but actual-event={}", eventQueue.peek(), event); - } - return true; - } - }); - - final CoreModuleManager coreModuleManager = new DefaultCoreModuleManager( - buildingCoreConfigureWithUserModuleLib(moduleJarFile), - new EmptyInstrumentation(), - this.getClass().getClassLoader(), - new EmptyCoreLoadedClassDataSource(), - moduleLifeCycleEventBus, - new EmptyProviderManager() + assertTracingLifeCycle( + coreModuleManager, + "normal-no-lazy-active-module", + LOAD, LOAD_COMPLETED ); - coreModuleManager.reset(); final CoreModule normalNoLazyActiveCoreModule = coreModuleManager .getThrowsExceptionIfNull("normal-no-lazy-active-module"); - { - eventQueue.offer(Event.ACTIVE); - coreModuleManager.active(normalNoLazyActiveCoreModule); - Assert.assertTrue(eventQueue.isEmpty()); - } + coreModuleManager.active(normalNoLazyActiveCoreModule); + assertTracingLifeCycle( + coreModuleManager, + "normal-no-lazy-active-module", + LOAD, LOAD_COMPLETED, ACTIVE + ); - { - eventQueue.offer(Event.FROZE); - coreModuleManager.frozen(normalNoLazyActiveCoreModule, false); - Assert.assertTrue(eventQueue.isEmpty()); - } + coreModuleManager.frozen(normalNoLazyActiveCoreModule, false); + assertTracingLifeCycle( + coreModuleManager, + "normal-no-lazy-active-module", + LOAD, LOAD_COMPLETED, ACTIVE, FROZEN + ); } @Test public void test$$CoreModuleManager$$activeOnFailed() throws IOException, ModuleException { - final File moduleJarFile = buildingModuleJarFileWithModuleClass( - createTempFile("test-", ".jar"), - BrokenOnLazyActiveModule.class - ); - - final Queue eventQueue = new LinkedList(); - eventQueue.offer(Event.LOAD); - eventQueue.offer(Event.LOAD_COMPLETED); - - final ModuleLifeCycleEventBus moduleLifeCycleEventBus = new DefaultModuleLifeCycleEventBus(); - moduleLifeCycleEventBus.append(new ModuleLifeCycleEventBus.ModuleLifeCycleEventListener() { - @Override - public boolean onFire(CoreModule coreModule, Event event) { - Assert.assertEquals("broken-on-lazy-active", coreModule.getUniqueId()); - Assert.assertTrue(coreModule.getModule() instanceof Module); - Assert.assertEquals(moduleJarFile, coreModule.getJarFile()); - if (eventQueue.peek() == event) { - eventQueue.poll(); - } else { - logger.warn("expect-event={} but actual-event={}", eventQueue.peek(), event); - } - return true; - } - }); + final CoreModuleManager coreModuleManager + = buildingCoreModuleManager( + buildingModuleJarFileWithModuleClass( + createTempFile("test-", ".jar"), + BrokenOnLazyActiveModule.class + ) + ); - final CoreModuleManager coreModuleManager = new DefaultCoreModuleManager( - buildingCoreConfigureWithUserModuleLib(moduleJarFile), - new EmptyInstrumentation(), - this.getClass().getClassLoader(), - new EmptyCoreLoadedClassDataSource(), - moduleLifeCycleEventBus, - new EmptyProviderManager() + assertTracingLifeCycle( + coreModuleManager, + "broken-on-lazy-active", + LOAD, LOAD_COMPLETED ); - coreModuleManager.reset(); final CoreModule brokenOnLazyActiveCoreModule = coreModuleManager .getThrowsExceptionIfNull("broken-on-lazy-active"); - { - eventQueue.offer(Event.ACTIVE); - try { - coreModuleManager.active(brokenOnLazyActiveCoreModule); - }catch (ModuleException me) { - Assert.assertEquals("broken-on-lazy-active", me.getUniqueId()); - Assert.assertEquals(MODULE_ACTIVE_ERROR, me.getErrorCode()); - } - - Assert.assertFalse(eventQueue.isEmpty()); + try { + coreModuleManager.active(brokenOnLazyActiveCoreModule); + } catch (ModuleException me) { + Assert.assertEquals("broken-on-lazy-active", me.getUniqueId()); + Assert.assertEquals(MODULE_ACTIVE_ERROR, me.getErrorCode()); } + assertTracingLifeCycle( + coreModuleManager, + "broken-on-lazy-active", + LOAD, LOAD_COMPLETED, ACTIVE + ); + } diff --git a/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/manager/ModuleLifeCycleAdapter.java b/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/manager/ModuleLifeCycleAdapter.java deleted file mode 100644 index accff653..00000000 --- a/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/manager/ModuleLifeCycleAdapter.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.alibaba.jvm.sandbox.qatest.core.manager; - -import com.alibaba.jvm.sandbox.api.ModuleLifecycle; - -public class ModuleLifeCycleAdapter implements ModuleLifecycle { - @Override - public void onLoad() throws Throwable { - - } - - @Override - public void onUnload() throws Throwable { - - } - - @Override - public void onActive() throws Throwable { - - } - - @Override - public void onFrozen() throws Throwable { - - } - - @Override - public void loadCompleted() { - - } -} diff --git a/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/manager/TracingLifeCycleModule.java b/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/manager/TracingLifeCycleModule.java new file mode 100644 index 00000000..14539afa --- /dev/null +++ b/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/manager/TracingLifeCycleModule.java @@ -0,0 +1,62 @@ +package com.alibaba.jvm.sandbox.qatest.core.manager; + +import com.alibaba.jvm.sandbox.api.Module; +import com.alibaba.jvm.sandbox.api.ModuleLifecycle; + +import java.util.ArrayList; +import java.util.List; + +import static com.alibaba.jvm.sandbox.qatest.core.util.AssertUtils.assertArrayEquals; + +/** + * 追踪生命周期管理模块 + */ +public abstract class TracingLifeCycleModule implements ModuleLifecycle, Module { + + private final List lifeCycleTypeTracings = new ArrayList(); + + @Override + public void onLoad() throws Throwable { + lifeCycleTypeTracings.add(LifeCycleType.LOAD); + } + + @Override + public void onUnload() { + lifeCycleTypeTracings.add(LifeCycleType.UNLOAD); + } + + @Override + public void onActive() { + lifeCycleTypeTracings.add(LifeCycleType.ACTIVE); + } + + @Override + public void onFrozen() { + lifeCycleTypeTracings.add(LifeCycleType.FROZEN); + } + + @Override + public void loadCompleted() { + lifeCycleTypeTracings.add(LifeCycleType.LOAD_COMPLETED); + } + + public void assertTracing(final LifeCycleType... exceptLifeCycleTypes) { + assertArrayEquals( + exceptLifeCycleTypes, + lifeCycleTypeTracings.toArray(new LifeCycleType[]{}) + ); + } + + + /** + * 生命周期类型 + */ + public enum LifeCycleType { + LOAD, + UNLOAD, + ACTIVE, + FROZEN, + LOAD_COMPLETED + } + +} diff --git a/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/mock/EmptyCoreLoadedClassDataSource.java b/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/mock/EmptyCoreLoadedClassDataSource.java new file mode 100644 index 00000000..1d763855 --- /dev/null +++ b/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/mock/EmptyCoreLoadedClassDataSource.java @@ -0,0 +1,54 @@ +package com.alibaba.jvm.sandbox.qatest.core.mock; + +import com.alibaba.jvm.sandbox.api.filter.Filter; +import com.alibaba.jvm.sandbox.core.manager.CoreLoadedClassDataSource; +import com.alibaba.jvm.sandbox.core.manager.LoadedClassLoaderListener; +import com.alibaba.jvm.sandbox.core.util.matcher.Matcher; + +import java.lang.instrument.IllegalClassFormatException; +import java.security.ProtectionDomain; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +public class EmptyCoreLoadedClassDataSource implements CoreLoadedClassDataSource { + @Override + public List> findForReTransform(Matcher matcher) { + return null; + } + + @Override + public ClassLoader[] listLoadedClassLoader() { + return new ClassLoader[0]; + } + + @Override + public void appendLoadedClassLoaderListener(LoadedClassLoaderListener listener) { + + } + + @Override + public void removeLoadedClassLoaderListener(LoadedClassLoaderListener listener) { + + } + + @Override + public Set> list() { + return null; + } + + @Override + public Set> find(Filter filter) { + return null; + } + + @Override + public Iterator> iteratorForLoadedClasses() { + return null; + } + + @Override + public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { + return new byte[0]; + } +} diff --git a/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/mock/EmptyInstrumentation.java b/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/mock/EmptyInstrumentation.java new file mode 100644 index 00000000..eddeb6ee --- /dev/null +++ b/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/mock/EmptyInstrumentation.java @@ -0,0 +1,84 @@ +package com.alibaba.jvm.sandbox.qatest.core.mock; + +import java.lang.instrument.ClassDefinition; +import java.lang.instrument.ClassFileTransformer; +import java.lang.instrument.Instrumentation; +import java.lang.instrument.UnmodifiableClassException; +import java.util.jar.JarFile; + +public class EmptyInstrumentation implements Instrumentation { + @Override + public void addTransformer(ClassFileTransformer transformer, boolean canRetransform) { + + } + + @Override + public void addTransformer(ClassFileTransformer transformer) { + + } + + @Override + public boolean removeTransformer(ClassFileTransformer transformer) { + return false; + } + + @Override + public boolean isRetransformClassesSupported() { + return false; + } + + @Override + public void retransformClasses(Class... classes) throws UnmodifiableClassException { + + } + + @Override + public boolean isRedefineClassesSupported() { + return false; + } + + @Override + public void redefineClasses(ClassDefinition... definitions) throws ClassNotFoundException, UnmodifiableClassException { + + } + + @Override + public boolean isModifiableClass(Class theClass) { + return false; + } + + @Override + public Class[] getAllLoadedClasses() { + return new Class[0]; + } + + @Override + public Class[] getInitiatedClasses(ClassLoader loader) { + return new Class[0]; + } + + @Override + public long getObjectSize(Object objectToSize) { + return 0; + } + + @Override + public void appendToBootstrapClassLoaderSearch(JarFile jarfile) { + + } + + @Override + public void appendToSystemClassLoaderSearch(JarFile jarfile) { + + } + + @Override + public boolean isNativeMethodPrefixSupported() { + return false; + } + + @Override + public void setNativeMethodPrefix(ClassFileTransformer transformer, String prefix) { + + } +} diff --git a/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/mock/EmptyProviderManager.java b/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/mock/EmptyProviderManager.java new file mode 100644 index 00000000..57dd549b --- /dev/null +++ b/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/mock/EmptyProviderManager.java @@ -0,0 +1,18 @@ +package com.alibaba.jvm.sandbox.qatest.core.mock; + +import com.alibaba.jvm.sandbox.api.Module; +import com.alibaba.jvm.sandbox.core.manager.ProviderManager; + +import java.io.File; + +public class EmptyProviderManager implements ProviderManager { + @Override + public void loading(File moduleJarFile) throws Throwable { + + } + + @Override + public void loading(String uniqueId, Class moduleClass, Module module, File moduleJarFile, ClassLoader moduleClassLoader) throws Throwable { + + } +} diff --git a/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/AssertUtils.java b/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/AssertUtils.java new file mode 100644 index 00000000..14b3b91f --- /dev/null +++ b/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/AssertUtils.java @@ -0,0 +1,25 @@ +package com.alibaba.jvm.sandbox.qatest.core.util; + +import org.apache.commons.lang3.StringUtils; + +import static org.apache.commons.lang3.ArrayUtils.getLength; +import static org.junit.Assert.assertEquals; + +public class AssertUtils { + + public static void assertArrayEquals(E[] exceptArray, E[] actualArray) { + assertEquals( + String.format( + "except size not matched!\n\texcept:%s\n\tactual:%s", + StringUtils.join(exceptArray, ","), + StringUtils.join(actualArray, ",") + ), + getLength(exceptArray), + getLength(actualArray) + ); + for (int index = 0; index < exceptArray.length; index++) { + assertEquals("[" + index + "] not matched", exceptArray[index], actualArray[index]); + } + } + +} diff --git a/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/CalculatorHelper.java b/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/CalculatorHelper.java index 6c6e6102..5c4fbd03 100644 --- a/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/CalculatorHelper.java +++ b/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/CalculatorHelper.java @@ -6,14 +6,12 @@ import com.alibaba.jvm.sandbox.api.event.ThrowsEvent; import com.alibaba.jvm.sandbox.api.filter.Filter; import com.alibaba.jvm.sandbox.api.filter.NameRegexFilter; -import com.alibaba.jvm.sandbox.core.manager.ModuleLifeCycleEventBus; import com.alibaba.jvm.sandbox.core.util.UnCaughtException; import com.alibaba.jvm.sandbox.qatest.core.enhance.target.Calculator; import java.lang.reflect.InvocationTargetException; import java.util.Stack; -import static com.alibaba.jvm.sandbox.api.ProcessController.returnImmediately; import static com.alibaba.jvm.sandbox.api.util.GaStringUtils.getJavaClassName; import static com.alibaba.jvm.sandbox.core.util.SandboxReflectUtils.unCaughtGetClassDeclaredJavaMethod; import static com.alibaba.jvm.sandbox.core.util.SandboxReflectUtils.unCaughtInvokeMethod; diff --git a/sandbox-debug-module/src/main/java/com/alibaba/jvm/sandbox/module/debug/OnJarUnLoadCompleted.java b/sandbox-debug-module/src/main/java/com/alibaba/jvm/sandbox/module/debug/OnJarUnLoadCompleted.java index 24aae83e..e4be0b00 100644 --- a/sandbox-debug-module/src/main/java/com/alibaba/jvm/sandbox/module/debug/OnJarUnLoadCompleted.java +++ b/sandbox-debug-module/src/main/java/com/alibaba/jvm/sandbox/module/debug/OnJarUnLoadCompleted.java @@ -8,6 +8,11 @@ @MetaInfServices(ModuleJarLifeCycleProvider.class) public class OnJarUnLoadCompleted implements ModuleJarLifeCycleProvider { + @Override + public ClassLoader waitingFor(ClassLoader[] loaded, ClassLoader inComing) { + return null; + } + @Override public void onJarUnLoadCompleted() { closeLogback(); diff --git a/sandbox-mgr-module/src/main/java/com/alibaba/jvm/sandbox/module/mgr/ControlModule.java b/sandbox-mgr-module/src/main/java/com/alibaba/jvm/sandbox/module/mgr/ControlModule.java index 37dbb0d1..2cb6bbbd 100644 --- a/sandbox-mgr-module/src/main/java/com/alibaba/jvm/sandbox/module/mgr/ControlModule.java +++ b/sandbox-mgr-module/src/main/java/com/alibaba/jvm/sandbox/module/mgr/ControlModule.java @@ -2,11 +2,8 @@ import com.alibaba.jvm.sandbox.api.Information; import com.alibaba.jvm.sandbox.api.Module; -import com.alibaba.jvm.sandbox.api.ModuleException; import com.alibaba.jvm.sandbox.api.annotation.Command; 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.MethodUtils; import org.kohsuke.MetaInfServices; import org.slf4j.Logger; @@ -15,10 +12,9 @@ import javax.annotation.Resource; import java.io.PrintWriter; import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; @MetaInfServices(Module.class) -@Information(id = "sandbox-control", version = "0.0.2", author = "luanjia@taobao.com") +@Information(id = "sandbox-control", version = "0.0.3", author = "luanjia@taobao.com") public class ControlModule implements Module { private final Logger logger = LoggerFactory.getLogger(getClass()); @@ -26,122 +22,30 @@ public class ControlModule implements Module { @Resource private ConfigInfo configInfo; - @Resource - private ModuleManager moduleManager; + // 卸载jvm-sandbox + private void uninstall() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException { + final Class classOfAgentLauncher = getClass().getClassLoader() + .loadClass("com.alibaba.jvm.sandbox.agent.AgentLauncher"); - private ClassLoader getSandboxClassLoader(final Class classOfAgentLauncher) - throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { - return (ClassLoader) MethodUtils.invokeStaticMethod( + MethodUtils.invokeStaticMethod( classOfAgentLauncher, - "getClassLoader", + "uninstall", configInfo.getNamespace() ); } - // 清理命名空间所对应的SandboxClassLoader - private ClassLoader cleanSandboxClassLoader(final Class classOfAgentLauncher) { - // 清理AgentLauncher.sandboxClassLoaderMap - try { - final ClassLoader sandboxClassLoader = (ClassLoader) MethodUtils.invokeStaticMethod( - classOfAgentLauncher, - "cleanClassLoader", - configInfo.getNamespace() - ); - logger.info("clean SandboxClassLoader from jvm-sandbox[{}] success, for shutdown.", configInfo.getNamespace()); - return sandboxClassLoader; - } catch (Throwable cause) { - logger.warn("clean SandboxClassLoader from jvm-sandbox[{}] occur error for shutdown!", configInfo.getNamespace(), cause); - return null; - } - } - - // 清理Spy中对Method的引用 - private void cleanSpy() throws ClassNotFoundException, IllegalAccessException, NoSuchMethodException, InvocationTargetException { - final String namespace = configInfo.getNamespace(); - MethodUtils.invokeStaticMethod( - getClass().getClassLoader().loadClass("java.com.alibaba.jvm.sandbox.spy.Spy"), - "clean", - namespace - ); - logger.info("clean Spy's method from jvm-sandbox[{}] success, for shutdown.", namespace); - } - - // 卸载所有模块 - // 从这里开始只允许调用JDK自带的反射方法,因为ControlModule已经完成卸载,你找不到apache的包了 - private void unloadModules() throws ModuleException { - - for (final Module module : moduleManager.list()) { - final Information information = module.getClass().getAnnotation(Information.class); - if (null == information - || StringUtils.isBlank(information.id())) { - continue; - } - // 如果遇到自己,需要最后才卸载 - if (module == this) { - continue; - } - moduleManager.unload(information.id()); - logger.info("unload module={} from jvm-sandbox[{}] success, for shutdown.", information.id(), configInfo.getNamespace()); - } - - } - - // 卸载自己 - private void unloadSelf() { - // 卸载自己 - try { - final String self = getClass().getAnnotation(Information.class).id(); - moduleManager.unload(self); - } catch (Throwable cause) { - cause.printStackTrace(); - } - // logger.info("unload module={} from jvm-sandbox[{}] success, for shutdown.", self, configInfo.getNamespace()); - } - - // 关闭HTTP服务器 - private void shutdownServer(final ClassLoader sandboxClassLoader) { - - try { - if (null == sandboxClassLoader) { - logger.warn("detection an warning, target SandboxClassLoader[namespace={}] is null, shutdown server will be ignore", - configInfo.getNamespace()); - return; - } - - final Class classOfCoreServer = sandboxClassLoader - .loadClass("com.alibaba.jvm.sandbox.core.server.ProxyCoreServer"); - final Object objectOfJettyCoreServer = classOfCoreServer.getMethod("getInstance").invoke(null); - final Method methodOfDestroy = classOfCoreServer.getMethod("destroy"); - methodOfDestroy.invoke(objectOfJettyCoreServer); - logger.info("shutdown jvm-sandbox[{}] server success for shutdown.", configInfo.getNamespace()); - } catch (Throwable cause) { - logger.warn("shutdown jvm-sandbox[{}] server occur error for shutdown!", configInfo.getNamespace(), cause); - } - } - // @Http("/shutdown") @Command("shutdown") - public void shutdown(final PrintWriter writer) throws Exception { + public void shutdown(final PrintWriter writer) { logger.info("prepare to shutdown jvm-sandbox[{}].", configInfo.getNamespace()); - final Class classOfAgentLauncher = getClass().getClassLoader() - .loadClass("com.alibaba.jvm.sandbox.agent.AgentLauncher"); - - // 卸载模块 - unloadModules(); - - // 清理Spy的注册方法回调 - cleanSpy(); - // 关闭HTTP服务器 final Thread shutdownJvmSandboxHook = new Thread(new Runnable() { @Override public void run() { try { - shutdownServer(getSandboxClassLoader(classOfAgentLauncher)); - cleanSandboxClassLoader(classOfAgentLauncher); - unloadSelf(); + uninstall(); } catch (Throwable cause) { logger.warn("shutdown jvm-sandbox[{}] failed.", configInfo.getNamespace(), cause); } diff --git a/sandbox-mgr-module/src/main/java/com/alibaba/jvm/sandbox/module/mgr/OnJarUnLoadCompleted.java b/sandbox-mgr-module/src/main/java/com/alibaba/jvm/sandbox/module/mgr/OnJarUnLoadCompleted.java index dd1f50db..d198fe71 100644 --- a/sandbox-mgr-module/src/main/java/com/alibaba/jvm/sandbox/module/mgr/OnJarUnLoadCompleted.java +++ b/sandbox-mgr-module/src/main/java/com/alibaba/jvm/sandbox/module/mgr/OnJarUnLoadCompleted.java @@ -8,6 +8,11 @@ @MetaInfServices(ModuleJarLifeCycleProvider.class) public class OnJarUnLoadCompleted implements ModuleJarLifeCycleProvider { + @Override + public ClassLoader waitingFor(ClassLoader[] loaded, ClassLoader inComing) { + return null; + } + @Override public void onJarUnLoadCompleted() { closeLogback();