Repository: alibaba/jvm-sandbox (language: java)

Issue:
Enhance the performance
6 Tips for a Better Transforming Performance:

1. Use `String.replace(char, char)` rather than `String.replace(String, String)`.
2. Fix #256 .  #256 would be a smelly kind of solution, which was incompatible with the previous repair.
3. Async parallel compute supports.
4. Combine the redundant class matchers (High cost in computing arising from a large number of loaded class matching leads to a poor performance in many cases).
5. Offer a SandboxProtector that can prevent all the event firing.
6. Extract Family ClassStructures when necessary.


Discussion / hints:

Fix patch:
diff --git a/pom.xml b/pom.xml
index 1d0ad8bb..93ebf7b0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -23,11 +23,42 @@
             <properties>
                 <tools-jar>${java.home}/../lib/tools.jar</tools-jar>
             </properties>
+            <modules>
+                <module>sandbox-agent</module>
+                <module>sandbox-core</module>
+                <module>sandbox-api</module>
+                <module>sandbox-spy</module>
+                <module>sandbox-mgr-module</module>
+                <module>sandbox-provider-api</module>
+                <module>sandbox-common-api</module>
+                <module>sandbox-mgr-provider</module>
+                <module>sandbox-module-starter</module>
+                <module>sandbox-debug-module</module>
+                <module>sandbox-test</module>
+            </modules>
             <activation>
                 <activeByDefault>true</activeByDefault>
             </activation>
         </profile>
 
+        <profile>
+            <id>benchmark</id>
+            <modules>
+                <module>sandbox-agent</module>
+                <module>sandbox-core</module>
+                <module>sandbox-api</module>
+                <module>sandbox-spy</module>
+                <module>sandbox-mgr-module</module>
+                <module>sandbox-provider-api</module>
+                <module>sandbox-common-api</module>
+                <module>sandbox-mgr-provider</module>
+                <module>sandbox-module-starter</module>
+                <module>sandbox-debug-module</module>
+                <module>sandbox-test</module>
+                <module>sandbox-benchmark</module>
+            </modules>
+        </profile>
+
     </profiles>
 
     <reporting>
@@ -79,6 +110,9 @@
                         <goals>
                             <goal>jar</goal>
                         </goals>
+                        <configuration>
+                            <additionalparam>-Xdoclint:none</additionalparam>
+                        </configuration>
                     </execution>
                 </executions>
             </plugin>
@@ -143,19 +177,6 @@
         </plugins>
     </build>
 
-    <modules>
-        <module>sandbox-agent</module>
-        <module>sandbox-core</module>
-        <module>sandbox-api</module>
-        <module>sandbox-spy</module>
-        <module>sandbox-mgr-module</module>
-        <module>sandbox-provider-api</module>
-        <module>sandbox-common-api</module>
-        <module>sandbox-mgr-provider</module>
-        <module>sandbox-module-starter</module>
-        <module>sandbox-debug-module</module>
-    </modules>
-
     <dependencyManagement>
         <dependencies>
             <dependency>
@@ -190,6 +211,12 @@
                 <version>${sandbox.version}</version>
                 <scope>test</scope>
             </dependency>
+            <dependency>
+                <groupId>com.alibaba.jvm.sandbox</groupId>
+                <artifactId>sandbox-test</artifactId>
+                <version>${sandbox.version}</version>
+                <scope>test</scope>
+            </dependency>
 
             <!-- servlet api -->
             <dependency>
diff --git a/sandbox-api/src/main/java/com/alibaba/jvm/sandbox/api/filter/ClassIdentifiable.java b/sandbox-api/src/main/java/com/alibaba/jvm/sandbox/api/filter/ClassIdentifiable.java
new file mode 100644
index 00000000..9602e308
--- /dev/null
+++ b/sandbox-api/src/main/java/com/alibaba/jvm/sandbox/api/filter/ClassIdentifiable.java
@@ -0,0 +1,36 @@
+package com.alibaba.jvm.sandbox.api.filter;
+
+/**
+ * <p>Define a unique class with a given id. The wrapped class would
+ * not be a unique class iff {@link #hasClassIdentity} is false.
+ *
+ * This class is useful when you decide to enhance the performance
+ * when finding appropriate classes.
+ *
+ * <code>
+ *     if (idClazz.hasUniqueIdentity) {
+ *         String id = idClazz.getUniqueIdentity();
+ *         ...
+ *     }
+ * </code>
+ *
+ * @author <a href="mailto:renyi.cry@alibaba-inc.com">renyi.cry<a/>
+ * @date 2020/11/9 11:20 上午
+ */
+public interface ClassIdentifiable {
+
+    /**
+     * Does the filter has a unique identity?
+     *
+     * @return
+     */
+    boolean hasClassIdentity();
+
+    /**
+     * Get the unique identity of the filter.
+     *
+     * @return
+     */
+    String getClassIdentity();
+
+}
diff --git a/sandbox-api/src/main/java/com/alibaba/jvm/sandbox/api/filter/ExtFilter.java b/sandbox-api/src/main/java/com/alibaba/jvm/sandbox/api/filter/ExtFilter.java
index 10f092b7..4c2139a0 100644
--- a/sandbox-api/src/main/java/com/alibaba/jvm/sandbox/api/filter/ExtFilter.java
+++ b/sandbox-api/src/main/java/com/alibaba/jvm/sandbox/api/filter/ExtFilter.java
@@ -12,7 +12,7 @@
  * @author luanjia@taobao.com
  * @since {@code sandbox-api:1.0.11}
  */
-public interface ExtFilter extends Filter {
+public interface ExtFilter extends Filter, ClassIdentifiable {
 
     /**
      * 是否搜索子类或实现类
@@ -29,6 +29,21 @@ public interface ExtFilter extends Filter {
      */
     boolean isIncludeBootstrap();
 
+    /**
+     * 是否至少配置实现了一组接口
+     *
+     * @return
+     */
+    boolean hasInterfaceTypes();
+
+    /**
+     * 是否至少配置了一个标注
+     *
+     * @return
+     */
+    boolean hasAnnotationTypes();
+
+
     /**
      * 增强过滤器工厂类
      */
@@ -45,8 +60,34 @@ class ExtFilterFactory {
         public static ExtFilter make(final Filter filter,
                                      final boolean isIncludeSubClasses,
                                      final boolean isIncludeBootstrap) {
+            return make(filter, isIncludeSubClasses, isIncludeBootstrap, true, true);
+        }
+
+        /**
+         * 生产增强过滤器
+         *
+         * @param filter              原生过滤器
+         * @param isIncludeSubClasses 是否包含子类
+         * @param isIncludeBootstrap  是否搜索BootstrapClassLoader所加载的类
+         * @return 增强过滤器
+         */
+        public static ExtFilter make(final Filter filter,
+                                     final boolean isIncludeSubClasses,
+                                     final boolean isIncludeBootstrap,
+                                     final boolean hasInterfaceTypes,
+                                     final boolean hasAnnotationTypes) {
             return new ExtFilter() {
 
+                @Override
+                public boolean hasClassIdentity() {
+                    return filter instanceof ClassIdentifiable;
+                }
+
+                @Override
+                public String getClassIdentity() {
+                    return ((ClassIdentifiable) filter).getClassIdentity();
+                }
+
                 @Override
                 public boolean isIncludeSubClasses() {
                     return isIncludeSubClasses;
@@ -57,6 +98,16 @@ public boolean isIncludeBootstrap() {
                     return isIncludeBootstrap;
                 }
 
+                @Override
+                public boolean hasInterfaceTypes() {
+                    return hasInterfaceTypes;
+                }
+
+                @Override
+                public boolean hasAnnotationTypes() {
+                    return hasAnnotationTypes;
+                }
+
                 @Override
                 public boolean doClassFilter(final int access,
                                              final String javaClassName,
@@ -96,8 +147,7 @@ public boolean doMethodFilter(final int access,
          * @return 增强过滤器
          */
         public static ExtFilter make(final Filter filter) {
-            return
-                    filter instanceof ExtFilter
+            return filter instanceof ExtFilter
                             ? (ExtFilter) filter
                             : make(
                             filter,
diff --git a/sandbox-api/src/main/java/com/alibaba/jvm/sandbox/api/listener/ext/AdviceAdapterListener.java b/sandbox-api/src/main/java/com/alibaba/jvm/sandbox/api/listener/ext/AdviceAdapterListener.java
index 8e0f6276..1b3123d2 100644
--- a/sandbox-api/src/main/java/com/alibaba/jvm/sandbox/api/listener/ext/AdviceAdapterListener.java
+++ b/sandbox-api/src/main/java/com/alibaba/jvm/sandbox/api/listener/ext/AdviceAdapterListener.java
@@ -298,7 +298,7 @@ private String toJavaClassName(final String internalClassName) {
         if (GaStringUtils.isEmpty(internalClassName)) {
             return internalClassName;
         } else {
-            return internalClassName.replaceAll("/", ".");
+            return internalClassName.replace('/', '.');
         }
     }
 
diff --git a/sandbox-api/src/main/java/com/alibaba/jvm/sandbox/api/listener/ext/EventWatchBuilder.java b/sandbox-api/src/main/java/com/alibaba/jvm/sandbox/api/listener/ext/EventWatchBuilder.java
index ab284bbc..0509a79a 100644
--- a/sandbox-api/src/main/java/com/alibaba/jvm/sandbox/api/listener/ext/EventWatchBuilder.java
+++ b/sandbox-api/src/main/java/com/alibaba/jvm/sandbox/api/listener/ext/EventWatchBuilder.java
@@ -4,16 +4,14 @@
 import com.alibaba.jvm.sandbox.api.filter.AccessFlags;
 import com.alibaba.jvm.sandbox.api.filter.ExtFilter;
 import com.alibaba.jvm.sandbox.api.filter.Filter;
+import com.alibaba.jvm.sandbox.api.filter.ClassIdentifiable;
 import com.alibaba.jvm.sandbox.api.listener.EventListener;
 import com.alibaba.jvm.sandbox.api.resource.ModuleEventWatcher;
 import com.alibaba.jvm.sandbox.api.resource.ModuleEventWatcher.Progress;
 import com.alibaba.jvm.sandbox.api.util.GaArrayUtils;
 import com.alibaba.jvm.sandbox.api.util.GaStringUtils;
 
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
+import java.util.*;
 
 import static com.alibaba.jvm.sandbox.api.event.Event.Type.*;
 import static com.alibaba.jvm.sandbox.api.listener.ext.EventWatchBuilder.PatternType.WILDCARD;
@@ -155,10 +153,14 @@ public interface IBuildingForClass {
      */
     public interface IBuildingForBehavior {
 
+        Event.Type[] DEFAULT_EVENT_TYPE_ARRAY = new Event.Type[]{BEFORE, RETURN, THROWS};
+
         IBuildingForBehavior withAccess(int access);
 
         IBuildingForBehavior withEmptyParameterTypes();
 
+        IBuildingForBehavior withLazyReload(boolean lazyReload);
+
         IBuildingForBehavior withParameterTypes(String... patterns);
 
         IBuildingForBehavior withParameterTypes(Class<?>... classes);
@@ -198,7 +200,6 @@ public interface IBuildingForBehavior {
          * @return this
          * @deprecated 根据 #256 的建议，这个接口废弃，请采用 {@link #onWatch(AdviceListener)} 代替
          */
-        @Deprecated
         EventWatcher onWatch(AdviceListener adviceListener, Event.Type... eventTypeArray);
 
         EventWatcher onWatch(EventListener eventListener, Event.Type... eventTypeArray);
@@ -300,15 +301,27 @@ public interface IBuildingForUnWatching {
      */
     public enum PatternType {
 
+        /**
+         * 精确完全匹配
+         */
+        PRECISE("**"),
+
         /**
          * 通配符表达式
          */
-        WILDCARD,
+        WILDCARD("*"),
 
         /**
          * 正则表达式
          */
-        REGEX
+        REGEX(".*");
+
+        private String anyClassPattern;
+
+        PatternType(String anyClassPattern) {
+            this.anyClassPattern = anyClassPattern;
+        }
+
     }
 
     private final ModuleEventWatcher moduleEventWatcher;
@@ -349,6 +362,8 @@ private static boolean patternMatching(final String string,
                                            final String pattern,
                                            final PatternType patternType) {
         switch (patternType) {
+            case PRECISE:
+                return (string == pattern) || (string != null && string.equals(pattern));
             case WILDCARD:
                 return GaStringUtils.matching(string, pattern);
             case REGEX:
@@ -385,13 +400,7 @@ private static String[] toRegexQuoteArray(final String[] stringArray) {
      * @return IBuildingForClass
      */
     public IBuildingForClass onAnyClass() {
-        switch (patternType) {
-            case REGEX:
-                return onClass(".*");
-            case WILDCARD:
-            default:
-                return onClass("*");
-        }
+        return onClass(patternType.anyClassPattern);
     }
 
     /**
@@ -409,6 +418,7 @@ public IBuildingForClass onClass(final Class<?> clazz) {
             case REGEX: {
                 return onClass(quote(getJavaClassName(clazz)));
             }
+            case PRECISE:
             case WILDCARD:
             default:
                 return onClass(getJavaClassName(clazz));
@@ -454,6 +464,74 @@ private class BuildingForClass implements IBuildingForClass {
             this.pattern = pattern;
         }
 
+        /**
+         * The signature also the unique key for {@link ClassIdentifiable}
+         *
+         * @return
+         */
+        String toClassSignature() {
+
+            StringBuilder result = new StringBuilder();
+            result.append(pattern);
+            result.append(withAccess);
+            result.append(isIncludeSubClasses ? 1 : 0);
+            result.append(isIncludeBootstrap ? 1 : 0);
+
+            for (Group group : hasInterfaceTypes.groups) {
+                for (String pattern : group.patternArray) {
+                    result.append(pattern);
+                }
+            }
+
+            for (Group group : hasAnnotationTypes.groups) {
+                for (String pattern : group.patternArray) {
+                    result.append(pattern);
+                }
+            }
+
+            return result.toString();
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (!(o instanceof BuildingForClass)) {
+                return false;
+            }
+
+            BuildingForClass that = (BuildingForClass) o;
+
+            if (withAccess != that.withAccess) {
+                return false;
+            }
+            if (isIncludeSubClasses != that.isIncludeSubClasses) {
+                return false;
+            }
+            if (isIncludeBootstrap != that.isIncludeBootstrap) {
+                return false;
+            }
+            if (pattern != null ? !pattern.equals(that.pattern) : that.pattern != null) {
+                return false;
+            }
+            if (hasInterfaceTypes != null ? !hasInterfaceTypes.equals(that.hasInterfaceTypes) : that.hasInterfaceTypes != null) {
+                return false;
+            }
+            return hasAnnotationTypes != null ? hasAnnotationTypes.equals(that.hasAnnotationTypes) : that.hasAnnotationTypes == null;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = pattern != null ? pattern.hashCode() : 0;
+            result = 31 * result + withAccess;
+            result = 31 * result + (isIncludeSubClasses ? 1 : 0);
+            result = 31 * result + (isIncludeBootstrap ? 1 : 0);
+            result = 31 * result + (hasInterfaceTypes != null ? hasInterfaceTypes.hashCode() : 0);
+            result = 31 * result + (hasAnnotationTypes != null ? hasAnnotationTypes.hashCode() : 0);
+            return result;
+        }
+
         @Override
         public IBuildingForClass includeBootstrap() {
             this.isIncludeBootstrap = true;
@@ -505,6 +583,7 @@ public IBuildingForClass hasInterfaceTypes(final Class<?>... classes) {
             switch (patternType) {
                 case REGEX:
                     return hasInterfaceTypes(toRegexQuoteArray(getJavaClassNameArray(classes)));
+                case PRECISE:
                 case WILDCARD:
                 default:
                     return hasInterfaceTypes(getJavaClassNameArray(classes));
@@ -516,6 +595,7 @@ public IBuildingForClass hasAnnotationTypes(final Class<?>... classes) {
             switch (patternType) {
                 case REGEX:
                     return hasAnnotationTypes(toRegexQuoteArray(getJavaClassNameArray(classes)));
+                case PRECISE:
                 case WILDCARD:
                 default:
                     return hasAnnotationTypes(getJavaClassNameArray(classes));
@@ -529,13 +609,7 @@ public IBuildingForBehavior onBehavior(final String pattern) {
 
         @Override
         public IBuildingForBehavior onAnyBehavior() {
-            switch (patternType) {
-                case REGEX:
-                    return onBehavior(".*");
-                case WILDCARD:
-                default:
-                    return onBehavior("*");
-            }
+            return onBehavior(patternType.anyClassPattern);
         }
 
     }
@@ -548,6 +622,7 @@ private class BuildingForBehavior implements IBuildingForBehavior {
         private final BuildingForClass bfClass;
         private final String pattern;
         private int withAccess = 0;
+        private boolean lazyReload;
         private final PatternGroupList withParameterTypes = new PatternGroupList();
         private final PatternGroupList hasExceptionTypes = new PatternGroupList();
         private final PatternGroupList hasAnnotationTypes = new PatternGroupList();
@@ -570,6 +645,12 @@ public IBuildingForBehavior withEmptyParameterTypes() {
             return this;
         }
 
+        @Override
+        public IBuildingForBehavior withLazyReload(boolean lazyReload) {
+            this.lazyReload = lazyReload;
+            return this;
+        }
+
         @Override
         public IBuildingForBehavior withParameterTypes(final String... patterns) {
             withParameterTypes.add(patterns);
@@ -581,6 +662,7 @@ public IBuildingForBehavior withParameterTypes(final Class<?>... classes) {
             switch (patternType) {
                 case REGEX:
                     return withParameterTypes(toRegexQuoteArray(getJavaClassNameArray(classes)));
+                case PRECISE:
                 case WILDCARD:
                 default:
                     return withParameterTypes(getJavaClassNameArray(classes));
@@ -598,6 +680,7 @@ public IBuildingForBehavior hasExceptionTypes(final Class<?>... classes) {
             switch (patternType) {
                 case REGEX:
                     return hasExceptionTypes(toRegexQuoteArray(getJavaClassNameArray(classes)));
+                case PRECISE:
                 case WILDCARD:
                 default:
                     return hasExceptionTypes(getJavaClassNameArray(classes));
@@ -615,6 +698,7 @@ public IBuildingForBehavior hasAnnotationTypes(final Class<?>... classes) {
             switch (patternType) {
                 case REGEX:
                     return hasAnnotationTypes(toRegexQuoteArray(getJavaClassNameArray(classes)));
+                case PRECISE:
                 case WILDCARD:
                 default:
                     return hasAnnotationTypes(getJavaClassNameArray(classes));
@@ -648,18 +732,39 @@ public IBuildingForWatching onWatching() {
 
         @Override
         public EventWatcher onWatch(AdviceListener adviceListener) {
-            return build(new AdviceAdapterListener(adviceListener), null, BEFORE, RETURN, THROWS, IMMEDIATELY_RETURN, IMMEDIATELY_THROWS);
+            return build(new AdviceAdapterListener(adviceListener), null, lazyReload, BEFORE, RETURN, THROWS, IMMEDIATELY_RETURN, IMMEDIATELY_THROWS);
         }
 
         @Deprecated
         @Override
         public EventWatcher onWatch(final AdviceListener adviceListener, Event.Type... eventTypeArray) {
-            return onWatch(adviceListener);
+
+            if (eventTypeArray == DEFAULT_EVENT_TYPE_ARRAY) {
+                return build(new AdviceAdapterListener(adviceListener), null, lazyReload, DEFAULT_EVENT_TYPE_ARRAY);
+            }
+
+            // new array box
+            Event.Type[] DEFAULT_EVENT_TYPE_ARRAY_BOX = new Event.Type[6];
+            System.arraycopy(IBuildingForBehavior.DEFAULT_EVENT_TYPE_ARRAY, 0, DEFAULT_EVENT_TYPE_ARRAY_BOX, 0, 3);
+
+            int lastIndex = 2;
+            if(eventTypeArray != null) {
+                for (Event.Type type : eventTypeArray) {
+                    if (lastIndex == 5) {
+                        break;
+                    }
+                    if (type != BEFORE && type != RETURN && type != THROWS) {
+                        DEFAULT_EVENT_TYPE_ARRAY_BOX[++lastIndex] = type;
+                    }
+                }
+            }
+
+            return build(new AdviceAdapterListener(adviceListener), null, lazyReload, Arrays.copyOf(DEFAULT_EVENT_TYPE_ARRAY_BOX, ++lastIndex));
         }
 
         @Override
         public EventWatcher onWatch(EventListener eventListener, Event.Type... eventTypeArray) {
-            return build(eventListener, null, eventTypeArray);
+            return build(eventListener, null, lazyReload, eventTypeArray);
         }
 
     }
@@ -700,8 +805,7 @@ public EventWatcher onWatch(AdviceListener adviceListener) {
             eventTypeSet.add(IMMEDIATELY_THROWS);
             return build(
                     new AdviceAdapterListener(adviceListener),
-                    toProgressGroup(progresses),
-                    eventTypeSet.toArray(EMPTY)
+                    toProgressGroup(progresses), eventTypeSet.toArray(EMPTY)
             );
         }
 
@@ -715,7 +819,19 @@ public EventWatcher onWatch(EventListener eventListener, Event.Type... eventType
     private EventWatchCondition toEventWatchCondition() {
         final List<Filter> filters = new ArrayList<Filter>();
         for (final BuildingForClass bfClass : bfClasses) {
-            final Filter filter = new Filter() {
+
+            final Filter filter = new IdentifiedConditionalFilter() {
+
+                @Override
+                public boolean hasClassIdentity() {
+                    return true;
+                }
+
+                @Override
+                public String getClassIdentity() {
+                    return bfClass.toClassSignature();
+                }
+
                 @Override
                 public boolean doClassFilter(final int access,
                                              final String javaClassName,
@@ -770,7 +886,9 @@ private Filter makeExtFilter(final Filter filter,
         return ExtFilter.ExtFilterFactory.make(
                 filter,
                 bfClass.isIncludeSubClasses,
-                bfClass.isIncludeBootstrap
+                bfClass.isIncludeBootstrap,
+                bfClass.hasInterfaceTypes.isEmpty(),
+                bfClass.hasAnnotationTypes.isEmpty()
         );
     }
 
@@ -784,11 +902,19 @@ private ProgressGroup toProgressGroup(final List<Progress> progresses) {
     private EventWatcher build(final EventListener listener,
                                final Progress progress,
                                final Event.Type... eventTypes) {
+        return build(listener, progress, false, eventTypes);
+    }
+
+    private EventWatcher build(final EventListener listener,
+                               final Progress progress,
+                               final boolean lazyReload,
+                               final Event.Type... eventTypes) {
 
         final int watchId = moduleEventWatcher.watch(
                 toEventWatchCondition(),
                 listener,
                 progress,
+                lazyReload,
                 eventTypes
         );
 
@@ -865,6 +991,10 @@ private class PatternGroupList {
 
         final List<Group> groups = new ArrayList<Group>();
 
+        boolean isEmpty() {
+            return groups.isEmpty();
+        }
+
         /*
          * 添加模式匹配组
          */
@@ -982,4 +1112,7 @@ boolean matchingWith(final String[] stringArray) {
 
     }
 
+    public interface IdentifiedConditionalFilter extends Filter, ClassIdentifiable {
+    }
+
 }
diff --git a/sandbox-api/src/main/java/com/alibaba/jvm/sandbox/api/listener/ext/WatchIdHolder.java b/sandbox-api/src/main/java/com/alibaba/jvm/sandbox/api/listener/ext/WatchIdHolder.java
new file mode 100644
index 00000000..3572fce0
--- /dev/null
+++ b/sandbox-api/src/main/java/com/alibaba/jvm/sandbox/api/listener/ext/WatchIdHolder.java
@@ -0,0 +1,45 @@
+package com.alibaba.jvm.sandbox.api.listener.ext;
+
+import java.util.Collection;
+import java.util.Set;
+import java.util.concurrent.ConcurrentSkipListSet;
+
+/**
+ * {@link WatchIdHolder} for lazy init.
+ *
+ * @author <a href="mailto:renyi.cry@alibaba-inc.com">renyi.cry<a/>
+ * @date 2020/11/16 10:37 上午
+ */
+public abstract class WatchIdHolder {
+
+    private final static Set<Integer> finishedWatchIds = new ConcurrentSkipListSet<Integer>();
+
+    private final static Set<Integer> waitingWatchIds = new ConcurrentSkipListSet<Integer>();
+
+    public static void addWaitingWatchId(Integer watchId) {
+        waitingWatchIds.add(watchId);
+    }
+
+    public static void addWaitingWatchIds(Collection<Integer> watchIds) {
+        waitingWatchIds.addAll(watchIds);
+    }
+
+    public static void finish(Integer watchId) {
+        if (waitingWatchIds.remove(watchId)) {
+            finishedWatchIds.add(watchId);
+        }
+    }
+
+    public static boolean hasUnfinishedWatchId() {
+        return !waitingWatchIds.isEmpty();
+    }
+
+    public static Set<Integer> getWaitingWatchIds() {
+        return waitingWatchIds;
+    }
+
+    public static Set<Integer> getFinishedWatchIds() {
+        return finishedWatchIds;
+    }
+
+}
diff --git a/sandbox-api/src/main/java/com/alibaba/jvm/sandbox/api/resource/ModuleEventWatcher.java b/sandbox-api/src/main/java/com/alibaba/jvm/sandbox/api/resource/ModuleEventWatcher.java
index 085b9939..24caa752 100755
--- a/sandbox-api/src/main/java/com/alibaba/jvm/sandbox/api/resource/ModuleEventWatcher.java
+++ b/sandbox-api/src/main/java/com/alibaba/jvm/sandbox/api/resource/ModuleEventWatcher.java
@@ -37,6 +37,12 @@ public interface ModuleEventWatcher {
      */
     int watch(Filter filter, EventListener listener, Event.Type... eventType);
 
+    int watch(Filter filter,
+              EventListener listener,
+              Progress progress,
+              boolean lazyReload,
+              Event.Type... eventType);
+
     /**
      * 观察事件
      *
@@ -50,6 +56,21 @@ public interface ModuleEventWatcher {
      */
     int watch(EventWatchCondition condition, EventListener listener, Progress progress, Event.Type... eventType);
 
+    /**
+     * 观察事件
+     *
+     * @param condition 事件观察条件，只有符合条件的类/方法才会被观察
+     * @param listener  事件监听器
+     *                  观察到的事件将会告知此事件监听器
+     * @param progress  观察渲染进度报告
+     * @param lazyReload 异步懒加载，不阻塞主线程，同时可以通过注入节点合并优化相同类的注入点注入
+     * @param eventType 观察事件类型
+     * @return {@code watchId}，本次观察的唯一编号，{@code watcherId}对象将会是整个操作的唯一KEY，后续删除观察事件的时候也需要通过同一个{@code watcherId}来完成
+     * @since {@code sandbox-api:1.0.10}
+     */
+    int watch(EventWatchCondition condition, EventListener listener, Progress progress, boolean lazyReload, Event.Type... eventType);
+
+
     /**
      * 删除观察事件
      *
diff --git a/sandbox-api/src/main/java/com/alibaba/jvm/sandbox/api/util/SandboxProtector.java b/sandbox-api/src/main/java/com/alibaba/jvm/sandbox/api/util/SandboxProtector.java
new file mode 100644
index 00000000..596c26e3
--- /dev/null
+++ b/sandbox-api/src/main/java/com/alibaba/jvm/sandbox/api/util/SandboxProtector.java
@@ -0,0 +1,69 @@
+package com.alibaba.jvm.sandbox.api.util;
+
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Sandbox守护者
+ * <p>
+ * 用来保护sandbox的操作所产生的事件不被响应
+ * </p>
+ *
+ * @author oldmanpushcart@gamil.com
+ */
+public interface SandboxProtector {
+
+    /**
+     * 进入守护区域
+     *
+     * @return 守护区域当前引用计数
+     */
+    int enterProtecting();
+
+    /**
+     * 离开守护区域
+     *
+     * @return 守护区域当前引用计数
+     */
+    int exitProtecting();
+
+    /**
+     * 守护接口定义的所有方法
+     *
+     * @param protectTargetInterface 保护目标接口类型
+     * @param protectTarget          保护目标接口实现
+     * @param <T>                    接口类型
+     * @return 被保护的目标接口实现
+     */
+    <T> T protectProxy(final Class<T> protectTargetInterface, final T protectTarget);
+
+    /**
+     * 判断当前是否处于守护区域中
+     *
+     * @return TRUE:在守护区域中；FALSE：非守护区域中
+     */
+    boolean isInProtecting();
+
+    class SandboxProtectors {
+
+        private static AtomicReference<SandboxProtector> sandboxProtectors = new AtomicReference<SandboxProtector>();
+
+        public static void prepare(SandboxProtector sandboxProtector) {
+            sandboxProtectors.weakCompareAndSet(null, sandboxProtector);
+        }
+
+        /**
+         * Force to reset instance. DO NOT USE THIS METHOD IF NO NECESSARY.
+         *
+         * @param sandboxProtector
+         */
+        public static void force2resetInstance(SandboxProtector sandboxProtector) {
+            sandboxProtectors.set(sandboxProtector);
+        }
+
+        public static SandboxProtector getInstance() {
+            return sandboxProtectors.get();
+        }
+
+    }
+
+}
diff --git a/sandbox-api/src/main/java/com/alibaba/jvm/sandbox/api/util/StopAllSandboxProtector.java b/sandbox-api/src/main/java/com/alibaba/jvm/sandbox/api/util/StopAllSandboxProtector.java
new file mode 100644
index 00000000..8f0308a0
--- /dev/null
+++ b/sandbox-api/src/main/java/com/alibaba/jvm/sandbox/api/util/StopAllSandboxProtector.java
@@ -0,0 +1,46 @@
+package com.alibaba.jvm.sandbox.api.util;
+
+/**
+ * A protector that do not allow any events, which is useful to enhance the perfomance when initializing as:
+ *
+ * <code>
+ *         SandboxProtector currentProtector = SandboxProtector.SandboxProtectors.getInstance();
+ *         SandboxProtector stopAllSandboxProtector = new StopAllSandboxProtector();
+ *         SandboxProtector.SandboxProtectors.force2resetInstance(stopAllSandboxProtector);
+ *         try {
+ *             initialize();
+ *         } finally {
+ *             SandboxProtector.SandboxProtectors.force2resetInstance(currentProtector);
+ *         }
+ * </code>
+ *
+ * @author <a href="mailto:renyi.cry@alibaba-inc.com">renyi.cry<a/>
+ * @date 2020/11/6 4:37 下午
+ */
+public class StopAllSandboxProtector implements SandboxProtector {
+
+
+    public StopAllSandboxProtector() {
+    }
+
+    @Override
+    public int enterProtecting() {
+        return 0;
+    }
+
+    @Override
+    public int exitProtecting() {
+        return 0;
+    }
+
+    @Override
+    public <T> T protectProxy(Class<T> protectTargetInterface, final T protectTarget) {
+        return protectTarget;
+    }
+
+    @Override
+    public boolean isInProtecting() {
+        return true;
+    }
+
+}
diff --git a/sandbox-benchmark/pom.xml b/sandbox-benchmark/pom.xml
new file mode 100644
index 00000000..c8d8ded1
--- /dev/null
+++ b/sandbox-benchmark/pom.xml
@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+         xmlns="http://maven.apache.org/POM/4.0.0">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.alibaba.jvm.sandbox</groupId>
+        <artifactId>sandbox-module-starter</artifactId>
+        <version>1.3.3</version>
+        <relativePath>../sandbox-module-starter/pom.xml</relativePath>
+    </parent>
+    <artifactId>sandbox-benchmark</artifactId>
+    <name>sandbox-benchmark ${sandbox.version}</name>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+            <version>1.7.24</version>
+        </dependency>
+        <dependency>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
+            <version>1.2.1</version>
+        </dependency>
+
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.powermock</groupId>
+            <artifactId>powermock-api-mockito</artifactId>
+            <version>1.7.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.powermock</groupId>
+            <artifactId>powermock-module-junit4</artifactId>
+            <version>1.7.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>net.bytebuddy</groupId>
+            <artifactId>byte-buddy-agent</artifactId>
+            <version>1.9.10</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.hamcrest</groupId>
+            <artifactId>hamcrest-all</artifactId>
+            <version>1.3</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.alibaba.jvm.sandbox</groupId>
+            <artifactId>sandbox-core</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.alibaba.jvm.sandbox</groupId>
+            <artifactId>sandbox-spy</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>com.alibaba.jvm.sandbox</groupId>
+            <artifactId>sandbox-test</artifactId>
+        </dependency>
+
+
+        <dependency>
+            <groupId>org.openjdk.jmh</groupId>
+            <artifactId>jmh-core</artifactId>
+            <version>1.26</version>
+        </dependency>
+        <dependency>
+            <groupId>org.openjdk.jmh</groupId>
+            <artifactId>jmh-generator-annprocess</artifactId>
+            <version>1.26</version>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>3.8.0</version>
+                <configuration>
+                    <source>1.7</source>
+                    <target>1.7</target>
+                    <encoding>UTF-8</encoding>
+                    <showDeprecation>true</showDeprecation>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-deploy-plugin</artifactId>
+                <configuration>
+                    <skip>true</skip>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <forkMode>once</forkMode>
+                    <argLine>-Xbootclasspath/p:./src/test/resources/lib/sandbox-spy-1.3.3-for-qatest.jar</argLine>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>cobertura-maven-plugin</artifactId>
+                <configuration>
+                    <skip>true</skip>
+                    <check/>
+                </configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>cobertura</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+
+    </build>
+
+</project>
diff --git a/sandbox-core/pom.xml b/sandbox-core/pom.xml
index de1cd4ec..9619e14d 100644
--- a/sandbox-core/pom.xml
+++ b/sandbox-core/pom.xml
@@ -61,6 +61,14 @@
                     <argLine>-Xbootclasspath/p:./src/test/resources/lib/sandbox-spy-1.3.0-for-qatest.jar</argLine>
                 </configuration>
             </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>7</source>
+                    <target>7</target>
+                </configuration>
+            </plugin>
         </plugins>
     </build>
 
@@ -80,6 +88,12 @@
             <systemPath>${tools-jar}</systemPath>
         </dependency>
 
+        <dependency>
+            <groupId>com.lmax</groupId>
+            <artifactId>disruptor</artifactId>
+            <version>3.4.2</version>
+        </dependency>
+
         <dependency>
             <groupId>javax.servlet</groupId>
             <artifactId>javax.servlet-api</artifactId>
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
index e60faa52..f2d3c03c 100644
--- 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
@@ -34,7 +34,7 @@ public JvmSandbox(final CoreConfigure cfg,
                       final Instrumentation inst) {
         EventListenerHandler.getSingleton();
         this.cfg = cfg;
-        this.coreModuleManager = SandboxProtector.instance.protectProxy(CoreModuleManager.class, new DefaultCoreModuleManager(
+        this.coreModuleManager = SandboxProtector.getOrCreateInstance().protectProxy(CoreModuleManager.class, new DefaultCoreModuleManager(
                 cfg,
                 inst,
                 new DefaultCoreLoadedClassDataSource(inst, cfg.isEnableUnsafe()),
diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/enhance/weaver/EventListenerHandler.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/enhance/weaver/EventListenerHandler.java
index 64036987..2bcc9cd7 100755
--- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/enhance/weaver/EventListenerHandler.java
+++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/enhance/weaver/EventListenerHandler.java
@@ -306,7 +306,7 @@ private boolean checkProcessStack(final int processId,
     public Spy.Ret handleOnBefore(int listenerId, int targetClassLoaderObjectID, Object[] argumentArray, String javaClassName, String javaMethodName, String javaMethodDesc, Object target) throws Throwable {
 
         // 在守护区内产生的事件不需要响应
-        if (SandboxProtector.instance.isInProtecting()) {
+        if (SandboxProtector.getOrCreateInstance().isInProtecting()) {
             logger.debug("listener={} is in protecting, ignore processing before-event", listenerId);
             return newInstanceForNone();
         }
@@ -380,7 +380,7 @@ private Spy.Ret handleOnEnd(final int listenerId,
                                 final boolean isReturn) throws Throwable {
 
         // 在守护区内产生的事件不需要响应
-        if (SandboxProtector.instance.isInProtecting()) {
+        if (SandboxProtector.getOrCreateInstance().isInProtecting()) {
             logger.debug("listener={} is in protecting, ignore processing {}-event", listenerId, isReturn ? "return" : "throws");
             return newInstanceForNone();
         }
@@ -446,7 +446,7 @@ private Spy.Ret handleOnEnd(final int listenerId,
     public void handleOnCallBefore(int listenerId, int lineNumber, String owner, String name, String desc) throws Throwable {
 
         // 在守护区内产生的事件不需要响应
-        if (SandboxProtector.instance.isInProtecting()) {
+        if (SandboxProtector.getOrCreateInstance().isInProtecting()) {
             logger.debug("listener={} is in protecting, ignore processing call-before-event", listenerId);
             return;
         }
@@ -490,7 +490,7 @@ public void handleOnCallBefore(int listenerId, int lineNumber, String owner, Str
     public void handleOnCallReturn(int listenerId) throws Throwable {
 
         // 在守护区内产生的事件不需要响应
-        if (SandboxProtector.instance.isInProtecting()) {
+        if (SandboxProtector.getOrCreateInstance().isInProtecting()) {
             logger.debug("listener={} is in protecting, ignore processing call-return-event", listenerId);
             return;
         }
@@ -528,7 +528,7 @@ public void handleOnCallReturn(int listenerId) throws Throwable {
     public void handleOnCallThrows(int listenerId, String throwException) throws Throwable {
 
         // 在守护区内产生的事件不需要响应
-        if (SandboxProtector.instance.isInProtecting()) {
+        if (SandboxProtector.getOrCreateInstance().isInProtecting()) {
             logger.debug("listener={} is in protecting, ignore processing call-throws-event", listenerId);
             return;
         }
@@ -566,7 +566,7 @@ public void handleOnCallThrows(int listenerId, String throwException) throws Thr
     public void handleOnLine(int listenerId, int lineNumber) throws Throwable {
 
         // 在守护区内产生的事件不需要响应
-        if (SandboxProtector.instance.isInProtecting()) {
+        if (SandboxProtector.getOrCreateInstance().isInProtecting()) {
             logger.debug("listener={} is in protecting, ignore processing call-line-event", listenerId);
             return;
         }
diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/enhance/weaver/asm/EventWeaver.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/enhance/weaver/asm/EventWeaver.java
index 1b43c5f9..71b50133 100755
--- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/enhance/weaver/asm/EventWeaver.java
+++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/enhance/weaver/asm/EventWeaver.java
@@ -10,7 +10,6 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.com.alibaba.jvm.sandbox.spy.Spy;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
@@ -18,7 +17,6 @@
 import static com.alibaba.jvm.sandbox.core.util.SandboxStringUtils.toInternalClassName;
 import static com.alibaba.jvm.sandbox.core.util.SandboxStringUtils.toJavaClassName;
 import static org.apache.commons.lang3.ArrayUtils.contains;
-import static org.apache.commons.lang3.ArrayUtils.subarray;
 import static org.apache.commons.lang3.StringUtils.join;
 
 /**
@@ -153,7 +151,7 @@ public MethodVisitor visitMethod(final int access, final String name, final Stri
         );
 
         if((access & Opcodes.ACC_NATIVE) != 0){
-            nativeMethodEnhanceAware.makrNativeMethodEnhance();
+            nativeMethodEnhanceAware.markNativeMethodEnhance();
             //native 方法插桩策略：
             //1.原始的native变为非native方法，并增加AOP式方法体
             //2.在AOP中增加调用wrapper后的native方法
diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/NativeMethodEnhanceAware.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/NativeMethodEnhanceAware.java
index a6d71ccc..d0ed406d 100644
--- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/NativeMethodEnhanceAware.java
+++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/NativeMethodEnhanceAware.java
@@ -14,5 +14,5 @@ public interface NativeMethodEnhanceAware {
      */
     String getNativeMethodPrefix();
 
-    void makrNativeMethodEnhance();
+    void markNativeMethodEnhance();
 }
diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/async/DisruptorExceptionHandler.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/async/DisruptorExceptionHandler.java
new file mode 100644
index 00000000..7ec10908
--- /dev/null
+++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/async/DisruptorExceptionHandler.java
@@ -0,0 +1,28 @@
+package com.alibaba.jvm.sandbox.core.manager.async;
+
+import com.lmax.disruptor.ExceptionHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author <a href="mailto:renyi.cry@alibaba-inc.com">renyi.cry<a/>
+ * @date 2020/6/10 11:46 上午
+ */
+public class DisruptorExceptionHandler implements ExceptionHandler<Object> {
+
+    private final Logger logger = LoggerFactory.getLogger(getClass());
+
+    @Override
+    public void handleEventException(Throwable ex, long sequence, Object event) {
+        logger.error(ex.getMessage(), ex);
+    }
+
+    @Override
+    public void handleOnStartException(Throwable ex) {
+    }
+
+    @Override
+    public void handleOnShutdownException(Throwable ex) {
+    }
+
+}
diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/async/TransformationEvent.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/async/TransformationEvent.java
new file mode 100644
index 00000000..2d681a79
--- /dev/null
+++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/async/TransformationEvent.java
@@ -0,0 +1,21 @@
+package com.alibaba.jvm.sandbox.core.manager.async;
+
+import com.alibaba.jvm.sandbox.core.manager.impl.DefaultModuleEventWatcher;
+
+/**
+ * @author <a href="mailto:renyi.cry@alibaba-inc.com">renyi.cry<a/>
+ * @date 2020/6/10 11:34 上午
+ */
+public class TransformationEvent extends TransformationQuintuple {
+
+    private DefaultModuleEventWatcher defaultModuleEventWatcher;
+
+    public DefaultModuleEventWatcher getDefaultModuleEventWatcher() {
+        return defaultModuleEventWatcher;
+    }
+
+    public void setDefaultModuleEventWatcher(DefaultModuleEventWatcher defaultModuleEventWatcher) {
+        this.defaultModuleEventWatcher = defaultModuleEventWatcher;
+    }
+
+}
diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/async/TransformationEventHandler.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/async/TransformationEventHandler.java
new file mode 100644
index 00000000..d7193a27
--- /dev/null
+++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/async/TransformationEventHandler.java
@@ -0,0 +1,154 @@
+package com.alibaba.jvm.sandbox.core.manager.async;
+
+import com.alibaba.jvm.sandbox.api.filter.ClassIdentifiable;
+import com.alibaba.jvm.sandbox.core.manager.impl.DefaultModuleEventWatcher;
+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.inner.BehaviorMatcher;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.lmax.disruptor.EventHandler;
+import com.lmax.disruptor.WorkHandler;
+import org.apache.commons.lang3.RandomStringUtils;
+
+import java.util.*;
+import java.util.concurrent.ArrayBlockingQueue;
+
+/**
+ * Handling {@link TransformationEvent} than report
+ *
+ * @author <a href="mailto:renyi.cry@alibaba-inc.com">renyi.cry<a/>
+ * @date 2020/6/10 11:35 上午
+ */
+public class TransformationEventHandler implements EventHandler<TransformationEvent>, WorkHandler<TransformationEvent> {
+
+    private static Map<String, List<TransformationEvent>> transformationEventMap = Maps.newLinkedHashMap();
+
+    private static final Queue<Map<String, List<TransformationEvent>>> QUEUE = new ArrayBlockingQueue<>(300);
+
+    @Override
+    public void onEvent(TransformationEvent event, long sequence, boolean endOfBatch) throws Exception {
+
+        offer(event);
+
+        // keep balance
+//        if (transformationEventMap.size() >= 2) {
+//            Map<String, List<TransformationEvent>> transformationEvents = take(20);
+//            QUEUE.offer(transformationEvents);
+//        }
+
+        if (endOfBatch) {
+            Map<String, List<TransformationEvent>> transformationEvents = takeAll();
+            QUEUE.offer(transformationEvents);
+        }
+
+
+    }
+
+    @Override
+    public void onEvent(TransformationEvent event) throws Exception {
+
+        // if it is the end of batch, compute all of them
+        Map<String, List<TransformationEvent>> transformationEvents = QUEUE.poll();
+
+        if (transformationEvents == null || event.getDefaultModuleEventWatcher() == null) {
+            return;
+        }
+
+        DefaultModuleEventWatcher eventWatcher = event.getDefaultModuleEventWatcher();
+
+        for (Map.Entry<String, List<TransformationEvent>> entry : transformationEvents.entrySet()) {
+            List<TransformationEvent> transformationEventList = entry.getValue();
+            Matcher matcher = transformationEventList.get(0).getMatcher();
+
+            // if it is a ExtFilterMatcher, just merge them
+            if (matcher instanceof ExtFilterMatcher) {
+                ExtFilterMatcher theMatcher = (ExtFilterMatcher) matcher;
+                List<BehaviorMatcher> behaviorMatchers = Lists.newArrayList();
+                for (TransformationEvent transformationEvent : transformationEventList) {
+                    behaviorMatchers.addAll(((ExtFilterMatcher) transformationEvent.getMatcher()).getBehaviorMatchers());
+                }
+                ExtFilterMatcher extFilterMatcher = new ExtFilterMatcher(theMatcher, behaviorMatchers);
+                eventWatcher.batchTransform(extFilterMatcher, transformationEventList);
+            } else {// else just transform one by one
+                for (TransformationEvent transformationEvent : transformationEventList) {
+                    eventWatcher.batchTransform(transformationEvent.getMatcher(), transformationEventList);
+                }
+            }
+        }
+
+    }
+
+
+    private boolean offer(TransformationEvent transformationEvent) {
+
+        if (transformationEvent == null) {
+            return false;
+        }
+
+        Matcher matcher = transformationEvent.getMatcher();
+
+        if (matcher == null) {
+            return false;
+        }
+
+        if (!(matcher instanceof ClassIdentifiable)) {
+            offer(RandomStringUtils.random(10, true, true), transformationEvent);
+            return true;
+        }
+
+        String classIdentity = ((ClassIdentifiable) matcher).getClassIdentity();
+
+        if (classIdentity == null) {
+            return false;
+        }
+
+        offer(classIdentity, transformationEvent);
+
+        return true;
+    }
+
+    private void offer(String classIdentity, TransformationEvent transformationEvent) {
+        // put if absent
+        if (!transformationEventMap.containsKey(classIdentity)) {
+            transformationEventMap.put(classIdentity, Lists.newArrayList(transformationEvent));
+        } else {
+            transformationEventMap.get(classIdentity).add(transformationEvent);
+        }
+    }
+
+    private Map<String, List<TransformationEvent>> take(int n) {
+
+        if (transformationEventMap.size() <= n) {
+            return takeAll();
+        }
+
+        Map<String, List<TransformationEvent>> copy = Maps.newHashMap();
+        Iterator<Map.Entry<String, List<TransformationEvent>>> iterator = transformationEventMap.entrySet().iterator();
+
+        int count = 0;
+        while (iterator.hasNext()) {
+            Map.Entry<String, List<TransformationEvent>> entry = iterator.next();
+            copy.put(entry.getKey(), entry.getValue());
+            iterator.remove();
+            if (++count >= n) {
+                break;
+            }
+        }
+
+        return copy;
+
+    }
+
+    private synchronized Map<String, List<TransformationEvent>> takeAll() {
+
+        Map<String, List<TransformationEvent>> copy = new HashMap<>(transformationEventMap);
+
+        transformationEventMap.clear();
+
+        return copy;
+
+    }
+
+
+}
diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/async/TransformationManager.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/async/TransformationManager.java
new file mode 100644
index 00000000..3eb30520
--- /dev/null
+++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/async/TransformationManager.java
@@ -0,0 +1,133 @@
+package com.alibaba.jvm.sandbox.core.manager.async;
+
+import com.alibaba.jvm.sandbox.api.event.Event;
+import com.alibaba.jvm.sandbox.api.listener.EventListener;
+import com.alibaba.jvm.sandbox.api.resource.ModuleEventWatcher;
+import com.alibaba.jvm.sandbox.core.manager.impl.DefaultModuleEventWatcher;
+import com.alibaba.jvm.sandbox.core.util.matcher.Matcher;
+import com.lmax.disruptor.EventFactory;
+import com.lmax.disruptor.RingBuffer;
+import com.lmax.disruptor.SleepingWaitStrategy;
+import com.lmax.disruptor.dsl.Disruptor;
+import com.lmax.disruptor.dsl.ProducerType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * @author <a href="mailto:renyi.cry@alibaba-inc.com">renyi.cry<a/>
+ * @date 2020/6/10 3:26 下午
+ */
+public class TransformationManager {
+
+    private final Logger logger = LoggerFactory.getLogger(getClass());
+
+    private static final int MAX_QUEUE_SIZE = 512;
+
+    private Disruptor<TransformationEvent> disruptor;
+
+    private static TransformationManager instance;
+
+    public static TransformationManager getInstance() {
+
+        if (instance == null) {
+            synchronized (TransformationManager.class) {
+                if (instance == null) {
+                    instance = new TransformationManager();
+                }
+            }
+        }
+
+        return instance;
+    }
+
+    private TransformationManager() {
+        init();
+    }
+
+    private void init() {
+
+        logger.info("On initializing transformation disruptor...");
+
+        ThreadFactory threadFactory = new ThreadFactory() {
+
+            private final AtomicInteger threadNumber = new AtomicInteger(1);
+
+            public Thread newThread(Runnable r) {
+                Thread t = new Thread(r, "Handling transformation event - " + threadNumber.getAndIncrement());
+                if (t.isDaemon()) {
+                    t.setDaemon(true);
+                }
+                if (t.getPriority() != Thread.NORM_PRIORITY) {
+                    t.setPriority(Thread.NORM_PRIORITY);
+                }
+                return t;
+            }
+
+        };
+
+        EventFactory<TransformationEvent> factory = new EventFactory<TransformationEvent>() {
+            @Override
+            public TransformationEvent newInstance() {
+                return new TransformationEvent();
+            }
+        };
+
+        // park for 1 minute
+        SleepingWaitStrategy sleepingWaitStrategy = new SleepingWaitStrategy(0, TimeUnit.MILLISECONDS.toNanos(1L));
+
+        // only one thread could be used
+        this.disruptor = new Disruptor<>(factory, MAX_QUEUE_SIZE, threadFactory, ProducerType.MULTI, sleepingWaitStrategy);
+
+        TransformationEventHandler transformationEventHandler = new TransformationEventHandler();
+
+        this.disruptor.handleEventsWith(transformationEventHandler)
+                .thenHandleEventsWithWorkerPool(transformationEventHandler, transformationEventHandler, transformationEventHandler, transformationEventHandler);
+
+        this.disruptor.setDefaultExceptionHandler(new DisruptorExceptionHandler());
+
+        this.disruptor.start();
+
+        logger.info("Disruptor for transformation is running...");
+
+    }
+
+    public void onData(int watchId,
+                       Matcher matcher,
+                       EventListener listener,
+                       ModuleEventWatcher.Progress progress,
+                       Event.Type[] eventType,
+                       DefaultModuleEventWatcher eventWatcher) {
+
+        RingBuffer<TransformationEvent> ringBuffer = disruptor.getRingBuffer();
+
+        long sequence = ringBuffer.next();
+
+        try {
+            TransformationEvent transformationEvent = ringBuffer.get(sequence);
+            transformationEvent.setWatchId(watchId);
+            transformationEvent.setMatcher(matcher);
+            transformationEvent.setListener(listener);
+            transformationEvent.setProgress(progress);
+            transformationEvent.setEventTypes(eventType);
+            transformationEvent.setDefaultModuleEventWatcher(eventWatcher);
+        } finally {
+            ringBuffer.publish(sequence);
+        }
+    }
+
+    public void halt() {
+        this.disruptor.halt();
+    }
+
+    public void shutdown() {
+        this.disruptor.shutdown();
+    }
+
+    public Disruptor<TransformationEvent> getDisruptor() {
+        return disruptor;
+    }
+
+}
diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/async/TransformationQuintuple.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/async/TransformationQuintuple.java
new file mode 100644
index 00000000..90d5b4f2
--- /dev/null
+++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/async/TransformationQuintuple.java
@@ -0,0 +1,61 @@
+package com.alibaba.jvm.sandbox.core.manager.async;
+
+import com.alibaba.jvm.sandbox.api.event.Event;
+import com.alibaba.jvm.sandbox.api.listener.EventListener;
+import com.alibaba.jvm.sandbox.api.resource.ModuleEventWatcher;
+import com.alibaba.jvm.sandbox.core.util.matcher.Matcher;
+
+/**
+ * Quintuple for event watching probe
+ *
+ * @author <a href="mailto:renyi.cry@alibaba-inc.com">renyi.cry<a/>
+ * @date 2020/11/11 4:34 下午
+ */
+public class TransformationQuintuple {
+
+    private int watchId;
+    private Matcher matcher;
+    private EventListener listener;
+    private ModuleEventWatcher.Progress progress;
+    private Event.Type[] eventTypes;
+
+    public int getWatchId() {
+        return watchId;
+    }
+
+    public void setWatchId(int watchId) {
+        this.watchId = watchId;
+    }
+
+    public Matcher getMatcher() {
+        return matcher;
+    }
+
+    public void setMatcher(Matcher matcher) {
+        this.matcher = matcher;
+    }
+
+    public EventListener getListener() {
+        return listener;
+    }
+
+    public void setListener(EventListener listener) {
+        this.listener = listener;
+    }
+
+    public ModuleEventWatcher.Progress getProgress() {
+        return progress;
+    }
+
+    public void setProgress(ModuleEventWatcher.Progress progress) {
+        this.progress = progress;
+    }
+
+    public Event.Type[] getEventTypes() {
+        return eventTypes;
+    }
+
+    public void setEventTypes(Event.Type[] eventTypes) {
+        this.eventTypes = eventTypes;
+    }
+}
diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/DefaultCoreLoadedClassDataSource.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/DefaultCoreLoadedClassDataSource.java
index 516cc560..3439b4cb 100644
--- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/DefaultCoreLoadedClassDataSource.java
+++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/DefaultCoreLoadedClassDataSource.java
@@ -2,6 +2,7 @@
 
 import com.alibaba.jvm.sandbox.api.filter.Filter;
 import com.alibaba.jvm.sandbox.core.manager.CoreLoadedClassDataSource;
+import com.alibaba.jvm.sandbox.core.util.SandboxClassUtils;
 import com.alibaba.jvm.sandbox.core.util.SandboxProtector;
 import com.alibaba.jvm.sandbox.core.util.matcher.ExtFilterMatcher;
 import com.alibaba.jvm.sandbox.core.util.matcher.Matcher;
@@ -73,35 +74,32 @@ public List<Class<?>> findForReTransform(final Matcher matcher) {
         return find(matcher, true);
     }
 
-    private List<Class<?>> find(final Matcher matcher,
-                                final boolean isRemoveUnsupported) {
+    private List<Class<?>> find(final Matcher matcher, final boolean isRemoveUnsupported) {
+
+        SandboxProtector.getOrCreateInstance().enterProtecting();
 
-        SandboxProtector.instance.enterProtecting();
         try {
 
             final List<Class<?>> classes = new ArrayList<Class<?>>();
-            if (null == matcher) {
-                return classes;
-            }
 
-            final Iterator<Class<?>> itForLoaded = iteratorForLoadedClasses();
-            while (itForLoaded.hasNext()) {
-                final Class<?> clazz = itForLoaded.next();
+            // 大量计算部分，需要非常小心处理性能问题，能不计算就不计算
+            for (Class clazz : inst.getAllLoadedClasses()) {
+                String className = clazz.getName();
+                ClassLoader classLoader = clazz.getClassLoader();
 
                 // #242 的建议，过滤掉sandbox家族的类
-                if (isComeFromSandboxFamily(toInternalClassName(clazz.getName()), clazz.getClassLoader())) {
+                if (SandboxClassUtils.startWithCom(className) && isComeFromSandboxFamily(toInternalClassName(className), classLoader)) {
                     continue;
                 }
 
                 // 过滤掉对于JVM认为不可修改的类
-                if (isRemoveUnsupported
-                        && !inst.isModifiableClass(clazz)) {
+                if (isRemoveUnsupported && !inst.isModifiableClass(clazz)) {
                     // logger.debug("remove from findForReTransform, because class:{} is unModifiable", clazz.getName());
                     continue;
                 }
                 try {
                     if (isRemoveUnsupported) {
-                        if (new UnsupportedMatcher(clazz.getClassLoader(), isEnableUnsafe)
+                        if (new UnsupportedMatcher(classLoader, isEnableUnsafe)
                                 .and(matcher)
                                 .matching(ClassStructureFactory.createClassStructure(clazz))
                                 .isMatched()) {
@@ -113,6 +111,7 @@ private List<Class<?>> find(final Matcher matcher,
                         }
                     }
 
+
                 } catch (Throwable cause) {
                     // 在这里可能会遇到非常坑爹的模块卸载错误
                     // 当一个URLClassLoader被动态关闭之后，但JVM已经加载的类并不知情（因为没有GC）
@@ -122,10 +121,11 @@ private List<Class<?>> find(final Matcher matcher,
                     logger.debug("remove from findForReTransform, because loading class:{} occur an exception", clazz.getName(), cause);
                 }
             }
+
             return classes;
 
         } finally {
-            SandboxProtector.instance.exitProtecting();
+            SandboxProtector.getOrCreateInstance().exitProtecting();
         }
 
     }
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 8746d718..16bbfda3 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
@@ -214,7 +214,7 @@ private void injectResourceOnLoadIfNecessary(final CoreModule coreModule) throws
                 else if (ModuleEventWatcher.class.isAssignableFrom(fieldType)) {
                     final ModuleEventWatcher moduleEventWatcher = coreModule.append(
                             new ReleaseResource<ModuleEventWatcher>(
-                                    SandboxProtector.instance.protectProxy(
+                                    SandboxProtector.getOrCreateInstance().protectProxy(
                                             ModuleEventWatcher.class,
                                             new DefaultModuleEventWatcher(inst, classDataSource, coreModule, cfg.isEnableUnsafe(), cfg.getNamespace())
                                     )
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 ea769784..d5b588f7 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
@@ -4,16 +4,19 @@
 import com.alibaba.jvm.sandbox.api.filter.Filter;
 import com.alibaba.jvm.sandbox.api.listener.EventListener;
 import com.alibaba.jvm.sandbox.api.listener.ext.EventWatchCondition;
+import com.alibaba.jvm.sandbox.api.listener.ext.WatchIdHolder;
 import com.alibaba.jvm.sandbox.api.resource.ModuleEventWatcher;
 import com.alibaba.jvm.sandbox.core.CoreModule;
 import com.alibaba.jvm.sandbox.core.enhance.weaver.EventListenerHandler;
 import com.alibaba.jvm.sandbox.core.manager.CoreLoadedClassDataSource;
+import com.alibaba.jvm.sandbox.core.manager.async.TransformationManager;
+import com.alibaba.jvm.sandbox.core.manager.async.TransformationQuintuple;
+import com.alibaba.jvm.sandbox.core.util.SandboxProtector;
 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;
 import com.alibaba.jvm.sandbox.core.util.matcher.Matcher;
 import org.apache.commons.collections.CollectionUtils;
-import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -40,6 +43,7 @@ public class DefaultModuleEventWatcher implements ModuleEventWatcher {
     private final CoreModule coreModule;
     private final boolean isEnableUnsafe;
     private final String namespace;
+    private final TransformationManager transformationManager;
 
     // 观察ID序列生成器
     private final Sequencer watchIdSequencer = new Sequencer();
@@ -54,6 +58,7 @@ public class DefaultModuleEventWatcher implements ModuleEventWatcher {
         this.coreModule = coreModule;
         this.isEnableUnsafe = isEnableUnsafe;
         this.namespace = namespace;
+        this.transformationManager = TransformationManager.getInstance();
     }
 
 
@@ -159,12 +164,46 @@ public int watch(final Filter filter,
         return watch(new ExtFilterMatcher(make(filter)), listener, progress, eventType);
     }
 
+    @Override
+    public int watch(final Filter filter,
+                     final EventListener listener,
+                     final Progress progress,
+                     final boolean lazyReload,
+                     final Event.Type... eventType) {
+        return watch(new ExtFilterMatcher(make(filter)), listener, progress, lazyReload, eventType);
+    }
+
     @Override
     public int watch(final EventWatchCondition condition,
                      final EventListener listener,
                      final Progress progress,
                      final Event.Type... eventType) {
-        return watch(toOrGroupMatcher(condition.getOrFilterArray()), listener, progress, eventType);
+
+        Filter[] orFilterArray = condition.getOrFilterArray();
+
+        if (orFilterArray.length == 1) {
+            return watch(orFilterArray[0], listener, progress, eventType);
+        }
+
+        return watch(toOrGroupMatcher(orFilterArray), listener, progress, eventType);
+
+    }
+
+    @Override
+    public int watch(EventWatchCondition condition,
+                     EventListener listener,
+                     Progress progress,
+                     boolean lazyReload,
+                     Event.Type... eventType) {
+
+        Filter[] orFilterArray = condition.getOrFilterArray();
+
+        if (orFilterArray.length == 1) {
+            return watch(orFilterArray[0], listener, progress, lazyReload, eventType);
+
+        }
+
+        return watch(toOrGroupMatcher(orFilterArray), listener, progress, lazyReload, eventType);
     }
 
     // 这里是用matcher重制过后的watch
@@ -172,13 +211,31 @@ private int watch(final Matcher matcher,
                       final EventListener listener,
                       final Progress progress,
                       final Event.Type... eventType) {
+        return watch(matcher, listener, progress, false, eventType);
+    }
+
+    // 这里是用matcher重制过后的watch
+    private int watch(final Matcher matcher,
+                      final EventListener listener,
+                      final Progress progress,
+                      boolean lazyReload,
+                      final Event.Type... eventType) {
+
         final int watchId = watchIdSequencer.next();
+
+        WatchIdHolder.addWaitingWatchId(watchId);
         // 给对应的模块追加ClassFileTransformer
         final SandboxClassFileTransformer sandClassFileTransformer = new SandboxClassFileTransformer(inst,
                 watchId, coreModule.getUniqueId(), matcher, listener, isEnableUnsafe, eventType, namespace);
 
-        // 注册到CoreModule中
-        coreModule.getSandboxClassFileTransformers().add(sandClassFileTransformer);
+        // 这里添加一下懒加载
+        if (lazyReload) {
+
+            transformationManager.onData(watchId, matcher, listener, progress, eventType, this);
+
+            return watchId;
+        }
+
 
         //这里addTransformer后，接下来引起的类加载都会经过sandClassFileTransformer
         inst.addTransformer(sandClassFileTransformer, true);
@@ -190,29 +247,7 @@ private int watch(final Matcher matcher,
                 waitingReTransformClasses.size()
         );
 
-        int cCnt = 0, mCnt = 0;
-
-        // 进度通知启动
-        beginProgress(progress, waitingReTransformClasses.size());
-        try {
-
-            // 应用JVM
-            reTransformClasses(watchId,waitingReTransformClasses, progress);
-            // 计数
-            cCnt += sandClassFileTransformer.getAffectStatistic().cCnt();
-            mCnt += sandClassFileTransformer.getAffectStatistic().mCnt();
-
-
-            // 激活增强类
-            if (coreModule.isActivated()) {
-                final int listenerId = sandClassFileTransformer.getListenerId();
-                EventListenerHandler.getSingleton()
-                        .active(listenerId, listener, eventType);
-            }
-
-        } finally {
-            finishProgress(progress, cCnt, mCnt);
-        }
+        _transform(watchId, matcher, listener, progress, waitingReTransformClasses, eventType);
 
         return watchId;
     }
@@ -269,6 +304,83 @@ public void delete(final int watcherId,
         }
     }
 
+    private void _transform(final int watchId,
+                            final Matcher matcher,
+                            final EventListener listener,
+                            final Progress progress,
+                            final List<Class<?>> waitingReTransformClasses,
+                            final Event.Type... eventType) {
+
+        SandboxProtector.getOrCreateInstance().enterProtecting();
+
+        try {
+
+            // 给对应的模块追加ClassFileTransformer
+            final SandboxClassFileTransformer sandClassFileTransformer = new SandboxClassFileTransformer(
+                    inst, watchId, coreModule.getUniqueId(), matcher, listener, isEnableUnsafe, eventType, namespace);
+
+            // 注册到CoreModule中
+            coreModule.getSandboxClassFileTransformers().add(sandClassFileTransformer);
+
+            //这里addTransformer后，接下来引起的类加载都会经过sandClassFileTransformer
+            inst.addTransformer(sandClassFileTransformer, true);
+            int cCnt = 0, mCnt = 0;
+
+            // 进度通知启动
+            beginProgress(progress, waitingReTransformClasses.size());
+            try {
+
+                // 应用JVM
+                reTransformClasses(watchId, waitingReTransformClasses, progress);
+
+                // 计数
+                cCnt += sandClassFileTransformer.getAffectStatistic().cCnt();
+                mCnt += sandClassFileTransformer.getAffectStatistic().mCnt();
+
+                // 激活增强类
+                if (coreModule.isActivated()) {
+                    final int listenerId = sandClassFileTransformer.getListenerId();
+                    EventListenerHandler.getSingleton().active(listenerId, listener, eventType);
+                }
+
+            } finally {
+                WatchIdHolder.finish(watchId);
+                finishProgress(progress, cCnt, mCnt);
+            }
+
+        } finally  {
+
+            SandboxProtector.getOrCreateInstance().exitProtecting();
+
+        }
+
+    }
+
+    public void batchTransform(final Matcher matcher,
+                               final List<? extends TransformationQuintuple> transformationQuintuples) {
+
+        // 查找需要渲染的类集合
+        final List<Class<?>> waitingReTransformClasses = classDataSource.findForReTransform(matcher);
+
+        for (TransformationQuintuple quintuple : transformationQuintuples) {
+
+            logger.info("Maybe watchId={} in module={} found {} classes for watch(ing).",
+                    quintuple.getWatchId(),
+                    coreModule.getUniqueId(),
+                    waitingReTransformClasses.size()
+            );
+
+            _transform(quintuple.getWatchId(),
+                    quintuple.getMatcher(),
+                    quintuple.getListener(),
+                    quintuple.getProgress(),
+                    waitingReTransformClasses,
+                    quintuple.getEventTypes());
+
+        }
+
+    }
+
     @Override
     public void delete(int watcherId) {
         delete(watcherId, null);
diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/SandboxClassFileTransformer.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/SandboxClassFileTransformer.java
index 25de9968..6b2e869a 100755
--- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/SandboxClassFileTransformer.java
+++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/SandboxClassFileTransformer.java
@@ -80,8 +80,8 @@ public byte[] transform(final ClassLoader loader,
                             final Class<?> classBeingRedefined,
                             final ProtectionDomain protectionDomain,
                             final byte[] srcByteCodeArray) {
+        SandboxProtector.getOrCreateInstance().enterProtecting();
 
-        SandboxProtector.instance.enterProtecting();
         try {
 
             // 这里过滤掉Sandbox所需要的类|来自SandboxClassLoader所加载的类|来自ModuleJarClassLoader加载的类
@@ -108,7 +108,7 @@ public byte[] transform(final ClassLoader loader,
             );
             return null;
         } finally {
-            SandboxProtector.instance.exitProtecting();
+            SandboxProtector.getOrCreateInstance().exitProtecting();
         }
     }
 
@@ -220,12 +220,12 @@ public String getNativeMethodPrefix() {
     }
 
     @Override
-    public void makrNativeMethodEnhance() {
+    public void markNativeMethodEnhance() {
         if(setNativeMethodPrefix.compareAndSet(false,true)){
             if(inst.isNativeMethodPrefixSupported()){
-                inst.setNativeMethodPrefix(this,getNativeMethodPrefix());
+                inst.setNativeMethodPrefix(this, getNativeMethodPrefix());
             }else{
-                throw new UnsupportedOperationException("Native Method Prefix Unspported");
+                throw new UnsupportedOperationException("Native Method Prefix Unsupported");
             }
         }
     }
diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/AccessUtils.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/AccessUtils.java
new file mode 100644
index 00000000..2d6e9a65
--- /dev/null
+++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/AccessUtils.java
@@ -0,0 +1,38 @@
+package com.alibaba.jvm.sandbox.core.util;
+
+import com.alibaba.jvm.sandbox.api.filter.AccessFlags;
+import com.alibaba.jvm.sandbox.core.util.matcher.structure.Access;
+
+import static com.alibaba.jvm.sandbox.api.filter.AccessFlags.*;
+import static com.alibaba.jvm.sandbox.api.filter.AccessFlags.ACF_ANNOTATION;
+
+/**
+ * Utilize for {@link Access}
+ *
+ * @author <a href="mailto:renyi.cry@alibaba-inc.com">renyi.cry<a/>
+ * @date 2020/11/9 1:17 上午
+ */
+public abstract class AccessUtils {
+
+    /**
+     * 转换为{@link AccessFlags}的Access体系
+     *
+     * @param access access flag
+     * @return 部分兼容ASM的access flag
+     */
+    public static int toFilterAccess(final Access access) {
+        int flag = 0;
+        if (access.isPublic()) flag |= ACF_PUBLIC;
+        if (access.isPrivate()) flag |= ACF_PRIVATE;
+        if (access.isProtected()) flag |= ACF_PROTECTED;
+        if (access.isStatic()) flag |= ACF_STATIC;
+        if (access.isFinal()) flag |= ACF_FINAL;
+        if (access.isInterface()) flag |= ACF_INTERFACE;
+        if (access.isNative()) flag |= ACF_NATIVE;
+        if (access.isAbstract()) flag |= ACF_ABSTRACT;
+        if (access.isEnum()) flag |= ACF_ENUM;
+        if (access.isAnnotation()) flag |= ACF_ANNOTATION;
+        return flag;
+    }
+
+}
diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/ClassStructureUtils.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/ClassStructureUtils.java
new file mode 100644
index 00000000..c857961f
--- /dev/null
+++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/ClassStructureUtils.java
@@ -0,0 +1,29 @@
+package com.alibaba.jvm.sandbox.core.util;
+
+
+import com.alibaba.jvm.sandbox.core.util.matcher.structure.ClassStructure;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Utilize for {@link ClassStructure}
+ *
+ * @author <a href="mailto:renyi.cry@alibaba-inc.com">renyi.cry<a/>
+ * @date 2020/11/9 1:19 上午
+ */
+public abstract class ClassStructureUtils {
+
+    public static String[] toJavaClassNameArray(final Collection<ClassStructure> classStructures) {
+        if (null == classStructures) {
+            return null;
+        }
+        final List<String> javaClassNames = new ArrayList<String>();
+        for (final ClassStructure classStructure : classStructures) {
+            javaClassNames.add(classStructure.getJavaClassName());
+        }
+        return javaClassNames.toArray(new String[0]);
+    }
+
+}
diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/SandboxClassUtils.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/SandboxClassUtils.java
index e6d02deb..ef2e354b 100644
--- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/SandboxClassUtils.java
+++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/SandboxClassUtils.java
@@ -3,11 +3,15 @@
 /**
  * Sandbox的类操作工具类
  */
-public class SandboxClassUtils {
+public abstract class SandboxClassUtils {
 
     private static final String SANDBOX_FAMILY_CLASS_RES_PREFIX = "com/alibaba/jvm/sandbox/";
     private static final String SANDBOX_FAMILY_CLASS_RES_QATEST_PREFIX = "com/alibaba/jvm/sandbox/qatest";
 
+    public static boolean startWithCom(final String className){
+        return className != null && className.startsWith("com");
+    }
+
     /**
      * 是否是SANDBOX家族所管理的类
      * <p>
@@ -50,7 +54,7 @@ && isSandboxPrefix(normalizeClass(loader.getClass().getName()))) {
      * @return 标准化类名
      */
     private static String normalizeClass(String className) {
-        return className.replace(".", "/");
+        return className.replace('.', '/');
     }
 
     /**
diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/SandboxProtector.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/SandboxProtector.java
index 77ff6674..ced73055 100644
--- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/SandboxProtector.java
+++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/SandboxProtector.java
@@ -6,7 +6,6 @@
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Method;
 import java.lang.reflect.Proxy;
-import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * Sandbox守护者
@@ -16,14 +15,14 @@
  *
  * @author oldmanpushcart@gamil.com
  */
-public class SandboxProtector {
+public class SandboxProtector implements com.alibaba.jvm.sandbox.api.util.SandboxProtector {
 
     private Logger logger = LoggerFactory.getLogger(getClass());
 
-    private final ThreadLocal<AtomicInteger> isInProtectingThreadLocal = new ThreadLocal<AtomicInteger>() {
+    private static final ThreadLocal<Integer> isInProtectingThreadLocal = new ThreadLocal<Integer>() {
         @Override
-        protected AtomicInteger initialValue() {
-            return new AtomicInteger(0);
+        protected Integer initialValue() {
+            return 0;
         }
     };
 
@@ -32,8 +31,10 @@ protected AtomicInteger initialValue() {
      *
      * @return 守护区域当前引用计数
      */
+    @Override
     public int enterProtecting() {
-        final int referenceCount = isInProtectingThreadLocal.get().getAndIncrement();
+        final int referenceCount = isInProtectingThreadLocal.get();
+        isInProtectingThreadLocal.set(referenceCount + 1);
         if (logger.isDebugEnabled()) {
             logger.debug("thread:{} enter protect:{}", Thread.currentThread(), referenceCount);
         }
@@ -45,11 +46,12 @@ public int enterProtecting() {
      *
      * @return 守护区域当前引用计数
      */
+    @Override
     public int exitProtecting() {
-        final int referenceCount = isInProtectingThreadLocal.get().decrementAndGet();
+        final int referenceCount = isInProtectingThreadLocal.get() - 1;
+        isInProtectingThreadLocal.set(referenceCount);
         assert referenceCount >= 0;
         if (referenceCount == 0) {
-            isInProtectingThreadLocal.remove();
             if (logger.isDebugEnabled()) {
                 logger.debug("thread:{} exit protect:{} with clean", Thread.currentThread(), referenceCount);
             }
@@ -68,8 +70,9 @@ public int exitProtecting() {
      *
      * @return TRUE:在守护区域中；FALSE：非守护区域中
      */
+    @Override
     public boolean isInProtecting() {
-        return isInProtectingThreadLocal.get().get() > 0;
+        return isInProtectingThreadLocal.get() > 0;
     }
 
     /**
@@ -80,6 +83,7 @@ public boolean isInProtecting() {
      * @param <T>                    接口类型
      * @return 被保护的目标接口实现
      */
+    @Override
     public <T> T protectProxy(final Class<T> protectTargetInterface,
                               final T protectTarget) {
         return (T) Proxy.newProxyInstance(getClass().getClassLoader(), new Class<?>[]{protectTargetInterface}, new InvocationHandler() {
@@ -109,6 +113,17 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl
     /**
      * Sandbox守护者单例
      */
-    public static final SandboxProtector instance = new SandboxProtector();
+    private static SandboxProtector instance;
 
+    public static com.alibaba.jvm.sandbox.api.util.SandboxProtector getOrCreateInstance() {
+        if (instance == null) {
+            synchronized (SandboxProtector.class) {
+                if (instance == null) {
+                    instance = new SandboxProtector();
+                    SandboxProtectors.prepare(instance);
+                }
+            }
+        }
+        return SandboxProtectors.getInstance();
+    }
 }
diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/SandboxStringUtils.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/SandboxStringUtils.java
index b6cea397..968a8c23 100644
--- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/SandboxStringUtils.java
+++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/SandboxStringUtils.java
@@ -23,7 +23,8 @@ public static String toInternalClassName(String javaClassName) {
         if (StringUtils.isEmpty(javaClassName)) {
             return javaClassName;
         }
-        return javaClassName.replace('.', '/');    }
+        return javaClassName.replace('.', '/');
+    }
 
     /**
      * internal's classname to java's classname
diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/SystemPropertyUtil.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/SystemPropertyUtil.java
deleted file mode 100644
index 545b66d9..00000000
--- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/SystemPropertyUtil.java
+++ /dev/null
@@ -1,181 +0,0 @@
-package com.alibaba.jvm.sandbox.core.util;
-
-/**
- *
- * copy from netty
- *
- * @author zhuangpeng
- * @since 2020/12/3
- */
-
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * A collection of utility methods to retrieve and parse the values of the Java system properties.
- */
-public final class SystemPropertyUtil {
-
-    private static final Logger logger = LoggerFactory.getLogger(SystemPropertyUtil.class);
-
-    /**
-     * Returns {@code true} if and only if the system property with the specified {@code key}
-     * exists.
-     */
-    public static boolean contains(String key) {
-        return get(key) != null;
-    }
-
-    /**
-     * Returns the value of the Java system property with the specified
-     * {@code key}, while falling back to {@code null} if the property access fails.
-     *
-     * @return the property value or {@code null}
-     */
-    public static String get(String key) {
-        return get(key, null);
-    }
-
-    /**
-     * Returns the value of the Java system property with the specified
-     * {@code key}, while falling back to the specified default value if
-     * the property access fails.
-     *
-     * @return the property value.
-     * {@code def} if there's no such property or if an access to the
-     * specified property is not allowed.
-     */
-    public static String get(final String key, String def) {
-        if (key == null) {
-            throw new NullPointerException("key");
-        }
-        if (key.isEmpty()) {
-            throw new IllegalArgumentException("key must not be empty.");
-        }
-
-        String value = null;
-        try {
-            if (System.getSecurityManager() == null) {
-                value = System.getProperty(key);
-            } else {
-                value = AccessController.doPrivileged(new PrivilegedAction<String>() {
-                    @Override
-                    public String run() {
-                        return System.getProperty(key);
-                    }
-                });
-            }
-        } catch (SecurityException e) {
-            logger.warn("Unable to retrieve a system property '{}'; default values will be used.", key, e);
-        }
-
-        if (value == null) {
-            return def;
-        }
-
-        return value;
-    }
-
-    /**
-     * Returns the value of the Java system property with the specified
-     * {@code key}, while falling back to the specified default value if
-     * the property access fails.
-     *
-     * @return the property value.
-     * {@code def} if there's no such property or if an access to the
-     * specified property is not allowed.
-     */
-    public static boolean getBoolean(String key, boolean def) {
-        String value = get(key);
-        if (value == null) {
-            return def;
-        }
-
-        value = value.trim().toLowerCase();
-        if (value.isEmpty()) {
-            return def;
-        }
-
-        if ("true".equals(value) || "yes".equals(value) || "1".equals(value)) {
-            return true;
-        }
-
-        if ("false".equals(value) || "no".equals(value) || "0".equals(value)) {
-            return false;
-        }
-
-        logger.warn(
-            "Unable to parse the boolean system property '{}':{} - using the default value: {}",
-            key, value, def
-        );
-
-        return def;
-    }
-
-    /**
-     * Returns the value of the Java system property with the specified
-     * {@code key}, while falling back to the specified default value if
-     * the property access fails.
-     *
-     * @return the property value.
-     * {@code def} if there's no such property or if an access to the
-     * specified property is not allowed.
-     */
-    public static int getInt(String key, int def) {
-        String value = get(key);
-        if (value == null) {
-            return def;
-        }
-
-        value = value.trim();
-        try {
-            return Integer.parseInt(value);
-        } catch (Exception e) {
-            // Ignore
-        }
-
-        logger.warn(
-            "Unable to parse the integer system property '{}':{} - using the default value: {}",
-            key, value, def
-        );
-
-        return def;
-    }
-
-    /**
-     * Returns the value of the Java system property with the specified
-     * {@code key}, while falling back to the specified default value if
-     * the property access fails.
-     *
-     * @return the property value.
-     * {@code def} if there's no such property or if an access to the
-     * specified property is not allowed.
-     */
-    public static long getLong(String key, long def) {
-        String value = get(key);
-        if (value == null) {
-            return def;
-        }
-
-        value = value.trim();
-        try {
-            return Long.parseLong(value);
-        } catch (Exception e) {
-            // Ignore
-        }
-
-        logger.warn(
-            "Unable to parse the long integer system property '{}':{} - using the default value: {}",
-            key, value, def
-        );
-
-        return def;
-    }
-
-    private SystemPropertyUtil() {
-        // Unused
-    }
-}
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 292b9a24..53817c86 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
@@ -1,20 +1,24 @@
 package com.alibaba.jvm.sandbox.core.util.matcher;
 
-import com.alibaba.jvm.sandbox.api.filter.AccessFlags;
 import com.alibaba.jvm.sandbox.api.filter.ExtFilter;
 import com.alibaba.jvm.sandbox.api.filter.ExtFilter.ExtFilterFactory;
 import com.alibaba.jvm.sandbox.api.filter.Filter;
 import com.alibaba.jvm.sandbox.api.listener.ext.EventWatchCondition;
-import com.alibaba.jvm.sandbox.core.util.matcher.structure.*;
+import com.alibaba.jvm.sandbox.core.util.matcher.inner.BehaviorExtFilterMatcher;
+import com.alibaba.jvm.sandbox.core.util.matcher.inner.BehaviorMatcher;
+import com.alibaba.jvm.sandbox.core.util.matcher.inner.ClassExtFilterMatcher;
+import com.alibaba.jvm.sandbox.core.util.matcher.inner.ClassMatcher;
+import com.alibaba.jvm.sandbox.core.util.matcher.structure.BehaviorStructure;
+import com.alibaba.jvm.sandbox.core.util.matcher.structure.ClassStructure;
+import com.alibaba.jvm.sandbox.core.util.matcher.structure.ClassStructureFactory;
+import com.alibaba.jvm.sandbox.core.util.matcher.structure.ClassStructureImplByJDK;
+import com.google.common.collect.Lists;
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang3.ArrayUtils;
 
 import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Collection;
 import java.util.List;
 
-import static com.alibaba.jvm.sandbox.api.filter.AccessFlags.*;
 import static com.alibaba.jvm.sandbox.core.util.SandboxStringUtils.toInternalClassName;
 
 /**
@@ -22,53 +26,20 @@
  *
  * @author luanjia@taobao.com
  */
-public class ExtFilterMatcher implements Matcher {
+public class ExtFilterMatcher implements Matcher, ClassMatcher, BehaviorMatcher {
 
-    private final ExtFilter extFilter;
+    private final ClassMatcher classMatcher;
 
-    public ExtFilterMatcher(final ExtFilter extFilter) {
-        this.extFilter = extFilter;
-    }
-
-    // 获取需要匹配的类结构
-    // 如果要匹配子类就需要将这个类的所有家族成员找出
-    private Collection<ClassStructure> getWaitingMatchClassStructures(final ClassStructure classStructure) {
-        final Collection<ClassStructure> waitingMatchClassStructures = new ArrayList<ClassStructure>();
-        waitingMatchClassStructures.add(classStructure);
-        if (extFilter.isIncludeSubClasses()) {
-            waitingMatchClassStructures.addAll(classStructure.getFamilyTypeClassStructures());
-        }
-        return waitingMatchClassStructures;
-    }
+    private final List<BehaviorMatcher> behaviorMatchers;
 
-    private String[] toJavaClassNameArray(final Collection<ClassStructure> classStructures) {
-        if (null == classStructures) {
-            return null;
-        }
-        final List<String> javaClassNames = new ArrayList<String>();
-        for (final ClassStructure classStructure : classStructures) {
-            javaClassNames.add(classStructure.getJavaClassName());
-        }
-        return javaClassNames.toArray(new String[0]);
+    public ExtFilterMatcher(final ExtFilter extFilter) {
+        this.classMatcher = new ClassExtFilterMatcher(extFilter);
+        this.behaviorMatchers = Lists.newArrayList((BehaviorMatcher) new BehaviorExtFilterMatcher(extFilter));
     }
 
-    private boolean matchingClassStructure(ClassStructure classStructure) {
-        for (final ClassStructure wmCs : getWaitingMatchClassStructures(classStructure)) {
-
-            // 匹配类结构
-            if (extFilter.doClassFilter(
-                    toFilterAccess(wmCs.getAccess()),
-                    wmCs.getJavaClassName(),
-                    null == wmCs.getSuperClassStructure()
-                            ? null
-                            : wmCs.getSuperClassStructure().getJavaClassName(),
-                    toJavaClassNameArray(wmCs.getFamilyInterfaceClassStructures()),
-                    toJavaClassNameArray(wmCs.getFamilyAnnotationTypeClassStructures())
-            )) {
-                return true;
-            }
-        }
-        return false;
+    public ExtFilterMatcher(final ClassMatcher classMatcher, List<BehaviorMatcher> behaviorMatchers) {
+        this.classMatcher = classMatcher;
+        this.behaviorMatchers = behaviorMatchers;
     }
 
     @Override
@@ -99,56 +70,41 @@ public MatchingResult matching(final ClassStructure classStructure) {
 
     }
 
+    @Override
+    public boolean matches(BehaviorStructure behaviorStructure) {
+        for (BehaviorMatcher behaviorMatcher : behaviorMatchers) {
+            if (behaviorMatcher.matches(behaviorStructure)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public boolean matches(ClassStructure classStructure) {
+        return classMatcher.matches(classStructure);
+    }
+
+
     private MatchingResult _matching(final ClassStructure classStructure) {
         final MatchingResult result = new MatchingResult();
-        // 如果不开启加载Bootstrap的类，遇到就过滤掉
-        if (!extFilter.isIncludeBootstrap()
-                && classStructure.getClassLoader() == null) {
-            return result;
-        }
 
         // 匹配ClassStructure
-        if (!matchingClassStructure(classStructure)) {
+        if (!classMatcher.matches(classStructure)) {
             return result;
         }
 
         // 匹配BehaviorStructure
         for (final BehaviorStructure behaviorStructure : classStructure.getBehaviorStructures()) {
-            if (extFilter.doMethodFilter(
-                    toFilterAccess(behaviorStructure.getAccess()),
-                    behaviorStructure.getName(),
-                    toJavaClassNameArray(behaviorStructure.getParameterTypeClassStructures()),
-                    toJavaClassNameArray(behaviorStructure.getExceptionTypeClassStructures()),
-                    toJavaClassNameArray(behaviorStructure.getAnnotationTypeClassStructures())
-            )) {
+            if (matches(behaviorStructure)) {
                 result.getBehaviorStructures().add(behaviorStructure);
             }
         }
+
         return result;
     }
 
 
-    /**
-     * 转换为{@link AccessFlags}的Access体系
-     *
-     * @param access access flag
-     * @return 部分兼容ASM的access flag
-     */
-    private static int toFilterAccess(final Access access) {
-        int flag = 0;
-        if (access.isPublic()) flag |= ACF_PUBLIC;
-        if (access.isPrivate()) flag |= ACF_PRIVATE;
-        if (access.isProtected()) flag |= ACF_PROTECTED;
-        if (access.isStatic()) flag |= ACF_STATIC;
-        if (access.isFinal()) flag |= ACF_FINAL;
-        if (access.isInterface()) flag |= ACF_INTERFACE;
-        if (access.isNative()) flag |= ACF_NATIVE;
-        if (access.isAbstract()) flag |= ACF_ABSTRACT;
-        if (access.isEnum()) flag |= ACF_ENUM;
-        if (access.isAnnotation()) flag |= ACF_ANNOTATION;
-        return flag;
-    }
-
     /**
      * 兼容{@code sandbox-api:1.0.10}时
      * 在{@link EventWatchCondition#getOrFilterArray()}中将{@link Filter}直接暴露出来的问题，
@@ -162,7 +118,7 @@ private static int toFilterAccess(final Access access) {
      * @param filterArray 过滤器数组
      * @return 兼容的Matcher
      */
-    public static Matcher toOrGroupMatcher(final Filter[] filterArray) {
+    public static GroupMatcher toOrGroupMatcher(final Filter[] filterArray) {
         final ExtFilter[] extFilterArray = new ExtFilter[filterArray.length];
         for (int index = 0; index < filterArray.length; index++) {
             extFilterArray[index] = ExtFilterFactory.make(filterArray[index]);
@@ -176,7 +132,7 @@ public static Matcher toOrGroupMatcher(final Filter[] filterArray) {
      * @param extFilterArray 增强过滤器数组
      * @return Or关系Matcher
      */
-    public static Matcher toOrGroupMatcher(final ExtFilter[] extFilterArray) {
+    public static GroupMatcher toOrGroupMatcher(final ExtFilter[] extFilterArray) {
         final Matcher[] matcherArray = new Matcher[ArrayUtils.getLength(extFilterArray)];
         for (int index = 0; index < matcherArray.length; index++) {
             matcherArray[index] = new ExtFilterMatcher(extFilterArray[index]);
@@ -184,4 +140,21 @@ public static Matcher toOrGroupMatcher(final ExtFilter[] extFilterArray) {
         return new GroupMatcher.Or(matcherArray);
     }
 
+    public ClassMatcher getClassMatcher() {
+        return classMatcher;
+    }
+
+    public List<BehaviorMatcher> getBehaviorMatchers() {
+        return behaviorMatchers;
+    }
+
+    @Override
+    public boolean hasClassIdentity() {
+        return classMatcher.hasClassIdentity();
+    }
+
+    @Override
+    public String getClassIdentity() {
+        return classMatcher.getClassIdentity();
+    }
 }
diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/inner/BehaviorExtFilterMatcher.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/inner/BehaviorExtFilterMatcher.java
new file mode 100644
index 00000000..0f7f1c1f
--- /dev/null
+++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/inner/BehaviorExtFilterMatcher.java
@@ -0,0 +1,29 @@
+package com.alibaba.jvm.sandbox.core.util.matcher.inner;
+
+import com.alibaba.jvm.sandbox.api.filter.ExtFilter;
+import com.alibaba.jvm.sandbox.core.util.matcher.structure.BehaviorStructure;
+
+import static com.alibaba.jvm.sandbox.core.util.ClassStructureUtils.toJavaClassNameArray;
+
+/**
+ * @author <a href="mailto:renyi.cry@alibaba-inc.com">renyi.cry<a/>
+ * @date 2020/11/9 1:13 上午
+ */
+public class BehaviorExtFilterMatcher implements BehaviorMatcher {
+
+    private final ExtFilter extFilter;
+
+    public BehaviorExtFilterMatcher(ExtFilter extFilter) {
+        this.extFilter = extFilter;
+    }
+
+    @Override
+    public boolean matches(BehaviorStructure behaviorStructure) {
+        return extFilter.doMethodFilter(
+                behaviorStructure.getAccess().getAccessCode(),
+                behaviorStructure.getName(),
+                toJavaClassNameArray(behaviorStructure.getParameterTypeClassStructures()),
+                toJavaClassNameArray(behaviorStructure.getExceptionTypeClassStructures()),
+                toJavaClassNameArray(behaviorStructure.getAnnotationTypeClassStructures()));
+    }
+}
diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/inner/BehaviorMatcher.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/inner/BehaviorMatcher.java
new file mode 100644
index 00000000..efefb885
--- /dev/null
+++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/inner/BehaviorMatcher.java
@@ -0,0 +1,19 @@
+package com.alibaba.jvm.sandbox.core.util.matcher.inner;
+
+import com.alibaba.jvm.sandbox.core.util.matcher.structure.BehaviorStructure;
+
+/**
+ * @author <a href="mailto:renyi.cry@alibaba-inc.com">renyi.cry<a/>
+ * @date 2020/11/8 11:11 下午
+ */
+public interface BehaviorMatcher {
+
+    /**
+     * 匹配函数结构
+     *
+     * @param behaviorStructure 函数结构
+     * @return 匹配结果
+     */
+    boolean matches(BehaviorStructure behaviorStructure);
+
+}
diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/inner/ClassExtFilterMatcher.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/inner/ClassExtFilterMatcher.java
new file mode 100644
index 00000000..e3ba829d
--- /dev/null
+++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/inner/ClassExtFilterMatcher.java
@@ -0,0 +1,80 @@
+package com.alibaba.jvm.sandbox.core.util.matcher.inner;
+
+import com.alibaba.jvm.sandbox.api.filter.ExtFilter;
+import com.alibaba.jvm.sandbox.core.util.matcher.structure.ClassStructure;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import static com.alibaba.jvm.sandbox.core.util.ClassStructureUtils.toJavaClassNameArray;
+
+/**
+ * A {@link ClassMatcher} with {@link ExtFilter}
+ *
+ * @author <a href="mailto:renyi.cry@alibaba-inc.com">renyi.cry<a/>
+ * @date 2020/11/9 12:58 上午
+ */
+public class ClassExtFilterMatcher implements ClassMatcher {
+
+    private final ExtFilter extFilter;
+
+    public ClassExtFilterMatcher(ExtFilter extFilter) {
+        this.extFilter = extFilter;
+    }
+
+    @Override
+    public boolean matches(ClassStructure classStructure) {
+
+        // 如果不开启加载Bootstrap的类，遇到就过滤掉
+        if (!extFilter.isIncludeBootstrap() && classStructure.getClassLoader() == null) {
+            return false;
+        }
+
+        // 匹配ClassStructure
+        for (final ClassStructure wmCs : getWaitingMatchClassStructures(classStructure)) {
+
+            ClassStructure superClassStructure = wmCs.getSuperClassStructure();
+            String[] interfaceTypeJavaClassNameArray = extFilter.hasInterfaceTypes() ?
+                    toJavaClassNameArray(wmCs.getFamilyInterfaceClassStructures()) : new String[]{};
+            String[] annotationTypeJavaClassNameArray = extFilter.hasAnnotationTypes() ?
+                    toJavaClassNameArray(wmCs.getFamilyAnnotationTypeClassStructures()) : new String[]{};
+
+            // 匹配类结构
+            if (extFilter.doClassFilter(
+                    wmCs.getAccess().getAccessCode(),
+                    wmCs.getJavaClassName(),
+                    null == superClassStructure ? null : superClassStructure.getJavaClassName(),
+                    interfaceTypeJavaClassNameArray,
+                    annotationTypeJavaClassNameArray)) {
+
+                return true;
+
+            }
+        }
+
+        return false;
+
+    }
+
+    @Override
+    public boolean hasClassIdentity() {
+        return extFilter.hasClassIdentity();
+    }
+
+    @Override
+    public String getClassIdentity() {
+        return extFilter.getClassIdentity();
+    }
+
+    // 获取需要匹配的类结构
+    // 如果要匹配子类就需要将这个类的所有家族成员找出
+    private Collection<ClassStructure> getWaitingMatchClassStructures(final ClassStructure classStructure) {
+        final Collection<ClassStructure> waitingMatchClassStructures = new ArrayList<ClassStructure>();
+        waitingMatchClassStructures.add(classStructure);
+        if (extFilter.isIncludeSubClasses()) {
+            waitingMatchClassStructures.addAll(classStructure.getFamilyTypeClassStructures());
+        }
+        return waitingMatchClassStructures;
+    }
+
+}
diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/inner/ClassMatcher.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/inner/ClassMatcher.java
new file mode 100644
index 00000000..d855474d
--- /dev/null
+++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/inner/ClassMatcher.java
@@ -0,0 +1,20 @@
+package com.alibaba.jvm.sandbox.core.util.matcher.inner;
+
+import com.alibaba.jvm.sandbox.api.filter.ClassIdentifiable;
+import com.alibaba.jvm.sandbox.core.util.matcher.structure.ClassStructure;
+
+/**
+ * @author <a href="mailto:renyi.cry@alibaba-inc.com">renyi.cry<a/>
+ * @date 2020/11/8 11:11 下午
+ */
+public interface ClassMatcher extends ClassIdentifiable {
+
+    /**
+     * 匹配类结构
+     *
+     * @param classStructure 类结构
+     * @return 匹配结果
+     */
+    boolean matches(ClassStructure classStructure);
+
+}
diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/structure/Access.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/structure/Access.java
index 7ee91abb..adb7e86e 100644
--- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/structure/Access.java
+++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/structure/Access.java
@@ -34,4 +34,6 @@ public interface Access {
 
     boolean isAnnotation();
 
+    int getAccessCode();
+
 }
diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/structure/ClassStructureFactory.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/structure/ClassStructureFactory.java
index 48c8e7e0..598db14b 100644
--- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/structure/ClassStructureFactory.java
+++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/structure/ClassStructureFactory.java
@@ -1,10 +1,15 @@
 package com.alibaba.jvm.sandbox.core.util.matcher.structure;
 
+
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.concurrent.TimeUnit;
 
 /**
  * 类结构工厂类
@@ -18,6 +23,17 @@ public class ClassStructureFactory {
 
     private static final Logger logger = LoggerFactory.getLogger(ClassStructureFactory.class);
 
+    // cache stat: hit ratio: 1024 - 41% ; 2048 - 56%
+    // 最佳的性能应该是Caffeine，但是jdk版本不够
+    private final static LoadingCache<Class<?>, ClassStructure> CLASS_STRUCTURE_CACHE
+            = CacheBuilder.newBuilder().expireAfterWrite(15, TimeUnit.MINUTES)
+            .maximumSize(2048).build(new CacheLoader<Class<?>, ClassStructure>() {
+                @Override
+                public ClassStructure load(Class<?> key) {
+                    return new ClassStructureImplByJDK(key);
+                }
+            });
+
     /**
      * 通过Class类来构造类结构
      *
@@ -25,7 +41,7 @@ public class ClassStructureFactory {
      * @return JDK实现的类结构
      */
     public static ClassStructure createClassStructure(final Class<?> clazz) {
-        return new ClassStructureImplByJDK(clazz);
+        return CLASS_STRUCTURE_CACHE.getUnchecked(clazz);
     }
 
     /**
diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/structure/ClassStructureImplByAsm.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/structure/ClassStructureImplByAsm.java
index b4467214..b9f1cad5 100644
--- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/structure/ClassStructureImplByAsm.java
+++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/structure/ClassStructureImplByAsm.java
@@ -1,6 +1,7 @@
 package com.alibaba.jvm.sandbox.core.util.matcher.structure;
 
 import com.alibaba.jvm.sandbox.api.util.LazyGet;
+import com.alibaba.jvm.sandbox.core.util.AccessUtils;
 import com.alibaba.jvm.sandbox.core.util.BitUtils;
 import com.alibaba.jvm.sandbox.core.util.collection.Pair;
 import com.alibaba.jvm.sandbox.core.util.matcher.structure.PrimitiveClassStructure.Primitive;
@@ -30,6 +31,8 @@ class AccessImplByAsm implements Access {
 
     private final int access;
 
+    private volatile int accessCode;
+
     AccessImplByAsm(final int access) {
         this.access = access;
     }
@@ -98,10 +101,21 @@ public boolean isEnum() {
     public boolean isAnnotation() {
         return BitUtils.isIn(getAccess(), ACC_ANNOTATION);
     }
+
+
+    @Override
+    public int getAccessCode() {
+        if (accessCode == -1) {
+            accessCode = AccessUtils.toFilterAccess(this);
+        }
+        return accessCode;
+    }
 }
 
 class EmptyClassStructure implements ClassStructure {
 
+    private static final Access access = new AccessImplByAsm(0);
+
     @Override
     public String getJavaClassName() {
         return null;
@@ -154,7 +168,7 @@ public List<BehaviorStructure> getBehaviorStructures() {
 
     @Override
     public Access getAccess() {
-        return new AccessImplByAsm(0);
+        return access;
     }
 }
 
diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/structure/ClassStructureImplByJDK.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/structure/ClassStructureImplByJDK.java
index d9dde606..c0ac25dd 100644
--- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/structure/ClassStructureImplByJDK.java
+++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/structure/ClassStructureImplByJDK.java
@@ -1,6 +1,7 @@
 package com.alibaba.jvm.sandbox.core.util.matcher.structure;
 
 import com.alibaba.jvm.sandbox.api.util.LazyGet;
+import com.alibaba.jvm.sandbox.core.util.AccessUtils;
 
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Constructor;
@@ -15,8 +16,11 @@ abstract class ModifierAccess implements Access {
 
     private final int modifiers;
 
+    private volatile int accessCode;
+
     ModifierAccess(int modifiers) {
         this.modifiers = modifiers;
+        this.accessCode = modifiers == 0 ? 0 : -1;
     }
 
     @Override
@@ -59,6 +63,14 @@ public boolean isAbstract() {
         return Modifier.isAbstract(modifiers);
     }
 
+    @Override
+    public int getAccessCode(){
+        if (accessCode == -1) {
+            accessCode = AccessUtils.toFilterAccess(this);
+        }
+        return accessCode;
+    }
+
 }
 
 class AccessImplByJDKClass extends ModifierAccess {
@@ -101,6 +113,7 @@ public boolean isEnum() {
     public boolean isAnnotation() {
         return false;
     }
+
 }
 
 /**
@@ -110,16 +123,18 @@ public class ClassStructureImplByJDK extends FamilyClassStructure {
 
     private final Class<?> clazz;
     private String javaClassName;
+    private Access access;
 
     public ClassStructureImplByJDK(final Class<?> clazz) {
         this.clazz = clazz;
+        this.access = new AccessImplByJDKClass(clazz);
     }
 
     private ClassStructure newInstance(final Class<?> clazz) {
         if (null == clazz) {
             return null;
         }
-        return new ClassStructureImplByJDK(clazz);
+        return ClassStructureFactory.createClassStructure(clazz);
     }
 
     private List<ClassStructure> newInstances(final Class[] classArray) {
@@ -242,7 +257,7 @@ public List<BehaviorStructure> getBehaviorStructures() {
 
     @Override
     public Access getAccess() {
-        return new AccessImplByJDKClass(clazz);
+        return access;
     }
 
     @Override
diff --git a/sandbox-debug-module/src/main/java/com/alibaba/jvm/sandbox/module/debug/DebugLifeCycleModule.java b/sandbox-debug-module/src/main/java/com/alibaba/jvm/sandbox/module/debug/DebugLifeCycleModule.java
index 412a1946..74e83502 100644
--- a/sandbox-debug-module/src/main/java/com/alibaba/jvm/sandbox/module/debug/DebugLifeCycleModule.java
+++ b/sandbox-debug-module/src/main/java/com/alibaba/jvm/sandbox/module/debug/DebugLifeCycleModule.java
@@ -82,7 +82,19 @@ public void control(final Map<String, String> param, final PrintWriter writer){
 
 
         int watcherId = moduleEventWatcher.watch(
-                new ExtFilter(){//不增强类，这里只是体验sandbox的生命周期，ExtFilter新增了增强接口的所有实现类，到boostrap ClassLoader中加载类 的能力
+                new ExtFilter(){
+
+                    @Override
+                    public boolean hasClassIdentity() {
+                        return false;
+                    }
+
+                    @Override
+                    public String getClassIdentity() {
+                        return null;
+                    }
+
+                    //不增强类，这里只是体验sandbox的生命周期，ExtFilter新增了增强接口的所有实现类，到boostrap ClassLoader中加载类 的能力
 
                     @Override
                     public boolean doClassFilter(int access, String javaClassName, String superClassTypeJavaClassName, String[] interfaceTypeJavaClassNameArray, String[] annotationTypeJavaClassNameArray) {
@@ -107,6 +119,16 @@ public boolean isIncludeSubClasses() {//搜索子类或实现类
                     public boolean isIncludeBootstrap() {//搜索来自BootstrapClassLoader所加载的类
                         return true;
                     }
+
+                    @Override
+                    public boolean hasInterfaceTypes() {
+                        return true;
+                    }
+
+                    @Override
+                    public boolean hasAnnotationTypes() {
+                        return true;
+                    }
                 },
                 new EventListener() {//监听到的事件，不做任何处理
                     @Override


Test patch:
diff --git a/sandbox-api/src/test/java/com/alibaba/jvm/sandbox/qatest/api/mock/MockForBuilderModuleEventWatcher.java b/sandbox-api/src/test/java/com/alibaba/jvm/sandbox/qatest/api/mock/MockForBuilderModuleEventWatcher.java
index 37d0e4f8..7eb2fc00 100644
--- a/sandbox-api/src/test/java/com/alibaba/jvm/sandbox/qatest/api/mock/MockForBuilderModuleEventWatcher.java
+++ b/sandbox-api/src/test/java/com/alibaba/jvm/sandbox/qatest/api/mock/MockForBuilderModuleEventWatcher.java
@@ -48,6 +48,11 @@ public int watch(Filter filter, EventListener listener, Event.Type... eventType)
         return 0;
     }
 
+    @Override
+    public int watch(Filter filter, EventListener listener, Progress progress, boolean lazyReload, Event.Type... eventType) {
+        return 0;
+    }
+
     @Override
     public int watch(EventWatchCondition condition, EventListener listener, Progress progress, Event.Type... eventType) {
         eventWatchConditionRef.set(condition);
@@ -57,6 +62,11 @@ public int watch(EventWatchCondition condition, EventListener listener, Progress
         return 0;
     }
 
+    @Override
+    public int watch(EventWatchCondition condition, EventListener listener, Progress progress, boolean lazyReload, Event.Type... eventType) {
+        return 0;
+    }
+
     @Override
     public void delete(int watcherId, Progress progress) {
 
diff --git a/sandbox-benchmark/src/test/main/com/alibaba/jvm/sandbox/benchmark/BenchmarkForParallelWatching.java b/sandbox-benchmark/src/test/main/com/alibaba/jvm/sandbox/benchmark/BenchmarkForParallelWatching.java
new file mode 100644
index 00000000..8bd01ecc
--- /dev/null
+++ b/sandbox-benchmark/src/test/main/com/alibaba/jvm/sandbox/benchmark/BenchmarkForParallelWatching.java
@@ -0,0 +1,31 @@
+package com.alibaba.jvm.sandbox.benchmark;
+
+import com.alibaba.jvm.sandbox.module.junit.annotations.PrepareForTest;
+import com.alibaba.jvm.sandbox.module.junit.rule.SandboxRule;
+import org.junit.Rule;
+import org.junit.Test;
+
+/**
+ * Average: 782 ms
+ *
+ * TODO benchmark with jmh
+ *
+ * @author <a href="mailto:renyi.cry@alibaba-inc.com">renyi.cry<a/>
+ * @date 2020/11/17 9:43 下午
+ */
+public class BenchmarkForParallelWatching {
+
+    @Rule
+    public SandboxRule sandboxRule = new SandboxRule();
+
+    static {
+        Holder.withLazyReload = true;
+    }
+
+    @Test
+    @PrepareForTest(testModule = DummyModule.class, fastMode = false)
+    public void sync_parallel_watching_benchmark() {
+
+    }
+
+}
diff --git a/sandbox-benchmark/src/test/main/com/alibaba/jvm/sandbox/benchmark/BenchmarkForWatching.java b/sandbox-benchmark/src/test/main/com/alibaba/jvm/sandbox/benchmark/BenchmarkForWatching.java
new file mode 100644
index 00000000..2b8c9da6
--- /dev/null
+++ b/sandbox-benchmark/src/test/main/com/alibaba/jvm/sandbox/benchmark/BenchmarkForWatching.java
@@ -0,0 +1,31 @@
+package com.alibaba.jvm.sandbox.benchmark;
+
+import com.alibaba.jvm.sandbox.module.junit.annotations.PrepareForTest;
+import com.alibaba.jvm.sandbox.module.junit.rule.SandboxRule;
+import org.junit.Rule;
+import org.junit.Test;
+
+/**
+ * Average: 2799 ms
+ *
+ * TODO benchmark with jmh
+ *
+ * @author <a href="mailto:renyi.cry@alibaba-inc.com">renyi.cry<a/>
+ * @date 2020/11/17 9:43 下午
+ */
+public class BenchmarkForWatching {
+
+    @Rule
+    public SandboxRule sandboxRule = new SandboxRule();
+
+    static {
+        Holder.withLazyReload = false;
+    }
+
+    @Test
+    @PrepareForTest(testModule = DummyModule.class, fastMode = false)
+    public void sync_watching_benchmark() {
+
+    }
+
+}
diff --git a/sandbox-benchmark/src/test/main/com/alibaba/jvm/sandbox/benchmark/DummyListener.java b/sandbox-benchmark/src/test/main/com/alibaba/jvm/sandbox/benchmark/DummyListener.java
new file mode 100644
index 00000000..2aed72e6
--- /dev/null
+++ b/sandbox-benchmark/src/test/main/com/alibaba/jvm/sandbox/benchmark/DummyListener.java
@@ -0,0 +1,30 @@
+package com.alibaba.jvm.sandbox.benchmark;
+
+import com.alibaba.jvm.sandbox.api.listener.ext.Advice;
+import com.alibaba.jvm.sandbox.api.listener.ext.AdviceListener;
+
+/**
+ * @author <a href="mailto:renyi.cry@alibaba-inc.com">renyi.cry<a/>
+ * @date 2020/11/17 4:06 下午
+ */
+public class DummyListener extends AdviceListener {
+
+    @Override
+    protected void before(Advice advice) throws Throwable {
+
+        if (!advice.isProcessTop()) {
+            return;
+        }
+
+        if (advice.getTarget() == null) {
+            return;
+        }
+
+    }
+
+    @Override
+    protected void afterReturning(Advice advice) throws Throwable {
+
+    }
+
+}
diff --git a/sandbox-benchmark/src/test/main/com/alibaba/jvm/sandbox/benchmark/DummyModule.java b/sandbox-benchmark/src/test/main/com/alibaba/jvm/sandbox/benchmark/DummyModule.java
new file mode 100644
index 00000000..48705870
--- /dev/null
+++ b/sandbox-benchmark/src/test/main/com/alibaba/jvm/sandbox/benchmark/DummyModule.java
@@ -0,0 +1,99 @@
+package com.alibaba.jvm.sandbox.benchmark;
+
+import ch.qos.logback.core.util.TimeUtil;
+import com.alibaba.jvm.sandbox.api.Information;
+import com.alibaba.jvm.sandbox.api.Module;
+import com.alibaba.jvm.sandbox.api.ModuleLifecycleAdapter;
+import com.alibaba.jvm.sandbox.api.event.Event;
+import com.alibaba.jvm.sandbox.api.filter.AccessFlags;
+import com.alibaba.jvm.sandbox.api.listener.ext.EventWatchBuilder;
+import com.alibaba.jvm.sandbox.api.listener.ext.WatchIdHolder;
+import com.alibaba.jvm.sandbox.api.resource.ModuleEventWatcher;
+import com.alibaba.jvm.sandbox.api.util.SandboxProtector;
+import com.alibaba.jvm.sandbox.api.util.StopAllSandboxProtector;
+import com.google.common.base.Stopwatch;
+import org.kohsuke.MetaInfServices;
+
+import javax.annotation.Resource;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author <a href="mailto:renyi.cry@alibaba-inc.com">renyi.cry<a/>
+ * @date 2020/11/17 2:54 下午
+ */
+@MetaInfServices(Module.class)
+@Information(id = "dummy-module", version = "1.0.0", author = "renyi.cry")
+public class DummyModule extends ModuleLifecycleAdapter implements Module {
+
+    @Resource
+    private ModuleEventWatcher moduleEventWatcher;
+
+    @Override
+    public void loadCompleted() {
+
+        Stopwatch stopwatch = Stopwatch.createStarted();
+
+        SandboxProtector currentProtector = SandboxProtector.SandboxProtectors.getInstance();
+        SandboxProtector stopAllSandboxProtector = new StopAllSandboxProtector(currentProtector);
+
+        SandboxProtector.SandboxProtectors.force2resetInstance(stopAllSandboxProtector);
+        try {
+
+            Class[] testClasses = new Class[20];
+            Arrays.fill(testClasses, TestClass.class);
+
+            for (int i = 0; i < 9; i++) {
+
+                watch(Character.toString((char)('a' + i)), testClasses);
+
+            }
+
+            while (Holder.withLazyReload && WatchIdHolder.hasUnfinishedWatchId()) {
+                try {
+                    Thread.sleep(50);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+            }
+        } finally {
+            while (WatchIdHolder.hasUnfinishedWatchId()) {
+                try {
+                    Thread.sleep(1);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+            }
+            SandboxProtector.SandboxProtectors.force2resetInstance(currentProtector);
+        }
+
+
+        if (Holder.withLazyReload) {
+            System.out.println("parallel time: " + stopwatch.elapsed(TimeUnit.MILLISECONDS));
+        } else {
+            System.out.println("single time: " + stopwatch.elapsed(TimeUnit.MILLISECONDS));
+        }
+
+    }
+
+    private void watch(String method, Class... classes) {
+
+        for (Class clazz : classes) {
+
+            new EventWatchBuilder(moduleEventWatcher, EventWatchBuilder.PatternType.WILDCARD)
+                    .onClass(clazz)
+                    .includeBootstrap()
+                    .includeSubClasses()
+                    .withAccess(AccessFlags.ACF_PUBLIC)
+                    .onBehavior(method)
+                    .withLazyReload(Holder.withLazyReload)
+                    .onWatch(new DummyListener(), Event.Type.BEFORE, Event.Type.RETURN, Event.Type.THROWS);
+
+        }
+
+    }
+
+
+}
diff --git a/sandbox-benchmark/src/test/main/com/alibaba/jvm/sandbox/benchmark/Holder.java b/sandbox-benchmark/src/test/main/com/alibaba/jvm/sandbox/benchmark/Holder.java
new file mode 100644
index 00000000..02c818dc
--- /dev/null
+++ b/sandbox-benchmark/src/test/main/com/alibaba/jvm/sandbox/benchmark/Holder.java
@@ -0,0 +1,10 @@
+package com.alibaba.jvm.sandbox.benchmark;
+
+/**
+ * @author <a href="mailto:renyi.cry@alibaba-inc.com">renyi.cry<a/>
+ * @date 2020/11/17 10:19 下午
+ */
+public class Holder {
+    public static boolean withLazyReload = false;
+
+}
diff --git a/sandbox-benchmark/src/test/main/com/alibaba/jvm/sandbox/benchmark/TestClass.java b/sandbox-benchmark/src/test/main/com/alibaba/jvm/sandbox/benchmark/TestClass.java
new file mode 100644
index 00000000..b4c1499b
--- /dev/null
+++ b/sandbox-benchmark/src/test/main/com/alibaba/jvm/sandbox/benchmark/TestClass.java
@@ -0,0 +1,47 @@
+package com.alibaba.jvm.sandbox.benchmark;
+
+/**
+ * @author <a href="mailto:renyi.cry@alibaba-inc.com">renyi.cry<a/>
+ * @date 2020/11/17 10:37 下午
+ */
+public class TestClass {
+
+    public void a() {
+
+    }
+
+    public void b() {
+
+    }
+
+    public void c() {
+
+    }
+
+
+    public void d() {
+
+    }
+
+    public void e() {
+
+    }
+
+    public void f() {
+
+    }
+
+
+    public void g() {
+
+    }
+
+    public void h() {
+
+    }
+
+    public void i() {
+
+    }
+
+}
diff --git a/sandbox-benchmark/src/test/resources/lib/sandbox-spy-1.3.3-for-qatest.jar b/sandbox-benchmark/src/test/resources/lib/sandbox-spy-1.3.3-for-qatest.jar
new file mode 100644
index 00000000..0717a42e
Binary files /dev/null and b/sandbox-benchmark/src/test/resources/lib/sandbox-spy-1.3.3-for-qatest.jar differ
diff --git a/sandbox-benchmark/src/test/resources/logback.xml b/sandbox-benchmark/src/test/resources/logback.xml
new file mode 100755
index 00000000..cdbe9fad
--- /dev/null
+++ b/sandbox-benchmark/src/test/resources/logback.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<configuration scan="true" scanPeriod="10000">
+
+    <appender name="STDOUT-APPENDER" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>%d{yyyy-MM-dd HH:mm:ss} %5level %msg%n</pattern>　　
+        </encoder>
+    </appender>
+
+    <root level="info">
+        <appender-ref ref="STDOUT-APPENDER"/>
+    </root>
+
+</configuration>
\ No newline at end of file
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 491087a3..b8d0e1ae 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
@@ -210,6 +210,25 @@ public boolean isIncludeBootstrap() {
             return false;
         }
 
+        @Override
+        public boolean hasInterfaceTypes() {
+            return true;
+        }
+
+        @Override
+        public boolean hasAnnotationTypes() {
+            return true;
+        }
+
+        @Override
+        public boolean hasClassIdentity() {
+            return false;
+        }
+
+        @Override
+        public String getClassIdentity() {
+            return null;
+        }
     }
 
     @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 328ed893..2255978d 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
@@ -147,7 +147,7 @@ private void assertLoadedModule(final CoreModuleManager coreModuleManager,
     }
 
     private CoreModuleManager buildingCoreModuleManager(final File... moduleJarFiles) throws ModuleException {
-        return SandboxProtector.instance.protectProxy(CoreModuleManager.class, new DefaultCoreModuleManager(
+        return SandboxProtector.getOrCreateInstance().protectProxy(CoreModuleManager.class, new DefaultCoreModuleManager(
                 buildingCoreConfigureWithUserModuleLib(moduleJarFiles),
                 new EmptyInstrumentation(),
                 new EmptyCoreLoadedClassDataSource(),
diff --git a/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/mock/EmptyModuleEventWatcher.java b/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/mock/EmptyModuleEventWatcher.java
index 577d5aaa..557d7801 100644
--- a/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/mock/EmptyModuleEventWatcher.java
+++ b/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/mock/EmptyModuleEventWatcher.java
@@ -18,11 +18,21 @@ public int watch(Filter filter, EventListener listener, Event.Type... eventType)
         return 0;
     }
 
+    @Override
+    public int watch(Filter filter, EventListener listener, Progress progress, boolean lazyReload, Event.Type... eventType) {
+        return 0;
+    }
+
     @Override
     public int watch(EventWatchCondition condition, EventListener listener, Progress progress, Event.Type... eventType) {
         return 0;
     }
 
+    @Override
+    public int watch(EventWatchCondition condition, EventListener listener, Progress progress, boolean lazyReload, Event.Type... eventType) {
+        return 0;
+    }
+
     @Override
     public void delete(int watcherId, Progress progress) {
 
diff --git a/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/JvmHelper.java b/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/JvmHelper.java
index 79c59bf3..9f240925 100644
--- a/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/JvmHelper.java
+++ b/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/JvmHelper.java
@@ -1,7 +1,6 @@
 package com.alibaba.jvm.sandbox.qatest.core.util;
 
 import com.alibaba.jvm.sandbox.api.event.Event;
-import com.alibaba.jvm.sandbox.api.event.Event.Type;
 import com.alibaba.jvm.sandbox.api.filter.Filter;
 import com.alibaba.jvm.sandbox.api.listener.EventListener;
 import com.alibaba.jvm.sandbox.api.listener.ext.AdviceListener;
@@ -149,7 +148,7 @@ public String getNativeMethodPrefix() {
         }
 
         @Override
-        public void makrNativeMethodEnhance() {
+        public void markNativeMethodEnhance() {
 
         }
     }
diff --git a/sandbox-test/pom.xml b/sandbox-test/pom.xml
new file mode 100755
index 00000000..70587bff
--- /dev/null
+++ b/sandbox-test/pom.xml
@@ -0,0 +1,150 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+         xmlns="http://maven.apache.org/POM/4.0.0">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.alibaba.jvm.sandbox</groupId>
+        <artifactId>sandbox-module-starter</artifactId>
+        <version>1.3.3</version>
+        <relativePath>../sandbox-module-starter/pom.xml</relativePath>
+    </parent>
+    <artifactId>sandbox-test</artifactId>
+    <name>A Test Framework For Sandbox - ${sandbox.version}</name>
+
+    <dependencies>
+
+        <!-- DEBUG工程公共依赖模块，SANDBOX父工程托管 -->
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>3.4</version>
+        </dependency>
+        <dependency>
+            <groupId>commons-collections</groupId>
+            <artifactId>commons-collections</artifactId>
+            <version>3.2.1</version>
+        </dependency>
+
+        <!-- DEBUG工程独有依赖模块，所以单独配置并指定了版本 -->
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+            <version>18.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+            <version>1.7.24</version>
+        </dependency>
+        <dependency>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
+            <version>1.2.1</version>
+        </dependency>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.hamcrest</groupId>
+            <artifactId>hamcrest-all</artifactId>
+            <version>1.3</version>
+            <scope>provided</scope>
+        </dependency>
+
+
+        <dependency>
+            <groupId>org.powermock</groupId>
+            <artifactId>powermock-api-mockito</artifactId>
+            <version>1.7.0</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.powermock</groupId>
+            <artifactId>powermock-module-junit4</artifactId>
+            <version>1.7.0</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>net.bytebuddy</groupId>
+            <artifactId>byte-buddy-agent</artifactId>
+            <version>1.9.10</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>com.alibaba.jvm.sandbox</groupId>
+            <artifactId>sandbox-core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>com.alibaba.jvm.sandbox</groupId>
+            <artifactId>sandbox-spy</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>3.8.0</version>
+                <configuration>
+                    <source>1.7</source>
+                    <target>1.7</target>
+                    <encoding>UTF-8</encoding>
+                    <showDeprecation>true</showDeprecation>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-deploy-plugin</artifactId>
+                <configuration>
+                    <skip>true</skip>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <forkMode>once</forkMode>
+                    <argLine>-Xbootclasspath/p:./src/test/resources/lib/sandbox-spy-1.3.3-for-qatest.jar</argLine>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>cobertura-maven-plugin</artifactId>
+                <configuration>
+                    <skip>true</skip>
+                    <check/>
+                </configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>cobertura</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+
+    </build>
+
+
+</project>
diff --git a/sandbox-test/src/main/java/com/alibaba/jvm/sandbox/module/junit/annotations/PrepareForTest.java b/sandbox-test/src/main/java/com/alibaba/jvm/sandbox/module/junit/annotations/PrepareForTest.java
new file mode 100644
index 00000000..0242e9b0
--- /dev/null
+++ b/sandbox-test/src/main/java/com/alibaba/jvm/sandbox/module/junit/annotations/PrepareForTest.java
@@ -0,0 +1,33 @@
+package com.alibaba.jvm.sandbox.module.junit.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @author <a href="mailto:renyi.cry@alibaba-inc.com">renyi.cry<a/>
+ * @date 2019-05-13 18:26
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface PrepareForTest {
+    Class testModule();
+
+    Class[] spyClasses() default {};
+
+    String[] spyClassNames() default {};
+
+    String namespace() default "default";
+
+    boolean isEnableUnsafe() default false;
+
+    /**
+     * Enable fast mode that only stubs when {@link #spyClasses} and {@link #spyClassNames} identified.
+     * Notice that disabling the fast mode may come with a significant performance overhead.
+     *
+     * @return
+     */
+    boolean fastMode() default true;
+
+}
diff --git a/sandbox-test/src/main/java/com/alibaba/jvm/sandbox/module/junit/annotations/SandboxTestConfig.java b/sandbox-test/src/main/java/com/alibaba/jvm/sandbox/module/junit/annotations/SandboxTestConfig.java
new file mode 100644
index 00000000..05c38b2d
--- /dev/null
+++ b/sandbox-test/src/main/java/com/alibaba/jvm/sandbox/module/junit/annotations/SandboxTestConfig.java
@@ -0,0 +1,24 @@
+package com.alibaba.jvm.sandbox.module.junit.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @deprecated this class is used for the early version
+ * @author <a href="mailto:renyi.cry@alibaba-inc.com">renyi.cry<a/>
+ * @date 2019-06-16 18:06
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+@Deprecated
+public @interface SandboxTestConfig {
+
+    boolean spySandboxCore() default false;
+
+    boolean spySandboxJunit() default false;
+
+    String[] spyPatterns() default {};
+
+}
diff --git a/sandbox-test/src/main/java/com/alibaba/jvm/sandbox/module/junit/mock/DummyProviderManager.java b/sandbox-test/src/main/java/com/alibaba/jvm/sandbox/module/junit/mock/DummyProviderManager.java
new file mode 100644
index 00000000..2fcbbbbd
--- /dev/null
+++ b/sandbox-test/src/main/java/com/alibaba/jvm/sandbox/module/junit/mock/DummyProviderManager.java
@@ -0,0 +1,18 @@
+package com.alibaba.jvm.sandbox.module.junit.mock;
+
+import com.alibaba.jvm.sandbox.api.Module;
+import com.alibaba.jvm.sandbox.core.manager.ProviderManager;
+
+import java.io.File;
+
+public class DummyProviderManager implements ProviderManager {
+    @Override
+    public void loading(File moduleJarFile) {
+
+    }
+
+    @Override
+    public void loading(String uniqueId, Class moduleClass, Module module, File moduleJarFile, ClassLoader moduleClassLoader) throws Throwable {
+
+    }
+}
diff --git a/sandbox-test/src/main/java/com/alibaba/jvm/sandbox/module/junit/mock/MockLoadedClassesOnlyInstrumentation.java b/sandbox-test/src/main/java/com/alibaba/jvm/sandbox/module/junit/mock/MockLoadedClassesOnlyInstrumentation.java
new file mode 100644
index 00000000..d906bd9c
--- /dev/null
+++ b/sandbox-test/src/main/java/com/alibaba/jvm/sandbox/module/junit/mock/MockLoadedClassesOnlyInstrumentation.java
@@ -0,0 +1,103 @@
+package com.alibaba.jvm.sandbox.module.junit.mock;
+
+import net.bytebuddy.agent.ByteBuddyAgent;
+
+import java.lang.instrument.ClassDefinition;
+import java.lang.instrument.ClassFileTransformer;
+import java.lang.instrument.Instrumentation;
+import java.lang.instrument.UnmodifiableClassException;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import java.util.jar.JarFile;
+
+/**
+ * Less classes for faster testing.
+ *
+ * @author <a href="mailto:renyi.cry@alibaba-inc.com">renyi.cry<a/>
+ * @date 2019-05-13 21:06
+ */
+public class MockLoadedClassesOnlyInstrumentation implements Instrumentation {
+
+    private final Set<Class<?>> loadedClasses = new LinkedHashSet<>();
+
+    private static Instrumentation instrumentation = ByteBuddyAgent.install();
+
+    public void regLoadedClass(Class<?> clazz) {
+        loadedClasses.add(clazz);
+    }
+
+    @Override
+    public Class[] getAllLoadedClasses() {
+        return loadedClasses.toArray(new Class<?>[]{});
+    }
+
+    @Override
+    public Class[] getInitiatedClasses(ClassLoader loader) {
+        return instrumentation.getInitiatedClasses(loader);
+    }
+
+    @Override
+    public long getObjectSize(Object objectToSize) {
+        return instrumentation.getObjectSize(objectToSize);
+    }
+
+    @Override
+    public void appendToBootstrapClassLoaderSearch(JarFile jarfile) {
+        instrumentation.appendToBootstrapClassLoaderSearch(jarfile);
+    }
+
+    @Override
+    public void appendToSystemClassLoaderSearch(JarFile jarfile) {
+        instrumentation.appendToSystemClassLoaderSearch(jarfile);
+    }
+
+    @Override
+    public boolean isNativeMethodPrefixSupported() {
+        return instrumentation.isNativeMethodPrefixSupported();
+    }
+
+    @Override
+    public void setNativeMethodPrefix(ClassFileTransformer transformer, String prefix) {
+        instrumentation.setNativeMethodPrefix(transformer, prefix);
+    }
+
+    @Override
+    public boolean isModifiableClass(Class<?> theClass) {
+        return instrumentation.isModifiableClass(theClass);
+    }
+
+    @Override
+    public void retransformClasses(Class<?>... classes) throws UnmodifiableClassException {
+        instrumentation.retransformClasses(classes);
+    }
+
+    @Override
+    public boolean isRedefineClassesSupported() {
+        return instrumentation.isRedefineClassesSupported();
+    }
+
+    @Override
+    public void redefineClasses(ClassDefinition... definitions) throws ClassNotFoundException, UnmodifiableClassException {
+        instrumentation.redefineClasses(definitions);
+    }
+
+    @Override
+    public boolean isRetransformClassesSupported() {
+        return instrumentation.isRetransformClassesSupported();
+    }
+
+    @Override
+    public void addTransformer(ClassFileTransformer transformer) {
+        instrumentation.addTransformer(transformer);
+    }
+
+    @Override
+    public boolean removeTransformer(ClassFileTransformer transformer) {
+        return instrumentation.removeTransformer(transformer);
+    }
+
+    @Override
+    public void addTransformer(ClassFileTransformer transformer, boolean canRetransform) {
+        instrumentation.addTransformer(transformer, canRetransform);
+    }
+}
diff --git a/sandbox-test/src/main/java/com/alibaba/jvm/sandbox/module/junit/rule/OutputCapture.java b/sandbox-test/src/main/java/com/alibaba/jvm/sandbox/module/junit/rule/OutputCapture.java
new file mode 100644
index 00000000..7f557265
--- /dev/null
+++ b/sandbox-test/src/main/java/com/alibaba/jvm/sandbox/module/junit/rule/OutputCapture.java
@@ -0,0 +1,145 @@
+package com.alibaba.jvm.sandbox.module.junit.rule;
+
+import org.hamcrest.Matcher;
+import org.junit.Assert;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.hamcrest.Matchers.allOf;
+
+/**
+ * An output capture that helps capture standard and error outputs.
+ *
+ * @author <a href="mailto:renyi.cry@alibaba-inc.com">renyi.cry<a/>
+ * @date 2018/9/4下午6:22
+ */
+public class OutputCapture implements TestRule {
+
+    private CaptureOutputStream captureOut;
+
+    private CaptureOutputStream captureErr;
+
+    private ByteArrayOutputStream copy;
+
+    private List<Matcher<? super String>> matchers = new ArrayList<>();
+
+    @Override
+    public Statement apply(final Statement base, Description description) {
+        return new Statement() {
+            @Override
+            public void evaluate() throws Throwable {
+                captureOutput();
+                try {
+                    base.evaluate();
+                }
+                finally {
+                    try {
+                        if (!OutputCapture.this.matchers.isEmpty()) {
+                            String output = OutputCapture.this.toString();
+                            Assert.assertThat(output, allOf(OutputCapture.this.matchers));
+                        }
+                    }
+                    finally {
+                        releaseOutput();
+                    }
+                }
+            }
+        };
+    }
+
+    protected void captureOutput() {
+        this.copy = new ByteArrayOutputStream();
+        this.captureOut = new CaptureOutputStream(System.out, this.copy);
+        this.captureErr = new CaptureOutputStream(System.err, this.copy);
+        System.setOut(new PrintStream(this.captureOut));
+        System.setErr(new PrintStream(this.captureErr));
+    }
+
+    protected void releaseOutput() {
+        System.setOut(this.captureOut.getOriginal());
+        System.setErr(this.captureErr.getOriginal());
+        this.copy = null;
+    }
+
+    /**
+     * Discard all currently accumulated output.
+     */
+    public void reset() {
+        this.copy.reset();
+    }
+
+    public void flush() {
+        try {
+            this.captureOut.flush();
+            this.captureErr.flush();
+        }
+        catch (IOException ex) {
+            // ignore
+        }
+    }
+
+    @Override
+    public String toString() {
+        flush();
+        return this.copy.toString();
+    }
+
+    /**
+     * Verify that the output is matched by the supplied {@code matcher}. Verification is
+     * performed after the test method has executed.
+     * @param matcher the matcher
+     */
+    public void expect(Matcher<? super String> matcher) {
+        this.matchers.add(matcher);
+    }
+
+    private static class CaptureOutputStream extends OutputStream {
+
+        private final PrintStream original;
+
+        private final OutputStream copy;
+
+        CaptureOutputStream(PrintStream original, OutputStream copy) {
+            this.original = original;
+            this.copy = copy;
+        }
+
+        @Override
+        public void write(int b) throws IOException {
+            this.copy.write(b);
+            this.original.write(b);
+            this.original.flush();
+        }
+
+        @Override
+        public void write(byte[] b) throws IOException {
+            write(b, 0, b.length);
+        }
+
+        @Override
+        public void write(byte[] b, int off, int len) throws IOException {
+            this.copy.write(b, off, len);
+            this.original.write(b, off, len);
+        }
+
+        public PrintStream getOriginal() {
+            return this.original;
+        }
+
+        @Override
+        public void flush() throws IOException {
+            this.copy.flush();
+            this.original.flush();
+        }
+
+    }
+
+}
\ No newline at end of file
diff --git a/sandbox-test/src/main/java/com/alibaba/jvm/sandbox/module/junit/rule/SandboxRule.java b/sandbox-test/src/main/java/com/alibaba/jvm/sandbox/module/junit/rule/SandboxRule.java
new file mode 100644
index 00000000..7f3f9929
--- /dev/null
+++ b/sandbox-test/src/main/java/com/alibaba/jvm/sandbox/module/junit/rule/SandboxRule.java
@@ -0,0 +1,170 @@
+package com.alibaba.jvm.sandbox.module.junit.rule;
+
+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.core.CoreConfigure;
+import com.alibaba.jvm.sandbox.core.CoreModule;
+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.DefaultCoreLoadedClassDataSource;
+import com.alibaba.jvm.sandbox.core.util.FeatureCodec;
+import com.alibaba.jvm.sandbox.module.junit.annotations.PrepareForTest;
+import com.alibaba.jvm.sandbox.module.junit.mock.DummyProviderManager;
+import com.alibaba.jvm.sandbox.module.junit.mock.MockLoadedClassesOnlyInstrumentation;
+import com.alibaba.jvm.sandbox.module.junit.support.JvmHelper;
+import com.alibaba.jvm.sandbox.module.junit.support.SandboxModuleJarBuilder;
+import net.bytebuddy.agent.ByteBuddyAgent;
+import org.apache.commons.lang3.StringUtils;
+import org.junit.Assert;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+
+import static com.alibaba.jvm.sandbox.api.ModuleException.ErrorCode.MODULE_ACTIVE_ERROR;
+import static java.io.File.createTempFile;
+
+/**
+ * @author <a href="mailto:renyi.cry@alibaba-inc.com">renyi.cry<a/>
+ * @date 2019-05-13 18:31
+ */
+public class SandboxRule implements TestRule {
+
+    private static final MockLoadedClassesOnlyInstrumentation mockInstrumentation
+            = new MockLoadedClassesOnlyInstrumentation();
+
+    private String id;
+
+    private String version;
+
+    private boolean unsafeEnable;
+
+    private File tempJarFile;
+
+    @Override
+    public Statement apply(final Statement statement, final Description description) {
+
+        return new Statement() {
+            @Override
+            public void evaluate() throws Throwable {
+
+                PrepareForTest prepareForTest = description.getAnnotation(PrepareForTest.class);
+
+                if (prepareForTest != null) {
+
+                    JvmHelper.createJvm(prepareForTest.namespace());
+
+                    CoreLoadedClassDataSource coreLoadedClassDataSource;
+
+                    if (prepareForTest.fastMode()) {
+
+                        unsafeEnable = prepareForTest.isEnableUnsafe();
+
+                        coreLoadedClassDataSource = new DefaultCoreLoadedClassDataSource(mockInstrumentation, unsafeEnable);
+
+                        Class[] classes = prepareForTest.spyClasses();
+                        for (Class aClass : classes) {
+                            mockInstrumentation.regLoadedClass(aClass);
+                        }
+
+                    } else {
+
+                        unsafeEnable = true;
+
+                        coreLoadedClassDataSource = new DefaultCoreLoadedClassDataSource(ByteBuddyAgent.install(), unsafeEnable);
+
+                    }
+
+                    tempJarFile = createTempFile("test-", ".jar");
+
+                    final CoreModuleManager coreModuleManager = buildingCoreModuleManager(
+                            coreLoadedClassDataSource,
+                            buildingModuleJarFileWithModuleClass(
+                                    tempJarFile,
+                                    prepareForTest.testModule()
+                            )
+                    );
+
+                    Information information = (Information) prepareForTest.testModule().getAnnotation(Information.class);
+
+                    version = information.version();
+
+                    final CoreModule secCheckModule = coreModuleManager
+                            .getThrowsExceptionIfNull(id = information.id());
+
+                    try {
+                        coreModuleManager.active(secCheckModule);
+                    } catch (ModuleException me) {
+                        Assert.assertEquals(MODULE_ACTIVE_ERROR, me.getErrorCode());
+                    }
+
+                }
+
+                statement.evaluate();
+            }
+        };
+
+    }
+
+
+    private CoreModuleManager buildingCoreModuleManager(final CoreLoadedClassDataSource coreLoadedClassDataSource,
+                                                        final File... moduleJarFiles) throws ModuleException {
+        // should be a better
+        return new DefaultCoreModuleManager(
+                buildingCoreConfigureWithUserModuleLib(moduleJarFiles),
+                mockInstrumentation,
+                coreLoadedClassDataSource,
+                new DummyProviderManager()
+        ).reset();
+    }
+
+    private File buildingModuleJarFileWithModuleClass(final File targetModuleJarFile,
+                                                      final Class<? extends Module>... classOfModules) throws IOException {
+
+        // 沙箱模块构造器，构造一个临时的jar file
+        final SandboxModuleJarBuilder sandboxModuleJarBuilder = SandboxModuleJarBuilder.building(targetModuleJarFile);
+
+        // 在这个jar file里加入各个class
+        for (final Class<? extends Module> classOfModule : classOfModules) {
+            sandboxModuleJarBuilder.putModuleClass(classOfModule);
+        }
+
+        return sandboxModuleJarBuilder.build();
+    }
+
+
+    private CoreConfigure buildingCoreConfigureWithUserModuleLib(final File... moduleJarFileArray) {
+
+        final Set<String> moduleJarFilePathSet = new LinkedHashSet<String>();
+        for (final File moduleJarFile : moduleJarFileArray) {
+            moduleJarFilePathSet.add(moduleJarFile.getPath());
+        }
+
+        final Map<String, String> featureMap = new HashMap<String, String>();
+        featureMap.put("user_module", StringUtils.join(moduleJarFilePathSet, ";"));
+        featureMap.put("system_module", System.getProperty("user.home"));
+        featureMap.put("unsafe.enable", String.valueOf(unsafeEnable));
+
+        return CoreConfigure.toConfigure(new FeatureCodec(';', '=').toString(featureMap), null);
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public String getVersion() {
+        return version;
+    }
+
+    public File getTempJarFile() {
+        return tempJarFile;
+    }
+}
diff --git a/sandbox-test/src/main/java/com/alibaba/jvm/sandbox/module/junit/runner/SandboxRunner.java b/sandbox-test/src/main/java/com/alibaba/jvm/sandbox/module/junit/runner/SandboxRunner.java
new file mode 100644
index 00000000..83580369
--- /dev/null
+++ b/sandbox-test/src/main/java/com/alibaba/jvm/sandbox/module/junit/runner/SandboxRunner.java
@@ -0,0 +1,129 @@
+package com.alibaba.jvm.sandbox.module.junit.runner;
+
+import com.alibaba.jvm.sandbox.module.junit.annotations.PrepareForTest;
+import com.alibaba.jvm.sandbox.module.junit.annotations.SandboxTestConfig;
+import com.alibaba.jvm.sandbox.module.junit.support.ReflectionUtils;
+import com.google.common.collect.Sets;
+import org.junit.runners.BlockJUnit4ClassRunner;
+import org.junit.runners.model.InitializationError;
+
+import java.lang.reflect.Method;
+import java.net.URLClassLoader;
+import java.util.List;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+/**
+ * A runner that manage the class loading
+ *
+ * @deprecated this class is used for the early version
+ * @author <a href="mailto:renyi.cry@alibaba-inc.com">renyi.cry<a/>
+ * @date 2019-05-13 19:35
+ */
+@Deprecated
+public class SandboxRunner extends BlockJUnit4ClassRunner {
+
+    private static final Pattern SANDBOX_CORE_PATTERN = Pattern.compile("com\\.alibaba\\.jvm\\.sandbox\\.core\\..*");
+
+    private static final Pattern SANDBOX_JUNIT_PATTERN = Pattern.compile("com\\.alibaba\\.jvm\\.sandbox\\.module\\.junit\\..*");
+
+    public SandboxRunner(Class<?> klass) throws InitializationError {
+        super(getFromTestClassloader(klass));
+    }
+
+    private static void fulfill(TestClassLoader testClassLoader, Class<?> clazz) {
+
+        SandboxTestConfig config = clazz.getAnnotation(SandboxTestConfig.class);
+
+        if (config != null) {
+            if (config.spySandboxCore()) {
+                testClassLoader.addSpyClassNamePattern(SANDBOX_CORE_PATTERN);
+            }
+            if (config.spySandboxJunit()) {
+                testClassLoader.addSpyClassNamePattern(SANDBOX_JUNIT_PATTERN);
+            }
+            String[] patterns = config.spyPatterns();
+            if (patterns.length > 0) {
+                for (String pattern : patterns) {
+                    testClassLoader.addSpyClassNamePattern(Pattern.compile(pattern));
+                }
+            }
+        }
+
+        // First, get the base list of tests
+        final List<Method> allMethods = ReflectionUtils.getMethodsAnnotatedWith(clazz, PrepareForTest.class);
+        if (allMethods.size() == 0) {
+            return;
+        }
+
+        for (Method method : allMethods) {
+            PrepareForTest prepareForTest = method.getAnnotation(PrepareForTest.class);
+            testClassLoader.addSpyClasses(prepareForTest.spyClasses());
+            String[] names = prepareForTest.spyClassNames();
+            for (String name : names) {
+                testClassLoader.addSpyClassNamePattern(Pattern.compile(name));
+            }
+        }
+
+    }
+
+    private static Class<?> getFromTestClassloader(Class<?> clazz) throws InitializationError {
+        try {
+            TestClassLoader testClassLoader = new TestClassLoader(clazz);
+            fulfill(testClassLoader, clazz);
+            return Class.forName(clazz.getName(), true, testClassLoader);
+        } catch (ClassNotFoundException e) {
+            throw new InitializationError(e);
+        }
+    }
+
+    public static class TestClassLoader extends URLClassLoader {
+
+        private Set<String> spyClasses = Sets.newConcurrentHashSet();
+
+        private Set<Pattern> spyClassNamePatterns = Sets.newConcurrentHashSet();
+
+        private Set<String> loadedClass = Sets.newConcurrentHashSet();
+
+        TestClassLoader(Class<?> clazz) {
+            super(((URLClassLoader) getSystemClassLoader()).getURLs());
+            spyClasses.add(clazz.getName());
+        }
+
+        @Override
+        public Class<?> loadClass(String name) throws ClassNotFoundException {
+
+            if (name.startsWith("java.")) {
+                loadedClass.add(name);
+            }
+
+            // the class should be spied if matches
+            for (Pattern spyClassNamePattern : spyClassNamePatterns) {
+                if (spyClassNamePattern.matcher(name).matches()) {
+                    spyClasses.add(name);
+                }
+            }
+
+            if (spyClasses.contains(name) && !loadedClass.contains(name)) {
+                loadedClass.add(name);
+                System.out.println("reload:" + name);
+                return super.findClass(name);
+            }
+
+            return super.loadClass(name);
+
+        }
+
+        void addSpyClasses(Class<?>[] classes) {
+            for (Class<?> aClass : classes) {
+                spyClasses.add(aClass.getName());
+            }
+        }
+
+        void addSpyClassNamePattern(Pattern pattern) {
+            spyClassNamePatterns.add(pattern);
+        }
+
+    }
+
+}
diff --git a/sandbox-test/src/main/java/com/alibaba/jvm/sandbox/module/junit/support/JarBuilder.java b/sandbox-test/src/main/java/com/alibaba/jvm/sandbox/module/junit/support/JarBuilder.java
new file mode 100644
index 00000000..ef4ad1ce
--- /dev/null
+++ b/sandbox-test/src/main/java/com/alibaba/jvm/sandbox/module/junit/support/JarBuilder.java
@@ -0,0 +1,84 @@
+package com.alibaba.jvm.sandbox.module.junit.support;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.jar.JarEntry;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+
+import static com.alibaba.jvm.sandbox.core.util.SandboxStringUtils.toInternalClassName;
+import static org.apache.commons.io.IOUtils.closeQuietly;
+
+public class JarBuilder {
+
+    private final File targetJarFile;
+    private final Manifest manifest = new Manifest();
+    private final Map<String, byte[]> entryDataMap = new LinkedHashMap<String, byte[]>();
+
+    public JarBuilder(File targetJarFile) {
+        this.targetJarFile = targetJarFile;
+    }
+
+    public JarBuilder manifest(String name, String value) {
+        manifest.getMainAttributes().putValue(name, value);
+        return this;
+    }
+
+    public JarBuilder putEntry(Class<?> clazz) throws IOException {
+        entryDataMap.put(
+                toInternalClassName(clazz.getName()) + ".class",
+                QaClassUtils.toByteArray(clazz)
+        );
+        return this;
+    }
+
+    public JarBuilder putEntry(String name, byte[] dataArray) {
+        entryDataMap.put(name, dataArray);
+        return this;
+    }
+
+    public JarBuilder putEntry(String name, String text, Charset charset) {
+        entryDataMap.put(name, text.getBytes(charset));
+        return this;
+    }
+
+    public JarBuilder putEntry(String name, String text) {
+        entryDataMap.put(name, text.getBytes());
+        return this;
+    }
+
+    private static Manifest mergeJarManifest(final Manifest targetJarManifest) {
+        Manifest mergeManifest = new Manifest();
+        if (null != targetJarManifest) {
+            mergeManifest.getEntries().putAll(targetJarManifest.getEntries());
+        }
+        mergeManifest.getMainAttributes().putValue("Manifest-Version", "1.0");
+        mergeManifest.getMainAttributes().putValue("Created-By", "QaJarUtils");
+        mergeManifest.getMainAttributes().putValue("Author", "oldmanpushcart@gmail.com");
+        return mergeManifest;
+    }
+
+    public File build() throws IOException {
+        JarOutputStream jos = null;
+        try {
+            jos = new JarOutputStream(new FileOutputStream(targetJarFile), mergeJarManifest(manifest));
+            for (Map.Entry<String, byte[]> entry : entryDataMap.entrySet()) {
+                jos.putNextEntry(new JarEntry(entry.getKey()));
+                jos.write(entry.getValue());
+            }
+        } finally {
+            closeQuietly(jos);
+        }
+        return targetJarFile;
+    }
+
+
+    public static JarBuilder building(final File targetJarFile) {
+        return new JarBuilder(targetJarFile);
+    }
+
+}
diff --git a/sandbox-test/src/main/java/com/alibaba/jvm/sandbox/module/junit/support/JvmHelper.java b/sandbox-test/src/main/java/com/alibaba/jvm/sandbox/module/junit/support/JvmHelper.java
new file mode 100644
index 00000000..3dbf9a0b
--- /dev/null
+++ b/sandbox-test/src/main/java/com/alibaba/jvm/sandbox/module/junit/support/JvmHelper.java
@@ -0,0 +1,29 @@
+package com.alibaba.jvm.sandbox.module.junit.support;
+
+import com.alibaba.jvm.sandbox.core.util.SpyUtils;
+import org.apache.commons.lang3.StringUtils;
+
+import static com.alibaba.jvm.sandbox.core.CoreConfigure.toConfigure;
+
+/**
+ * JVM帮助类，能模拟一个JVM对类的管理行为
+ */
+public class JvmHelper {
+
+    private final String namespace;
+
+    private JvmHelper(final String namespace) {
+        this.namespace = namespace;
+        SpyUtils.init(namespace);
+        toConfigure(String.format(";namespace=%s;", namespace), "");
+    }
+
+    public static JvmHelper createJvm(final String namespace) {
+        return new JvmHelper(StringUtils.isBlank(namespace) ? "default" : namespace);
+    }
+
+    public String getNamespace() {
+        return namespace;
+    }
+
+}
diff --git a/sandbox-test/src/main/java/com/alibaba/jvm/sandbox/module/junit/support/QaClassUtils.java b/sandbox-test/src/main/java/com/alibaba/jvm/sandbox/module/junit/support/QaClassUtils.java
new file mode 100644
index 00000000..57d11c5e
--- /dev/null
+++ b/sandbox-test/src/main/java/com/alibaba/jvm/sandbox/module/junit/support/QaClassUtils.java
@@ -0,0 +1,32 @@
+package com.alibaba.jvm.sandbox.module.junit.support;
+
+import org.apache.commons.io.IOUtils;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import static com.alibaba.jvm.sandbox.core.util.SandboxStringUtils.toInternalClassName;
+
+public class QaClassUtils {
+
+    /**
+     * 目标Class文件转换为字节码数组
+     *
+     * @param targetClass 目标Class文件
+     * @return 目标Class文件字节码数组
+     * @throws IOException 转换出错
+     */
+    public static byte[] toByteArray(final Class<?> targetClass) throws IOException {
+        final InputStream is = targetClass.getClassLoader().getResourceAsStream(toResourceName(targetClass.getName()));
+        try {
+            return IOUtils.toByteArray(is);
+        } finally {
+            IOUtils.closeQuietly(is);
+        }
+    }
+
+    public static String toResourceName(String javaClassName) {
+        return toInternalClassName(javaClassName).concat(".class");
+    }
+
+}
diff --git a/sandbox-test/src/main/java/com/alibaba/jvm/sandbox/module/junit/support/ReflectionUtils.java b/sandbox-test/src/main/java/com/alibaba/jvm/sandbox/module/junit/support/ReflectionUtils.java
new file mode 100644
index 00000000..7314ccc7
--- /dev/null
+++ b/sandbox-test/src/main/java/com/alibaba/jvm/sandbox/module/junit/support/ReflectionUtils.java
@@ -0,0 +1,32 @@
+package com.alibaba.jvm.sandbox.module.junit.support;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:renyi.cry@alibaba-inc.com">renyi.cry<a/>
+ * @date 2019-05-13 20:52
+ */
+public class ReflectionUtils {
+
+    public static List<Method> getMethodsAnnotatedWith(final Class<?> type, final Class<? extends Annotation> annotation) {
+        final List<Method> methods = new ArrayList<Method>();
+        Class<?> klass = type;
+        while (klass != Object.class) { // need to iterated thought hierarchy in order to retrieve methods from above the current instance
+            // iterate though the list of methods declared in the class represented by klass variable, and add those annotated with the specified annotation
+            final List<Method> allMethods = new ArrayList<Method>(Arrays.asList(klass.getDeclaredMethods()));
+            for (final Method method : allMethods) {
+                if (method.isAnnotationPresent(annotation)) {
+                    methods.add(method);
+                }
+            }
+            // move to the upper class in the hierarchy in search for more methods
+            klass = klass.getSuperclass();
+        }
+        return methods;
+    }
+
+}
diff --git a/sandbox-test/src/main/java/com/alibaba/jvm/sandbox/module/junit/support/SandboxModuleJarBuilder.java b/sandbox-test/src/main/java/com/alibaba/jvm/sandbox/module/junit/support/SandboxModuleJarBuilder.java
new file mode 100644
index 00000000..ba8e2f28
--- /dev/null
+++ b/sandbox-test/src/main/java/com/alibaba/jvm/sandbox/module/junit/support/SandboxModuleJarBuilder.java
@@ -0,0 +1,43 @@
+package com.alibaba.jvm.sandbox.module.junit.support;
+
+import com.alibaba.jvm.sandbox.api.Module;
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+public class SandboxModuleJarBuilder extends JarBuilder {
+
+    private final Set<String> moduleSpiSet = new LinkedHashSet<String>();
+
+    public SandboxModuleJarBuilder(File targetJarFile) {
+        super(targetJarFile);
+    }
+
+    public SandboxModuleJarBuilder putModuleClass(final Class<? extends Module> classOfModule) throws IOException {
+        super.putEntry(classOfModule);
+        moduleSpiSet.add(classOfModule.getName());
+        return this;
+    }
+
+    private void putModuleSpi() {
+        putEntry(
+                "META-INF/services/com.alibaba.jvm.sandbox.api.Module",
+                StringUtils.join(moduleSpiSet, "\n")
+        );
+    }
+
+    @Override
+    public File build() throws IOException {
+        putModuleSpi();
+        return super.build();
+    }
+
+
+    public static SandboxModuleJarBuilder building(final File targetJarFile) {
+        return new SandboxModuleJarBuilder(targetJarFile);
+    }
+
+}
diff --git a/sandbox-test/src/main/resources/lib/sandbox-spy-1.3.3-for-qatest.jar b/sandbox-test/src/main/resources/lib/sandbox-spy-1.3.3-for-qatest.jar
new file mode 100644
index 00000000..0717a42e
Binary files /dev/null and b/sandbox-test/src/main/resources/lib/sandbox-spy-1.3.3-for-qatest.jar differ
diff --git a/sandbox-test/src/main/resources/logback.xml b/sandbox-test/src/main/resources/logback.xml
new file mode 100755
index 00000000..11a2117d
--- /dev/null
+++ b/sandbox-test/src/main/resources/logback.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<configuration scan="true" scanPeriod="10000">
+
+    <appender name="STDOUT-APPENDER" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>%d{yyyy-MM-dd HH:mm:ss} %5level %msg%n</pattern>　　
+        </encoder>
+    </appender>
+
+    <root level="all">
+        <appender-ref ref="STDOUT-APPENDER"/>
+    </root>
+
+</configuration>
\ No newline at end of file
diff --git a/sandbox-test/src/test/java/com/alibaba/jvm/sandbox/module/junit/probe/DummyModule.java b/sandbox-test/src/test/java/com/alibaba/jvm/sandbox/module/junit/probe/DummyModule.java
new file mode 100644
index 00000000..d4d5900c
--- /dev/null
+++ b/sandbox-test/src/test/java/com/alibaba/jvm/sandbox/module/junit/probe/DummyModule.java
@@ -0,0 +1,53 @@
+package com.alibaba.jvm.sandbox.module.junit.probe;
+
+import com.alibaba.jvm.sandbox.api.Information;
+import com.alibaba.jvm.sandbox.api.Module;
+import com.alibaba.jvm.sandbox.api.ModuleLifecycleAdapter;
+import com.alibaba.jvm.sandbox.api.event.Event;
+import com.alibaba.jvm.sandbox.api.filter.AccessFlags;
+import com.alibaba.jvm.sandbox.api.listener.ext.EventWatchBuilder;
+import com.alibaba.jvm.sandbox.api.resource.ModuleEventWatcher;
+import org.kohsuke.MetaInfServices;
+
+import javax.annotation.Resource;
+
+/**
+ * @author <a href="mailto:renyi.cry@alibaba-inc.com">renyi.cry<a/>
+ * @date 2020/11/17 2:54 下午
+ */
+@MetaInfServices(Module.class)
+@Information(id = "dummy-module", version = "1.0.0", author = "renyi.cry")
+public class DummyModule extends ModuleLifecycleAdapter implements Module {
+
+    @Resource
+    private ModuleEventWatcher moduleEventWatcher;
+
+    @Override
+    public void loadCompleted() {
+
+        new EventWatchBuilder(moduleEventWatcher, EventWatchBuilder.PatternType.WILDCARD)
+                .onClass("javax.servlet.http.HttpServlet")
+                .includeBootstrap()
+                .includeSubClasses()
+                .withAccess(AccessFlags.ACF_PUBLIC)
+                .onBehavior("service")
+                .withParameterTypes(
+                        "javax.servlet.http.HttpServletRequest",
+                        "javax.servlet.http.HttpServletResponse"
+                )
+                .onWatch(new ServletListner(), Event.Type.BEFORE, Event.Type.RETURN, Event.Type.THROWS);
+
+        new EventWatchBuilder(moduleEventWatcher, EventWatchBuilder.PatternType.WILDCARD)
+                .onClass(String.class)
+                .includeBootstrap()
+                .includeSubClasses()
+                .withAccess(AccessFlags.ACF_PUBLIC)
+                .onBehavior("<init>")
+                .withParameterTypes(String.class)
+                .onWatch(new StringListener(), Event.Type.BEFORE, Event.Type.RETURN, Event.Type.THROWS);
+
+
+    }
+
+
+}
diff --git a/sandbox-test/src/test/java/com/alibaba/jvm/sandbox/module/junit/probe/HttpAccess.java b/sandbox-test/src/test/java/com/alibaba/jvm/sandbox/module/junit/probe/HttpAccess.java
new file mode 100644
index 00000000..83ffdfdf
--- /dev/null
+++ b/sandbox-test/src/test/java/com/alibaba/jvm/sandbox/module/junit/probe/HttpAccess.java
@@ -0,0 +1,54 @@
+package com.alibaba.jvm.sandbox.module.junit.probe;
+
+import java.util.Map;
+
+public class HttpAccess {
+
+    private final String from;
+    private final String method;
+    private final String uri;
+    private final Map<String, String[]> parameterMap;
+    private final String userAgent;
+    private int status = 200;
+
+    public HttpAccess(final String from,
+                      final String method,
+                      final String uri,
+                      final Map<String, String[]> parameterMap,
+                      final String userAgent) {
+        this.from = from;
+        this.method = method;
+        this.uri = uri;
+        this.parameterMap = parameterMap;
+        this.userAgent = userAgent;
+    }
+
+    public String getFrom() {
+        return from;
+    }
+
+    public String getMethod() {
+        return method;
+    }
+
+    public String getUri() {
+        return uri;
+    }
+
+    public Map<String, String[]> getParameterMap() {
+        return parameterMap;
+    }
+
+    public String getUserAgent() {
+        return userAgent;
+    }
+
+    public int getStatus() {
+        return status;
+    }
+
+    public void setStatus(int status) {
+        this.status = status;
+    }
+
+}
diff --git a/sandbox-test/src/test/java/com/alibaba/jvm/sandbox/module/junit/probe/InterfaceProxyUtils.java b/sandbox-test/src/test/java/com/alibaba/jvm/sandbox/module/junit/probe/InterfaceProxyUtils.java
new file mode 100644
index 00000000..9f581ede
--- /dev/null
+++ b/sandbox-test/src/test/java/com/alibaba/jvm/sandbox/module/junit/probe/InterfaceProxyUtils.java
@@ -0,0 +1,171 @@
+package com.alibaba.jvm.sandbox.module.junit.probe;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static com.alibaba.jvm.sandbox.api.util.GaStringUtils.getJavaClassName;
+import static com.alibaba.jvm.sandbox.api.util.GaStringUtils.getJavaClassNameArray;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import static java.util.Arrays.deepEquals;
+
+public class InterfaceProxyUtils {
+
+    @Target(METHOD)
+    @Retention(RUNTIME)
+    public @interface ProxyMethod {
+
+        /**
+         * 目标方法名
+         *
+         * @return 目标方法名
+         */
+        String name();
+
+    }
+
+    /**
+     * 用于包装目标对象操作的代理方法处理
+     */
+    static abstract class WrapInvocationHandler implements InvocationHandler {
+
+        final Map<Method, Method> mappingOfWrapMethods = new ConcurrentHashMap<Method, Method>();
+
+        String getInterfaceMethodName(final Method interfaceMethod) {
+            final ProxyMethod proxyMethod = interfaceMethod.getAnnotation(ProxyMethod.class);
+            return null == proxyMethod
+                    ? interfaceMethod.getName()
+                    : proxyMethod.name();
+        }
+
+        /**
+         * 比较interfaceMethod和targetMethod两个方法是否接近
+         *
+         * @param interfaceMethod 接口声明的方法
+         * @param targetMethod    目标对象声明的方法
+         * @return TRUE:接近;FALSE:不接近
+         */
+        boolean isCloseTo(final Method interfaceMethod, final Method targetMethod) {
+            return StringUtils.equals(getInterfaceMethodName(interfaceMethod), targetMethod.getName())
+                    && deepEquals(getJavaClassNameArray(interfaceMethod.getParameterTypes()), getJavaClassNameArray(targetMethod.getParameterTypes()));
+        }
+
+        Method getTargetMethod(final Method interfaceMethod, final Object target) throws NoSuchMethodException {
+            if (mappingOfWrapMethods.containsKey(interfaceMethod)) {
+                return mappingOfWrapMethods.get(interfaceMethod);
+            }
+            for (final Method targetMethod : target.getClass().getMethods()) {
+                if (isCloseTo(interfaceMethod, targetMethod)) {
+                    mappingOfWrapMethods.put(interfaceMethod, targetMethod);
+                    return targetMethod;
+                }
+            }
+            throw new NoSuchMethodException(String.format("%s.%s(%s) method not found!",
+                    getJavaClassName(target.getClass()),
+                    getInterfaceMethodName(interfaceMethod),
+                    StringUtils.join(getJavaClassNameArray(interfaceMethod.getParameterTypes()), ",")
+            ));
+        }
+
+    }
+
+    /**
+     * 构造一个接口的实现傀儡类，用接口去调用目标类
+     *
+     * @param interfaceClass 目标接口
+     * @param target         傀儡类实例
+     * @param <T>            目标接口类型
+     * @return 被目标接口操纵的傀儡对象实例
+     */
+    public static <T> T puppet(final Class<T> interfaceClass,
+                               final Object target) {
+        return (T) Proxy.newProxyInstance(
+                interfaceClass.getClassLoader(),
+                new Class<?>[]{interfaceClass},
+                new WrapInvocationHandler() {
+
+                    @Override
+                    public Object invoke(Object proxy, Method interfaceMethod, Object[] args) throws Throwable {
+                        return getTargetMethod(interfaceMethod, target).invoke(target, args);
+                    }
+
+                }
+        );
+    }
+
+
+    public interface MethodInterceptor {
+        Object invoke(MethodInvocation methodInvocation) throws Throwable;
+    }
+
+    public interface MethodInvocation {
+        Method getMethod();
+
+        Object[] getArguments();
+
+        Object proceed() throws Throwable;
+
+        Object getThis();
+
+        AccessibleObject getStaticPart();
+    }
+
+    /**
+     * 拦截目标类的方法
+     *
+     * @param interfaceClassInTargetClassLoader 目标接口
+     * @param targetClassLoader                 目标对象所在ClassLoader
+     * @param target                            目标对象实例
+     * @param interceptor                       拦截器
+     * @return 带拦截器的目标对象实例
+     */
+    public static Object intercept(final Class<?> interfaceClassInTargetClassLoader,
+                                   final ClassLoader targetClassLoader,
+                                   final Object target,
+                                   final MethodInterceptor interceptor) {
+        return Proxy.newProxyInstance(
+                targetClassLoader,
+                new Class<?>[]{interfaceClassInTargetClassLoader},
+                new InvocationHandler() {
+                    @Override
+                    public Object invoke(Object proxy, final Method method, final Object[] args) throws Throwable {
+                        return interceptor.invoke(new MethodInvocation() {
+                            @Override
+                            public Method getMethod() {
+                                return method;
+                            }
+
+                            @Override
+                            public Object[] getArguments() {
+                                return args;
+                            }
+
+                            @Override
+                            public Object proceed() throws Throwable {
+                                return method.invoke(target, args);
+                            }
+
+                            @Override
+                            public Object getThis() {
+                                return target;
+                            }
+
+                            @Override
+                            public AccessibleObject getStaticPart() {
+                                return method;
+                            }
+                        });
+                    }
+                }
+        );
+    }
+
+}
diff --git a/sandbox-test/src/test/java/com/alibaba/jvm/sandbox/module/junit/probe/ServletListner.java b/sandbox-test/src/test/java/com/alibaba/jvm/sandbox/module/junit/probe/ServletListner.java
new file mode 100644
index 00000000..b9e9f702
--- /dev/null
+++ b/sandbox-test/src/test/java/com/alibaba/jvm/sandbox/module/junit/probe/ServletListner.java
@@ -0,0 +1,65 @@
+package com.alibaba.jvm.sandbox.module.junit.probe;
+
+import com.alibaba.jvm.sandbox.api.listener.ext.Advice;
+import com.alibaba.jvm.sandbox.api.listener.ext.AdviceListener;
+
+import java.util.Map;
+
+
+/**
+ * @author <a href="mailto:renyi.cry@alibaba-inc.com">renyi.cry<a/>
+ * @date 2020-10-13 12:17
+ */
+public class ServletListner extends AdviceListener {
+
+    @Override
+    protected void before(Advice advice) throws Throwable {
+
+        if (!advice.isProcessTop()) {
+            return;
+        }
+
+        // wrap httpServletRequest
+        final IHttpServletRequest httpServletRequest = InterfaceProxyUtils.puppet(
+                IHttpServletRequest.class,
+                advice.getParameterArray()[0]
+        );
+
+        // init HttpAccess
+        final HttpAccess httpAccess = new HttpAccess(
+                httpServletRequest.getRemoteAddress(),
+                httpServletRequest.getMethod(),
+                httpServletRequest.getRequestURI(),
+                httpServletRequest.getParameterMap(),
+                httpServletRequest.getHeader("User-Agent")
+        );
+
+        // attach
+        advice.attach(httpAccess);
+
+        String username = httpServletRequest.getHeader("username");
+        if ("admin".equals(username)) {
+            System.out.println("Admin login");
+        } else {
+            System.out.println("login user: " + username);
+        }
+
+
+    }
+
+    private interface IHttpServletRequest {
+
+        @InterfaceProxyUtils.ProxyMethod(name = "getRemoteAddr")
+        String getRemoteAddress();
+
+        String getMethod();
+
+        String getRequestURI();
+
+        Map<String, String[]> getParameterMap();
+
+        String getHeader(String name);
+
+    }
+
+}
diff --git a/sandbox-test/src/test/java/com/alibaba/jvm/sandbox/module/junit/probe/StringListener.java b/sandbox-test/src/test/java/com/alibaba/jvm/sandbox/module/junit/probe/StringListener.java
new file mode 100644
index 00000000..86e42943
--- /dev/null
+++ b/sandbox-test/src/test/java/com/alibaba/jvm/sandbox/module/junit/probe/StringListener.java
@@ -0,0 +1,35 @@
+package com.alibaba.jvm.sandbox.module.junit.probe;
+
+import com.alibaba.jvm.sandbox.api.listener.ext.Advice;
+import com.alibaba.jvm.sandbox.api.listener.ext.AdviceListener;
+
+/**
+ * @author <a href="mailto:renyi.cry@alibaba-inc.com">renyi.cry<a/>
+ * @date 2020/11/17 4:06 下午
+ */
+public class StringListener extends AdviceListener {
+    @Override
+    protected void before(Advice advice) throws Throwable {
+
+        if (!advice.isProcessTop()) {
+            return;
+        }
+
+        if (advice.getTarget() == null) {
+            return;
+        }
+
+        String target = (String)advice.getParameterArray()[0];
+
+        try {
+            if ("password".equals(target)) {
+                System.out.println("has password keyword");
+            }
+        }catch (Exception ex) {
+            ex.printStackTrace();
+        }
+
+
+    }
+
+}
diff --git a/sandbox-test/src/test/java/com/alibaba/jvm/sandbox/module/junit/tests/RuleCase1.java b/sandbox-test/src/test/java/com/alibaba/jvm/sandbox/module/junit/tests/RuleCase1.java
new file mode 100644
index 00000000..dbe10cd0
--- /dev/null
+++ b/sandbox-test/src/test/java/com/alibaba/jvm/sandbox/module/junit/tests/RuleCase1.java
@@ -0,0 +1,85 @@
+package com.alibaba.jvm.sandbox.module.junit.tests;
+
+import com.alibaba.jvm.sandbox.module.junit.annotations.PrepareForTest;
+import com.alibaba.jvm.sandbox.module.junit.probe.DummyModule;
+import com.alibaba.jvm.sandbox.module.junit.rule.OutputCapture;
+import com.alibaba.jvm.sandbox.module.junit.rule.SandboxRule;
+import com.google.common.collect.Maps;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import servlet.cases.DummyServlet;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+import static org.hamcrest.core.StringContains.containsString;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * @author <a href="mailto:renyi.cry@alibaba-inc.com">renyi.cry<a/>
+ * @date 2020/11/17 2:52 下午
+ */
+public class RuleCase1 {
+
+    private HttpServletRequest request;
+
+    private HttpServletResponse response;
+
+    @Rule
+    public SandboxRule sandboxRule = new SandboxRule();
+
+    @Rule
+    public OutputCapture outputCapture = new OutputCapture();
+
+    @Before
+    public void before() {
+
+        // mock http servlet
+        request = mock(HttpServletRequest.class);
+        response = mock(HttpServletResponse.class);
+
+        when(request.getRemoteAddr()).thenReturn("10.10.10.10");
+        when(request.getMethod()).thenReturn("GET");
+        when(request.getRequestURI()).thenReturn("http://mytest.com");
+        when(request.getHeader("User-Agent")).thenReturn("User-Agent");
+        when(request.getParameterMap()).thenReturn(Maps.<String, String[]>newHashMap());
+
+    }
+
+    @Test
+    @PrepareForTest(testModule = DummyModule.class, fastMode = false)
+    public void testcase1() throws ServletException, IOException {
+
+        when(request.getHeader("username")).thenReturn("admin");
+
+        HttpServlet servlet = new DummyServlet();
+
+        servlet.service(request, response);
+
+        String result = outputCapture.toString();
+
+        assertThat(result, containsString("Admin login"));
+    }
+
+    @Test
+    @PrepareForTest(testModule = DummyModule.class, fastMode = false)
+    public void testcase2() throws ServletException, IOException {
+
+        when(request.getHeader("username")).thenReturn("test");
+
+        HttpServlet servlet = new DummyServlet();
+
+        servlet.service(request, response);
+
+        String result = outputCapture.toString();
+
+        assertThat(result, containsString("login user: test"));
+    }
+
+}
diff --git a/sandbox-test/src/test/java/com/alibaba/jvm/sandbox/module/junit/tests/RuleCase2.java b/sandbox-test/src/test/java/com/alibaba/jvm/sandbox/module/junit/tests/RuleCase2.java
new file mode 100644
index 00000000..06c30ed5
--- /dev/null
+++ b/sandbox-test/src/test/java/com/alibaba/jvm/sandbox/module/junit/tests/RuleCase2.java
@@ -0,0 +1,72 @@
+package com.alibaba.jvm.sandbox.module.junit.tests;
+
+import com.alibaba.jvm.sandbox.module.junit.annotations.PrepareForTest;
+import com.alibaba.jvm.sandbox.module.junit.probe.DummyModule;
+import com.alibaba.jvm.sandbox.module.junit.rule.OutputCapture;
+import com.alibaba.jvm.sandbox.module.junit.rule.SandboxRule;
+import com.alibaba.jvm.sandbox.module.junit.runner.SandboxRunner;
+import com.google.common.collect.Maps;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import servlet.cases.DummyServlet;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+import static org.hamcrest.core.StringContains.containsString;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * @author <a href="mailto:renyi.cry@alibaba-inc.com">renyi.cry<a/>
+ * @date 2020/11/17 2:52 下午
+ */
+public class RuleCase2 {
+
+    private HttpServletRequest request;
+
+    private HttpServletResponse response;
+
+    @Rule
+    public SandboxRule sandboxRule = new SandboxRule();
+
+    @Rule
+    public OutputCapture outputCapture = new OutputCapture();
+
+    @Before
+    public void before() {
+
+        // mock http servlet
+        request = mock(HttpServletRequest.class);
+        response = mock(HttpServletResponse.class);
+
+        when(request.getRemoteAddr()).thenReturn("10.10.10.10");
+        when(request.getMethod()).thenReturn("GET");
+        when(request.getRequestURI()).thenReturn("http://mytest.com");
+        when(request.getHeader("User-Agent")).thenReturn("User-Agent");
+        when(request.getParameterMap()).thenReturn(Maps.<String, String[]>newHashMap());
+
+    }
+
+    @Test
+    @PrepareForTest(testModule = DummyModule.class, spyClasses = DummyServlet.class)
+    public void testcaseWithFastMode() throws ServletException, IOException {
+
+        when(request.getHeader("username")).thenReturn("admin");
+
+        HttpServlet servlet = new DummyServlet();
+
+        servlet.service(request, response);
+
+        String result = outputCapture.toString();
+
+        assertThat(result, containsString("Admin login"));
+    }
+
+}
diff --git a/sandbox-test/src/test/java/com/alibaba/jvm/sandbox/module/junit/tests/RuleCase3.java b/sandbox-test/src/test/java/com/alibaba/jvm/sandbox/module/junit/tests/RuleCase3.java
new file mode 100644
index 00000000..4d40d45a
--- /dev/null
+++ b/sandbox-test/src/test/java/com/alibaba/jvm/sandbox/module/junit/tests/RuleCase3.java
@@ -0,0 +1,64 @@
+package com.alibaba.jvm.sandbox.module.junit.tests;
+
+import com.alibaba.jvm.sandbox.module.junit.annotations.PrepareForTest;
+import com.alibaba.jvm.sandbox.module.junit.probe.DummyModule;
+import com.alibaba.jvm.sandbox.module.junit.rule.OutputCapture;
+import com.alibaba.jvm.sandbox.module.junit.rule.SandboxRule;
+import org.hamcrest.Matchers;
+import org.junit.Rule;
+import org.junit.Test;
+
+import static org.hamcrest.core.StringContains.containsString;
+import static org.junit.Assert.assertThat;
+
+/**
+ * @author <a href="mailto:renyi.cry@alibaba-inc.com">renyi.cry<a/>
+ * @date 2020/11/17 3:29 下午
+ */
+public class RuleCase3 {
+    @Rule
+    public SandboxRule sandboxRule = new SandboxRule();
+
+    @Rule
+    public OutputCapture outputCapture = new OutputCapture();
+
+    @Test
+    @PrepareForTest(testModule = DummyModule.class, spyClasses = String.class)
+    public void testcase1() {
+
+        String test = new String("password");
+
+        System.out.println(test);
+
+        String result = outputCapture.toString();
+
+        assertThat(result, Matchers.not(containsString("has password keyword")));
+    }
+
+    @Test
+    @PrepareForTest(testModule = DummyModule.class, spyClasses = String.class, isEnableUnsafe = true)
+    public void testcase2() {
+
+        String test = new String("password");
+
+        System.out.println(test);
+
+        String result = outputCapture.toString();
+
+        assertThat(result, containsString("has password keyword"));
+    }
+
+    @Test
+    @PrepareForTest(testModule = DummyModule.class, fastMode = false)
+    public void testcase3() {
+
+        String test = new String("password");
+
+        System.out.println(test);
+
+        String result = outputCapture.toString();
+
+        assertThat(result, containsString("has password keyword"));
+    }
+
+}
diff --git a/sandbox-test/src/test/java/servlet/cases/DummyServlet.java b/sandbox-test/src/test/java/servlet/cases/DummyServlet.java
new file mode 100644
index 00000000..97be7c4f
--- /dev/null
+++ b/sandbox-test/src/test/java/servlet/cases/DummyServlet.java
@@ -0,0 +1,20 @@
+package servlet.cases;
+
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * @author <a href="mailto:renyi.cry@alibaba-inc.com">renyi.cry<a/>
+ * @date 2020/11/17 2:39 下午
+ */
+public class DummyServlet extends HttpServlet {
+
+    @Override
+    protected void service(HttpServletRequest req, HttpServletResponse resp) {
+
+        System.out.println("dummy1:" + req.getHeader("username"));
+
+    }
+
+}
diff --git a/sandbox-test/src/test/resources/lib/sandbox-spy-1.3.3-for-qatest.jar b/sandbox-test/src/test/resources/lib/sandbox-spy-1.3.3-for-qatest.jar
new file mode 100644
index 00000000..0717a42e
Binary files /dev/null and b/sandbox-test/src/test/resources/lib/sandbox-spy-1.3.3-for-qatest.jar differ
diff --git a/sandbox-test/src/test/resources/logback.xml b/sandbox-test/src/test/resources/logback.xml
new file mode 100755
index 00000000..cdbe9fad
--- /dev/null
+++ b/sandbox-test/src/test/resources/logback.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<configuration scan="true" scanPeriod="10000">
+
+    <appender name="STDOUT-APPENDER" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>%d{yyyy-MM-dd HH:mm:ss} %5level %msg%n</pattern>　　
+        </encoder>
+    </appender>
+
+    <root level="info">
+        <appender-ref ref="STDOUT-APPENDER"/>
+    </root>
+
+</configuration>
\ No newline at end of file