This is an automated email from the ASF dual-hosted git repository.

xiaoyu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-shenyu.git


The following commit(s) were added to refs/heads/master by this push:
     new 9b21e9c8f [ISSUE #3221]record log handle selector (#3387)
9b21e9c8f is described below

commit 9b21e9c8f9b571e0cb11ad6bad291b60d84be0c8
Author: likeguo <[email protected]>
AuthorDate: Fri May 6 15:42:04 2022 +0800

    [ISSUE #3221]record log handle selector (#3387)
    
    * fixbug/pg script error
    
    * feature/record-log-handle-selector
    
    * feature/record-log-handle-selector
    
    * feature/record-log-handle-selector
    
    * feature/record-log-handle-selector
    
    * feature/record-log-handle-selector
---
 .../shenyu/admin/mapper/PluginHandleMapper.java    |  18 ++
 .../shenyu/admin/model/enums/EventTypeEnum.java    |  63 ++++-
 .../admin/model/event/BatchChangedEvent.java       |   2 +-
 .../BatchPluginHandleChangedEvent.java}            |  17 +-
 .../PluginHandleChangedEvent.java}                 |  40 +--
 .../{ => plugin}/BatchPluginChangedEvent.java      |   3 +-
 .../BatchPluginDeletedEvent.java}                  |  30 +-
 .../event/{ => plugin}/PluginChangedEvent.java     |   3 +-
 .../PluginCreatedEvent.java}                       |  37 +--
 .../event/selector/BatchSelectorDeletedEvent.java  |  66 +++++
 .../SelectorChangedEvent.java}                     |  34 ++-
 .../model/event/selector/SelectorCreatedEvent.java |  48 ++++
 .../shenyu/admin/service/PluginHandleService.java  |  36 ++-
 .../shenyu/admin/service/ResourceService.java      |   9 +-
 .../shenyu/admin/service/SelectorService.java      |  28 +-
 .../admin/service/impl/PermissionServiceImpl.java  |  14 +-
 .../service/impl/PluginHandleServiceImpl.java      | 135 +++++----
 .../admin/service/impl/PluginServiceImpl.java      | 197 ++------------
 .../admin/service/impl/ResourceServiceImpl.java    | 180 ++++--------
 .../admin/service/impl/SelectorServiceImpl.java    | 302 ++++++++++-----------
 .../service/publish/PluginEventPublisher.java      |  12 +-
 .../publish/PluginHandleEventPublisher.java        |  94 +++++++
 .../service/publish/SelectorEventPublisher.java    | 110 ++++++++
 .../org/apache/shenyu/admin/utils/ListUtil.java    | 138 ++++++++++
 .../apache/shenyu/admin/utils/ResourceUtil.java    | 247 +++++++++++++++++
 .../apache/shenyu/admin/utils/SelectorUtil.java    | 115 ++++++++
 .../resources/mappers/plugin-handle-sqlmap.xml     |  20 ++
 .../src/main/resources/mybatis/mybatis-config.xml  |   2 +
 .../admin/service/PermissionServiceTest.java       |   4 +-
 .../admin/service/PluginHandleServiceTest.java     |   6 +-
 .../shenyu/admin/service/PluginServiceTest.java    |  22 +-
 .../shenyu/admin/service/ResourceServiceTest.java  |   7 +-
 .../shenyu/admin/service/SelectorServiceTest.java  |   6 +-
 33 files changed, 1388 insertions(+), 657 deletions(-)

diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/mapper/PluginHandleMapper.java
 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/mapper/PluginHandleMapper.java
index 37a34b56f..fe5ca7ed5 100644
--- 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/mapper/PluginHandleMapper.java
+++ 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/mapper/PluginHandleMapper.java
@@ -89,6 +89,15 @@ public interface PluginHandleMapper extends ExistProvider {
      */
     List<PluginHandleDO> selectByQuery(PluginHandleQuery pluginHandleQuery);
     
+    /**
+     * bach delete by idList.
+     *
+     * @param ids a list of ids
+     * @return the count of deleted
+     */
+    List<PluginHandleDO> selectByIdList(@Param("ids") List<String> ids);
+    
+    
     /**
      * update some selective columns in plugin_handle.
      *
@@ -121,6 +130,15 @@ public interface PluginHandleMapper extends ExistProvider {
      */
     int deleteByIdList(@Param("idList") List<String> idList);
     
+    
+    /**
+     * bach delete by idList.
+     *
+     * @param pluginId a list of ids
+     * @return the count of deleted
+     */
+    List<PluginHandleDO> selectByPluginIdList(@Param("pluginIds") List<String> 
pluginId);
+    
     /**
      * delete string id.
      *
diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/enums/EventTypeEnum.java
 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/enums/EventTypeEnum.java
index 58771af5c..c90855693 100644
--- 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/enums/EventTypeEnum.java
+++ 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/enums/EventTypeEnum.java
@@ -28,7 +28,7 @@ public enum EventTypeEnum {
     /**
      * created event.
      */
-    CREATE(DataEventTypeEnum.CREATE, "green"),
+    CREATE(DataEventTypeEnum.CREATE, Color.CREATE_COLOR),
     
     /**
      * register event.
@@ -38,13 +38,23 @@ public enum EventTypeEnum {
     /**
      * plugin created event.
      */
-    PLUGIN_CREATE("CREATE:PLUGIN", DataEventTypeEnum.CREATE, "green"),
+    PLUGIN_CREATE("CREATE:PLUGIN", DataEventTypeEnum.CREATE, 
Color.CREATE_COLOR),
+    
+    /**
+     * plugin handle created event.
+     */
+    PLUGIN_HANDLE_CREATE("CREATE:PLUGIN-HANDLE", DataEventTypeEnum.CREATE, 
Color.CREATE_COLOR),
+    
+    /**
+     * selector created event.
+     */
+    SELECTOR_CREATE("CREATE:SELECTOR", DataEventTypeEnum.CREATE, 
Color.CREATE_COLOR),
     
     // ============== delete ===================
     /**
      * deleted event.
      */
-    DELETE(DataEventTypeEnum.DELETE, "red"),
+    DELETE(DataEventTypeEnum.DELETE, Color.DELETE_COLOR),
     
     /**
      * clean event.
@@ -54,19 +64,40 @@ public enum EventTypeEnum {
     /**
      * plugin deleted event.
      */
-    PLUGIN_DELETE("DELETE:PLUGIN", DataEventTypeEnum.DELETE, "red"),
+    PLUGIN_DELETE("DELETE:PLUGIN", DataEventTypeEnum.DELETE, 
Color.DELETE_COLOR),
+    
+    
+    /**
+     * plugin handle deleted event.
+     */
+    PLUGIN_HANDLE_DELETE("DELETE:PLUGIN-HANDLE", DataEventTypeEnum.DELETE, 
Color.DELETE_COLOR),
+    
+    /**
+     * selector deleted event.
+     */
+    SELECTOR_DELETE("DELETE:SELECTOR", DataEventTypeEnum.DELETE, 
Color.DELETE_COLOR),
     
     // ============== update ===================
     
     /**
      * update event.
      */
-    UPDATE(DataEventTypeEnum.UPDATE, "yellow"),
+    UPDATE(DataEventTypeEnum.UPDATE, Color.UPDATE_COLOR),
     
     /**
      * plugin update.
      */
-    PLUGIN_UPDATE("UPDATE:PLUGIN", DataEventTypeEnum.UPDATE, "yellow");
+    PLUGIN_UPDATE("UPDATE:PLUGIN", DataEventTypeEnum.UPDATE, 
Color.UPDATE_COLOR),
+    
+    /**
+     * plugin handle update.
+     */
+    PLUGIN_HANDLE_UPDATE("UPDATE:PLUGIN-HANDLE", DataEventTypeEnum.UPDATE, 
Color.UPDATE_COLOR),
+    
+    /**
+     * selector update.
+     */
+    SELECTOR_UPDATE("UPDATE:PLUGIN-HANDLE", DataEventTypeEnum.UPDATE, 
Color.UPDATE_COLOR);
     
     /**
      * type name.
@@ -121,4 +152,24 @@ public enum EventTypeEnum {
         return color;
     }
     
+    /**
+     * default color.
+     */
+    private static class Color {
+        /**
+         * default create event color.
+         */
+        public static final String CREATE_COLOR = "green";
+        
+        /**
+         * default delete event color.
+         */
+        public static final String DELETE_COLOR = "red";
+        
+        /**
+         * default update event color.
+         */
+        public static final String UPDATE_COLOR = "yellow";
+    }
+    
 }
diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/BatchChangedEvent.java
 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/BatchChangedEvent.java
index 41eebd34e..27a811308 100644
--- 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/BatchChangedEvent.java
+++ 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/BatchChangedEvent.java
@@ -40,7 +40,7 @@ public class BatchChangedEvent extends 
AdminDataModelChangedEvent {
     }
     
     /**
-     * before plguin snapshot.
+     * before plugin snapshot.
      *
      * @return snapshot
      */
diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/BatchPluginChangedEvent.java
 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/handle/BatchPluginHandleChangedEvent.java
similarity index 68%
copy from 
shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/BatchPluginChangedEvent.java
copy to 
shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/handle/BatchPluginHandleChangedEvent.java
index da552eb76..898fbe878 100644
--- 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/BatchPluginChangedEvent.java
+++ 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/handle/BatchPluginHandleChangedEvent.java
@@ -15,11 +15,12 @@
  * limitations under the License.
  */
 
-package org.apache.shenyu.admin.model.event;
+package org.apache.shenyu.admin.model.event.handle;
 
 import org.apache.commons.lang3.StringUtils;
-import org.apache.shenyu.admin.model.entity.PluginDO;
+import org.apache.shenyu.admin.model.entity.PluginHandleDO;
 import org.apache.shenyu.admin.model.enums.EventTypeEnum;
+import org.apache.shenyu.admin.model.event.BatchChangedEvent;
 
 import java.util.Collection;
 import java.util.stream.Collectors;
@@ -27,7 +28,7 @@ import java.util.stream.Collectors;
 /**
  * BatchPluginChangedEvent.
  */
-public class BatchPluginChangedEvent extends BatchChangedEvent {
+public class BatchPluginHandleChangedEvent extends BatchChangedEvent {
     
     
     /**
@@ -37,21 +38,21 @@ public class BatchPluginChangedEvent extends 
BatchChangedEvent {
      * @param before Before the change plugin state
      * @param type   event type
      */
-    public BatchPluginChangedEvent(final Collection<PluginDO> source, final 
Collection<PluginDO> before, final EventTypeEnum type, final String operator) {
+    public BatchPluginHandleChangedEvent(final Collection<PluginHandleDO> 
source, final Collection<PluginHandleDO> before, final EventTypeEnum type, 
final String operator) {
         super(source, before, type, operator);
     }
     
     @Override
     public String buildContext() {
-        final String plugins = ((Collection<?>) getSource())
+        final String handle = ((Collection<?>) getSource())
                 .stream()
-                .map(s -> ((PluginDO) s).getName())
+                .map(s -> ((PluginHandleDO) s).getField())
                 .collect(Collectors.joining(","));
-        return String.format("the plugins[%s] is %s", plugins, 
StringUtils.lowerCase(getType().getType().toString()));
+        return String.format("the plugin handle[%s] is %s", handle, 
StringUtils.lowerCase(getType().getType().toString()));
     }
     
     @Override
     public String eventName() {
-        return "plugin";
+        return "plugin-handle";
     }
 }
diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/PluginChangedEvent.java
 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/handle/PluginHandleChangedEvent.java
similarity index 53%
copy from 
shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/PluginChangedEvent.java
copy to 
shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/handle/PluginHandleChangedEvent.java
index 9bacf6a06..9ffbf7a77 100644
--- 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/PluginChangedEvent.java
+++ 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/handle/PluginHandleChangedEvent.java
@@ -15,18 +15,19 @@
  * limitations under the License.
  */
 
-package org.apache.shenyu.admin.model.event;
+package org.apache.shenyu.admin.model.event.handle;
 
 import org.apache.commons.lang3.StringUtils;
-import org.apache.shenyu.admin.model.entity.PluginDO;
+import org.apache.shenyu.admin.model.entity.PluginHandleDO;
 import org.apache.shenyu.admin.model.enums.EventTypeEnum;
+import org.apache.shenyu.admin.model.event.AdminDataModelChangedEvent;
 
 import java.util.Objects;
 
 /**
- * AdminDataModelChangedEvent.
+ * PluginHandleChangedEvent.
  */
-public class PluginChangedEvent extends AdminDataModelChangedEvent {
+public class PluginHandleChangedEvent extends AdminDataModelChangedEvent {
     
     
     /**
@@ -36,40 +37,39 @@ public class PluginChangedEvent extends 
AdminDataModelChangedEvent {
      * @param before Before the change plugiin state
      * @param type   event type
      */
-    public PluginChangedEvent(final PluginDO source, final PluginDO before, 
final EventTypeEnum type, final String operator) {
+    public PluginHandleChangedEvent(final PluginHandleDO source, final 
PluginHandleDO before, final EventTypeEnum type, final String operator) {
         super(source, before, type, operator);
     }
     
     @Override
     public String buildContext() {
-        final PluginDO after = (PluginDO) getAfter();
+        final PluginHandleDO after = (PluginHandleDO) getAfter();
         if (Objects.isNull(getBefore())) {
-            return String.format("the plugin [%s] is %s", after.getName(), 
StringUtils.lowerCase(getType().getType().toString()));
+            return String.format("the plugin-handle [%s] is %s", 
after.getField(), StringUtils.lowerCase(getType().getType().toString()));
         }
-        return String.format("the plugin [%s] is %s : %s", after.getName(), 
StringUtils.lowerCase(getType().getType().toString()), contrast());
-        
+        return String.format("the plugin-handle [%s] is %s : %s", 
after.getField(), StringUtils.lowerCase(getType().getType().toString()), 
contrast());
     }
     
     private String contrast() {
-        final PluginDO before = (PluginDO) getBefore();
+        final PluginHandleDO before = (PluginHandleDO) getBefore();
         Objects.requireNonNull(before);
-        final PluginDO after = (PluginDO) getAfter();
+        final PluginHandleDO after = (PluginHandleDO) getAfter();
         Objects.requireNonNull(after);
         if (Objects.equals(before, after)) {
             return "it no change";
         }
         final StringBuilder builder = new StringBuilder();
-        if (!Objects.equals(before.getName(), after.getName())) {
-            builder.append(String.format("name[%s => %s] ", before.getName(), 
after.getName()));
+        if (!Objects.equals(before.getField(), after.getField())) {
+            builder.append(String.format("field[%s => %s] ", 
before.getField(), after.getField()));
         }
-        if (!Objects.equals(before.getConfig(), after.getConfig())) {
-            builder.append(String.format("config[%s => %s] ", 
before.getConfig(), after.getConfig()));
+        if (!Objects.equals(before.getLabel(), after.getLabel())) {
+            builder.append(String.format("label[%s => %s] ", 
before.getLabel(), after.getLabel()));
         }
-        if (!Objects.equals(before.getRole(), after.getRole())) {
-            builder.append(String.format("role[%s => %s] ", before.getRole(), 
after.getRole()));
+        if (!Objects.equals(before.getType(), after.getType())) {
+            builder.append(String.format("type[%s => %s] ", before.getType(), 
after.getType()));
         }
-        if (!Objects.equals(before.getEnabled(), after.getEnabled())) {
-            builder.append(String.format("enable[%s => %s] ", 
before.getEnabled(), after.getEnabled()));
+        if (!Objects.equals(before.getDataType(), after.getDataType())) {
+            builder.append(String.format("dataType[%s => %s] ", 
before.getDateCreated(), after.getDataType()));
         }
         if (!Objects.equals(before.getSort(), after.getSort())) {
             builder.append(String.format("sort[%s => %s] ", before.getSort(), 
after.getSort()));
@@ -79,6 +79,6 @@ public class PluginChangedEvent extends 
AdminDataModelChangedEvent {
     
     @Override
     public String eventName() {
-        return "plugin";
+        return "plugin-handle";
     }
 }
diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/BatchPluginChangedEvent.java
 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/plugin/BatchPluginChangedEvent.java
similarity index 94%
copy from 
shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/BatchPluginChangedEvent.java
copy to 
shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/plugin/BatchPluginChangedEvent.java
index da552eb76..14947dbbd 100644
--- 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/BatchPluginChangedEvent.java
+++ 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/plugin/BatchPluginChangedEvent.java
@@ -15,11 +15,12 @@
  * limitations under the License.
  */
 
-package org.apache.shenyu.admin.model.event;
+package org.apache.shenyu.admin.model.event.plugin;
 
 import org.apache.commons.lang3.StringUtils;
 import org.apache.shenyu.admin.model.entity.PluginDO;
 import org.apache.shenyu.admin.model.enums.EventTypeEnum;
+import org.apache.shenyu.admin.model.event.BatchChangedEvent;
 
 import java.util.Collection;
 import java.util.stream.Collectors;
diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/BatchPluginChangedEvent.java
 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/plugin/BatchPluginDeletedEvent.java
similarity index 66%
copy from 
shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/BatchPluginChangedEvent.java
copy to 
shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/plugin/BatchPluginDeletedEvent.java
index da552eb76..e9a296fa6 100644
--- 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/BatchPluginChangedEvent.java
+++ 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/plugin/BatchPluginDeletedEvent.java
@@ -15,30 +15,34 @@
  * limitations under the License.
  */
 
-package org.apache.shenyu.admin.model.event;
+package org.apache.shenyu.admin.model.event.plugin;
 
 import org.apache.commons.lang3.StringUtils;
+import org.apache.shenyu.admin.model.entity.BaseDO;
 import org.apache.shenyu.admin.model.entity.PluginDO;
 import org.apache.shenyu.admin.model.enums.EventTypeEnum;
+import org.apache.shenyu.admin.utils.ListUtil;
 
 import java.util.Collection;
+import java.util.List;
 import java.util.stream.Collectors;
 
 /**
- * BatchPluginChangedEvent.
+ * BatchPluginDeletedEvent.
  */
-public class BatchPluginChangedEvent extends BatchChangedEvent {
+public class BatchPluginDeletedEvent extends BatchPluginChangedEvent {
     
+    private final List<String> deletedPluginIds;
     
     /**
      * Create a new {@code PluginChangedEvent}.operator is unknown.
      *
-     * @param source Current plugin state
-     * @param before Before the change plugin state
-     * @param type   event type
+     * @param source   Current plugin state
+     * @param operator operator
      */
-    public BatchPluginChangedEvent(final Collection<PluginDO> source, final 
Collection<PluginDO> before, final EventTypeEnum type, final String operator) {
-        super(source, before, type, operator);
+    public BatchPluginDeletedEvent(final Collection<PluginDO> source, final 
String operator) {
+        super(source, null, EventTypeEnum.PLUGIN_DELETE, operator);
+        this.deletedPluginIds = ListUtil.map(source, BaseDO::getId);
     }
     
     @Override
@@ -50,8 +54,12 @@ public class BatchPluginChangedEvent extends 
BatchChangedEvent {
         return String.format("the plugins[%s] is %s", plugins, 
StringUtils.lowerCase(getType().getType().toString()));
     }
     
-    @Override
-    public String eventName() {
-        return "plugin";
+    /**
+     * get deleted iss.
+     *
+     * @return list
+     */
+    public List<String> getDeletedPluginIds() {
+        return deletedPluginIds;
     }
 }
diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/PluginChangedEvent.java
 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/plugin/PluginChangedEvent.java
similarity index 96%
copy from 
shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/PluginChangedEvent.java
copy to 
shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/plugin/PluginChangedEvent.java
index 9bacf6a06..2d6816da7 100644
--- 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/PluginChangedEvent.java
+++ 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/plugin/PluginChangedEvent.java
@@ -15,11 +15,12 @@
  * limitations under the License.
  */
 
-package org.apache.shenyu.admin.model.event;
+package org.apache.shenyu.admin.model.event.plugin;
 
 import org.apache.commons.lang3.StringUtils;
 import org.apache.shenyu.admin.model.entity.PluginDO;
 import org.apache.shenyu.admin.model.enums.EventTypeEnum;
+import org.apache.shenyu.admin.model.event.AdminDataModelChangedEvent;
 
 import java.util.Objects;
 
diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/BatchPluginChangedEvent.java
 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/plugin/PluginCreatedEvent.java
similarity index 50%
rename from 
shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/BatchPluginChangedEvent.java
rename to 
shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/plugin/PluginCreatedEvent.java
index da552eb76..825f5c663 100644
--- 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/BatchPluginChangedEvent.java
+++ 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/plugin/PluginCreatedEvent.java
@@ -15,43 +15,34 @@
  * limitations under the License.
  */
 
-package org.apache.shenyu.admin.model.event;
+package org.apache.shenyu.admin.model.event.plugin;
 
-import org.apache.commons.lang3.StringUtils;
 import org.apache.shenyu.admin.model.entity.PluginDO;
 import org.apache.shenyu.admin.model.enums.EventTypeEnum;
 
-import java.util.Collection;
-import java.util.stream.Collectors;
-
 /**
- * BatchPluginChangedEvent.
+ * PluginCreatedEvent.
  */
-public class BatchPluginChangedEvent extends BatchChangedEvent {
+public class PluginCreatedEvent extends PluginChangedEvent {
     
     
     /**
      * Create a new {@code PluginChangedEvent}.operator is unknown.
      *
-     * @param source Current plugin state
-     * @param before Before the change plugin state
-     * @param type   event type
+     * @param source   Current plugin state
+     * @param operator operator
      */
-    public BatchPluginChangedEvent(final Collection<PluginDO> source, final 
Collection<PluginDO> before, final EventTypeEnum type, final String operator) {
-        super(source, before, type, operator);
+    public PluginCreatedEvent(final PluginDO source, final String operator) {
+        super(source, null, EventTypeEnum.PLUGIN_CREATE, operator);
     }
     
-    @Override
-    public String buildContext() {
-        final String plugins = ((Collection<?>) getSource())
-                .stream()
-                .map(s -> ((PluginDO) s).getName())
-                .collect(Collectors.joining(","));
-        return String.format("the plugins[%s] is %s", plugins, 
StringUtils.lowerCase(getType().getType().toString()));
+    /**
+     * the created plugin.
+     *
+     * @return plugin
+     */
+    public PluginDO getPlugin() {
+        return (PluginDO) getSource();
     }
     
-    @Override
-    public String eventName() {
-        return "plugin";
-    }
 }
diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/selector/BatchSelectorDeletedEvent.java
 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/selector/BatchSelectorDeletedEvent.java
new file mode 100644
index 000000000..455b5da06
--- /dev/null
+++ 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/selector/BatchSelectorDeletedEvent.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shenyu.admin.model.event.selector;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.shenyu.admin.model.entity.BaseDO;
+import org.apache.shenyu.admin.model.entity.SelectorDO;
+import org.apache.shenyu.admin.model.enums.EventTypeEnum;
+import org.apache.shenyu.admin.model.event.BatchChangedEvent;
+import org.apache.shenyu.admin.utils.ListUtil;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * BatchPluginDeletedEvent.
+ */
+public class BatchSelectorDeletedEvent extends BatchChangedEvent {
+    
+    private final List<String> deletedIds;
+    
+    /**
+     * Create a new {@code BatchChangedEvent}.operator is unknown.
+     *
+     * @param source   Current plugin state
+     * @param operator operator
+     */
+    public BatchSelectorDeletedEvent(final Collection<SelectorDO> source, 
final String operator) {
+        super(source, null, EventTypeEnum.SELECTOR_DELETE, operator);
+        this.deletedIds = ListUtil.map(source, BaseDO::getId);
+    }
+    
+    @Override
+    public String buildContext() {
+        final String selector = ((Collection<?>) getSource())
+                .stream()
+                .map(s -> ((SelectorDO) s).getName())
+                .collect(Collectors.joining(","));
+        return String.format("the selector[%s] is %s", selector, 
StringUtils.lowerCase(getType().getType().toString()));
+    }
+    
+    /**
+     * get deleted ids.
+     *
+     * @return ids.
+     */
+    public List<String> getDeletedIds() {
+        return deletedIds;
+    }
+}
diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/PluginChangedEvent.java
 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/selector/SelectorChangedEvent.java
similarity index 61%
rename from 
shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/PluginChangedEvent.java
rename to 
shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/selector/SelectorChangedEvent.java
index 9bacf6a06..0325653b6 100644
--- 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/PluginChangedEvent.java
+++ 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/selector/SelectorChangedEvent.java
@@ -15,18 +15,19 @@
  * limitations under the License.
  */
 
-package org.apache.shenyu.admin.model.event;
+package org.apache.shenyu.admin.model.event.selector;
 
 import org.apache.commons.lang3.StringUtils;
-import org.apache.shenyu.admin.model.entity.PluginDO;
+import org.apache.shenyu.admin.model.entity.SelectorDO;
 import org.apache.shenyu.admin.model.enums.EventTypeEnum;
+import org.apache.shenyu.admin.model.event.AdminDataModelChangedEvent;
 
 import java.util.Objects;
 
 /**
- * AdminDataModelChangedEvent.
+ * SelectorChangedEvent.
  */
-public class PluginChangedEvent extends AdminDataModelChangedEvent {
+public class SelectorChangedEvent extends AdminDataModelChangedEvent {
     
     
     /**
@@ -36,24 +37,24 @@ public class PluginChangedEvent extends 
AdminDataModelChangedEvent {
      * @param before Before the change plugiin state
      * @param type   event type
      */
-    public PluginChangedEvent(final PluginDO source, final PluginDO before, 
final EventTypeEnum type, final String operator) {
+    public SelectorChangedEvent(final SelectorDO source, final SelectorDO 
before, final EventTypeEnum type, final String operator) {
         super(source, before, type, operator);
     }
     
     @Override
     public String buildContext() {
-        final PluginDO after = (PluginDO) getAfter();
+        final SelectorDO after = (SelectorDO) getAfter();
         if (Objects.isNull(getBefore())) {
-            return String.format("the plugin [%s] is %s", after.getName(), 
StringUtils.lowerCase(getType().getType().toString()));
+            return String.format("the selector [%s] is %s", after.getName(), 
StringUtils.lowerCase(getType().getType().toString()));
         }
-        return String.format("the plugin [%s] is %s : %s", after.getName(), 
StringUtils.lowerCase(getType().getType().toString()), contrast());
+        return String.format("the selector [%s] is %s : %s", after.getName(), 
StringUtils.lowerCase(getType().getType().toString()), contrast());
         
     }
     
     private String contrast() {
-        final PluginDO before = (PluginDO) getBefore();
+        final SelectorDO before = (SelectorDO) getBefore();
         Objects.requireNonNull(before);
-        final PluginDO after = (PluginDO) getAfter();
+        final SelectorDO after = (SelectorDO) getAfter();
         Objects.requireNonNull(after);
         if (Objects.equals(before, after)) {
             return "it no change";
@@ -62,11 +63,11 @@ public class PluginChangedEvent extends 
AdminDataModelChangedEvent {
         if (!Objects.equals(before.getName(), after.getName())) {
             builder.append(String.format("name[%s => %s] ", before.getName(), 
after.getName()));
         }
-        if (!Objects.equals(before.getConfig(), after.getConfig())) {
-            builder.append(String.format("config[%s => %s] ", 
before.getConfig(), after.getConfig()));
+        if (!Objects.equals(before.getHandle(), after.getHandle())) {
+            builder.append(String.format("handle[%s => %s] ", 
before.getHandle(), after.getHandle()));
         }
-        if (!Objects.equals(before.getRole(), after.getRole())) {
-            builder.append(String.format("role[%s => %s] ", before.getRole(), 
after.getRole()));
+        if (!Objects.equals(before.getType(), after.getType())) {
+            builder.append(String.format("type[%s => %s] ", before.getType(), 
after.getType()));
         }
         if (!Objects.equals(before.getEnabled(), after.getEnabled())) {
             builder.append(String.format("enable[%s => %s] ", 
before.getEnabled(), after.getEnabled()));
@@ -74,11 +75,14 @@ public class PluginChangedEvent extends 
AdminDataModelChangedEvent {
         if (!Objects.equals(before.getSort(), after.getSort())) {
             builder.append(String.format("sort[%s => %s] ", before.getSort(), 
after.getSort()));
         }
+        if (!Objects.equals(before.getLoged(), after.getLoged())) {
+            builder.append(String.format("loged[%s => %s] ", 
before.getLoged(), after.getLoged()));
+        }
         return builder.toString();
     }
     
     @Override
     public String eventName() {
-        return "plugin";
+        return "selector";
     }
 }
diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/selector/SelectorCreatedEvent.java
 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/selector/SelectorCreatedEvent.java
new file mode 100644
index 000000000..ccf8af7b0
--- /dev/null
+++ 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/selector/SelectorCreatedEvent.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shenyu.admin.model.event.selector;
+
+import org.apache.shenyu.admin.model.entity.SelectorDO;
+import org.apache.shenyu.admin.model.enums.EventTypeEnum;
+
+/**
+ * SelectorCreatedEvent.
+ */
+public class SelectorCreatedEvent extends SelectorChangedEvent {
+    
+    
+    /**
+     * Create a new {@code SelectorChangedEvent}.operator is unknown.
+     *
+     * @param source   Current plugin state
+     * @param operator operator
+     */
+    public SelectorCreatedEvent(final SelectorDO source, final String 
operator) {
+        super(source, null, EventTypeEnum.SELECTOR_CREATE, operator);
+    }
+    
+    /**
+     * the created selector.
+     *
+     * @return selector
+     */
+    public SelectorDO getSelector() {
+        return (SelectorDO) getSource();
+    }
+    
+}
diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/PluginHandleService.java
 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/PluginHandleService.java
index ea4aa571c..572026b72 100644
--- 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/PluginHandleService.java
+++ 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/PluginHandleService.java
@@ -17,6 +17,7 @@
 
 package org.apache.shenyu.admin.service;
 
+import org.apache.commons.lang3.StringUtils;
 import org.apache.shenyu.admin.model.dto.PluginHandleDTO;
 import org.apache.shenyu.admin.model.page.CommonPager;
 import org.apache.shenyu.admin.model.query.PluginHandleQuery;
@@ -30,36 +31,59 @@ import java.util.List;
 public interface PluginHandleService {
     /**
      * find page of plugin handle by query.
+     *
      * @param pluginHandleQuery {@linkplain PluginHandleQuery}
      * @return {@link CommonPager}
      */
     CommonPager<PluginHandleVO> listByPage(PluginHandleQuery 
pluginHandleQuery);
-
+    
     /**
      * create or update plugin handle.
+     *
      * @param pluginHandleDTO {@linkplain PluginHandleDTO}
      * @return affected rows
      */
-    Integer createOrUpdate(PluginHandleDTO pluginHandleDTO);
-
+    default Integer createOrUpdate(PluginHandleDTO pluginHandleDTO) {
+        return StringUtils.isBlank(pluginHandleDTO.getId()) ? 
create(pluginHandleDTO) : update(pluginHandleDTO);
+    }
+    
+    /**
+     * create.
+     *
+     * @param pluginHandleDTO param
+     * @return changed count
+     */
+    Integer create(PluginHandleDTO pluginHandleDTO);
+    
+    /**
+     * update.
+     *
+     * @param pluginHandleDTO param
+     * @return changed count
+     */
+    Integer update(PluginHandleDTO pluginHandleDTO);
+    
     /**
      * delete plugin handles.
+     *
      * @param ids ids to delete
      * @return The number of rows deleted
      */
     Integer deletePluginHandles(List<String> ids);
-
+    
     /**
      * find plugin handle by id.
+     *
      * @param id plugin handle id.
      * @return {@linkplain PluginHandleVO}
      */
     PluginHandleVO findById(String id);
-
+    
     /**
      * find plugin handle list by plugin id.
+     *
      * @param pluginId the plugin id.
-     * @param type type 1:selector,2:rule
+     * @param type     type 1:selector,2:rule
      * @return plugin handle list.
      */
     List<PluginHandleVO> list(String pluginId, Integer type);
diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/ResourceService.java
 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/ResourceService.java
index 04b7eeea7..93a298efa 100644
--- 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/ResourceService.java
+++ 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/ResourceService.java
@@ -109,12 +109,5 @@ public interface ResourceService {
      * @return {@linkplain List}
      */
     List<ResourceVO> findByParentId(String id);
-
-    /**
-     * get Menu Info.
-     *
-     * @param metaList {@linkplain List} resource list
-     * @return {@linkplain List} menu infos.
-     */
-    List<MenuInfo> getMenuInfo(List<ResourceVO> metaList);
+    
 }
diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/SelectorService.java
 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/SelectorService.java
index 36b1963b9..0594d76fb 100644
--- 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/SelectorService.java
+++ 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/SelectorService.java
@@ -17,16 +17,20 @@
 
 package org.apache.shenyu.admin.service;
 
+import org.apache.commons.lang3.StringUtils;
 import org.apache.shenyu.admin.model.dto.SelectorDTO;
 import org.apache.shenyu.admin.model.entity.SelectorDO;
 import org.apache.shenyu.admin.model.page.CommonPager;
 import org.apache.shenyu.admin.model.query.SelectorQuery;
 import org.apache.shenyu.admin.model.query.SelectorQueryCondition;
 import org.apache.shenyu.admin.model.vo.SelectorVO;
+import org.apache.shenyu.admin.utils.Assert;
 import org.apache.shenyu.common.dto.SelectorData;
+import org.apache.shenyu.common.enums.SelectorTypeEnum;
 import org.apache.shenyu.register.common.dto.MetaDataRegisterDTO;
 
 import java.util.List;
+import java.util.Objects;
 
 /**
  * this is selector service.
@@ -57,7 +61,29 @@ public interface SelectorService extends 
PageService<SelectorQueryCondition, Sel
      * @param selectorDTO {@linkplain SelectorDTO}
      * @return rows int
      */
-    int createOrUpdate(SelectorDTO selectorDTO);
+    default int createOrUpdate(SelectorDTO selectorDTO) {
+        if (Objects.equals(SelectorTypeEnum.CUSTOM_FLOW.getCode(), 
selectorDTO.getType())) {
+            Assert.notNull(selectorDTO.getMatchMode(), "if type is custom, 
matchMode is not null");
+            Assert.notEmpty(selectorDTO.getSelectorConditions(), "if type is 
custom, selectorConditions is not empty");
+        }
+        return StringUtils.isEmpty(selectorDTO.getId()) ? create(selectorDTO) 
: update(selectorDTO);
+    }
+    
+    /**
+     * create  selector.
+     *
+     * @param selectorDTO {@linkplain SelectorDTO}
+     * @return rows int
+     */
+    int create(SelectorDTO selectorDTO);
+    
+    /**
+     * update selector.
+     *
+     * @param selectorDTO {@linkplain SelectorDTO}
+     * @return rows int
+     */
+    int update(SelectorDTO selectorDTO);
     
     /**
      * update selective selector.
diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/PermissionServiceImpl.java
 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/PermissionServiceImpl.java
index c58cd0c2e..2bbea2c9b 100644
--- 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/PermissionServiceImpl.java
+++ 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/PermissionServiceImpl.java
@@ -28,11 +28,10 @@ import org.apache.shenyu.admin.model.entity.PermissionDO;
 import org.apache.shenyu.admin.model.entity.UserRoleDO;
 import org.apache.shenyu.admin.model.vo.PermissionMenuVO;
 import org.apache.shenyu.admin.model.vo.PermissionMenuVO.AuthPerm;
-import org.apache.shenyu.admin.model.vo.PermissionMenuVO.MenuInfo;
 import org.apache.shenyu.admin.model.vo.ResourceVO;
 import org.apache.shenyu.admin.service.PermissionService;
-import org.apache.shenyu.admin.service.ResourceService;
 import org.apache.shenyu.admin.utils.JwtUtils;
+import org.apache.shenyu.admin.utils.ResourceUtil;
 import org.apache.shenyu.common.constant.ResourceTypeConstants;
 import org.springframework.stereotype.Service;
 
@@ -56,18 +55,14 @@ public class PermissionServiceImpl implements 
PermissionService {
 
     private final ResourceMapper resourceMapper;
 
-    private final ResourceService resourceService;
-
     public PermissionServiceImpl(final DashboardUserMapper dashboardUserMapper,
                                  final UserRoleMapper userRoleMapper,
                                  final PermissionMapper permissionMapper,
-                                 final ResourceMapper resourceMapper,
-                                 final ResourceService resourceService) {
+                                 final ResourceMapper resourceMapper) {
         this.dashboardUserMapper = dashboardUserMapper;
         this.userRoleMapper = userRoleMapper;
         this.permissionMapper = permissionMapper;
         this.resourceMapper = resourceMapper;
-        this.resourceService = resourceService;
     }
 
     /**
@@ -87,9 +82,8 @@ public class PermissionServiceImpl implements 
PermissionService {
         if (CollectionUtils.isEmpty(resourceVOList)) {
             return null;
         }
-
-        List<MenuInfo> menuInfoList = 
resourceService.getMenuInfo(resourceVOList);
-        return new PermissionMenuVO(menuInfoList, getAuthPerm(resourceVOList), 
getAllAuthPerms());
+        
+        return new PermissionMenuVO(ResourceUtil.buildMenu(resourceVOList), 
getAuthPerm(resourceVOList), getAllAuthPerms());
     }
 
     /**
diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/PluginHandleServiceImpl.java
 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/PluginHandleServiceImpl.java
index 5b2db72a6..e6fff3c41 100644
--- 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/PluginHandleServiceImpl.java
+++ 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/PluginHandleServiceImpl.java
@@ -17,21 +17,23 @@
 
 package org.apache.shenyu.admin.service.impl;
 
-import com.google.common.collect.Lists;
 import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.lang3.StringUtils;
 import org.apache.shenyu.admin.aspect.annotation.Pageable;
 import org.apache.shenyu.admin.mapper.PluginHandleMapper;
 import org.apache.shenyu.admin.mapper.ShenyuDictMapper;
 import org.apache.shenyu.admin.model.dto.PluginHandleDTO;
+import org.apache.shenyu.admin.model.entity.BaseDO;
 import org.apache.shenyu.admin.model.entity.PluginHandleDO;
-import org.apache.shenyu.admin.model.entity.ShenyuDictDO;
+import org.apache.shenyu.admin.model.event.plugin.BatchPluginDeletedEvent;
 import org.apache.shenyu.admin.model.page.CommonPager;
 import org.apache.shenyu.admin.model.page.PageResultUtils;
 import org.apache.shenyu.admin.model.query.PluginHandleQuery;
 import org.apache.shenyu.admin.model.vo.PluginHandleVO;
 import org.apache.shenyu.admin.model.vo.ShenyuDictVO;
 import org.apache.shenyu.admin.service.PluginHandleService;
+import org.apache.shenyu.admin.service.publish.PluginHandleEventPublisher;
+import org.apache.shenyu.admin.utils.ListUtil;
+import org.springframework.context.event.EventListener;
 import org.springframework.stereotype.Service;
 
 import java.util.ArrayList;
@@ -46,98 +48,117 @@ import java.util.stream.Collectors;
  */
 @Service
 public class PluginHandleServiceImpl implements PluginHandleService {
-
+    
     private static final int SELECT_BOX_DATA_TYPE = 3;
-
+    
     private final PluginHandleMapper pluginHandleMapper;
-
+    
     private final ShenyuDictMapper shenyuDictMapper;
-
-    public PluginHandleServiceImpl(final PluginHandleMapper 
pluginHandleMapper, final ShenyuDictMapper shenyuDictMapper) {
+    
+    private final PluginHandleEventPublisher eventPublisher;
+    
+    public PluginHandleServiceImpl(final PluginHandleMapper pluginHandleMapper,
+                                   final ShenyuDictMapper shenyuDictMapper,
+                                   final PluginHandleEventPublisher 
eventPublisher) {
         this.pluginHandleMapper = pluginHandleMapper;
         this.shenyuDictMapper = shenyuDictMapper;
+        this.eventPublisher = eventPublisher;
     }
-
+    
     @Override
     @Pageable
     public CommonPager<PluginHandleVO> listByPage(final PluginHandleQuery 
pluginHandleQuery) {
-
         List<PluginHandleDO> pluginHandleDOList = 
pluginHandleMapper.selectByQuery(pluginHandleQuery);
-
-        return PageResultUtils.result(pluginHandleQuery.getPageParameter(),
-            () -> this.buildPluginHandleVO(pluginHandleDOList));
+        return PageResultUtils.result(pluginHandleQuery.getPageParameter(), () 
-> this.buildPluginHandleVO(pluginHandleDOList));
     }
-
+    
     @Override
-    public Integer createOrUpdate(final PluginHandleDTO pluginHandleDTO) {
-        int pluginHandleCount;
+    public Integer create(final PluginHandleDTO pluginHandleDTO) {
         PluginHandleDO pluginHandleDO = 
PluginHandleDO.buildPluginHandleDO(pluginHandleDTO);
-        if (StringUtils.isEmpty(pluginHandleDTO.getId())) {
-            pluginHandleCount = 
pluginHandleMapper.insertSelective(pluginHandleDO);
-        } else {
-            pluginHandleCount = 
pluginHandleMapper.updateByPrimaryKeySelective(pluginHandleDO);
+        int pluginHandleCount = 
pluginHandleMapper.insertSelective(pluginHandleDO);
+        if (pluginHandleCount > 0) {
+            eventPublisher.onCreated(pluginHandleDO);
         }
         return pluginHandleCount;
     }
-
+    
+    @Override
+    public Integer update(final PluginHandleDTO pluginHandleDTO) {
+        PluginHandleDO pluginHandleDO = 
PluginHandleDO.buildPluginHandleDO(pluginHandleDTO);
+        final PluginHandleDO before = 
pluginHandleMapper.selectById(pluginHandleDTO.getId());
+        int pluginHandleCount = 
pluginHandleMapper.updateByPrimaryKeySelective(pluginHandleDO);
+        if (pluginHandleCount > 0) {
+            eventPublisher.onUpdated(pluginHandleDO, before);
+        }
+        return pluginHandleCount;
+    }
+    
     @Override
     public Integer deletePluginHandles(final List<String> ids) {
-        List<String> distinctIds = 
ids.stream().distinct().collect(Collectors.toList());
-        if (CollectionUtils.isNotEmpty(distinctIds)) {
-            return pluginHandleMapper.deleteByIdList(distinctIds);
+        if (CollectionUtils.isEmpty(ids)) {
+            return 0;
         }
-        return 0;
+        final List<PluginHandleDO> handles = 
pluginHandleMapper.selectByIdList(ids);
+        final int count = pluginHandleMapper.deleteByIdList(ids);
+        if (count > 0) {
+            eventPublisher.onDeleted(handles);
+        }
+        return count;
     }
-
+    
     @Override
     public PluginHandleVO findById(final String id) {
         return buildPluginHandleVO(pluginHandleMapper.selectById(id));
     }
-
+    
     @Override
     public List<PluginHandleVO> list(final String pluginId, final Integer 
type) {
-        PluginHandleQuery pluginHandleQuery = PluginHandleQuery.builder()
+        List<PluginHandleDO> pluginHandleDOList = 
pluginHandleMapper.selectByQuery(PluginHandleQuery.builder()
                 .pluginId(pluginId)
                 .type(type)
-                .build();
-
-        List<PluginHandleDO> pluginHandleDOList = 
pluginHandleMapper.selectByQuery(pluginHandleQuery);
+                .build());
         return buildPluginHandleVO(pluginHandleDOList);
     }
-
+    
+    /**
+     * The associated Handle needs to be deleted synchronously.
+     *
+     * @param event event
+     */
+    @EventListener(value = BatchPluginDeletedEvent.class)
+    public void onPluginDeleted(final BatchPluginDeletedEvent event) {
+        
deletePluginHandles(ListUtil.map(pluginHandleMapper.selectByPluginIdList(event.getDeletedPluginIds()),
 BaseDO::getId));
+    }
+    
     private PluginHandleVO buildPluginHandleVO(final PluginHandleDO 
pluginHandleDO) {
         List<ShenyuDictVO> dictOptions = null;
-
         if (pluginHandleDO.getDataType() == SELECT_BOX_DATA_TYPE) {
-            dictOptions = 
shenyuDictMapper.findByType(pluginHandleDO.getField())
-                    .stream()
-                    .map(ShenyuDictVO::buildShenyuDictVO)
-                    .collect(Collectors.toList());
+            dictOptions = 
ListUtil.map(shenyuDictMapper.findByType(pluginHandleDO.getField()), 
ShenyuDictVO::buildShenyuDictVO);
         }
         return PluginHandleVO.buildPluginHandleVO(pluginHandleDO, dictOptions);
     }
-
+    
     private List<PluginHandleVO> buildPluginHandleVO(final 
List<PluginHandleDO> pluginHandleDOList) {
-
+        
         List<String> fieldList = pluginHandleDOList.stream()
                 .filter(pluginHandleDO -> pluginHandleDO.getDataType() == 
SELECT_BOX_DATA_TYPE)
-                
.map(PluginHandleDO::getField).distinct().collect(Collectors.toList());
-
-        Map<String, List<ShenyuDictVO>> shenyuDictDOMap = new HashMap<>();
-        if (CollectionUtils.isNotEmpty(fieldList)) {
-            List<ShenyuDictDO> shenyuDictDOList = 
shenyuDictMapper.findByTypeBatch(fieldList);
-            
shenyuDictDOMap.putAll(Optional.ofNullable(shenyuDictDOList).orElseGet(ArrayList::new)
-                    .stream().map(ShenyuDictVO::buildShenyuDictVO)
-                    .collect(Collectors.toMap(ShenyuDictVO::getType, 
Lists::newArrayList,
-                        (list1, list2) -> {
-                            list1.addAll(list2);
-                            return list1;
-                        })));
-        }
-
-        return pluginHandleDOList.stream().map(pluginHandleDO -> {
-            List<ShenyuDictVO> dictOptions = 
shenyuDictDOMap.get(pluginHandleDO.getField());
-            return PluginHandleVO.buildPluginHandleVO(pluginHandleDO, 
dictOptions);
-        }).collect(Collectors.toList());
+                .map(PluginHandleDO::getField)
+                .distinct()
+                .collect(Collectors.toList());
+        
+        Map<String, List<ShenyuDictVO>> shenyuDictMap = 
CollectionUtils.isNotEmpty(fieldList)
+                ? 
Optional.ofNullable(shenyuDictMapper.findByTypeBatch(fieldList))
+                .orElseGet(ArrayList::new)
+                .stream()
+                .map(ShenyuDictVO::buildShenyuDictVO)
+                .collect(Collectors.groupingBy(ShenyuDictVO::getType))
+                : new HashMap<>(0);
+        
+        return pluginHandleDOList.stream()
+                .map(pluginHandleDO -> {
+                    List<ShenyuDictVO> dictOptions = 
shenyuDictMap.get(pluginHandleDO.getField());
+                    return PluginHandleVO.buildPluginHandleVO(pluginHandleDO, 
dictOptions);
+                })
+                .collect(Collectors.toList());
     }
 }
diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/PluginServiceImpl.java
 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/PluginServiceImpl.java
index 94385a694..f28cd91fb 100644
--- 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/PluginServiceImpl.java
+++ 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/PluginServiceImpl.java
@@ -20,43 +20,30 @@ package org.apache.shenyu.admin.service.impl;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.shenyu.admin.aspect.annotation.Pageable;
-import org.apache.shenyu.admin.mapper.PluginHandleMapper;
 import org.apache.shenyu.admin.mapper.PluginMapper;
-import org.apache.shenyu.admin.mapper.RuleConditionMapper;
-import org.apache.shenyu.admin.mapper.RuleMapper;
-import org.apache.shenyu.admin.mapper.SelectorConditionMapper;
-import org.apache.shenyu.admin.mapper.SelectorMapper;
 import org.apache.shenyu.admin.model.dto.PluginDTO;
-import org.apache.shenyu.admin.model.dto.ResourceDTO;
 import org.apache.shenyu.admin.model.entity.PluginDO;
-import org.apache.shenyu.admin.model.entity.ResourceDO;
-import org.apache.shenyu.admin.model.entity.RuleDO;
-import org.apache.shenyu.admin.model.entity.SelectorDO;
+import org.apache.shenyu.admin.model.event.plugin.PluginCreatedEvent;
 import org.apache.shenyu.admin.model.page.CommonPager;
 import org.apache.shenyu.admin.model.page.PageResultUtils;
 import org.apache.shenyu.admin.model.query.PluginQuery;
 import org.apache.shenyu.admin.model.query.PluginQueryCondition;
 import org.apache.shenyu.admin.model.vo.PluginSnapshotVO;
 import org.apache.shenyu.admin.model.vo.PluginVO;
-import org.apache.shenyu.admin.model.vo.ResourceVO;
 import org.apache.shenyu.admin.service.PluginService;
-import org.apache.shenyu.admin.service.ResourceService;
 import org.apache.shenyu.admin.service.publish.PluginEventPublisher;
 import org.apache.shenyu.admin.transfer.PluginTransfer;
 import org.apache.shenyu.admin.utils.Assert;
+import org.apache.shenyu.admin.utils.ListUtil;
 import org.apache.shenyu.admin.utils.ShenyuResultMessage;
 import org.apache.shenyu.common.constant.AdminConstants;
 import org.apache.shenyu.common.dto.PluginData;
-import org.apache.shenyu.common.enums.AdminPluginOperateEnum;
-import org.apache.shenyu.common.enums.AdminResourceEnum;
-import org.apache.shenyu.common.enums.ConfigGroupEnum;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
-import java.util.Optional;
 import java.util.stream.Collectors;
 
 /**
@@ -67,36 +54,12 @@ public class PluginServiceImpl implements PluginService {
     
     private final PluginMapper pluginMapper;
     
-    private final PluginHandleMapper pluginHandleMapper;
-    
-    private final SelectorMapper selectorMapper;
-    
-    private final SelectorConditionMapper selectorConditionMapper;
-    
-    private final RuleMapper ruleMapper;
-    
-    private final RuleConditionMapper ruleConditionMapper;
-    
-    private final ResourceService resourceService;
-    
-    private final PluginEventPublisher modelDataEventPublisher;
+    private final PluginEventPublisher pluginEventPublisher;
     
     public PluginServiceImpl(final PluginMapper pluginMapper,
-                             final PluginHandleMapper pluginHandleMapper,
-                             final SelectorMapper selectorMapper,
-                             final SelectorConditionMapper 
selectorConditionMapper,
-                             final RuleMapper ruleMapper,
-                             final RuleConditionMapper ruleConditionMapper,
-                             final ResourceService resourceService,
-                             final PluginEventPublisher 
modelDataEventPublisher) {
+                             final PluginEventPublisher pluginEventPublisher) {
         this.pluginMapper = pluginMapper;
-        this.pluginHandleMapper = pluginHandleMapper;
-        this.selectorMapper = selectorMapper;
-        this.selectorConditionMapper = selectorConditionMapper;
-        this.ruleMapper = ruleMapper;
-        this.ruleConditionMapper = ruleConditionMapper;
-        this.resourceService = resourceService;
-        this.modelDataEventPublisher = modelDataEventPublisher;
+        this.pluginEventPublisher = pluginEventPublisher;
     }
     
     @Override
@@ -125,52 +88,16 @@ public class PluginServiceImpl implements PluginService {
     @Override
     @Transactional(rollbackFor = Exception.class)
     public String delete(final List<String> ids) {
-        // 1. select plugin id.
+        // select plugin id.
         List<PluginDO> plugins = this.pluginMapper.selectByIds(ids);
         if (CollectionUtils.isEmpty(plugins)) {
             return AdminConstants.SYS_PLUGIN_ID_NOT_EXIST;
         }
-        final List<String> pluginIds = plugins.stream()
-                .map(PluginDO::getId).collect(Collectors.toList());
-        
-        // 2. delete plugins.
-        this.pluginMapper.deleteByIds(pluginIds);
-        
-        // TODO move to plugin handle service, listen plugin delete event 
execute
-        // 3. delete plugin handle.
-        this.pluginHandleMapper.deleteByPluginIds(pluginIds);
-        
-        // 4. all selectors.
-        final List<String> selectorIds = 
Optional.ofNullable(this.selectorMapper.findByPluginIds(pluginIds))
-                .orElse(Collections.emptyList())
-                .stream().map(SelectorDO::getId).collect(Collectors.toList());
-        if (CollectionUtils.isNotEmpty(selectorIds)) {
-            // delete all selectors
-            this.selectorMapper.deleteByIds(selectorIds);
-            // delete all selector conditions
-            this.selectorConditionMapper.deleteBySelectorIds(selectorIds);
-            // delete all rules
-            final List<String> ruleIds = 
Optional.ofNullable(this.ruleMapper.findBySelectorIds(selectorIds))
-                    .orElse(Collections.emptyList())
-                    .stream()
-                    .map(RuleDO::getId)
-                    .collect(Collectors.toList());
-            if (CollectionUtils.isNotEmpty(ruleIds)) {
-                this.ruleMapper.deleteByIds(ruleIds);
-                // delete all rule conditions
-                this.ruleConditionMapper.deleteByRuleIds(ruleIds);
-            }
-        }
-        
-        // 5. delete resource & permission.
-        final List<ResourceVO> resources = 
this.resourceService.listByTitles(plugins.stream()
-                .map(PluginDO::getName).collect(Collectors.toList()));
-        if (CollectionUtils.isNotEmpty(resources)) {
-            
this.resourceService.delete(resources.stream().map(ResourceVO::getId).collect(Collectors.toList()));
+        // delete plugins.
+        if (this.pluginMapper.deleteByIds(ListUtil.map(plugins, 
PluginDO::getId)) > 0) {
+            // publish deleted event. synchronously delete and link 
data[selector,rule,condition,resource]
+            pluginEventPublisher.onDeleted(plugins);
         }
-        
-        // 6. publish change event.
-        modelDataEventPublisher.onDeleted(plugins);
         return StringUtils.EMPTY;
     }
     
@@ -191,7 +118,7 @@ public class PluginServiceImpl implements PluginService {
         pluginMapper.updateEnableByIdList(ids, enabled);
         // publish change event.
         if (CollectionUtils.isNotEmpty(plugins)) {
-            modelDataEventPublisher.onEnabled(plugins);
+            pluginEventPublisher.onEnabled(plugins);
         }
         return StringUtils.EMPTY;
     }
@@ -217,7 +144,9 @@ public class PluginServiceImpl implements PluginService {
     @Pageable
     public CommonPager<PluginVO> listByPage(final PluginQuery pluginQuery) {
         return PageResultUtils.result(pluginQuery.getPageParameter(), () -> 
pluginMapper.selectByQuery(pluginQuery)
-                
.stream().map(PluginVO::buildPluginVO).collect(Collectors.toList()));
+                .stream()
+                .map(PluginVO::buildPluginVO)
+                .collect(Collectors.toList()));
     }
     
     /**
@@ -227,16 +156,12 @@ public class PluginServiceImpl implements PluginService {
      */
     @Override
     public List<PluginData> listAll() {
-        return pluginMapper.selectAll().stream()
-                .map(PluginTransfer.INSTANCE::mapToData)
-                .collect(Collectors.toList());
+        return ListUtil.map(pluginMapper.selectAll(), 
PluginTransfer.INSTANCE::mapToData);
     }
     
     @Override
     public List<PluginData> listAllNotInResource() {
-        return pluginMapper.listAllNotInResource().stream()
-                .map(PluginTransfer.INSTANCE::mapToData)
-                .collect(Collectors.toList());
+        return ListUtil.map(pluginMapper.listAllNotInResource(), 
PluginTransfer.INSTANCE::mapToData);
     }
     
     @Override
@@ -262,92 +187,22 @@ public class PluginServiceImpl implements PluginService {
         return pluginMapper.activePluginSnapshot();
     }
     
-    /**
-     * add plugin and add plugin resource.
-     *
-     * @param pluginDTO {@linkplain PluginDTO}
-     */
-    private void insertPluginDataToResource(final PluginDTO pluginDTO) {
-        ResourceDO resourceDO = 
ResourceDO.buildResourceDO(ResourceDTO.builder()
-                .parentId(AdminConstants.RESOURCE_PLUGIN_ID)
-                .title(pluginDTO.getName())
-                .name(pluginDTO.getName())
-                .url(AdminConstants.RESOURCE_PLUGIN_URL_PREFIX + 
pluginDTO.getName())
-                .component(pluginDTO.getName())
-                .resourceType(AdminResourceEnum.SECOND_MENU.getCode())
-                .sort(0)
-                .icon(AdminConstants.RESOURCE_PLUGIN_DEFAULT_ICON)
-                
.isLeaf(Boolean.FALSE).isRoute(0).status(1).perms(StringUtils.EMPTY).build());
-        insertPluginMenuResource(resourceDO);
-        insertPluginButtonResource(resourceDO.getId(), pluginDTO.getName(), 
ConfigGroupEnum.SELECTOR, AdminPluginOperateEnum.ADD);
-        insertPluginButtonResource(resourceDO.getId(), pluginDTO.getName(), 
ConfigGroupEnum.SELECTOR, AdminPluginOperateEnum.DELETE);
-        insertPluginButtonResource(resourceDO.getId(), pluginDTO.getName(), 
ConfigGroupEnum.SELECTOR, AdminPluginOperateEnum.EDIT);
-        insertPluginButtonResource(resourceDO.getId(), pluginDTO.getName(), 
ConfigGroupEnum.SELECTOR, AdminPluginOperateEnum.QUERY);
-        insertPluginButtonResource(resourceDO.getId(), pluginDTO.getName(), 
ConfigGroupEnum.RULE, AdminPluginOperateEnum.ADD);
-        insertPluginButtonResource(resourceDO.getId(), pluginDTO.getName(), 
ConfigGroupEnum.RULE, AdminPluginOperateEnum.DELETE);
-        insertPluginButtonResource(resourceDO.getId(), pluginDTO.getName(), 
ConfigGroupEnum.RULE, AdminPluginOperateEnum.EDIT);
-        insertPluginButtonResource(resourceDO.getId(), pluginDTO.getName(), 
ConfigGroupEnum.RULE, AdminPluginOperateEnum.QUERY);
-        insertPluginButtonResource(resourceDO.getId(), pluginDTO.getName(), 
ConfigGroupEnum.PLUGIN, AdminPluginOperateEnum.SYNCHRONIZE);
-    }
-    
-    /**
-     * insert Resource Data.
-     *
-     * @param resourceDO {@linkplain ResourceDO}
-     */
-    private void insertPluginMenuResource(final ResourceDO resourceDO) {
-        resourceService.createResource(resourceDO);
-    }
-    
-    /**
-     * insert Plugin Selector Button Resource.
-     *
-     * @param parentId               parent menu id
-     * @param pluginName             plugin name
-     * @param configGroupEnum        {@linkplain ConfigGroupEnum}
-     * @param adminPluginOperateEnum {@linkplain AdminPluginOperateEnum}
-     */
-    private void insertPluginButtonResource(final String parentId, final 
String pluginName,
-                                            final ConfigGroupEnum 
configGroupEnum, final AdminPluginOperateEnum adminPluginOperateEnum) {
-        ResourceDO resourceDO = 
ResourceDO.buildResourceDO(ResourceDTO.builder()
-                .parentId(parentId)
-                
.name(StringUtils.EMPTY).url(StringUtils.EMPTY).component(StringUtils.EMPTY)
-                .resourceType(AdminResourceEnum.THREE_MENU.getCode())
-                
.isLeaf(Boolean.TRUE).status(1).sort(0).icon(StringUtils.EMPTY).isRoute(0).build());
-        switch (configGroupEnum) {
-            case SELECTOR:
-                resourceDO.setTitle("SHENYU.BUTTON.PLUGIN." + 
ConfigGroupEnum.SELECTOR.name() + "." + adminPluginOperateEnum.name());
-                resourceDO.setPerms("plugin:" + pluginName + "Selector:" + 
adminPluginOperateEnum.getName());
-                break;
-            case RULE:
-                resourceDO.setTitle("SHENYU.BUTTON.PLUGIN." + 
ConfigGroupEnum.RULE.name() + "." + adminPluginOperateEnum.name());
-                resourceDO.setPerms("plugin:" + pluginName + "Rule:" + 
adminPluginOperateEnum.getName());
-                break;
-            case PLUGIN:
-                resourceDO.setTitle("SHENYU.BUTTON.PLUGIN." + 
adminPluginOperateEnum.name());
-                resourceDO.setPerms("plugin:" + pluginName + ":" + 
adminPluginOperateEnum.getName());
-                break;
-            default:
-                break;
-        }
-        
-        insertPluginMenuResource(resourceDO);
-    }
-    
     /**
      * create plugin.<br>
      * insert plugin and insert plugin data.
      *
      * @param pluginDTO plugin info
      * @return success is empty
+     * @see ResourceServiceImpl#onPluginCreated(PluginCreatedEvent)
+     * @see PluginCreatedEvent
      */
     private String create(final PluginDTO pluginDTO) {
         Assert.isNull(pluginMapper.nameExisted(pluginDTO.getName()), 
AdminConstants.PLUGIN_NAME_IS_EXIST);
         PluginDO pluginDO = PluginDO.buildPluginDO(pluginDTO);
-        insertPluginDataToResource(pluginDTO);
-        pluginMapper.insertSelective(pluginDO);
-        // publish create event.
-        modelDataEventPublisher.onCreated(pluginDO);
+        if (pluginMapper.insertSelective(pluginDO) > 0) {
+            // publish create event. init plugin data
+            pluginEventPublisher.onCreated(pluginDO);
+        }
         return ShenyuResultMessage.CREATE_SUCCESS;
     }
     
@@ -361,10 +216,10 @@ public class PluginServiceImpl implements PluginService {
         Assert.isNull(pluginMapper.nameExistedExclude(pluginDTO.getName(), 
Collections.singletonList(pluginDTO.getId())), 
AdminConstants.PLUGIN_NAME_IS_EXIST);
         final PluginDO before = pluginMapper.selectById(pluginDTO.getId());
         PluginDO pluginDO = PluginDO.buildPluginDO(pluginDTO);
-        pluginMapper.updateSelective(pluginDO);
-        
-        // publish update event.
-        modelDataEventPublisher.onUpdated(pluginDO, before);
+        if (pluginMapper.updateSelective(pluginDO) > 0) {
+            // publish update event.
+            pluginEventPublisher.onUpdated(pluginDO, before);
+        }
         return ShenyuResultMessage.UPDATE_SUCCESS;
     }
 }
diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/ResourceServiceImpl.java
 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/ResourceServiceImpl.java
index 928b45ccc..e2c9d6104 100644
--- 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/ResourceServiceImpl.java
+++ 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/ResourceServiceImpl.java
@@ -25,28 +25,26 @@ import org.apache.shenyu.admin.mapper.ResourceMapper;
 import org.apache.shenyu.admin.model.dto.PermissionDTO;
 import org.apache.shenyu.admin.model.dto.ResourceDTO;
 import org.apache.shenyu.admin.model.entity.PermissionDO;
+import org.apache.shenyu.admin.model.entity.PluginDO;
 import org.apache.shenyu.admin.model.entity.ResourceDO;
+import org.apache.shenyu.admin.model.event.plugin.BatchPluginDeletedEvent;
+import org.apache.shenyu.admin.model.event.plugin.PluginCreatedEvent;
 import org.apache.shenyu.admin.model.page.CommonPager;
 import org.apache.shenyu.admin.model.page.PageResultUtils;
 import org.apache.shenyu.admin.model.query.ResourceQuery;
 import org.apache.shenyu.admin.model.vo.PermissionMenuVO.MenuInfo;
 import org.apache.shenyu.admin.model.vo.ResourceVO;
 import org.apache.shenyu.admin.service.ResourceService;
+import org.apache.shenyu.admin.utils.ListUtil;
+import org.apache.shenyu.admin.utils.ResourceUtil;
 import org.apache.shenyu.common.constant.AdminConstants;
 import org.apache.shenyu.common.enums.AdminResourceEnum;
+import org.springframework.context.event.EventListener;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Deque;
-import java.util.HashSet;
 import java.util.List;
-import java.util.Map;
 import java.util.Objects;
-import java.util.Set;
-import java.util.function.Function;
 import java.util.stream.Collectors;
 
 /**
@@ -54,17 +52,17 @@ import java.util.stream.Collectors;
  */
 @Service
 public class ResourceServiceImpl implements ResourceService {
-
+    
     private final ResourceMapper resourceMapper;
-
+    
     private final PermissionMapper permissionMapper;
-
+    
     public ResourceServiceImpl(final ResourceMapper resourceMapper,
                                final PermissionMapper permissionMapper) {
         this.resourceMapper = resourceMapper;
         this.permissionMapper = permissionMapper;
     }
-
+    
     /**
      * create resource and return data.
      *
@@ -74,7 +72,7 @@ public class ResourceServiceImpl implements ResourceService {
     public void createResource(final ResourceDO resourceDO) {
         insertResource(resourceDO);
     }
-
+    
     /**
      * create Resources.
      *
@@ -85,7 +83,7 @@ public class ResourceServiceImpl implements ResourceService {
     public int createResourceBatch(final List<ResourceDO> resourceDOList) {
         return this.insertResourceBatch(resourceDOList);
     }
-
+    
     /**
      * create or update resource.
      *
@@ -102,7 +100,7 @@ public class ResourceServiceImpl implements ResourceService 
{
             return resourceMapper.updateSelective(resourceDO);
         }
     }
-
+    
     /**
      * delete resource info.
      *
@@ -112,18 +110,17 @@ public class ResourceServiceImpl implements 
ResourceService {
     @Override
     @Transactional(rollbackFor = Exception.class)
     public int delete(final List<String> ids) {
-
         int ret = 0;
-        List<ResourceVO> resourceVOList = 
resourceMapper.selectAll().stream().map(ResourceVO::buildResourceVO).collect(Collectors.toList());
-        List<String> deleteResourceIds = getDeleteResourceIds(ids, 
resourceVOList);
+        List<ResourceVO> resourceVOList = 
ListUtil.map(resourceMapper.selectAll(), ResourceVO::buildResourceVO);
+        List<String> deleteResourceIds = 
ResourceUtil.getDeleteResourceIds(ids, resourceVOList);
         if (CollectionUtils.isNotEmpty(deleteResourceIds)) {
             permissionMapper.deleteByResourceId(deleteResourceIds);
             ret = resourceMapper.delete(deleteResourceIds);
         }
-
+        
         return ret;
     }
-
+    
     /**
      * find resource info by id.
      *
@@ -134,7 +131,7 @@ public class ResourceServiceImpl implements ResourceService 
{
     public ResourceVO findById(final String id) {
         return ResourceVO.buildResourceVO(resourceMapper.selectById(id));
     }
-
+    
     /**
      * find resource info by title.
      *
@@ -145,7 +142,7 @@ public class ResourceServiceImpl implements ResourceService 
{
     public ResourceVO findByTitle(final String title) {
         return ResourceVO.buildResourceVO(resourceMapper.selectByTitle(title));
     }
-
+    
     /**
      * find by title.
      *
@@ -154,14 +151,9 @@ public class ResourceServiceImpl implements 
ResourceService {
      */
     @Override
     public List<ResourceVO> listByTitles(final List<String> titles) {
-        final List<ResourceDO> resources = 
this.resourceMapper.selectByTitles(titles);
-        if (CollectionUtils.isEmpty(resources)) {
-            return Collections.emptyList();
-        }
-        return resources.stream().map(ResourceVO::buildResourceVO)
-                .filter(Objects::nonNull).collect(Collectors.toList());
+        return ListUtil.map(resourceMapper.selectByTitles(titles), 
ResourceVO::buildResourceVO);
     }
-
+    
     /**
      * find page of role by query.
      *
@@ -176,7 +168,7 @@ public class ResourceServiceImpl implements ResourceService 
{
                 .map(ResourceVO::buildResourceVO)
                 .collect(Collectors.toList()));
     }
-
+    
     /**
      * get menu info.
      *
@@ -184,14 +176,10 @@ public class ResourceServiceImpl implements 
ResourceService {
      */
     @Override
     public List<MenuInfo> getMenuTree() {
-        List<ResourceVO> resourceVOList = 
resourceMapper.selectAll().stream().map(ResourceVO::buildResourceVO).collect(Collectors.toList());
-        if (CollectionUtils.isEmpty(resourceVOList)) {
-            return null;
-        }
-
-        return this.getMenuInfo(resourceVOList);
+        List<ResourceVO> resourceVOList = 
ListUtil.map(resourceMapper.selectAll(), ResourceVO::buildResourceVO);
+        return CollectionUtils.isEmpty(resourceVOList) ? null : 
ResourceUtil.buildMenu(resourceVOList);
     }
-
+    
     /**
      * get button by parent id.
      *
@@ -202,103 +190,39 @@ public class ResourceServiceImpl implements 
ResourceService {
     public List<ResourceVO> findByParentId(final String id) {
         return resourceMapper.selectByParentId(id).stream()
                 .filter(item -> 
item.getResourceType().equals(AdminResourceEnum.THREE_MENU.getCode()))
-                .map(ResourceVO::buildResourceVO).collect(Collectors.toList());
+                .map(ResourceVO::buildResourceVO)
+                .collect(Collectors.toList());
     }
-
+    
     /**
-     * get Menu Info.
+     * The associated Handle needs to be created synchronously.
+     * add plugin and add plugin resource.
      *
-     * @param metaList {@linkplain List} resource list
-     * @return {@linkplain List} menu infos.
+     * @param event event
      */
-    @Override
-    public List<MenuInfo> getMenuInfo(final List<ResourceVO> metaList) {
-
-        List<MenuInfo> retList = new ArrayList<>();
-        if (CollectionUtils.isEmpty(metaList)) {
-            return retList;
+    @EventListener(value = PluginCreatedEvent.class)
+    public void onPluginCreated(final PluginCreatedEvent event) {
+        ResourceDO resourceDO = 
ResourceUtil.buildPluginResource(event.getPlugin().getName());
+        createResource(resourceDO);
+        for (ResourceDO resource : 
ResourceUtil.buildPluginDataPermissionResource(resourceDO.getId(), 
event.getPlugin().getName())) {
+            createResource(resource);
         }
-        Map<String, MenuInfo> menuInfoMap = 
metaList.stream().map(MenuInfo::buildMenuInfo).filter(menuInfo -> 
Objects.nonNull(menuInfo) && StringUtils.isNotEmpty(menuInfo.getId()))
-                .collect(Collectors.toMap(MenuInfo::getId, 
Function.identity(), (value1, value2) -> value1));
-        Map<String, Set<String>> metaChildrenMap = 
this.dealChildrenMap(metaList);
-
-        metaChildrenMap.forEach((parent, children) -> {
-            MenuInfo menuInfo = menuInfoMap.get(parent);
-            if (CollectionUtils.isNotEmpty(children)) {
-                List<MenuInfo> targetList;
-                if (Objects.isNull(menuInfo)) {
-                    targetList = retList;
-                } else {
-                    targetList = menuInfo.getChildren();
-                }
-                children.forEach(child -> {
-                    MenuInfo data = menuInfoMap.get(child);
-                    if (Objects.nonNull(data)) {
-                        targetList.add(data);
-                    }
-                });
-            }
-        });
-
-        return retList;
-    }
-
-    /**
-     * convert the list to a map, the key is the parent id, and the value is 
the set of child ids.
-     *
-     * @param metaList the list to be converted
-     * @return the map
-     */
-    private Map<String, Set<String>> dealChildrenMap(final List<ResourceVO> 
metaList) {
-        return metaList.stream().filter(meta -> Objects.nonNull(meta) && 
StringUtils.isNotEmpty(meta.getId()))
-                .collect(Collectors.toMap(ResourceVO::getParentId,
-                    resourceVO -> {
-                        Set<String> idSet = new HashSet<>();
-                        idSet.add(resourceVO.getId());
-                        return idSet;
-                    }, (set1, set2) -> {
-                        set1.addAll(set2);
-                        return set1;
-                    }));
     }
-
-
+    
     /**
-     * get delete resource ids.
+     * The associated Handle needs to be deleted synchronously.
      *
-     * @param resourceIds resource ids
-     * @param metaList    all resource object
-     * @return the list of ids to delete
+     * @param event event
      */
-    private List<String> getDeleteResourceIds(final List<String> resourceIds, 
final List<ResourceVO> metaList) {
-
-        List<String> deleteResourceIds = null;
-        if (CollectionUtils.isEmpty(metaList) || 
CollectionUtils.isEmpty(resourceIds)) {
-            return deleteResourceIds;
+    @EventListener(value = BatchPluginDeletedEvent.class)
+    public void onPluginDeleted(final BatchPluginDeletedEvent event) {
+        // 5. delete resource & permission.
+        final List<ResourceVO> resources = listByTitles(ListUtil.map((List<?>) 
event.getSource(), s -> ((PluginDO) s).getName()));
+        if (CollectionUtils.isNotEmpty(resources)) {
+            delete(ListUtil.map(resources, ResourceVO::getId));
         }
-        deleteResourceIds = new ArrayList<>();
-        Map<String, ResourceVO> metaMap = 
metaList.stream().filter(Objects::nonNull)
-                .collect(Collectors.toMap(ResourceVO::getId, 
Function.identity(), (value1, value2) -> value1));
-
-        Map<String, Set<String>> metaChildrenMap = 
this.dealChildrenMap(metaList);
-
-        Deque<String> cacheDatas = new ArrayDeque<>(resourceIds);
-        while (!cacheDatas.isEmpty()) {
-            String resourceId = cacheDatas.pollFirst();
-            ResourceVO resourceVO = metaMap.get(resourceId);
-            Set<String> children = metaChildrenMap.get(resourceId);
-            if (Objects.nonNull(resourceVO)) {
-                deleteResourceIds.add(resourceVO.getId());
-                metaMap.remove(resourceId);
-            }
-            if (CollectionUtils.isNotEmpty(children)) {
-                children.forEach(cacheDatas::addFirst);
-                metaChildrenMap.remove(resourceId);
-            }
-        }
-        return deleteResourceIds;
     }
-
+    
     /**
      * insert Resource.
      *
@@ -311,8 +235,8 @@ public class ResourceServiceImpl implements ResourceService 
{
                 .resourceId(resourceDO.getId()).build()));
         return resourceMapper.insertSelective(resourceDO);
     }
-
-
+    
+    
     /**
      * insert Resources.
      *
@@ -320,16 +244,16 @@ public class ResourceServiceImpl implements 
ResourceService {
      * @return row int
      */
     private int insertResourceBatch(final List<ResourceDO> resourceDOList) {
-
+        
         if (CollectionUtils.isEmpty(resourceDOList)) {
             return 0;
         }
         List<PermissionDO> permissionDOList = 
resourceDOList.stream().filter(Objects::nonNull).map(resourceDO -> 
PermissionDO.buildPermissionDO(PermissionDTO.builder()
                 .objectId(AdminConstants.ROLE_SUPER_ID)
                 
.resourceId(resourceDO.getId()).build())).collect(Collectors.toList());
-
+        
         permissionMapper.insertBatch(permissionDOList);
-
+        
         return resourceMapper.insertBatch(resourceDOList);
     }
 }
diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/SelectorServiceImpl.java
 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/SelectorServiceImpl.java
index b75543724..2772dc37c 100644
--- 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/SelectorServiceImpl.java
+++ 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/SelectorServiceImpl.java
@@ -33,11 +33,13 @@ import org.apache.shenyu.admin.mapper.SelectorMapper;
 import org.apache.shenyu.admin.model.dto.DataPermissionDTO;
 import org.apache.shenyu.admin.model.dto.SelectorConditionDTO;
 import org.apache.shenyu.admin.model.dto.SelectorDTO;
+import org.apache.shenyu.admin.model.entity.BaseDO;
 import org.apache.shenyu.admin.model.entity.DataPermissionDO;
 import org.apache.shenyu.admin.model.entity.PluginDO;
 import org.apache.shenyu.admin.model.entity.RuleDO;
 import org.apache.shenyu.admin.model.entity.SelectorConditionDO;
 import org.apache.shenyu.admin.model.entity.SelectorDO;
+import org.apache.shenyu.admin.model.event.plugin.BatchPluginDeletedEvent;
 import org.apache.shenyu.admin.model.page.CommonPager;
 import org.apache.shenyu.admin.model.page.PageResultUtils;
 import org.apache.shenyu.admin.model.query.SelectorConditionQuery;
@@ -46,28 +48,26 @@ import 
org.apache.shenyu.admin.model.query.SelectorQueryCondition;
 import org.apache.shenyu.admin.model.vo.SelectorConditionVO;
 import org.apache.shenyu.admin.model.vo.SelectorVO;
 import org.apache.shenyu.admin.service.SelectorService;
+import org.apache.shenyu.admin.service.publish.SelectorEventPublisher;
 import org.apache.shenyu.admin.transfer.ConditionTransfer;
-import org.apache.shenyu.admin.utils.Assert;
 import org.apache.shenyu.admin.utils.CommonUpstreamUtils;
 import org.apache.shenyu.admin.utils.JwtUtils;
+import org.apache.shenyu.admin.utils.ListUtil;
+import org.apache.shenyu.admin.utils.SelectorUtil;
 import org.apache.shenyu.common.constant.AdminConstants;
-import org.apache.shenyu.common.constant.Constants;
 import org.apache.shenyu.common.dto.ConditionData;
 import org.apache.shenyu.common.dto.RuleData;
 import org.apache.shenyu.common.dto.SelectorData;
 import org.apache.shenyu.common.dto.convert.selector.DivideUpstream;
-import org.apache.shenyu.common.dto.convert.selector.SpringCloudSelectorHandle;
 import org.apache.shenyu.common.enums.ConfigGroupEnum;
 import org.apache.shenyu.common.enums.DataEventTypeEnum;
 import org.apache.shenyu.common.enums.MatchModeEnum;
-import org.apache.shenyu.common.enums.OperatorEnum;
-import org.apache.shenyu.common.enums.ParamTypeEnum;
 import org.apache.shenyu.common.enums.PluginEnum;
 import org.apache.shenyu.common.enums.SelectorTypeEnum;
 import org.apache.shenyu.common.utils.ContextPathUtils;
-import org.apache.shenyu.common.utils.GsonUtils;
 import org.apache.shenyu.register.common.dto.MetaDataRegisterDTO;
 import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.context.event.EventListener;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -79,7 +79,6 @@ import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
-import java.util.function.Function;
 import java.util.stream.Collectors;
 
 /**
@@ -104,6 +103,8 @@ public class SelectorServiceImpl implements SelectorService 
{
     
     private final UpstreamCheckService upstreamCheckService;
     
+    private final SelectorEventPublisher selectorEventPublisher;
+    
     public SelectorServiceImpl(final SelectorMapper selectorMapper,
                                final SelectorConditionMapper 
selectorConditionMapper,
                                final PluginMapper pluginMapper,
@@ -111,7 +112,8 @@ public class SelectorServiceImpl implements SelectorService 
{
                                final RuleConditionMapper ruleConditionMapper,
                                final ApplicationEventPublisher eventPublisher,
                                final DataPermissionMapper dataPermissionMapper,
-                               final UpstreamCheckService 
upstreamCheckService) {
+                               final UpstreamCheckService upstreamCheckService,
+                               final SelectorEventPublisher 
selectorEventPublisher) {
         this.selectorMapper = selectorMapper;
         this.selectorConditionMapper = selectorConditionMapper;
         this.pluginMapper = pluginMapper;
@@ -120,6 +122,7 @@ public class SelectorServiceImpl implements SelectorService 
{
         this.eventPublisher = eventPublisher;
         this.dataPermissionMapper = dataPermissionMapper;
         this.upstreamCheckService = upstreamCheckService;
+        this.selectorEventPublisher = selectorEventPublisher;
     }
     
     @Override
@@ -136,15 +139,11 @@ public class SelectorServiceImpl implements 
SelectorService {
     @Override
     public String registerDefault(final SelectorDTO selectorDTO) {
         SelectorDO selectorDO = SelectorDO.buildSelectorDO(selectorDTO);
-        List<SelectorConditionDTO> selectorConditionDTOs = 
selectorDTO.getSelectorConditions();
         if (StringUtils.isEmpty(selectorDTO.getId())) {
             selectorMapper.insertSelective(selectorDO);
-            selectorConditionDTOs.forEach(selectorConditionDTO -> {
-                selectorConditionDTO.setSelectorId(selectorDO.getId());
-                
selectorConditionMapper.insertSelective(SelectorConditionDO.buildSelectorConditionDO(selectorConditionDTO));
-            });
+            createCondition(selectorDO.getId(), 
selectorDTO.getSelectorConditions());
         }
-        publishEvent(selectorDO, selectorConditionDTOs);
+        publishEvent(selectorDO, selectorDTO.getSelectorConditions());
         return selectorDO.getId();
     }
     
@@ -153,7 +152,9 @@ public class SelectorServiceImpl implements SelectorService 
{
         String contextPath = 
ContextPathUtils.buildContextPath(dto.getContextPath(), dto.getAppName());
         SelectorDO selectorDO = findByNameAndPluginName(contextPath, 
pluginName);
         if (Objects.isNull(selectorDO)) {
-            return registerSelector(contextPath, pluginName, selectorHandler);
+            SelectorDTO selectorDTO = 
SelectorUtil.buildSelectorDTO(contextPath, 
pluginMapper.selectByName(pluginName).getId());
+            selectorDTO.setHandle(selectorHandler);
+            return registerDefault(selectorDTO);
         }
         return selectorDO.getId();
     }
@@ -167,39 +168,36 @@ public class SelectorServiceImpl implements 
SelectorService {
     @Override
     @Transactional(rollbackFor = Exception.class)
     public int createOrUpdate(final SelectorDTO selectorDTO) {
-        if (Objects.equals(SelectorTypeEnum.CUSTOM_FLOW.getCode(), 
selectorDTO.getType())) {
-            Assert.notNull(selectorDTO.getMatchMode(), "if type is custom, 
matchMode is not null");
-            Assert.notEmpty(selectorDTO.getSelectorConditions(), "if type is 
custom, selectorConditions is not empty");
+        return SelectorService.super.createOrUpdate(selectorDTO);
+    }
+    
+    @Override
+    public int create(final SelectorDTO selectorDTO) {
+        SelectorDO selectorDO = SelectorDO.buildSelectorDO(selectorDTO);
+        final int selectorCount = selectorMapper.insertSelective(selectorDO);
+        createCondition(selectorDO.getId(), 
selectorDTO.getSelectorConditions());
+        initSelectorPermission(selectorDO);
+        publishEvent(selectorDO, selectorDTO.getSelectorConditions());
+        if (selectorCount > 0) {
+            selectorEventPublisher.onCreated(selectorDO);
         }
-        int selectorCount;
+        updateDivideUpstream(selectorDO);
+        return selectorCount;
+        
+    }
+    
+    @Override
+    public int update(final SelectorDTO selectorDTO) {
+        final SelectorDO before = 
selectorMapper.selectById(selectorDTO.getId());
         SelectorDO selectorDO = SelectorDO.buildSelectorDO(selectorDTO);
-        List<SelectorConditionDTO> selectorConditionDTOs = 
selectorDTO.getSelectorConditions();
-        if (StringUtils.isEmpty(selectorDTO.getId())) {
-            selectorCount = selectorMapper.insertSelective(selectorDO);
-            selectorConditionDTOs.forEach(selectorConditionDTO -> {
-                selectorConditionDTO.setSelectorId(selectorDO.getId());
-                
selectorConditionMapper.insertSelective(SelectorConditionDO.buildSelectorConditionDO(selectorConditionDTO));
-            });
-            // check selector add
-            if 
(Boolean.TRUE.equals(dataPermissionMapper.existed(JwtUtils.getUserInfo().getUserId())))
 {
-                DataPermissionDTO dataPermissionDTO = new DataPermissionDTO();
-                
dataPermissionDTO.setUserId(JwtUtils.getUserInfo().getUserId());
-                dataPermissionDTO.setDataId(selectorDO.getId());
-                
dataPermissionDTO.setDataType(AdminConstants.SELECTOR_DATA_TYPE);
-                
dataPermissionMapper.insertSelective(DataPermissionDO.buildPermissionDO(dataPermissionDTO));
-            }
-            
-        } else {
-            selectorCount = selectorMapper.updateSelective(selectorDO);
-            //delete rule condition then add
-            selectorConditionMapper.deleteByQuery(new 
SelectorConditionQuery(selectorDO.getId()));
-            selectorConditionDTOs.forEach(selectorConditionDTO -> {
-                selectorConditionDTO.setSelectorId(selectorDO.getId());
-                SelectorConditionDO selectorConditionDO = 
SelectorConditionDO.buildSelectorConditionDO(selectorConditionDTO);
-                selectorConditionMapper.insertSelective(selectorConditionDO);
-            });
+        final int selectorCount = selectorMapper.updateSelective(selectorDO);
+        //delete rule condition then add
+        selectorConditionMapper.deleteByQuery(new 
SelectorConditionQuery(selectorDO.getId()));
+        createCondition(selectorDO.getId(), 
selectorDTO.getSelectorConditions());
+        publishEvent(selectorDO, selectorDTO.getSelectorConditions());
+        if (selectorCount > 0) {
+            selectorEventPublisher.onUpdated(selectorDO, before);
         }
-        publishEvent(selectorDO, selectorConditionDTOs);
         updateDivideUpstream(selectorDO);
         return selectorCount;
     }
@@ -225,41 +223,27 @@ public class SelectorServiceImpl implements 
SelectorService {
         Set<String> idSet = new HashSet<>(ids);
         List<SelectorDO> selectorDOList = selectorMapper.selectByIdSet(idSet);
         if (CollectionUtils.isNotEmpty(selectorDOList)) {
-            Map<String, SelectorDO> selectorDOMap = 
selectorDOList.stream().filter(Objects::nonNull)
-                    .collect(Collectors.toMap(SelectorDO::getId, 
Function.identity(), (value1, value2) -> value1));
-            List<String> pluginIdList = 
selectorDOMap.values().stream().map(SelectorDO::getPluginId).collect(Collectors.toList());
-            List<PluginDO> pluginDOList = pluginMapper.selectByIds(new 
ArrayList<>(pluginIdList));
+            Map<String, SelectorDO> selectorMap = 
ListUtil.toMap(selectorDOList, SelectorDO::getId);
+            List<String> pluginIdList = ListUtil.map(selectorMap.values(), 
SelectorDO::getPluginId);
+            List<PluginDO> pluginDOList = 
pluginMapper.selectByIds(pluginIdList);
             
             if (CollectionUtils.isNotEmpty(pluginDOList)) {
-                Map<String, String> pluginMap = 
pluginDOList.stream().filter(Objects::nonNull)
-                        .collect(Collectors.toMap(PluginDO::getId, 
PluginDO::getName, (value1, value2) -> value1));
+                Map<String, String> pluginMap = ListUtil.toMap(pluginDOList, 
PluginDO::getId, PluginDO::getName);
                 if (pluginMap.size() == pluginIdList.size()) {
                     selectorMapper.deleteByIds(ids);
                     selectorConditionMapper.deleteBySelectorIds(ids);
                     dataPermissionMapper.deleteByDataIdList(ids);
                     
-                    List<SelectorData> selectorDataList = 
selectorDOMap.values().stream().map(selectorDO -> {
-                        String pluginName = 
pluginMap.get(selectorDO.getPluginId());
-                        if (pluginName.equals(PluginEnum.DIVIDE.getName())) {
-                            
UpstreamCheckService.removeByKey(selectorDO.getId());
-                        }
-                        return SelectorDO.transFrom(selectorDO, pluginName, 
null);
-                    }).collect(Collectors.toList());
-                    eventPublisher.publishEvent(new 
DataChangedEvent(ConfigGroupEnum.SELECTOR, DataEventTypeEnum.DELETE, 
selectorDataList));
-                    
-                    List<RuleDO> ruleDOList = 
ruleMapper.findBySelectorIds(ids);
-                    if (CollectionUtils.isNotEmpty(ruleDOList)) {
-                        List<String> ruleIdList = new ArrayList<>();
-                        List<RuleData> ruleDataList = 
ruleDOList.stream().filter(Objects::nonNull).map(ruleDO -> {
-                            ruleIdList.add(ruleDO.getId());
-                            SelectorDO selectorDO = 
selectorDOMap.get(ruleDO.getSelectorId());
-                            String pluginName = 
pluginMap.get(selectorDO.getPluginId());
-                            return RuleDO.transFrom(ruleDO, pluginName, null);
-                        }).collect(Collectors.toList());
-                        ruleMapper.deleteByIds(ruleIdList);
-                        ruleConditionMapper.deleteByRuleIds(ruleIdList);
-                        eventPublisher.publishEvent(new 
DataChangedEvent(ConfigGroupEnum.RULE, DataEventTypeEnum.DELETE, ruleDataList));
-                    }
+                    List<SelectorData> selectorDataList = 
selectorMap.values().stream()
+                            .map(selectorDO -> {
+                                String pluginName = 
pluginMap.get(selectorDO.getPluginId());
+                                if 
(pluginName.equals(PluginEnum.DIVIDE.getName())) {
+                                    
UpstreamCheckService.removeByKey(selectorDO.getId());
+                                }
+                                return SelectorDO.transFrom(selectorDO, 
pluginName, null);
+                            }).collect(Collectors.toList());
+                    selectorEventPublisher.onDeleted(selectorDOList, 
selectorDataList);
+                    deleteRule(ids, selectorMap, pluginMap);
                 }
             }
         }
@@ -270,16 +254,12 @@ public class SelectorServiceImpl implements 
SelectorService {
      * find selector by id.
      *
      * @param id primary key.
-     * @return {@linkplain SelectorVO}
+     * @return {@link SelectorVO}
      */
     @Override
     public SelectorVO findById(final String id) {
-        return SelectorVO.buildSelectorVO(selectorMapper.selectById(id),
-                selectorConditionMapper.selectByQuery(
-                        new SelectorConditionQuery(id))
-                        .stream()
-                        .map(SelectorConditionVO::buildSelectorConditionVO)
-                        .collect(Collectors.toList()));
+        final List<SelectorConditionVO> conditions = 
ListUtil.map(selectorConditionMapper.selectByQuery(new 
SelectorConditionQuery(id)), SelectorConditionVO::buildSelectorConditionVO);
+        return SelectorVO.buildSelectorVO(selectorMapper.selectById(id), 
conditions);
     }
     
     @Override
@@ -335,24 +315,87 @@ public class SelectorServiceImpl implements 
SelectorService {
     
     @Override
     public List<SelectorData> findByPluginId(final String pluginId) {
-        
-        List<SelectorDO> selectorDOList = 
selectorMapper.findByPluginId(pluginId);
-        
-        return this.buildSelectorDataList(selectorDOList);
+        return 
this.buildSelectorDataList(selectorMapper.findByPluginId(pluginId));
     }
     
     @Override
     public List<SelectorData> listAll() {
-        
-        List<SelectorDO> selectorDOList = selectorMapper.selectAll();
-        
-        return this.buildSelectorDataList(selectorDOList);
+        return this.buildSelectorDataList(selectorMapper.selectAll());
     }
     
-    private void publishEvent(final SelectorDO selectorDO, final 
List<SelectorConditionDTO> selectorConditionDTOs) {
+    /**
+     * the plugin delete, synchronously delete selectors.
+     *
+     * @param event event
+     */
+    @EventListener(value = BatchPluginDeletedEvent.class)
+    public void onPluginDeleted(final BatchPluginDeletedEvent event) {
+        final List<SelectorDO> selectors = 
this.selectorMapper.findByPluginIds(event.getDeletedPluginIds());
+        if (CollectionUtils.isNotEmpty(selectors)) {
+            final List<String> selectorIds = ListUtil.map(selectors, 
BaseDO::getId);
+            final int count = selectorMapper.deleteByIds(selectorIds);
+            // delete all selector conditions
+            this.selectorConditionMapper.deleteBySelectorIds(selectorIds);
+            deleteRefRule(selectorIds);
+            if (count > 0) {
+                selectorEventPublisher.onDeleted(selectors);
+            }
+        }
+    }
+    
+    private void deleteRefRule(final List<String> selectorIds) {
+        // todo: delete rule will move rule service
+        // delete all rules
+        final List<String> ruleIds = 
ListUtil.map(ruleMapper.findBySelectorIds(selectorIds), RuleDO::getId);
+        if (CollectionUtils.isNotEmpty(ruleIds)) {
+            this.ruleMapper.deleteByIds(ruleIds);
+            // delete all rule conditions
+            this.ruleConditionMapper.deleteByRuleIds(ruleIds);
+        }
+    }
+    
+    private void deleteRule(final List<String> ids, final Map<String, 
SelectorDO> selectorDOMap, final Map<String, String> pluginMap) {
+        // todo: delete rule will move rule service
+        List<RuleDO> ruleDOList = ruleMapper.findBySelectorIds(ids);
+        if (CollectionUtils.isNotEmpty(ruleDOList)) {
+            List<String> ruleIdList = new ArrayList<>();
+            List<RuleData> ruleDataList = ruleDOList.stream()
+                    .filter(Objects::nonNull)
+                    .map(ruleDO -> {
+                        ruleIdList.add(ruleDO.getId());
+                        SelectorDO selectorDO = 
selectorDOMap.get(ruleDO.getSelectorId());
+                        String pluginName = 
pluginMap.get(selectorDO.getPluginId());
+                        return RuleDO.transFrom(ruleDO, pluginName, null);
+                    })
+                    .collect(Collectors.toList());
+            ruleMapper.deleteByIds(ruleIdList);
+            ruleConditionMapper.deleteByRuleIds(ruleIdList);
+            eventPublisher.publishEvent(new 
DataChangedEvent(ConfigGroupEnum.RULE, DataEventTypeEnum.DELETE, ruleDataList));
+        }
+    }
+    
+    private void createCondition(final String selectorId, final 
List<SelectorConditionDTO> selectorConditions) {
+        for (SelectorConditionDTO condition : selectorConditions) {
+            condition.setSelectorId(selectorId);
+            
selectorConditionMapper.insertSelective(SelectorConditionDO.buildSelectorConditionDO(condition));
+        }
+    }
+    
+    private void initSelectorPermission(final SelectorDO selectorDO) {
+        // todo add permission will move permission service
+        // check selector add
+        if 
(Boolean.TRUE.equals(dataPermissionMapper.existed(JwtUtils.getUserInfo().getUserId())))
 {
+            DataPermissionDTO dataPermissionDTO = new DataPermissionDTO();
+            dataPermissionDTO.setUserId(JwtUtils.getUserInfo().getUserId());
+            dataPermissionDTO.setDataId(selectorDO.getId());
+            dataPermissionDTO.setDataType(AdminConstants.SELECTOR_DATA_TYPE);
+            
dataPermissionMapper.insertSelective(DataPermissionDO.buildPermissionDO(dataPermissionDTO));
+        }
+    }
+    
+    private void publishEvent(final SelectorDO selectorDO, final 
List<SelectorConditionDTO> selectorConditions) {
         PluginDO pluginDO = pluginMapper.selectById(selectorDO.getPluginId());
-        List<ConditionData> conditionDataList =
-                
selectorConditionDTOs.stream().map(ConditionTransfer.INSTANCE::mapToSelectorDTO).collect(Collectors.toList());
+        List<ConditionData> conditionDataList = 
ListUtil.map(selectorConditions, ConditionTransfer.INSTANCE::mapToSelectorDTO);
         // publish change event.
         eventPublisher.publishEvent(new 
DataChangedEvent(ConfigGroupEnum.SELECTOR, DataEventTypeEnum.UPDATE,
                 Collections.singletonList(SelectorDO.transFrom(selectorDO, 
pluginDO.getName(), conditionDataList))));
@@ -371,27 +414,18 @@ public class SelectorServiceImpl implements 
SelectorService {
     
     private List<SelectorData> buildSelectorDataList(final List<SelectorDO> 
selectorDOList) {
         
-        Map<String, String> idMap = 
Optional.ofNullable(selectorDOList).orElseGet(ArrayList::new)
-                .stream().filter(Objects::nonNull)
-                .collect(Collectors.toMap(SelectorDO::getId, 
SelectorDO::getPluginId, (value1, value2) -> value1));
+        Map<String, String> idMap = ListUtil.toMap(selectorDOList, 
SelectorDO::getId, SelectorDO::getPluginId);
         if (MapUtils.isEmpty(idMap)) {
             return new ArrayList<>();
         }
-        Map<String, List<SelectorConditionDO>> selectorConditionMap = 
Optional.ofNullable(selectorConditionMapper.selectBySelectorIds(idMap.keySet()))
-                
.orElseGet(ArrayList::new).stream().collect(Collectors.toMap(SelectorConditionDO::getSelectorId,
 selectorConditionDO -> {
-                    List<SelectorConditionDO> dataList = new ArrayList<>();
-                    dataList.add(selectorConditionDO);
-                    return dataList;
-                }, (list1, list2) -> {
-                        list1.addAll(list2);
-                        return list1;
-                    }));
+        Map<String, List<SelectorConditionDO>> selectorConditionMap = 
ListUtil.groupBy(selectorConditionMapper.selectBySelectorIds(idMap.keySet()), 
SelectorConditionDO::getSelectorId);
         
-        Map<String, PluginDO> pluginDOMap = 
Optional.ofNullable(pluginMapper.selectByIds(Lists.newArrayList(idMap.values()))).orElseGet(ArrayList::new)
-                
.stream().filter(Objects::nonNull).collect(Collectors.toMap(PluginDO::getId, 
Function.identity(), (value1, value2) -> value1));
+        Map<String, PluginDO> pluginDOMap = 
ListUtil.toMap(pluginMapper.selectByIds(Lists.newArrayList(idMap.values())), 
PluginDO::getId);
         
         return Optional.ofNullable(selectorDOList).orElseGet(ArrayList::new)
-                .stream().filter(Objects::nonNull).map(selectorDO -> {
+                .stream()
+                .filter(Objects::nonNull)
+                .map(selectorDO -> {
                     String id = selectorDO.getId();
                     String pluginId = selectorDO.getPluginId();
                     PluginDO pluginDO = pluginDOMap.get(pluginId);
@@ -400,61 +434,17 @@ public class SelectorServiceImpl implements 
SelectorService {
                     }
                     List<ConditionData> conditionDataList = 
ConditionTransfer.INSTANCE.mapToSelectorDOS(selectorConditionMap.get(id));
                     return SelectorDO.transFrom(selectorDO, 
pluginDO.getName(), conditionDataList);
-                }).collect(Collectors.toList());
+                })
+                .collect(Collectors.toList());
     }
     
     private void updateDivideUpstream(final SelectorDO selectorDO) {
-        String selectorId = selectorDO.getId();
-        PluginDO pluginDO = pluginMapper.selectById(selectorDO.getPluginId());
-        List<DivideUpstream> existDivideUpstreams = null;
-        if (PluginEnum.SPRING_CLOUD.getName().equals(pluginDO.getName())) {
-            if (Objects.nonNull(selectorDO.getHandle())) {
-                SpringCloudSelectorHandle springCloudSelectorHandle = 
GsonUtils.getInstance()
-                        .fromJson(selectorDO.getHandle(), 
SpringCloudSelectorHandle.class);
-                existDivideUpstreams = 
springCloudSelectorHandle.getDivideUpstreams();
-            }
-        } else if (PluginEnum.DIVIDE.getName().equals(pluginDO.getName())) {
-            String handle = selectorDO.getHandle();
-            if (StringUtils.isNotBlank(handle)) {
-                existDivideUpstreams = 
GsonUtils.getInstance().fromList(handle, DivideUpstream.class);
-            }
-        }
+        // todo update divide upstream will move upstream check service
+        final PluginDO plugin = 
pluginMapper.selectById(selectorDO.getPluginId());
+        List<DivideUpstream> existDivideUpstreams = 
SelectorUtil.buildDivideUpstream(selectorDO, plugin.getName());
         if (CollectionUtils.isNotEmpty(existDivideUpstreams)) {
-            upstreamCheckService.replace(selectorId, 
CommonUpstreamUtils.convertCommonUpstreamList(existDivideUpstreams));
+            upstreamCheckService.replace(selectorDO.getId(), 
CommonUpstreamUtils.convertCommonUpstreamList(existDivideUpstreams));
         }
     }
     
-    private String registerSelector(final String contextPath, final String 
pluginName, final String selectorHandler) {
-        SelectorDTO selectorDTO = buildSelectorDTO(contextPath, 
pluginMapper.selectByName(pluginName).getId());
-        selectorDTO.setHandle(selectorHandler);
-        return registerDefault(selectorDTO);
-    }
-    
-    private SelectorDTO buildSelectorDTO(final String contextPath, final 
String pluginId) {
-        SelectorDTO selectorDTO = buildDefaultSelectorDTO(contextPath);
-        selectorDTO.setPluginId(pluginId);
-        
selectorDTO.setSelectorConditions(buildDefaultSelectorConditionDTO(contextPath));
-        return selectorDTO;
-    }
-    
-    private SelectorDTO buildDefaultSelectorDTO(final String name) {
-        return SelectorDTO.builder()
-                .name(name)
-                .type(SelectorTypeEnum.CUSTOM_FLOW.getCode())
-                .matchMode(MatchModeEnum.AND.getCode())
-                .enabled(Boolean.TRUE)
-                .loged(Boolean.TRUE)
-                .continued(Boolean.TRUE)
-                .sort(1)
-                .build();
-    }
-    
-    private List<SelectorConditionDTO> buildDefaultSelectorConditionDTO(final 
String contextPath) {
-        SelectorConditionDTO selectorConditionDTO = new SelectorConditionDTO();
-        selectorConditionDTO.setParamType(ParamTypeEnum.URI.getName());
-        selectorConditionDTO.setParamName("/");
-        selectorConditionDTO.setOperator(OperatorEnum.STARTS_WITH.getAlias());
-        selectorConditionDTO.setParamValue(contextPath + 
Constants.PATH_SEPARATOR);
-        return Collections.singletonList(selectorConditionDTO);
-    }
 }
diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/publish/PluginEventPublisher.java
 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/publish/PluginEventPublisher.java
index b029e9afc..49bcd075d 100644
--- 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/publish/PluginEventPublisher.java
+++ 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/publish/PluginEventPublisher.java
@@ -21,8 +21,10 @@ import org.apache.shenyu.admin.listener.DataChangedEvent;
 import org.apache.shenyu.admin.model.entity.PluginDO;
 import org.apache.shenyu.admin.model.enums.EventTypeEnum;
 import org.apache.shenyu.admin.model.event.AdminDataModelChangedEvent;
-import org.apache.shenyu.admin.model.event.BatchPluginChangedEvent;
-import org.apache.shenyu.admin.model.event.PluginChangedEvent;
+import org.apache.shenyu.admin.model.event.plugin.BatchPluginChangedEvent;
+import org.apache.shenyu.admin.model.event.plugin.BatchPluginDeletedEvent;
+import org.apache.shenyu.admin.model.event.plugin.PluginChangedEvent;
+import org.apache.shenyu.admin.model.event.plugin.PluginCreatedEvent;
 import org.apache.shenyu.admin.transfer.PluginTransfer;
 import org.apache.shenyu.admin.utils.SessionUtil;
 import org.apache.shenyu.common.enums.ConfigGroupEnum;
@@ -36,7 +38,7 @@ import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 /**
- * ModelDataEventPublisher.
+ * PluginEventPublisher.
  */
 @Component
 public class PluginEventPublisher implements 
AdminDataModelChangedEventPublisher<PluginDO> {
@@ -56,7 +58,7 @@ public class PluginEventPublisher implements 
AdminDataModelChangedEventPublisher
     public void onCreated(final PluginDO plugin) {
         publisher.publishEvent(new DataChangedEvent(ConfigGroupEnum.PLUGIN, 
DataEventTypeEnum.CREATE,
                 
Collections.singletonList(PluginTransfer.INSTANCE.mapToData(plugin))));
-        publish(new PluginChangedEvent(plugin, null, 
EventTypeEnum.PLUGIN_CREATE, SessionUtil.visitorName()));
+        publish(new PluginCreatedEvent(plugin, SessionUtil.visitorName()));
     }
     
     /**
@@ -91,7 +93,7 @@ public class PluginEventPublisher implements 
AdminDataModelChangedEventPublisher
      */
     @Override
     public void onDeleted(final Collection<PluginDO> plugins) {
-        publish(new BatchPluginChangedEvent(plugins, null, 
EventTypeEnum.PLUGIN_DELETE, SessionUtil.visitorName()));
+        publish(new BatchPluginDeletedEvent(plugins, 
SessionUtil.visitorName()));
         publisher.publishEvent(new DataChangedEvent(ConfigGroupEnum.PLUGIN, 
DataEventTypeEnum.DELETE,
                 
plugins.stream().map(PluginTransfer.INSTANCE::mapToData).collect(Collectors.toList())));
     }
diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/publish/PluginHandleEventPublisher.java
 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/publish/PluginHandleEventPublisher.java
new file mode 100644
index 000000000..ecf5905b6
--- /dev/null
+++ 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/publish/PluginHandleEventPublisher.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shenyu.admin.service.publish;
+
+import org.apache.shenyu.admin.model.entity.PluginHandleDO;
+import org.apache.shenyu.admin.model.enums.EventTypeEnum;
+import org.apache.shenyu.admin.model.event.AdminDataModelChangedEvent;
+import 
org.apache.shenyu.admin.model.event.handle.BatchPluginHandleChangedEvent;
+import org.apache.shenyu.admin.model.event.handle.PluginHandleChangedEvent;
+import org.apache.shenyu.admin.utils.SessionUtil;
+import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.stereotype.Component;
+
+import java.util.Collection;
+
+/**
+ * PluginHandleEventPublisher.
+ */
+@Component
+public class PluginHandleEventPublisher implements 
AdminDataModelChangedEventPublisher<PluginHandleDO> {
+    
+    private final ApplicationEventPublisher publisher;
+    
+    public PluginHandleEventPublisher(final ApplicationEventPublisher 
publisher) {
+        this.publisher = publisher;
+    }
+    
+    /**
+     * on pluginHandle created.
+     *
+     * @param pluginHandle pluginHandle
+     */
+    @Override
+    public void onCreated(final PluginHandleDO pluginHandle) {
+        publish(new PluginHandleChangedEvent(pluginHandle, null, 
EventTypeEnum.PLUGIN_HANDLE_CREATE, SessionUtil.visitorName()));
+    }
+    
+    /**
+     * on pluginHandle updated.
+     *
+     * @param pluginHandle pluginHandle
+     * @param before before pluginHandle
+     */
+    @Override
+    public void onUpdated(final PluginHandleDO pluginHandle, final 
PluginHandleDO before) {
+        publish(new PluginHandleChangedEvent(pluginHandle, before, 
EventTypeEnum.PLUGIN_HANDLE_UPDATE, SessionUtil.visitorName()));
+    }
+    
+    /**
+     * on plugin deleted.
+     *
+     * @param plugin plugin
+     */
+    @Override
+    public void onDeleted(final PluginHandleDO plugin) {
+        publish(new PluginHandleChangedEvent(plugin, null, 
EventTypeEnum.PLUGIN_HANDLE_DELETE, SessionUtil.visitorName()));
+    }
+    
+    /**
+     * on plugin deleted.
+     *
+     * @param plugins plugins
+     */
+    @Override
+    public void onDeleted(final Collection<PluginHandleDO> plugins) {
+        publish(new BatchPluginHandleChangedEvent(plugins, null, 
EventTypeEnum.PLUGIN_HANDLE_DELETE, SessionUtil.visitorName()));
+    }
+    
+    
+    /**
+     * event.
+     *
+     * @param event event.
+     */
+    @Override
+    public void publish(final AdminDataModelChangedEvent event) {
+        publisher.publishEvent(event);
+    }
+}
diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/publish/SelectorEventPublisher.java
 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/publish/SelectorEventPublisher.java
new file mode 100644
index 000000000..71ace4d0d
--- /dev/null
+++ 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/publish/SelectorEventPublisher.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shenyu.admin.service.publish;
+
+import org.apache.shenyu.admin.listener.DataChangedEvent;
+import org.apache.shenyu.admin.model.entity.SelectorDO;
+import org.apache.shenyu.admin.model.enums.EventTypeEnum;
+import org.apache.shenyu.admin.model.event.AdminDataModelChangedEvent;
+import org.apache.shenyu.admin.model.event.selector.BatchSelectorDeletedEvent;
+import org.apache.shenyu.admin.model.event.selector.SelectorChangedEvent;
+import org.apache.shenyu.admin.model.event.selector.SelectorCreatedEvent;
+import org.apache.shenyu.admin.utils.SessionUtil;
+import org.apache.shenyu.common.dto.SelectorData;
+import org.apache.shenyu.common.enums.ConfigGroupEnum;
+import org.apache.shenyu.common.enums.DataEventTypeEnum;
+import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.stereotype.Component;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * SelectorEventPublisher.
+ */
+@Component
+public class SelectorEventPublisher implements 
AdminDataModelChangedEventPublisher<SelectorDO> {
+    
+    private final ApplicationEventPublisher publisher;
+    
+    public SelectorEventPublisher(final ApplicationEventPublisher publisher) {
+        this.publisher = publisher;
+    }
+    
+    /**
+     * on selector created.
+     *
+     * @param selector selector
+     */
+    @Override
+    public void onCreated(final SelectorDO selector) {
+        publish(new SelectorCreatedEvent(selector, SessionUtil.visitorName()));
+    }
+    
+    /**
+     * on selector updated.
+     *
+     * @param selector selector
+     * @param before   before selector
+     */
+    @Override
+    public void onUpdated(final SelectorDO selector, final SelectorDO before) {
+        publish(new SelectorChangedEvent(selector, before, 
EventTypeEnum.SELECTOR_UPDATE, SessionUtil.visitorName()));
+    }
+    
+    /**
+     * on selector deleted.
+     *
+     * @param selector selector
+     */
+    @Override
+    public void onDeleted(final SelectorDO selector) {
+        publish(new SelectorChangedEvent(selector, null, 
EventTypeEnum.SELECTOR_DELETE, SessionUtil.visitorName()));
+    }
+    
+    /**
+     * on plugin deleted.
+     *
+     * @param selectors        selectors
+     * @param selectorDataList selectorDataList
+     */
+    public void onDeleted(final Collection<SelectorDO> selectors, final 
List<SelectorData> selectorDataList) {
+        onDeleted(selectors);
+        publisher.publishEvent(new DataChangedEvent(ConfigGroupEnum.SELECTOR, 
DataEventTypeEnum.DELETE, selectorDataList));
+    }
+    
+    /**
+     * on plugin deleted.
+     *
+     * @param selectors selectors
+     */
+    @Override
+    public void onDeleted(final Collection<SelectorDO> selectors) {
+        publish(new BatchSelectorDeletedEvent(selectors, 
SessionUtil.visitorName()));
+    }
+    
+    /**
+     * event.
+     *
+     * @param event event.
+     */
+    @Override
+    public void publish(final AdminDataModelChangedEvent event) {
+        publisher.publishEvent(event);
+    }
+}
diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/utils/ListUtil.java 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/utils/ListUtil.java
new file mode 100644
index 000000000..a1c49bc3d
--- /dev/null
+++ b/shenyu-admin/src/main/java/org/apache/shenyu/admin/utils/ListUtil.java
@@ -0,0 +1,138 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shenyu.admin.utils;
+
+import org.apache.commons.collections4.CollectionUtils;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * ListUtil.
+ */
+public final class ListUtil {
+    
+    private ListUtil() {
+    }
+    
+    /**
+     * list.
+     *
+     * @param t   e
+     * @param <T> type
+     * @return list
+     */
+    @SafeVarargs
+    public static <T> List<T> list(final T... t) {
+        return Stream.of(t).collect(Collectors.toList());
+    }
+    
+    /**
+     * list map.<br>
+     * if element is null it filter.
+     *
+     * @param list     list
+     * @param function map fun
+     * @param <R>      resource type
+     * @param <T>      target type
+     * @return list
+     */
+    public static <R, T> List<T> map(final Collection<R> list, final 
Function<? super R, ? extends T> function) {
+        if (CollectionUtils.isEmpty(list)) {
+            return Collections.emptyList();
+        }
+        return list.stream()
+                .filter(Objects::nonNull)
+                .map(function)
+                .collect(Collectors.toList());
+    }
+    
+    /**
+     * list to map.<br>
+     * if element is null it filters.
+     *
+     * @param list     list
+     * @param function map fun
+     * @param <K>      map key type
+     * @param <U>      map value type
+     * @return list
+     */
+    public static <K, U> Map<K, U> toMap(final Collection<U> list, final 
Function<? super U, ? extends K> function) {
+        return toMap(list, function, Function.identity());
+    }
+    
+    /**
+     * list to map.<br>
+     * if element is null it filters.
+     *
+     * @param list        list
+     * @param keyMapper   map key convert
+     * @param valueMapper map value convert
+     * @param <K>         map key type
+     * @param <U>         map value type
+     * @param <T>         list value type
+     * @return list
+     */
+    public static <K, U, T> Map<K, U> toMap(final Collection<T> list, final 
Function<? super T, ? extends K> keyMapper, final Function<? super T, ? extends 
U> valueMapper) {
+        if (CollectionUtils.isEmpty(list)) {
+            return Collections.emptyMap();
+        }
+        return list.stream()
+                .filter(Objects::nonNull)
+                .collect(Collectors.toMap(keyMapper, valueMapper, (value1, 
value2) -> value1));
+    }
+    
+    /**
+     * list group by.<br>
+     * if element is null it filters.
+     *
+     * @param list     list
+     * @param function group key fun
+     * @param <K>      map key type
+     * @param <U>      map value type
+     * @return list
+     */
+    public static <K, U> Map<K, List<U>> groupBy(final Collection<U> list, 
final Function<? super U, ? extends K> function) {
+        if (CollectionUtils.isEmpty(list)) {
+            return Collections.emptyMap();
+        }
+        return list.stream()
+                .filter(Objects::nonNull)
+                .collect(Collectors.groupingBy(function));
+    }
+    
+    /**
+     * merge.
+     *
+     * @param set1 merge to.
+     * @param set2 merge from.
+     * @param <T>  type
+     * @return collection1
+     */
+    public static <T> Set<T> mergeSet(final Set<T> set1, final Set<T> set2) {
+        set1.addAll(set2);
+        return set1;
+    }
+}
diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/utils/ResourceUtil.java 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/utils/ResourceUtil.java
new file mode 100644
index 000000000..3c6eff0f9
--- /dev/null
+++ b/shenyu-admin/src/main/java/org/apache/shenyu/admin/utils/ResourceUtil.java
@@ -0,0 +1,247 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shenyu.admin.utils;
+
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.shenyu.admin.model.dto.ResourceDTO;
+import org.apache.shenyu.admin.model.entity.ResourceDO;
+import org.apache.shenyu.admin.model.vo.PermissionMenuVO;
+import org.apache.shenyu.admin.model.vo.ResourceVO;
+import org.apache.shenyu.common.constant.AdminConstants;
+import org.apache.shenyu.common.enums.AdminPluginOperateEnum;
+import org.apache.shenyu.common.enums.AdminResourceEnum;
+import org.apache.shenyu.common.enums.ConfigGroupEnum;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Deque;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * ResourceUtil.
+ */
+public final class ResourceUtil {
+    
+    /**
+     * new plugin init data permission.
+     */
+    private static final List<DataPermission> NEW_PLUGIN_DATA_PERMISSION = new 
ArrayList<>();
+    
+    private ResourceUtil() {
+    }
+    
+    static {
+        // selector.
+        NEW_PLUGIN_DATA_PERMISSION.add(new 
DataPermission(ConfigGroupEnum.SELECTOR, AdminPluginOperateEnum.ADD));
+        NEW_PLUGIN_DATA_PERMISSION.add(new 
DataPermission(ConfigGroupEnum.SELECTOR, AdminPluginOperateEnum.DELETE));
+        NEW_PLUGIN_DATA_PERMISSION.add(new 
DataPermission(ConfigGroupEnum.SELECTOR, AdminPluginOperateEnum.EDIT));
+        NEW_PLUGIN_DATA_PERMISSION.add(new 
DataPermission(ConfigGroupEnum.SELECTOR, AdminPluginOperateEnum.QUERY));
+        // rule
+        NEW_PLUGIN_DATA_PERMISSION.add(new 
DataPermission(ConfigGroupEnum.RULE, AdminPluginOperateEnum.ADD));
+        NEW_PLUGIN_DATA_PERMISSION.add(new 
DataPermission(ConfigGroupEnum.RULE, AdminPluginOperateEnum.DELETE));
+        NEW_PLUGIN_DATA_PERMISSION.add(new 
DataPermission(ConfigGroupEnum.RULE, AdminPluginOperateEnum.EDIT));
+        NEW_PLUGIN_DATA_PERMISSION.add(new 
DataPermission(ConfigGroupEnum.RULE, AdminPluginOperateEnum.QUERY));
+        // plugin synchronize data
+        NEW_PLUGIN_DATA_PERMISSION.add(new 
DataPermission(ConfigGroupEnum.PLUGIN, AdminPluginOperateEnum.SYNCHRONIZE));
+    }
+    
+    /**
+     * build plugin resource.
+     *
+     * @param pluginName plugin name
+     * @return resource
+     */
+    public static ResourceDO buildPluginResource(final String pluginName) {
+        return ResourceDO.buildResourceDO(ResourceDTO.builder()
+                .parentId(AdminConstants.RESOURCE_PLUGIN_ID)
+                .title(pluginName)
+                .name(pluginName)
+                .url(AdminConstants.RESOURCE_PLUGIN_URL_PREFIX + pluginName)
+                .component(pluginName)
+                .resourceType(AdminResourceEnum.SECOND_MENU.getCode())
+                .sort(0)
+                .icon(AdminConstants.RESOURCE_PLUGIN_DEFAULT_ICON)
+                
.isLeaf(Boolean.FALSE).isRoute(0).status(1).perms(StringUtils.EMPTY).build());
+    }
+    
+    /**
+     * build new plugin data permission resource.
+     *
+     * @param pluginResourceId plugin resources id
+     * @param pluginName       plugin name
+     * @return resource
+     */
+    public static List<ResourceDO> buildPluginDataPermissionResource(final 
String pluginResourceId, final String pluginName) {
+        return NEW_PLUGIN_DATA_PERMISSION.stream()
+                .map(p -> buildPluginButtonResource(pluginResourceId, 
pluginName, p.dataType, p.operate))
+                .collect(Collectors.toList());
+        
+    }
+    
+    /**
+     * build Plugin Selector Button Resource.
+     *
+     * @param parentId               parent menu id
+     * @param pluginName             plugin name
+     * @param configGroupEnum        {@linkplain ConfigGroupEnum}
+     * @param adminPluginOperateEnum {@linkplain AdminPluginOperateEnum}
+     */
+    private static ResourceDO buildPluginButtonResource(final String parentId, 
final String pluginName,
+                                                        final ConfigGroupEnum 
configGroupEnum, final AdminPluginOperateEnum adminPluginOperateEnum) {
+        ResourceDO resourceDO = 
ResourceDO.buildResourceDO(ResourceDTO.builder()
+                .parentId(parentId)
+                
.name(StringUtils.EMPTY).url(StringUtils.EMPTY).component(StringUtils.EMPTY)
+                .resourceType(AdminResourceEnum.THREE_MENU.getCode())
+                .isLeaf(Boolean.TRUE)
+                .status(1)
+                .sort(0)
+                .icon(StringUtils.EMPTY)
+                .isRoute(0)
+                .build());
+        switch (configGroupEnum) {
+            case SELECTOR:
+                resourceDO.setTitle("SHENYU.BUTTON.PLUGIN." + 
ConfigGroupEnum.SELECTOR.name() + "." + adminPluginOperateEnum.name());
+                resourceDO.setPerms("plugin:" + pluginName + "Selector:" + 
adminPluginOperateEnum.getName());
+                break;
+            case RULE:
+                resourceDO.setTitle("SHENYU.BUTTON.PLUGIN." + 
ConfigGroupEnum.RULE.name() + "." + adminPluginOperateEnum.name());
+                resourceDO.setPerms("plugin:" + pluginName + "Rule:" + 
adminPluginOperateEnum.getName());
+                break;
+            case PLUGIN:
+                resourceDO.setTitle("SHENYU.BUTTON.PLUGIN." + 
adminPluginOperateEnum.name());
+                resourceDO.setPerms("plugin:" + pluginName + ":" + 
adminPluginOperateEnum.getName());
+                break;
+            default:
+                break;
+        }
+        
+        return resourceDO;
+    }
+    
+    
+    /**
+     * get Menu Info.
+     *
+     * @param metaList {@linkplain List} resource list
+     * @return {@linkplain List} menu infos.
+     */
+    public static List<PermissionMenuVO.MenuInfo> buildMenu(final 
List<ResourceVO> metaList) {
+        
+        List<PermissionMenuVO.MenuInfo> retList = new ArrayList<>();
+        if (CollectionUtils.isEmpty(metaList)) {
+            return retList;
+        }
+        Map<String, PermissionMenuVO.MenuInfo> menuInfoMap = metaList.stream()
+                .map(PermissionMenuVO.MenuInfo::buildMenuInfo)
+                .filter(menuInfo -> Objects.nonNull(menuInfo) && 
StringUtils.isNotEmpty(menuInfo.getId()))
+                .collect(Collectors.toMap(PermissionMenuVO.MenuInfo::getId, 
Function.identity(), (value1, value2) -> value1));
+        
+        metaList.stream()
+                .filter(meta -> Objects.nonNull(meta) && 
StringUtils.isNotEmpty(meta.getId()))
+                .collect(Collectors.toMap(ResourceVO::getParentId, 
ResourceUtil::convertIds, ListUtil::mergeSet))
+                .forEach((parent, children) -> {
+                    PermissionMenuVO.MenuInfo menuInfo = 
menuInfoMap.get(parent);
+                    if (CollectionUtils.isNotEmpty(children)) {
+                        List<PermissionMenuVO.MenuInfo> targetList = 
Objects.isNull(menuInfo) ? retList : menuInfo.getChildren();
+                        children.forEach(child -> {
+                            PermissionMenuVO.MenuInfo data = 
menuInfoMap.get(child);
+                            if (Objects.nonNull(data)) {
+                                targetList.add(data);
+                            }
+                        });
+                    }
+                });
+        
+        return retList;
+    }
+    
+    
+    /**
+     * get delete resource ids.
+     *
+     * @param resourceIds resource ids
+     * @param metaList    all resource object
+     * @return the list of ids to delete
+     */
+    public static List<String> getDeleteResourceIds(final List<String> 
resourceIds, final List<ResourceVO> metaList) {
+        
+        List<String> deleteResourceIds = null;
+        if (CollectionUtils.isEmpty(metaList) || 
CollectionUtils.isEmpty(resourceIds)) {
+            return deleteResourceIds;
+        }
+        deleteResourceIds = new ArrayList<>();
+        Map<String, ResourceVO> metaMap = 
metaList.stream().filter(Objects::nonNull)
+                .collect(Collectors.toMap(ResourceVO::getId, 
Function.identity(), (value1, value2) -> value1));
+        
+        Map<String, Set<String>> metaChildrenMap = dealChildrenMap(metaList);
+        
+        Deque<String> cacheDatas = new ArrayDeque<>(resourceIds);
+        while (!cacheDatas.isEmpty()) {
+            String resourceId = cacheDatas.pollFirst();
+            ResourceVO resourceVO = metaMap.get(resourceId);
+            Set<String> children = metaChildrenMap.get(resourceId);
+            if (Objects.nonNull(resourceVO)) {
+                deleteResourceIds.add(resourceVO.getId());
+                metaMap.remove(resourceId);
+            }
+            if (CollectionUtils.isNotEmpty(children)) {
+                children.forEach(cacheDatas::addFirst);
+                metaChildrenMap.remove(resourceId);
+            }
+        }
+        return deleteResourceIds;
+    }
+    
+    /**
+     * convert the list to a map, the key is the parent id, and the value is 
the set of child ids.
+     *
+     * @param metaList the list to be converted
+     * @return the map
+     */
+    private static Map<String, Set<String>> dealChildrenMap(final 
List<ResourceVO> metaList) {
+        return metaList.stream()
+                .filter(meta -> Objects.nonNull(meta) && 
StringUtils.isNotEmpty(meta.getId()))
+                .collect(Collectors.toMap(ResourceVO::getParentId, 
ResourceUtil::convertIds, ListUtil::mergeSet));
+    }
+    
+    private static Set<String> convertIds(final ResourceVO resourceVO) {
+        Set<String> idSet = new HashSet<>();
+        idSet.add(resourceVO.getId());
+        return idSet;
+    }
+    
+    public static class DataPermission {
+        
+        private final ConfigGroupEnum dataType;
+        
+        private final AdminPluginOperateEnum operate;
+        
+        public DataPermission(final ConfigGroupEnum dataType, final 
AdminPluginOperateEnum operate) {
+            this.dataType = dataType;
+            this.operate = operate;
+        }
+    }
+    
+}
diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/utils/SelectorUtil.java 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/utils/SelectorUtil.java
new file mode 100644
index 000000000..3256b1e12
--- /dev/null
+++ b/shenyu-admin/src/main/java/org/apache/shenyu/admin/utils/SelectorUtil.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shenyu.admin.utils;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.shenyu.admin.model.dto.SelectorConditionDTO;
+import org.apache.shenyu.admin.model.dto.SelectorDTO;
+import org.apache.shenyu.admin.model.entity.SelectorDO;
+import org.apache.shenyu.common.constant.Constants;
+import org.apache.shenyu.common.dto.convert.selector.DivideUpstream;
+import org.apache.shenyu.common.dto.convert.selector.SpringCloudSelectorHandle;
+import org.apache.shenyu.common.enums.MatchModeEnum;
+import org.apache.shenyu.common.enums.OperatorEnum;
+import org.apache.shenyu.common.enums.ParamTypeEnum;
+import org.apache.shenyu.common.enums.PluginEnum;
+import org.apache.shenyu.common.enums.SelectorTypeEnum;
+import org.apache.shenyu.common.utils.GsonUtils;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * ResourceUtil.
+ */
+public final class SelectorUtil {
+    
+    private SelectorUtil() {
+    }
+    
+    
+    /**
+     * build divide upstream<br>.
+     * if plugin is spring-cloud used {@link SpringCloudSelectorHandle}.<br>
+     * if plugin is divide used {@link DivideUpstream}.<br>
+     *
+     * @param selectorDO selector
+     * @param pluginName plugin name
+     * @return default is empty list.
+     */
+    public static List<DivideUpstream> buildDivideUpstream(final SelectorDO 
selectorDO, final String pluginName) {
+        if (PluginEnum.SPRING_CLOUD.getName().equals(pluginName) && 
Objects.nonNull(selectorDO.getHandle())) {
+            return GsonUtils.getInstance()
+                    .fromJson(selectorDO.getHandle(), 
SpringCloudSelectorHandle.class)
+                    .getDivideUpstreams();
+        }
+        if (PluginEnum.DIVIDE.getName().equals(pluginName) && 
StringUtils.isNotBlank(selectorDO.getHandle())) {
+            return GsonUtils.getInstance()
+                    .fromList(selectorDO.getHandle(), DivideUpstream.class);
+        }
+        return Collections.emptyList();
+    }
+    
+    /**
+     * build selector.
+     *
+     * @param contextPath context path
+     * @param pluginId    plugin id
+     * @return selector
+     */
+    public static SelectorDTO buildSelectorDTO(final String contextPath, final 
String pluginId) {
+        SelectorDTO selectorDTO = buildDefaultSelectorDTO(contextPath);
+        selectorDTO.setPluginId(pluginId);
+        
selectorDTO.setSelectorConditions(buildDefaultSelectorConditionDTO(contextPath));
+        return selectorDTO;
+    }
+    
+    /**
+     * build default selector.
+     *
+     * @param name selector name
+     * @return selector
+     */
+    public static SelectorDTO buildDefaultSelectorDTO(final String name) {
+        return SelectorDTO.builder()
+                .name(name)
+                .type(SelectorTypeEnum.CUSTOM_FLOW.getCode())
+                .matchMode(MatchModeEnum.AND.getCode())
+                .enabled(Boolean.TRUE)
+                .loged(Boolean.TRUE)
+                .continued(Boolean.TRUE)
+                .sort(1)
+                .build();
+    }
+    
+    /**
+     * build default selector condition list.
+     *
+     * @param contextPath context path
+     * @return list
+     */
+    public static List<SelectorConditionDTO> 
buildDefaultSelectorConditionDTO(final String contextPath) {
+        SelectorConditionDTO selectorConditionDTO = new SelectorConditionDTO();
+        selectorConditionDTO.setParamType(ParamTypeEnum.URI.getName());
+        selectorConditionDTO.setParamName("/");
+        selectorConditionDTO.setOperator(OperatorEnum.STARTS_WITH.getAlias());
+        selectorConditionDTO.setParamValue(contextPath + 
Constants.PATH_SEPARATOR);
+        return Collections.singletonList(selectorConditionDTO);
+    }
+}
diff --git a/shenyu-admin/src/main/resources/mappers/plugin-handle-sqlmap.xml 
b/shenyu-admin/src/main/resources/mappers/plugin-handle-sqlmap.xml
index a0e0da0e9..0338881fc 100644
--- a/shenyu-admin/src/main/resources/mappers/plugin-handle-sqlmap.xml
+++ b/shenyu-admin/src/main/resources/mappers/plugin-handle-sqlmap.xml
@@ -259,4 +259,24 @@
         WHERE id = #{id}
         LIMIT 1
     </select>
+
+    <select id="selectByPluginIdList" 
resultType="org.apache.shenyu.admin.model.entity.PluginHandleDO">
+        SELECT
+        <include refid="Base_Column_List"/>
+        FROM plugin_handle
+        where plugin_id in
+        <foreach item="pluginId" collection="pluginIds" open="(" separator="," 
close=")">
+            #{pluginId,jdbcType=VARCHAR}
+        </foreach>
+    </select>
+
+    <select id="selectByIdList" 
resultType="org.apache.shenyu.admin.model.entity.PluginHandleDO">
+        SELECT
+        <include refid="Base_Column_List"/>
+        FROM plugin_handle
+        where id in
+        <foreach item="id" collection="ids" open="(" separator="," close=")">
+            #{id,jdbcType=VARCHAR}
+        </foreach>
+    </select>
 </mapper>
diff --git a/shenyu-admin/src/main/resources/mybatis/mybatis-config.xml 
b/shenyu-admin/src/main/resources/mybatis/mybatis-config.xml
index e67962899..5232045b6 100644
--- a/shenyu-admin/src/main/resources/mybatis/mybatis-config.xml
+++ b/shenyu-admin/src/main/resources/mybatis/mybatis-config.xml
@@ -25,6 +25,8 @@
     </properties>
 
     <settings>
+        <!--    used print sql debug log    -->
+        <!-- <setting name="logImpl" value="STDOUT_LOGGING" />-->
         <!-- Enables automatic mapping from classic database column names 
A_COLUMN to camel case classic Java property names aColumn. -->
         <setting name="mapUnderscoreToCamelCase" value="true"/>
         <!-- Globally enables or disables any caches configured in any mapper 
under this configuration. default:true -->
diff --git 
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/PermissionServiceTest.java
 
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/PermissionServiceTest.java
index 564fa1238..ee99b4a0b 100644
--- 
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/PermissionServiceTest.java
+++ 
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/PermissionServiceTest.java
@@ -28,7 +28,6 @@ import org.apache.shenyu.admin.model.entity.ResourceDO;
 import org.apache.shenyu.admin.model.entity.UserRoleDO;
 import org.apache.shenyu.admin.model.vo.PermissionMenuVO;
 import org.apache.shenyu.admin.service.impl.PermissionServiceImpl;
-import org.apache.shenyu.admin.service.impl.ResourceServiceImpl;
 import org.apache.shenyu.admin.spring.SpringBeanUtils;
 import org.apache.shenyu.admin.utils.JwtUtils;
 import org.apache.shenyu.common.constant.ResourceTypeConstants;
@@ -127,8 +126,7 @@ public final class PermissionServiceTest {
 //        
when(mockResourceMapper.selectAll()).thenReturn(Arrays.asList(resourceDO1, 
resourceDO2, resourceDO3, resourceDO4));
         
when(mockResourceMapper.selectByIdsBatch(resourceIds)).thenReturn(Arrays.asList(resourceDO2,
 resourceDO3, resourceDO1, resourceDO4));
         
when(mockResourceMapper.selectByResourceType(ResourceTypeConstants.MENU_TYPE_2)).thenReturn(Collections.singletonList(resourceDO4));
-        ResourceService resourceService = new 
ResourceServiceImpl(mockResourceMapper, mockPermissionMapper);
-        permissionServiceImplUnderTest = new 
PermissionServiceImpl(mockDashboardUserMapper, mockUserRoleMapper, 
mockPermissionMapper, mockResourceMapper, resourceService);
+        permissionServiceImplUnderTest = new 
PermissionServiceImpl(mockDashboardUserMapper, mockUserRoleMapper, 
mockPermissionMapper, mockResourceMapper);
     }
 
     @Test
diff --git 
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/PluginHandleServiceTest.java
 
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/PluginHandleServiceTest.java
index f904e3947..10951f959 100644
--- 
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/PluginHandleServiceTest.java
+++ 
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/PluginHandleServiceTest.java
@@ -27,6 +27,7 @@ import org.apache.shenyu.admin.model.page.PageParameter;
 import org.apache.shenyu.admin.model.query.PluginHandleQuery;
 import org.apache.shenyu.admin.model.vo.PluginHandleVO;
 import org.apache.shenyu.admin.service.impl.PluginHandleServiceImpl;
+import org.apache.shenyu.admin.service.publish.PluginHandleEventPublisher;
 import org.assertj.core.util.Lists;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
@@ -61,10 +62,13 @@ public final class PluginHandleServiceTest {
 
     @Mock
     private ShenyuDictMapper shenyuDictMapper;
+    
+    @Mock
+    private PluginHandleEventPublisher eventPublisher;
 
     @BeforeEach
     public void setUp() {
-        pluginHandleService = new PluginHandleServiceImpl(pluginHandleMapper, 
shenyuDictMapper);
+        pluginHandleService = new PluginHandleServiceImpl(pluginHandleMapper, 
shenyuDictMapper, eventPublisher);
     }
 
     @Test
diff --git 
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/PluginServiceTest.java
 
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/PluginServiceTest.java
index 167dd58f4..a846aa871 100644
--- 
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/PluginServiceTest.java
+++ 
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/PluginServiceTest.java
@@ -18,11 +18,7 @@
 package org.apache.shenyu.admin.service;
 
 import org.apache.commons.lang3.StringUtils;
-import org.apache.shenyu.admin.mapper.PluginHandleMapper;
 import org.apache.shenyu.admin.mapper.PluginMapper;
-import org.apache.shenyu.admin.mapper.RuleConditionMapper;
-import org.apache.shenyu.admin.mapper.RuleMapper;
-import org.apache.shenyu.admin.mapper.SelectorConditionMapper;
 import org.apache.shenyu.admin.mapper.SelectorMapper;
 import org.apache.shenyu.admin.model.dto.BatchCommonDTO;
 import org.apache.shenyu.admin.model.dto.PluginDTO;
@@ -75,31 +71,15 @@ public final class PluginServiceTest {
     @Mock
     private PluginMapper pluginMapper;
     
-    @Mock
-    private PluginHandleMapper pluginHandleMapper;
-    
     @Mock
     private SelectorMapper selectorMapper;
     
-    @Mock
-    private RuleMapper ruleMapper;
-    
-    @Mock
-    private RuleConditionMapper ruleConditionMapper;
-    
-    @Mock
-    private SelectorConditionMapper selectorConditionMapper;
-    
-    @Mock
-    private ResourceService resourceService;
-    
     @Mock
     private PluginEventPublisher modelDataEventPublisher;
     
     @BeforeEach
     public void setUp() {
-        pluginService = new PluginServiceImpl(pluginMapper, 
pluginHandleMapper, selectorMapper, selectorConditionMapper,
-                ruleMapper, ruleConditionMapper, resourceService, 
modelDataEventPublisher);
+        pluginService = new PluginServiceImpl(pluginMapper, 
modelDataEventPublisher);
     }
     
     @Test
diff --git 
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/ResourceServiceTest.java
 
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/ResourceServiceTest.java
index c70527abc..24a8eea37 100644
--- 
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/ResourceServiceTest.java
+++ 
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/ResourceServiceTest.java
@@ -27,6 +27,7 @@ import org.apache.shenyu.admin.model.query.ResourceQuery;
 import org.apache.shenyu.admin.model.vo.PermissionMenuVO;
 import org.apache.shenyu.admin.model.vo.ResourceVO;
 import org.apache.shenyu.admin.service.impl.ResourceServiceImpl;
+import org.apache.shenyu.admin.utils.ResourceUtil;
 import org.apache.shenyu.common.constant.ResourceTypeConstants;
 import org.apache.shenyu.common.enums.AdminResourceEnum;
 import org.assertj.core.util.Lists;
@@ -215,7 +216,7 @@ public class ResourceServiceTest {
         reset(resourceMapper);
         when(resourceMapper.selectAll()).thenReturn(mockSelectAllResult);
 
-        List<PermissionMenuVO.MenuInfo> menuInfoList = 
resourceService.getMenuInfo(mockSelectAllResult.stream().map(ResourceVO::buildResourceVO).collect(Collectors.toList()));
+        List<PermissionMenuVO.MenuInfo> menuInfoList = 
ResourceUtil.buildMenu(mockSelectAllResult.stream().map(ResourceVO::buildResourceVO).collect(Collectors.toList()));
         assertThat(resourceService.getMenuTree(), equalTo(menuInfoList));
     }
 
@@ -244,7 +245,7 @@ public class ResourceServiceTest {
 
     @Test
     public void 
testGetMenuInfoWithGivingEmptyOrJustContainsNullResourceVoListItShouldNotAppendMenuInfoIntoResult()
 {
-        final List<PermissionMenuVO.MenuInfo> expect = 
resourceService.getMenuInfo(Collections.emptyList());
+        final List<PermissionMenuVO.MenuInfo> expect = 
ResourceUtil.buildMenu(Collections.emptyList());
         assertThat(expect, equalTo(newArrayList()));
     }
 
@@ -272,7 +273,7 @@ public class ResourceServiceTest {
         mockThirdLevelResource.setIsLeaf(true);
 
         final List<ResourceVO> resourceParam = 
newArrayList(nullMenuInfoResource, mockParentResource, mockSecondLevelResource, 
mockThirdLevelResource);
-        final List<PermissionMenuVO.MenuInfo> actual = 
resourceService.getMenuInfo(resourceParam);
+        final List<PermissionMenuVO.MenuInfo> actual = 
ResourceUtil.buildMenu(resourceParam);
 
         PermissionMenuVO.MenuInfo parentMenuInfo = 
PermissionMenuVO.MenuInfo.buildMenuInfo(mockParentResource);
         PermissionMenuVO.MenuInfo secondMenuInfo = 
PermissionMenuVO.MenuInfo.buildMenuInfo(mockSecondLevelResource);
diff --git 
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/SelectorServiceTest.java
 
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/SelectorServiceTest.java
index 425079686..0de94846e 100644
--- 
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/SelectorServiceTest.java
+++ 
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/SelectorServiceTest.java
@@ -39,6 +39,7 @@ import org.apache.shenyu.admin.model.vo.SelectorConditionVO;
 import org.apache.shenyu.admin.model.vo.SelectorVO;
 import org.apache.shenyu.admin.service.impl.SelectorServiceImpl;
 import org.apache.shenyu.admin.service.impl.UpstreamCheckService;
+import org.apache.shenyu.admin.service.publish.SelectorEventPublisher;
 import org.apache.shenyu.admin.utils.JwtUtils;
 import org.apache.shenyu.common.dto.SelectorData;
 import org.apache.shenyu.common.enums.SelectorTypeEnum;
@@ -110,12 +111,15 @@ public final class SelectorServiceTest {
 
     @Mock
     private UpstreamCheckService upstreamCheckService;
+    
+    @Mock
+    private SelectorEventPublisher selectorEventPublisher;
 
     @BeforeEach
     public void setUp() {
         
when(dataPermissionMapper.listByUserId("1")).thenReturn(Collections.singletonList(DataPermissionDO.buildPermissionDO(new
 DataPermissionDTO())));
         selectorService = new SelectorServiceImpl(selectorMapper, 
selectorConditionMapper, pluginMapper,
-                ruleMapper, ruleConditionMapper, eventPublisher, 
dataPermissionMapper, upstreamCheckService);
+                ruleMapper, ruleConditionMapper, eventPublisher, 
dataPermissionMapper, upstreamCheckService, selectorEventPublisher);
     }
 
     @Test

Reply via email to