You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shenyu.apache.org by zh...@apache.org on 2023/01/03 15:16:19 UTC

[shenyu] branch master updated: [ISSUE #4029] add shenyu-client-api-doc part1 client module (#4270)

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

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


The following commit(s) were added to refs/heads/master by this push:
     new e5bb1e390 [ISSUE #4029] add shenyu-client-api-doc part1 client module (#4270)
e5bb1e390 is described below

commit e5bb1e3906bb877fc95cfffb9016a3cb3de1094b
Author: zhengpeng <84...@qq.com>
AuthorDate: Tue Jan 3 23:16:08 2023 +0800

    [ISSUE #4029] add shenyu-client-api-doc part1 client module (#4270)
    
    * shenyu client api doc part1
    
    * shenyu client api doc part1 fix
    
    * shenyu client api doc part1 fix temp commit
    
    * shenyu client api doc part1 buildApiDocSextet use template method
    
    * Empty Commit to setup deployments
    
    * shenyu client api doc part1 remove example code
    
    * shenyu client api doc part1 remove example code
    
    * shenyu client api doc part1 pom
    
    * Empty Commit to setup deployments
    
    Co-authored-by: xiaoyu <xi...@apache.org>
    Co-authored-by: dragon-zhang <zh...@apache.org>
    Co-authored-by: likeguo <33...@users.noreply.github.com>
---
 pom.xml                                            |   1 +
 shenyu-client/pom.xml                              |   6 +
 .../pom.xml                                        |  38 +-
 .../shenyu/client/apidocs/annotations/ApiDoc.java  |  37 +-
 .../client/apidocs/annotations/ApiModule.java      |  35 +-
 .../brpc/BrpcContextRefreshedEventListener.java    |  19 +
 .../client/brpc/BrpcClientEventListenerTest.java   |   4 +-
 shenyu-client/shenyu-client-core/pom.xml           |   5 +
 .../AbstractContextRefreshedEventListener.java     |  76 +++
 .../core/constant/ShenyuClientConstants.java       |   5 +
 .../ShenyuClientRegisterEventPublisher.java        |   2 +
 .../ShenyuClientApiDocExecutorSubscriber.java      |  53 ++
 .../client/core/model/bean/RegisterInfo.java       | 210 -------
 .../dubbo/AlibabaDubboServiceBeanListener.java     |  20 +
 .../dubbo/ApacheDubboServiceBeanListener.java      |  24 +-
 .../client/grpc/GrpcClientEventListener.java       |  20 +-
 .../init/SpringCloudClientEventListener.java       |  26 +-
 .../init/SpringCloudClientEventListenerTest.java   |   4 +-
 .../init/SpringMvcClientEventListener.java         |  52 +-
 .../init/SpringMvcClientEventListenerTest.java     |   4 +-
 .../client/motan/MotanServiceEventListener.java    |  18 +
 .../client/sofa/SofaServiceEventListener.java      |  18 +
 .../client/tars/TarsServiceBeanEventListener.java  |  17 +
 .../tars/TarsServiceBeanPostProcessorTest.java     |   4 +-
 .../init/SpringWebSocketClientEventListener.java   |  18 +-
 .../apache/shenyu/common/constant/Constants.java   |   5 +
 .../shenyu/common/enums/ApiHttpMethodEnum.java     | 132 +++++
 .../apache/shenyu/common/enums/ApiSourceEnum.java  |  73 ++-
 .../apache/shenyu/common/enums/ApiStateEnum.java   |  39 +-
 .../client/api/FailbackRegistryRepository.java     |  21 +
 .../client/api/ShenyuClientRegisterRepository.java |   8 +
 .../client/http/HttpClientRegisterRepository.java  |  21 +-
 .../register/common/dto/ApiDocRegisterDTO.java     | 614 +++++++++++++++++++++
 .../shenyu/register/common/enums/EventType.java    |   7 +-
 .../shenyu/register/common/type/DataType.java      |   5 +
 35 files changed, 1292 insertions(+), 349 deletions(-)

diff --git a/pom.xml b/pom.xml
index 0d8c4ae20..0a26a6239 100644
--- a/pom.xml
+++ b/pom.xml
@@ -136,6 +136,7 @@
         <kafka-clients.version>3.2.0</kafka-clients.version>
         <clickhouse-http-client.version>0.3.2-patch11</clickhouse-http-client.version>
         <eureka.version>1.10.17</eureka.version>
+        <javatuples.version>1.2</javatuples.version>
         <!--maven plugin version-->
         <exec-maven-plugin.version>1.6.0</exec-maven-plugin.version>
         <jacoco-maven-plugin.version>0.8.7</jacoco-maven-plugin.version>
diff --git a/shenyu-client/pom.xml b/shenyu-client/pom.xml
index 7f669abe8..89954e26c 100644
--- a/shenyu-client/pom.xml
+++ b/shenyu-client/pom.xml
@@ -36,6 +36,7 @@
         <module>shenyu-client-motan</module>
         <module>shenyu-client-websocket</module>
         <module>shenyu-client-brpc</module>
+        <module>shenyu-client-api-docs-annotations</module>
     </modules>
 
     <dependencies>
@@ -49,6 +50,11 @@
             <artifactId>gson</artifactId>
             <version>${gson.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.javatuples</groupId>
+            <artifactId>javatuples</artifactId>
+            <version>${javatuples.version}</version>
+        </dependency>
         <dependency>
             <groupId>org.springframework</groupId>
             <artifactId>spring-test</artifactId>
diff --git a/shenyu-client/pom.xml b/shenyu-client/shenyu-client-api-docs-annotations/pom.xml
similarity index 51%
copy from shenyu-client/pom.xml
copy to shenyu-client/shenyu-client-api-docs-annotations/pom.xml
index 7f669abe8..741936ce6 100644
--- a/shenyu-client/pom.xml
+++ b/shenyu-client/shenyu-client-api-docs-annotations/pom.xml
@@ -15,44 +15,14 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <parent>
         <groupId>org.apache.shenyu</groupId>
-        <artifactId>shenyu</artifactId>
+        <artifactId>shenyu-client</artifactId>
         <version>2.5.1-SNAPSHOT</version>
     </parent>
+
     <modelVersion>4.0.0</modelVersion>
-    <artifactId>shenyu-client</artifactId>
-    <packaging>pom</packaging>
-    
-    <modules>
-        <module>shenyu-client-core</module>
-        <module>shenyu-client-http</module>
-        <module>shenyu-client-dubbo</module>
-        <module>shenyu-client-sofa</module>
-        <module>shenyu-client-tars</module>
-        <module>shenyu-client-grpc</module>
-        <module>shenyu-client-motan</module>
-        <module>shenyu-client-websocket</module>
-        <module>shenyu-client-brpc</module>
-    </modules>
+    <artifactId>shenyu-client-api-docs-annotations</artifactId>
 
-    <dependencies>
-        <dependency>
-            <groupId>com.squareup.okhttp3</groupId>
-            <artifactId>okhttp</artifactId>
-            <version>${okhttp.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>com.google.code.gson</groupId>
-            <artifactId>gson</artifactId>
-            <version>${gson.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.springframework</groupId>
-            <artifactId>spring-test</artifactId>
-            <scope>test</scope>
-        </dependency>
-    </dependencies>
-</project>
+</project>
\ No newline at end of file
diff --git a/shenyu-register-center/shenyu-register-common/src/main/java/org/apache/shenyu/register/common/enums/EventType.java b/shenyu-client/shenyu-client-api-docs-annotations/src/main/java/org/apache/shenyu/client/apidocs/annotations/ApiDoc.java
similarity index 63%
copy from shenyu-register-center/shenyu-register-common/src/main/java/org/apache/shenyu/register/common/enums/EventType.java
copy to shenyu-client/shenyu-client-api-docs-annotations/src/main/java/org/apache/shenyu/client/apidocs/annotations/ApiDoc.java
index 5dbb7653c..c89fe8c4c 100644
--- a/shenyu-register-center/shenyu-register-common/src/main/java/org/apache/shenyu/register/common/enums/EventType.java
+++ b/shenyu-client/shenyu-client-api-docs-annotations/src/main/java/org/apache/shenyu/client/apidocs/annotations/ApiDoc.java
@@ -15,30 +15,27 @@
  * limitations under the License.
  */
 
-package org.apache.shenyu.register.common.enums;
+package org.apache.shenyu.client.apidocs.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 
 /**
- * The enum Event type.
+ * ApiDoc
+ * declaring {@code @ApiDoc}.
  */
-public enum EventType {
-    
-    /**
-     * Register event type.
-     */
-    REGISTER,
-
-    /**
-     * Updated event type.
-     */
-    UPDATED,
-
-    /**
-     * Deleted event type.
-     */
-    DELETED,
+@Target({ElementType.TYPE, ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface ApiDoc {
 
     /**
-     * Ignored event type.
+     * desc.
+     *
+     * @return String
      */
-    IGNORED
+    String desc();
 }
diff --git a/shenyu-register-center/shenyu-register-common/src/main/java/org/apache/shenyu/register/common/enums/EventType.java b/shenyu-client/shenyu-client-api-docs-annotations/src/main/java/org/apache/shenyu/client/apidocs/annotations/ApiModule.java
similarity index 63%
copy from shenyu-register-center/shenyu-register-common/src/main/java/org/apache/shenyu/register/common/enums/EventType.java
copy to shenyu-client/shenyu-client-api-docs-annotations/src/main/java/org/apache/shenyu/client/apidocs/annotations/ApiModule.java
index 5dbb7653c..5cd24101e 100644
--- a/shenyu-register-center/shenyu-register-common/src/main/java/org/apache/shenyu/register/common/enums/EventType.java
+++ b/shenyu-client/shenyu-client-api-docs-annotations/src/main/java/org/apache/shenyu/client/apidocs/annotations/ApiModule.java
@@ -15,30 +15,27 @@
  * limitations under the License.
  */
 
-package org.apache.shenyu.register.common.enums;
+package org.apache.shenyu.client.apidocs.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 
 /**
- * The enum Event type.
+ * ApiModule
+ * declaring {@code @ApiModule}.
  */
-public enum EventType {
-    
-    /**
-     * Register event type.
-     */
-    REGISTER,
-
-    /**
-     * Updated event type.
-     */
-    UPDATED,
+@Target({ElementType.TYPE, ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface ApiModule {
 
     /**
-     * Deleted event type.
+     * value.
+     * @return value
      */
-    DELETED,
+    String value();
 
-    /**
-     * Ignored event type.
-     */
-    IGNORED
 }
diff --git a/shenyu-client/shenyu-client-brpc/src/main/java/org/apache/shenyu/client/brpc/BrpcContextRefreshedEventListener.java b/shenyu-client/shenyu-client-brpc/src/main/java/org/apache/shenyu/client/brpc/BrpcContextRefreshedEventListener.java
index 9dbb06285..5b07c298d 100644
--- a/shenyu-client/shenyu-client-brpc/src/main/java/org/apache/shenyu/client/brpc/BrpcContextRefreshedEventListener.java
+++ b/shenyu-client/shenyu-client-brpc/src/main/java/org/apache/shenyu/client/brpc/BrpcContextRefreshedEventListener.java
@@ -23,7 +23,9 @@ import org.apache.commons.lang3.tuple.Pair;
 import org.apache.shenyu.client.brpc.common.annotation.ShenyuBrpcClient;
 import org.apache.shenyu.client.brpc.common.dto.BrpcRpcExt;
 import org.apache.shenyu.client.core.client.AbstractContextRefreshedEventListener;
+import org.apache.shenyu.client.core.constant.ShenyuClientConstants;
 import org.apache.shenyu.client.core.disruptor.ShenyuClientRegisterEventPublisher;
+import org.apache.shenyu.common.enums.ApiHttpMethodEnum;
 import org.apache.shenyu.common.enums.RpcTypeEnum;
 import org.apache.shenyu.common.utils.GsonUtils;
 import org.apache.shenyu.common.utils.IpUtils;
@@ -31,10 +33,13 @@ import org.apache.shenyu.register.client.api.ShenyuClientRegisterRepository;
 import org.apache.shenyu.register.common.config.PropertiesConfig;
 import org.apache.shenyu.register.common.dto.MetaDataRegisterDTO;
 import org.apache.shenyu.register.common.dto.URIRegisterDTO;
+import org.javatuples.Sextet;
 import org.springframework.context.ApplicationContext;
 import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
+import org.springframework.core.annotation.AnnotatedElementUtils;
 import org.springframework.util.ReflectionUtils;
 
+import java.lang.annotation.Annotation;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -65,6 +70,20 @@ public class BrpcContextRefreshedEventListener extends AbstractContextRefreshedE
         super(clientConfig, shenyuClientRegisterRepository);
     }
 
+    @Override
+    protected Sextet<String[], String, String, ApiHttpMethodEnum[], RpcTypeEnum, String> buildApiDocSextet(final Method method, final Annotation annotation) {
+        ShenyuBrpcClient shenyuBrpcClient = AnnotatedElementUtils.findMergedAnnotation(method, ShenyuBrpcClient.class);
+        if (Objects.isNull(shenyuBrpcClient)) {
+            return null;
+        }
+        String produce = ShenyuClientConstants.MEDIA_TYPE_ALL_VALUE;
+        String consume = ShenyuClientConstants.MEDIA_TYPE_ALL_VALUE;
+        String[] values = new String[]{shenyuBrpcClient.value()};
+        ApiHttpMethodEnum[] apiHttpMethodEnums = new ApiHttpMethodEnum[]{ApiHttpMethodEnum.NOT_HTTP};
+        String version = "v0.01";
+        return Sextet.with(values, consume, produce, apiHttpMethodEnums, RpcTypeEnum.BRPC, version);
+    }
+
     @Override
     protected Map<String, Object> getBeans(final ApplicationContext context) {
         applicationContext = context;
diff --git a/shenyu-client/shenyu-client-brpc/src/test/java/org/apache/shenyu/client/brpc/BrpcClientEventListenerTest.java b/shenyu-client/shenyu-client-brpc/src/test/java/org/apache/shenyu/client/brpc/BrpcClientEventListenerTest.java
index 815a7056b..89f5f6984 100644
--- a/shenyu-client/shenyu-client-brpc/src/test/java/org/apache/shenyu/client/brpc/BrpcClientEventListenerTest.java
+++ b/shenyu-client/shenyu-client-brpc/src/test/java/org/apache/shenyu/client/brpc/BrpcClientEventListenerTest.java
@@ -72,7 +72,7 @@ public class BrpcClientEventListenerTest {
         registerUtilsMockedStatic.when(() -> RegisterUtils.doLogin(any(), any(), any())).thenReturn(Optional.of("token"));
         BrpcContextRefreshedEventListener springMvcClientEventListener = buildBrpcClientEventListener();
         springMvcClientEventListener.onApplicationEvent(contextRefreshedEvent);
-        verify(applicationContext, times(1)).getBeansWithAnnotation(any());
+        verify(applicationContext, times(2)).getBeansWithAnnotation(any());
         registerUtilsMockedStatic.close();
     }
     
@@ -83,7 +83,7 @@ public class BrpcClientEventListenerTest {
                 .thenAnswer((Answer<Void>) invocation -> null);
         BrpcContextRefreshedEventListener springMvcClientEventListener = buildBrpcClientEventListener();
         springMvcClientEventListener.onApplicationEvent(contextRefreshedEvent);
-        verify(applicationContext, times(1)).getBeansWithAnnotation(any());
+        verify(applicationContext, times(2)).getBeansWithAnnotation(any());
         registerUtilsMockedStatic.close();
     }
     
diff --git a/shenyu-client/shenyu-client-core/pom.xml b/shenyu-client/shenyu-client-core/pom.xml
index 5828086c1..6912b3f79 100644
--- a/shenyu-client/shenyu-client-core/pom.xml
+++ b/shenyu-client/shenyu-client-core/pom.xml
@@ -76,5 +76,10 @@
             <artifactId>spring-context-support</artifactId>
             <scope>provided</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.shenyu</groupId>
+            <artifactId>shenyu-client-api-docs-annotations</artifactId>
+            <version>${project.version}</version>
+        </dependency>
     </dependencies>
 </project>
\ No newline at end of file
diff --git a/shenyu-client/shenyu-client-core/src/main/java/org/apache/shenyu/client/core/client/AbstractContextRefreshedEventListener.java b/shenyu-client/shenyu-client-core/src/main/java/org/apache/shenyu/client/core/client/AbstractContextRefreshedEventListener.java
index 80b74a393..084e714d4 100644
--- a/shenyu-client/shenyu-client-core/src/main/java/org/apache/shenyu/client/core/client/AbstractContextRefreshedEventListener.java
+++ b/shenyu-client/shenyu-client-core/src/main/java/org/apache/shenyu/client/core/client/AbstractContextRefreshedEventListener.java
@@ -17,16 +17,26 @@
 
 package org.apache.shenyu.client.core.client;
 
+import com.google.common.collect.Lists;
 import org.apache.commons.collections4.MapUtils;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.shenyu.client.apidocs.annotations.ApiDoc;
+import org.apache.shenyu.client.apidocs.annotations.ApiModule;
 import org.apache.shenyu.client.core.constant.ShenyuClientConstants;
 import org.apache.shenyu.client.core.disruptor.ShenyuClientRegisterEventPublisher;
 import org.apache.shenyu.client.core.exception.ShenyuClientIllegalArgumentException;
+import org.apache.shenyu.common.enums.ApiHttpMethodEnum;
+import org.apache.shenyu.common.enums.ApiSourceEnum;
+import org.apache.shenyu.common.enums.ApiStateEnum;
+import org.apache.shenyu.common.enums.RpcTypeEnum;
 import org.apache.shenyu.common.utils.UriUtils;
 import org.apache.shenyu.register.client.api.ShenyuClientRegisterRepository;
 import org.apache.shenyu.register.common.config.PropertiesConfig;
+import org.apache.shenyu.register.common.dto.ApiDocRegisterDTO;
 import org.apache.shenyu.register.common.dto.MetaDataRegisterDTO;
 import org.apache.shenyu.register.common.dto.URIRegisterDTO;
+import org.apache.shenyu.register.common.enums.EventType;
+import org.javatuples.Sextet;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.aop.support.AopUtils;
@@ -40,11 +50,13 @@ import org.springframework.util.ReflectionUtils;
 
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Method;
+import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.Properties;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.stream.Stream;
 
 /**
  * The type abstract context refreshed event listener.
@@ -108,7 +120,71 @@ public abstract class AbstractContextRefreshedEventListener<T, A extends Annotat
         }
         publisher.publishEvent(buildURIRegisterDTO(context, beans));
         beans.forEach(this::handle);
+        Map<String, Object> apiModules = context.getBeansWithAnnotation(ApiModule.class);
+        apiModules.forEach(this::handleApiDoc);
     }
+
+    private void handleApiDoc(final String name, final Object bean) {
+        Class<?> apiModuleClass = AopUtils.isAopProxy(bean) ? AopUtils.getTargetClass(bean) : bean.getClass();
+        final Method[] methods = ReflectionUtils.getUniqueDeclaredMethods(apiModuleClass);
+        for (Method method : methods) {
+            if (method.isAnnotationPresent(ApiDoc.class)) {
+                List<ApiDocRegisterDTO> apis = buildApiDocDTO(bean, method);
+                for (ApiDocRegisterDTO apiDocRegisterDTO : apis) {
+                    publisher.publishEvent(apiDocRegisterDTO);
+                }
+            }
+        }
+    }
+
+    private List<ApiDocRegisterDTO> buildApiDocDTO(final Object bean, final Method method) {
+        String apiDesc = Stream.of(method.getDeclaredAnnotations()).filter(item -> item instanceof ApiDoc).findAny().map(item -> {
+            ApiDoc apiDoc = (ApiDoc) item;
+            return apiDoc.desc();
+        }).orElse("");
+        Class<?> clazz = AopUtils.isAopProxy(bean) ? AopUtils.getTargetClass(bean) : bean.getClass();
+        String superPath = buildApiSuperPath(clazz, AnnotatedElementUtils.findMergedAnnotation(clazz, getAnnotationType()));
+        if (superPath.indexOf("*") > 0) {
+            superPath = superPath.substring(0, superPath.lastIndexOf("/"));
+        }
+        Annotation annotation = AnnotatedElementUtils.findMergedAnnotation(clazz, getAnnotationType());
+        if (Objects.isNull(annotation)) {
+            return Lists.newArrayList();
+        }
+        Sextet<String[], String, String, ApiHttpMethodEnum[], RpcTypeEnum, String> sextet = buildApiDocSextet(method, annotation);
+        if (Objects.isNull(sextet)) {
+            return Lists.newArrayList();
+        }
+        String contextPath = getContextPath();
+        String[] value0 = sextet.getValue0();
+        List<ApiDocRegisterDTO> list = Lists.newArrayList();
+        for (String value : value0) {
+            String apiPath = contextPath + superPath + value;
+            ApiHttpMethodEnum[] value3 = sextet.getValue3();
+            for (ApiHttpMethodEnum apiHttpMethodEnum : value3) {
+                ApiDocRegisterDTO build = ApiDocRegisterDTO.builder()
+                        .consume(sextet.getValue1())
+                        .produce(sextet.getValue2())
+                        .httpMethod(apiHttpMethodEnum.getValue())
+                        .contextPath(contextPath)
+                        .ext("{}")
+                        .document("{}")
+                        .rpcType(sextet.getValue4().getName())
+                        .version(sextet.getValue5())
+                        .apiDesc(apiDesc)
+                        .apiPath(apiPath)
+                        .apiSource(ApiSourceEnum.ANNOTATION_GENERATION.getValue())
+                        .state(ApiStateEnum.PUBLISHED.getState())
+                        .apiOwner("admin")
+                        .eventType(EventType.REGISTER)
+                        .build();
+                list.add(build);
+            }
+        }
+        return list;
+    }
+
+    protected abstract Sextet<String[], String, String, ApiHttpMethodEnum[], RpcTypeEnum, String> buildApiDocSextet(Method method, Annotation annotation);
     
     protected abstract Map<String, T> getBeans(ApplicationContext context);
     
diff --git a/shenyu-client/shenyu-client-core/src/main/java/org/apache/shenyu/client/core/constant/ShenyuClientConstants.java b/shenyu-client/shenyu-client-core/src/main/java/org/apache/shenyu/client/core/constant/ShenyuClientConstants.java
index 2b2d84f5b..56b3a763b 100644
--- a/shenyu-client/shenyu-client-core/src/main/java/org/apache/shenyu/client/core/constant/ShenyuClientConstants.java
+++ b/shenyu-client/shenyu-client-core/src/main/java/org/apache/shenyu/client/core/constant/ShenyuClientConstants.java
@@ -76,4 +76,9 @@ public final class ShenyuClientConstants {
      * prefix forward status.
      */
     public static final String ADD_PREFIXED = "addPrefixed";
+
+    /**
+     * media type all value.
+     */
+    public static final String MEDIA_TYPE_ALL_VALUE = "*/*";
 }
diff --git a/shenyu-client/shenyu-client-core/src/main/java/org/apache/shenyu/client/core/disruptor/ShenyuClientRegisterEventPublisher.java b/shenyu-client/shenyu-client-core/src/main/java/org/apache/shenyu/client/core/disruptor/ShenyuClientRegisterEventPublisher.java
index a13080bdd..62201ffad 100644
--- a/shenyu-client/shenyu-client-core/src/main/java/org/apache/shenyu/client/core/disruptor/ShenyuClientRegisterEventPublisher.java
+++ b/shenyu-client/shenyu-client-core/src/main/java/org/apache/shenyu/client/core/disruptor/ShenyuClientRegisterEventPublisher.java
@@ -18,6 +18,7 @@
 package org.apache.shenyu.client.core.disruptor;
 
 import org.apache.shenyu.client.core.disruptor.executor.RegisterClientConsumerExecutor.RegisterClientExecutorFactory;
+import org.apache.shenyu.client.core.disruptor.subcriber.ShenyuClientApiDocExecutorSubscriber;
 import org.apache.shenyu.client.core.disruptor.subcriber.ShenyuClientMetadataExecutorSubscriber;
 import org.apache.shenyu.client.core.disruptor.subcriber.ShenyuClientURIExecutorSubscriber;
 import org.apache.shenyu.disruptor.DisruptorProviderManage;
@@ -52,6 +53,7 @@ public class ShenyuClientRegisterEventPublisher {
         RegisterClientExecutorFactory factory = new RegisterClientExecutorFactory();
         factory.addSubscribers(new ShenyuClientMetadataExecutorSubscriber(shenyuClientRegisterRepository));
         factory.addSubscribers(new ShenyuClientURIExecutorSubscriber(shenyuClientRegisterRepository));
+        factory.addSubscribers(new ShenyuClientApiDocExecutorSubscriber(shenyuClientRegisterRepository));
         providerManage = new DisruptorProviderManage<>(factory);
         providerManage.startup();
     }
diff --git a/shenyu-client/shenyu-client-core/src/main/java/org/apache/shenyu/client/core/disruptor/subcriber/ShenyuClientApiDocExecutorSubscriber.java b/shenyu-client/shenyu-client-core/src/main/java/org/apache/shenyu/client/core/disruptor/subcriber/ShenyuClientApiDocExecutorSubscriber.java
new file mode 100644
index 000000000..24d239e73
--- /dev/null
+++ b/shenyu-client/shenyu-client-core/src/main/java/org/apache/shenyu/client/core/disruptor/subcriber/ShenyuClientApiDocExecutorSubscriber.java
@@ -0,0 +1,53 @@
+/*
+ * 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.client.core.disruptor.subcriber;
+
+import org.apache.shenyu.register.client.api.ShenyuClientRegisterRepository;
+import org.apache.shenyu.register.common.dto.ApiDocRegisterDTO;
+import org.apache.shenyu.register.common.subsriber.ExecutorTypeSubscriber;
+import org.apache.shenyu.register.common.type.DataType;
+import java.util.Collection;
+
+/**
+ * The type Shenyu client apiDoc executor subscriber.
+ */
+public class ShenyuClientApiDocExecutorSubscriber implements ExecutorTypeSubscriber<ApiDocRegisterDTO> {
+
+    private final ShenyuClientRegisterRepository shenyuClientRegisterRepository;
+
+    /**
+     * Instantiates a new Shenyu client uri executor subscriber.
+     *
+     * @param shenyuClientRegisterRepository the shenyu client register repository
+     */
+    public ShenyuClientApiDocExecutorSubscriber(final ShenyuClientRegisterRepository shenyuClientRegisterRepository) {
+        this.shenyuClientRegisterRepository = shenyuClientRegisterRepository;
+    }
+
+    @Override
+    public DataType getType() {
+        return DataType.API_DOC;
+    }
+
+    @Override
+    public void executor(final Collection<ApiDocRegisterDTO> dataList) {
+        for (ApiDocRegisterDTO apiDocRegisterDTO : dataList) {
+            shenyuClientRegisterRepository.persistApiDoc(apiDocRegisterDTO);
+        }
+    }
+}
diff --git a/shenyu-client/shenyu-client-core/src/main/java/org/apache/shenyu/client/core/model/bean/RegisterInfo.java b/shenyu-client/shenyu-client-core/src/main/java/org/apache/shenyu/client/core/model/bean/RegisterInfo.java
deleted file mode 100644
index 3d89f580f..000000000
--- a/shenyu-client/shenyu-client-core/src/main/java/org/apache/shenyu/client/core/model/bean/RegisterInfo.java
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * 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.client.core.model.bean;
-
-import java.util.Objects;
-
-/**
- * RegisterInfo.
- */
-public class RegisterInfo {
-
-    private static String registerType;
-
-    private static String serverLists;
-
-    private static String username;
-
-    private static String password;
-
-    private static String appName;
-
-    private static String contextPath;
-
-    private static String port;
-
-    private static String host;
-
-    /**
-     * getPort.
-     *
-     * @return port.
-     */
-    public static String getPort() {
-        return port;
-    }
-
-    /**
-     * setPort.
-     *
-     * @param port port to set.
-     */
-    public static void setPort(final String port) {
-        RegisterInfo.port = port;
-    }
-
-    /**
-     * getHost.
-     *
-     * @return host.
-     */
-    public static String getHost() {
-        return host;
-    }
-
-    /**
-     * setHost.
-     *
-     * @param host host to set.
-     */
-    public static void setHost(final String host) {
-        RegisterInfo.host = host;
-    }
-
-    /**
-     * getRegisterType.
-     *
-     * @return registerType.
-     */
-    public static String getRegisterType() {
-        return registerType;
-    }
-
-    /**
-     * setRegisterType.
-     *
-     * @param registerType registerType to set.
-     */
-    public static void setRegisterType(final String registerType) {
-        RegisterInfo.registerType = registerType;
-    }
-
-    /**
-     * getServerLists.
-     *
-     * @return server list.
-     */
-    public static String getServerLists() {
-        return serverLists;
-    }
-
-    /**
-     * setServerLists.
-     *
-     * @param serverLists server list.
-     */
-    public static void setServerLists(final String serverLists) {
-        RegisterInfo.serverLists = serverLists;
-    }
-
-    /**
-     * getusername.
-     *
-     * @return username.
-     */
-    public static String getUsername() {
-        return username;
-    }
-
-    /**
-     * setusername.
-     *
-     * @param username username to set.
-     */
-    public static void setUsername(final String username) {
-        RegisterInfo.username = username;
-    }
-
-    /**
-     * getpassword.
-     *
-     * @return password.
-     */
-    public static String getPassword() {
-        return password;
-    }
-
-    /**
-     * ser password.
-     *
-     * @param password password to set.
-     */
-    public static void setPassword(final String password) {
-        RegisterInfo.password = password;
-    }
-
-    /**
-     * get appName.
-     *
-     * @return appName.
-     */
-    public static String getAppName() {
-        return appName;
-    }
-
-    /**
-     * set appName.
-     *
-     * @param appName app name to set.
-     */
-    public static void setAppName(final String appName) {
-        RegisterInfo.appName = appName;
-    }
-
-    /**
-     * get contextPath.
-     *
-     * @return contextPath.
-     */
-    public static String getContextPath() {
-        return contextPath;
-    }
-
-    /**
-     * set contextPath.
-     *
-     * @param contextPath context path to set.
-     */
-    public static void setContextPath(final String contextPath) {
-        RegisterInfo.contextPath = contextPath;
-    }
-
-    /**
-     * validateNull.
-     */
-    public static void validateNull() {
-        if (Objects.isNull(registerType)) {
-            throw new IllegalArgumentException("RegisterBeanInfo registerType is null");
-        }
-        if (Objects.isNull(serverLists)) {
-            throw new IllegalArgumentException("RegisterBeanInfo serverLists is null");
-        }
-        if (Objects.isNull(username)) {
-            throw new IllegalArgumentException("RegisterBeanInfo username is null");
-        }
-        if (Objects.isNull(password)) {
-            throw new IllegalArgumentException("RegisterBeanInfo password is null");
-        }
-        if (Objects.isNull(appName)) {
-            throw new IllegalArgumentException("RegisterBeanInfo appName is null");
-        }
-        if (Objects.isNull(contextPath)) {
-            throw new IllegalArgumentException("RegisterBeanInfo contextPath is null");
-        }
-    }
-}
diff --git a/shenyu-client/shenyu-client-dubbo/shenyu-client-alibaba-dubbo/src/main/java/org/apache/shenyu/client/alibaba/dubbo/AlibabaDubboServiceBeanListener.java b/shenyu-client/shenyu-client-dubbo/shenyu-client-alibaba-dubbo/src/main/java/org/apache/shenyu/client/alibaba/dubbo/AlibabaDubboServiceBeanListener.java
index fd41f872a..d2ba01cea 100644
--- a/shenyu-client/shenyu-client-dubbo/shenyu-client-alibaba-dubbo/src/main/java/org/apache/shenyu/client/alibaba/dubbo/AlibabaDubboServiceBeanListener.java
+++ b/shenyu-client/shenyu-client-dubbo/shenyu-client-alibaba-dubbo/src/main/java/org/apache/shenyu/client/alibaba/dubbo/AlibabaDubboServiceBeanListener.java
@@ -21,8 +21,10 @@ import com.alibaba.dubbo.common.Constants;
 import com.alibaba.dubbo.config.spring.ServiceBean;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.shenyu.client.core.client.AbstractContextRefreshedEventListener;
+import org.apache.shenyu.client.core.constant.ShenyuClientConstants;
 import org.apache.shenyu.client.dubbo.common.annotation.ShenyuDubboClient;
 import org.apache.shenyu.client.dubbo.common.dto.DubboRpcExt;
+import org.apache.shenyu.common.enums.ApiHttpMethodEnum;
 import org.apache.shenyu.common.enums.RpcTypeEnum;
 import org.apache.shenyu.common.exception.ShenyuException;
 import org.apache.shenyu.common.utils.GsonUtils;
@@ -31,11 +33,14 @@ import org.apache.shenyu.register.client.api.ShenyuClientRegisterRepository;
 import org.apache.shenyu.register.common.config.PropertiesConfig;
 import org.apache.shenyu.register.common.dto.MetaDataRegisterDTO;
 import org.apache.shenyu.register.common.dto.URIRegisterDTO;
+import org.javatuples.Sextet;
 import org.springframework.aop.support.AopUtils;
 import org.springframework.context.ApplicationContext;
+import org.springframework.core.annotation.AnnotatedElementUtils;
 import org.springframework.lang.NonNull;
 import org.springframework.util.ReflectionUtils;
 
+import java.lang.annotation.Annotation;
 import java.lang.reflect.Method;
 import java.util.Arrays;
 import java.util.Map;
@@ -60,6 +65,21 @@ public class AlibabaDubboServiceBeanListener extends AbstractContextRefreshedEve
         super(clientConfig, shenyuClientRegisterRepository);
     }
 
+    @Override
+    protected Sextet<String[], String, String, ApiHttpMethodEnum[], RpcTypeEnum, String> buildApiDocSextet(final Method method, final Annotation annotation) {
+        ShenyuDubboClient shenyuDubboClient = AnnotatedElementUtils.findMergedAnnotation(method, ShenyuDubboClient.class);
+        if (Objects.isNull(shenyuDubboClient)) {
+            return null;
+        }
+        String produce = ShenyuClientConstants.MEDIA_TYPE_ALL_VALUE;
+        String consume = ShenyuClientConstants.MEDIA_TYPE_ALL_VALUE;
+        String[] values = new String[]{shenyuDubboClient.value()};
+        ApiHttpMethodEnum[] apiHttpMethodEnums = new ApiHttpMethodEnum[]{ApiHttpMethodEnum.NOT_HTTP};
+        //TODO 获取dubbo version
+        String version = "v0.01";
+        return Sextet.with(values, consume, produce, apiHttpMethodEnums, RpcTypeEnum.DUBBO, version);
+    }
+
     @Override
     protected Map<String, ServiceBean> getBeans(final ApplicationContext context) {
         return context.getBeansOfType(ServiceBean.class);
diff --git a/shenyu-client/shenyu-client-dubbo/shenyu-client-apache-dubbo/src/main/java/org/apache/shenyu/client/apache/dubbo/ApacheDubboServiceBeanListener.java b/shenyu-client/shenyu-client-dubbo/shenyu-client-apache-dubbo/src/main/java/org/apache/shenyu/client/apache/dubbo/ApacheDubboServiceBeanListener.java
index d5efaceb3..96d010e53 100644
--- a/shenyu-client/shenyu-client-dubbo/shenyu-client-apache-dubbo/src/main/java/org/apache/shenyu/client/apache/dubbo/ApacheDubboServiceBeanListener.java
+++ b/shenyu-client/shenyu-client-dubbo/shenyu-client-apache-dubbo/src/main/java/org/apache/shenyu/client/apache/dubbo/ApacheDubboServiceBeanListener.java
@@ -21,9 +21,11 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.dubbo.common.constants.CommonConstants;
 import org.apache.dubbo.config.spring.ServiceBean;
 import org.apache.shenyu.client.core.client.AbstractContextRefreshedEventListener;
+import org.apache.shenyu.client.core.constant.ShenyuClientConstants;
 import org.apache.shenyu.client.dubbo.common.annotation.ShenyuDubboClient;
 import org.apache.shenyu.client.dubbo.common.dto.DubboRpcExt;
 import org.apache.shenyu.common.constant.Constants;
+import org.apache.shenyu.common.enums.ApiHttpMethodEnum;
 import org.apache.shenyu.common.enums.RpcTypeEnum;
 import org.apache.shenyu.common.exception.ShenyuException;
 import org.apache.shenyu.common.utils.GsonUtils;
@@ -32,12 +34,15 @@ import org.apache.shenyu.register.client.api.ShenyuClientRegisterRepository;
 import org.apache.shenyu.register.common.config.PropertiesConfig;
 import org.apache.shenyu.register.common.dto.MetaDataRegisterDTO;
 import org.apache.shenyu.register.common.dto.URIRegisterDTO;
+import org.javatuples.Sextet;
 import org.springframework.aop.support.AopUtils;
 import org.springframework.context.ApplicationContext;
+import org.springframework.core.annotation.AnnotatedElementUtils;
 import org.springframework.lang.NonNull;
 import org.springframework.lang.Nullable;
 import org.springframework.util.ReflectionUtils;
 
+import java.lang.annotation.Annotation;
 import java.lang.reflect.Method;
 import java.util.Arrays;
 import java.util.Map;
@@ -51,7 +56,7 @@ import static org.apache.dubbo.remoting.Constants.DEFAULT_CONNECT_TIMEOUT;
  * The Apache Dubbo ServiceBean Listener.
  */
 public class ApacheDubboServiceBeanListener extends AbstractContextRefreshedEventListener<ServiceBean, ShenyuDubboClient> {
-    
+
     /**
      * Instantiates a new context refreshed event listener.
      *
@@ -62,7 +67,22 @@ public class ApacheDubboServiceBeanListener extends AbstractContextRefreshedEven
                                           final ShenyuClientRegisterRepository shenyuClientRegisterRepository) {
         super(clientConfig, shenyuClientRegisterRepository);
     }
-    
+
+    @Override
+    protected Sextet<String[], String, String, ApiHttpMethodEnum[], RpcTypeEnum, String> buildApiDocSextet(final Method method, final Annotation annotation) {
+        ShenyuDubboClient shenyuDubboClient = AnnotatedElementUtils.findMergedAnnotation(method, ShenyuDubboClient.class);
+        if (Objects.isNull(shenyuDubboClient)) {
+            return null;
+        }
+        String produce = ShenyuClientConstants.MEDIA_TYPE_ALL_VALUE;
+        String consume = ShenyuClientConstants.MEDIA_TYPE_ALL_VALUE;
+        String[] values = new String[]{shenyuDubboClient.value()};
+        ApiHttpMethodEnum[] apiHttpMethodEnums = new ApiHttpMethodEnum[]{ApiHttpMethodEnum.NOT_HTTP};
+        //TODO 获取dubbo version
+        String version = "v0.01";
+        return Sextet.with(values, consume, produce, apiHttpMethodEnums, RpcTypeEnum.DUBBO, version);
+    }
+
     @Override
     protected Map<String, ServiceBean> getBeans(final ApplicationContext context) {
         return context.getBeansOfType(ServiceBean.class);
diff --git a/shenyu-client/shenyu-client-grpc/src/main/java/org/apache/shenyu/client/grpc/GrpcClientEventListener.java b/shenyu-client/shenyu-client-grpc/src/main/java/org/apache/shenyu/client/grpc/GrpcClientEventListener.java
index 501bfb001..89ad7a42f 100644
--- a/shenyu-client/shenyu-client-grpc/src/main/java/org/apache/shenyu/client/grpc/GrpcClientEventListener.java
+++ b/shenyu-client/shenyu-client-grpc/src/main/java/org/apache/shenyu/client/grpc/GrpcClientEventListener.java
@@ -28,6 +28,7 @@ import org.apache.shenyu.client.core.exception.ShenyuClientIllegalArgumentExcept
 import org.apache.shenyu.client.grpc.common.annotation.ShenyuGrpcClient;
 import org.apache.shenyu.client.grpc.common.dto.GrpcExt;
 import org.apache.shenyu.client.grpc.json.JsonServerServiceInterceptor;
+import org.apache.shenyu.common.enums.ApiHttpMethodEnum;
 import org.apache.shenyu.common.enums.RpcTypeEnum;
 import org.apache.shenyu.common.utils.GsonUtils;
 import org.apache.shenyu.common.utils.IpUtils;
@@ -35,10 +36,13 @@ import org.apache.shenyu.register.client.api.ShenyuClientRegisterRepository;
 import org.apache.shenyu.register.common.config.PropertiesConfig;
 import org.apache.shenyu.register.common.dto.MetaDataRegisterDTO;
 import org.apache.shenyu.register.common.dto.URIRegisterDTO;
+import org.javatuples.Sextet;
 import org.springframework.context.ApplicationContext;
+import org.springframework.core.annotation.AnnotatedElementUtils;
 import org.springframework.lang.NonNull;
 import org.springframework.util.ReflectionUtils;
 
+import java.lang.annotation.Annotation;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
@@ -67,7 +71,21 @@ public class GrpcClientEventListener extends AbstractContextRefreshedEventListen
             throw new ShenyuClientIllegalArgumentException("grpc client must config the contextPath, ipAndPort");
         }
     }
-    
+
+    @Override
+    protected Sextet<String[], String, String, ApiHttpMethodEnum[], RpcTypeEnum, String> buildApiDocSextet(final Method method, final Annotation annotation) {
+        ShenyuGrpcClient shenyuGrpcClient = AnnotatedElementUtils.findMergedAnnotation(method, ShenyuGrpcClient.class);
+        if (Objects.isNull(shenyuGrpcClient)) {
+            return null;
+        }
+        String produce = ShenyuClientConstants.MEDIA_TYPE_ALL_VALUE;
+        String consume = ShenyuClientConstants.MEDIA_TYPE_ALL_VALUE;
+        String[] values = new String[]{shenyuGrpcClient.value()};
+        ApiHttpMethodEnum[] apiHttpMethodEnums = new ApiHttpMethodEnum[]{ApiHttpMethodEnum.NOT_HTTP};
+        String version = "v0.01";
+        return Sextet.with(values, consume, produce, apiHttpMethodEnums, RpcTypeEnum.GRPC, version);
+    }
+
     @Override
     protected void handle(final String beanName, final BindableService bean) {
         exportJsonGenericService(bean);
diff --git a/shenyu-client/shenyu-client-http/shenyu-client-springcloud/src/main/java/org/apache/shenyu/client/springcloud/init/SpringCloudClientEventListener.java b/shenyu-client/shenyu-client-http/shenyu-client-springcloud/src/main/java/org/apache/shenyu/client/springcloud/init/SpringCloudClientEventListener.java
index 815ad0ff6..c31592252 100644
--- a/shenyu-client/shenyu-client-http/shenyu-client-springcloud/src/main/java/org/apache/shenyu/client/springcloud/init/SpringCloudClientEventListener.java
+++ b/shenyu-client/shenyu-client-http/shenyu-client-springcloud/src/main/java/org/apache/shenyu/client/springcloud/init/SpringCloudClientEventListener.java
@@ -22,16 +22,20 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.shenyu.client.core.client.AbstractContextRefreshedEventListener;
 import org.apache.shenyu.client.core.constant.ShenyuClientConstants;
 import org.apache.shenyu.client.core.exception.ShenyuClientIllegalArgumentException;
+import org.apache.shenyu.client.core.utils.PortUtils;
 import org.apache.shenyu.client.springcloud.annotation.ShenyuSpringCloudClient;
+import org.apache.shenyu.common.enums.ApiHttpMethodEnum;
 import org.apache.shenyu.common.enums.RpcTypeEnum;
 import org.apache.shenyu.common.exception.ShenyuException;
 import org.apache.shenyu.common.utils.IpUtils;
 import org.apache.shenyu.common.utils.PathUtils;
-import org.apache.shenyu.client.core.utils.PortUtils;
 import org.apache.shenyu.register.client.api.ShenyuClientRegisterRepository;
 import org.apache.shenyu.register.common.config.PropertiesConfig;
 import org.apache.shenyu.register.common.dto.MetaDataRegisterDTO;
 import org.apache.shenyu.register.common.dto.URIRegisterDTO;
+import org.javatuples.Sextet;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.context.ApplicationContext;
 import org.springframework.core.annotation.AnnotatedElementUtils;
 import org.springframework.core.annotation.AnnotationUtils;
@@ -40,6 +44,7 @@ import org.springframework.lang.NonNull;
 import org.springframework.lang.Nullable;
 import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
 
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Method;
@@ -51,12 +56,15 @@ import java.util.Objects;
 import java.util.Optional;
 import java.util.Properties;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 /**
  * The type Spring cloud client event listener.
  */
 public class SpringCloudClientEventListener extends AbstractContextRefreshedEventListener<Object, ShenyuSpringCloudClient> {
 
+    private static final Logger LOG = LoggerFactory.getLogger(SpringCloudClientEventListener.class);
+
     private final Boolean isFull;
     
     private final Environment env;
@@ -92,6 +100,22 @@ public class SpringCloudClientEventListener extends AbstractContextRefreshedEven
         mappingAnnotation.add(RequestMapping.class);
     }
 
+    @Override
+    protected Sextet<String[], String, String, ApiHttpMethodEnum[], RpcTypeEnum, String> buildApiDocSextet(final Method method, final Annotation annotation) {
+        RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(method, RequestMapping.class);
+        String produce = requestMapping.produces().length == 0 ? ShenyuClientConstants.MEDIA_TYPE_ALL_VALUE : String.join(",", requestMapping.produces());
+        String consume = requestMapping.consumes().length == 0 ? ShenyuClientConstants.MEDIA_TYPE_ALL_VALUE : String.join(",", requestMapping.consumes());
+        String[] values = requestMapping.value();
+        RequestMethod[] requestMethods = requestMapping.method();
+        if (requestMethods.length == 0) {
+            requestMethods = RequestMethod.values();
+        }
+        List<ApiHttpMethodEnum> collect = Stream.of(requestMethods).map(item -> ApiHttpMethodEnum.of(item.name())).collect(Collectors.toList());
+        ApiHttpMethodEnum[] apiHttpMethodEnums = collect.toArray(new ApiHttpMethodEnum[]{});
+        String version = "v0.01";
+        return Sextet.with(values, consume, produce, apiHttpMethodEnums, RpcTypeEnum.SPRING_CLOUD, version);
+    }
+
     @Override
     protected Map<String, Object> getBeans(final ApplicationContext context) {
         // Filter out is not controller out
diff --git a/shenyu-client/shenyu-client-http/shenyu-client-springcloud/src/test/java/org/apache/shenyu/client/springcloud/init/SpringCloudClientEventListenerTest.java b/shenyu-client/shenyu-client-http/shenyu-client-springcloud/src/test/java/org/apache/shenyu/client/springcloud/init/SpringCloudClientEventListenerTest.java
index 3df376fbf..b11ab06aa 100644
--- a/shenyu-client/shenyu-client-http/shenyu-client-springcloud/src/test/java/org/apache/shenyu/client/springcloud/init/SpringCloudClientEventListenerTest.java
+++ b/shenyu-client/shenyu-client-http/shenyu-client-springcloud/src/test/java/org/apache/shenyu/client/springcloud/init/SpringCloudClientEventListenerTest.java
@@ -100,7 +100,7 @@ public final class SpringCloudClientEventListenerTest {
         registerUtilsMockedStatic.when(() -> RegisterUtils.doLogin(any(), any(), any())).thenReturn(Optional.of("token"));
         SpringCloudClientEventListener springCloudClientEventListener = buildSpringCloudClientEventListener(false);
         springCloudClientEventListener.onApplicationEvent(contextRefreshedEvent);
-        verify(applicationContext, times(1)).getBeansWithAnnotation(any());
+        verify(applicationContext, times(2)).getBeansWithAnnotation(any());
         registerUtilsMockedStatic.close();
     }
 
@@ -112,7 +112,7 @@ public final class SpringCloudClientEventListenerTest {
                 .thenAnswer((Answer<Void>) invocation -> null);
         SpringCloudClientEventListener springCloudClientEventListener = buildSpringCloudClientEventListener(false);
         springCloudClientEventListener.onApplicationEvent(contextRefreshedEvent);
-        verify(applicationContext, times(1)).getBeansWithAnnotation(any());
+        verify(applicationContext, times(2)).getBeansWithAnnotation(any());
         registerUtilsMockedStatic.close();
     }
 
diff --git a/shenyu-client/shenyu-client-http/shenyu-client-springmvc/src/main/java/org/apache/shenyu/client/springmvc/init/SpringMvcClientEventListener.java b/shenyu-client/shenyu-client-http/shenyu-client-springmvc/src/main/java/org/apache/shenyu/client/springmvc/init/SpringMvcClientEventListener.java
index dd1ef9020..71f67857b 100644
--- a/shenyu-client/shenyu-client-http/shenyu-client-springmvc/src/main/java/org/apache/shenyu/client/springmvc/init/SpringMvcClientEventListener.java
+++ b/shenyu-client/shenyu-client-http/shenyu-client-springmvc/src/main/java/org/apache/shenyu/client/springmvc/init/SpringMvcClientEventListener.java
@@ -21,16 +21,20 @@ import org.apache.commons.lang3.ArrayUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.shenyu.client.core.client.AbstractContextRefreshedEventListener;
 import org.apache.shenyu.client.core.constant.ShenyuClientConstants;
+import org.apache.shenyu.client.core.utils.PortUtils;
 import org.apache.shenyu.client.springmvc.annotation.ShenyuSpringMvcClient;
+import org.apache.shenyu.common.enums.ApiHttpMethodEnum;
 import org.apache.shenyu.common.enums.RpcTypeEnum;
 import org.apache.shenyu.common.exception.ShenyuException;
 import org.apache.shenyu.common.utils.IpUtils;
 import org.apache.shenyu.common.utils.PathUtils;
-import org.apache.shenyu.client.core.utils.PortUtils;
 import org.apache.shenyu.register.client.api.ShenyuClientRegisterRepository;
 import org.apache.shenyu.register.common.config.PropertiesConfig;
 import org.apache.shenyu.register.common.dto.MetaDataRegisterDTO;
 import org.apache.shenyu.register.common.dto.URIRegisterDTO;
+import org.javatuples.Sextet;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.context.ApplicationContext;
 import org.springframework.core.annotation.AnnotatedElementUtils;
 import org.springframework.core.annotation.AnnotationUtils;
@@ -38,6 +42,7 @@ import org.springframework.lang.NonNull;
 import org.springframework.lang.Nullable;
 import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
 
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Method;
@@ -49,20 +54,23 @@ import java.util.Objects;
 import java.util.Optional;
 import java.util.Properties;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 /**
  * The type Shenyu spring mvc client event listener.
  */
 public class SpringMvcClientEventListener extends AbstractContextRefreshedEventListener<Object, ShenyuSpringMvcClient> {
-    
+
+    private static final Logger LOG = LoggerFactory.getLogger(SpringMvcClientEventListener.class);
+
     private final List<Class<? extends Annotation>> mappingAnnotation = new ArrayList<>(3);
-    
+
     private final Boolean isFull;
-    
+
     private final String protocol;
 
     private final boolean addPrefixed;
-    
+
     /**
      * Instantiates a new context refreshed event listener.
      *
@@ -80,7 +88,23 @@ public class SpringMvcClientEventListener extends AbstractContextRefreshedEventL
         mappingAnnotation.add(ShenyuSpringMvcClient.class);
         mappingAnnotation.add(RequestMapping.class);
     }
-    
+
+    @Override
+    protected Sextet<String[], String, String, ApiHttpMethodEnum[], RpcTypeEnum, String> buildApiDocSextet(final Method method, final Annotation annotation) {
+        RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(method, RequestMapping.class);
+        String produce = requestMapping.produces().length == 0 ? ShenyuClientConstants.MEDIA_TYPE_ALL_VALUE : String.join(",", requestMapping.produces());
+        String consume = requestMapping.consumes().length == 0 ? ShenyuClientConstants.MEDIA_TYPE_ALL_VALUE : String.join(",", requestMapping.consumes());
+        String[] values = requestMapping.value();
+        RequestMethod[] requestMethods = requestMapping.method();
+        if (requestMethods.length == 0) {
+            requestMethods = RequestMethod.values();
+        }
+        List<ApiHttpMethodEnum> collect = Stream.of(requestMethods).map(item -> ApiHttpMethodEnum.of(item.name())).collect(Collectors.toList());
+        ApiHttpMethodEnum[] apiHttpMethodEnums = collect.toArray(new ApiHttpMethodEnum[]{});
+        String version = "v0.01";
+        return Sextet.with(values, consume, produce, apiHttpMethodEnums, RpcTypeEnum.HTTP, version);
+    }
+
     @Override
     protected Map<String, Object> getBeans(final ApplicationContext context) {
         // Filter out
@@ -98,7 +122,7 @@ public class SpringMvcClientEventListener extends AbstractContextRefreshedEventL
         }
         return context.getBeansWithAnnotation(Controller.class);
     }
-    
+
     @Override
     protected URIRegisterDTO buildURIRegisterDTO(final ApplicationContext context,
                                                  final Map<String, Object> beans) {
@@ -118,7 +142,7 @@ public class SpringMvcClientEventListener extends AbstractContextRefreshedEventL
             throw new ShenyuException(e.getMessage() + "please config ${shenyu.client.http.props.port} in xml/yml !");
         }
     }
-    
+
     @Override
     protected String buildApiSuperPath(final Class<?> clazz, @Nullable final ShenyuSpringMvcClient beanShenyuClient) {
         if (Objects.nonNull(beanShenyuClient) && StringUtils.isNotBlank(beanShenyuClient.path())) {
@@ -131,12 +155,12 @@ public class SpringMvcClientEventListener extends AbstractContextRefreshedEventL
         }
         return "";
     }
-    
+
     @Override
     protected Class<ShenyuSpringMvcClient> getAnnotationType() {
         return ShenyuSpringMvcClient.class;
     }
-    
+
     @Override
     protected void handleMethod(final Object bean, final Class<?> clazz,
                                 @Nullable final ShenyuSpringMvcClient beanShenyuClient,
@@ -150,7 +174,7 @@ public class SpringMvcClientEventListener extends AbstractContextRefreshedEventL
             getPublisher().publishEvent(buildMetaDataDTO(bean, methodShenyuClient, buildApiPath(method, superPath, methodShenyuClient), clazz, method));
         }
     }
-    
+
     @Override
     protected String buildApiPath(final Method method, final String superPath,
                                   @NonNull final ShenyuSpringMvcClient methodShenyuClient) {
@@ -164,7 +188,7 @@ public class SpringMvcClientEventListener extends AbstractContextRefreshedEventL
         }
         return pathJoin(contextPath, superPath);
     }
-    
+
     private String getPathByMethod(@NonNull final Method method) {
         for (Class<? extends Annotation> mapping : mappingAnnotation) {
             final String pathByAnnotation = getPathByAnnotation(AnnotatedElementUtils.findMergedAnnotation(method, mapping));
@@ -174,7 +198,7 @@ public class SpringMvcClientEventListener extends AbstractContextRefreshedEventL
         }
         return null;
     }
-    
+
     private String getPathByAnnotation(@Nullable final Annotation annotation) {
         if (Objects.isNull(annotation)) {
             return null;
@@ -189,7 +213,7 @@ public class SpringMvcClientEventListener extends AbstractContextRefreshedEventL
         }
         return null;
     }
-    
+
     @Override
     protected MetaDataRegisterDTO buildMetaDataDTO(final Object bean,
                                                    @NonNull final ShenyuSpringMvcClient shenyuClient,
diff --git a/shenyu-client/shenyu-client-http/shenyu-client-springmvc/src/test/java/org/apache/shenyu/client/springmvc/init/SpringMvcClientEventListenerTest.java b/shenyu-client/shenyu-client-http/shenyu-client-springmvc/src/test/java/org/apache/shenyu/client/springmvc/init/SpringMvcClientEventListenerTest.java
index e168cdf33..ab80d1347 100644
--- a/shenyu-client/shenyu-client-http/shenyu-client-springmvc/src/test/java/org/apache/shenyu/client/springmvc/init/SpringMvcClientEventListenerTest.java
+++ b/shenyu-client/shenyu-client-http/shenyu-client-springmvc/src/test/java/org/apache/shenyu/client/springmvc/init/SpringMvcClientEventListenerTest.java
@@ -109,7 +109,7 @@ public class SpringMvcClientEventListenerTest {
         registerUtilsMockedStatic.when(() -> RegisterUtils.doLogin(any(), any(), any())).thenReturn(Optional.of("token"));
         SpringMvcClientEventListener springMvcClientEventListener = buildSpringMvcClientEventListener(false, true);
         springMvcClientEventListener.onApplicationEvent(contextRefreshedEvent);
-        verify(applicationContext, times(1)).getBeansWithAnnotation(any());
+        verify(applicationContext, times(2)).getBeansWithAnnotation(any());
         registerUtilsMockedStatic.close();
     }
 
@@ -121,7 +121,7 @@ public class SpringMvcClientEventListenerTest {
                 .thenAnswer((Answer<Void>) invocation -> null);
         SpringMvcClientEventListener springMvcClientEventListener = buildSpringMvcClientEventListener(false, true);
         springMvcClientEventListener.onApplicationEvent(contextRefreshedEvent);
-        verify(applicationContext, times(1)).getBeansWithAnnotation(any());
+        verify(applicationContext, times(2)).getBeansWithAnnotation(any());
         registerUtilsMockedStatic.close();
     }
 
diff --git a/shenyu-client/shenyu-client-motan/src/main/java/org/apache/shenyu/client/motan/MotanServiceEventListener.java b/shenyu-client/shenyu-client-motan/src/main/java/org/apache/shenyu/client/motan/MotanServiceEventListener.java
index 11568e0df..365809ade 100644
--- a/shenyu-client/shenyu-client-motan/src/main/java/org/apache/shenyu/client/motan/MotanServiceEventListener.java
+++ b/shenyu-client/shenyu-client-motan/src/main/java/org/apache/shenyu/client/motan/MotanServiceEventListener.java
@@ -22,10 +22,12 @@ import com.weibo.api.motan.config.springsupport.annotation.MotanService;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.shenyu.client.core.client.AbstractContextRefreshedEventListener;
+import org.apache.shenyu.client.core.constant.ShenyuClientConstants;
 import org.apache.shenyu.client.core.disruptor.ShenyuClientRegisterEventPublisher;
 import org.apache.shenyu.client.core.exception.ShenyuClientIllegalArgumentException;
 import org.apache.shenyu.client.motan.common.annotation.ShenyuMotanClient;
 import org.apache.shenyu.client.motan.common.dto.MotanRpcExt;
+import org.apache.shenyu.common.enums.ApiHttpMethodEnum;
 import org.apache.shenyu.common.enums.RpcTypeEnum;
 import org.apache.shenyu.common.utils.GsonUtils;
 import org.apache.shenyu.common.utils.IpUtils;
@@ -33,11 +35,13 @@ import org.apache.shenyu.register.client.api.ShenyuClientRegisterRepository;
 import org.apache.shenyu.register.common.config.PropertiesConfig;
 import org.apache.shenyu.register.common.dto.MetaDataRegisterDTO;
 import org.apache.shenyu.register.common.dto.URIRegisterDTO;
+import org.javatuples.Sextet;
 import org.springframework.context.ApplicationContext;
 import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
 import org.springframework.core.annotation.AnnotatedElementUtils;
 import org.springframework.util.ReflectionUtils;
 
+import java.lang.annotation.Annotation;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -67,6 +71,20 @@ public class MotanServiceEventListener extends AbstractContextRefreshedEventList
         super(clientConfig, shenyuClientRegisterRepository);
     }
 
+    @Override
+    protected Sextet<String[], String, String, ApiHttpMethodEnum[], RpcTypeEnum, String> buildApiDocSextet(final Method method, final Annotation annotation) {
+        ShenyuMotanClient shenyuMotanClient = AnnotatedElementUtils.findMergedAnnotation(method, ShenyuMotanClient.class);
+        if (Objects.isNull(shenyuMotanClient)) {
+            return null;
+        }
+        String produce = ShenyuClientConstants.MEDIA_TYPE_ALL_VALUE;
+        String consume = ShenyuClientConstants.MEDIA_TYPE_ALL_VALUE;
+        String[] values = new String[]{shenyuMotanClient.value()};
+        ApiHttpMethodEnum[] apiHttpMethodEnums = new ApiHttpMethodEnum[]{ApiHttpMethodEnum.NOT_HTTP};
+        String version = "v0.01";
+        return Sextet.with(values, consume, produce, apiHttpMethodEnums, RpcTypeEnum.MOTAN, version);
+    }
+
     @Override
     protected Map<String, Object> getBeans(final ApplicationContext context) {
         applicationContext = context;
diff --git a/shenyu-client/shenyu-client-sofa/src/main/java/org/apache/shenyu/client/sofa/SofaServiceEventListener.java b/shenyu-client/shenyu-client-sofa/src/main/java/org/apache/shenyu/client/sofa/SofaServiceEventListener.java
index 31facbfad..ee2fcf2ae 100644
--- a/shenyu-client/shenyu-client-sofa/src/main/java/org/apache/shenyu/client/sofa/SofaServiceEventListener.java
+++ b/shenyu-client/shenyu-client-sofa/src/main/java/org/apache/shenyu/client/sofa/SofaServiceEventListener.java
@@ -21,8 +21,10 @@ import com.alipay.sofa.runtime.service.component.Service;
 import com.alipay.sofa.runtime.spring.factory.ServiceFactoryBean;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.shenyu.client.core.client.AbstractContextRefreshedEventListener;
+import org.apache.shenyu.client.core.constant.ShenyuClientConstants;
 import org.apache.shenyu.client.sofa.common.annotation.ShenyuSofaClient;
 import org.apache.shenyu.client.sofa.common.dto.SofaRpcExt;
+import org.apache.shenyu.common.enums.ApiHttpMethodEnum;
 import org.apache.shenyu.common.enums.RpcTypeEnum;
 import org.apache.shenyu.common.utils.GsonUtils;
 import org.apache.shenyu.common.utils.IpUtils;
@@ -30,6 +32,7 @@ import org.apache.shenyu.register.client.api.ShenyuClientRegisterRepository;
 import org.apache.shenyu.register.common.config.PropertiesConfig;
 import org.apache.shenyu.register.common.dto.MetaDataRegisterDTO;
 import org.apache.shenyu.register.common.dto.URIRegisterDTO;
+import org.javatuples.Sextet;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.aop.support.AopUtils;
@@ -39,6 +42,7 @@ import org.springframework.core.annotation.AnnotatedElementUtils;
 import org.springframework.lang.NonNull;
 import org.springframework.util.ReflectionUtils;
 
+import java.lang.annotation.Annotation;
 import java.lang.reflect.Method;
 import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
@@ -151,6 +155,20 @@ public class SofaServiceEventListener extends AbstractContextRefreshedEventListe
         }
     }
 
+    @Override
+    protected Sextet<String[], String, String, ApiHttpMethodEnum[], RpcTypeEnum, String> buildApiDocSextet(final Method method, final Annotation annotation) {
+        ShenyuSofaClient shenyuSofaClient = AnnotatedElementUtils.findMergedAnnotation(method, ShenyuSofaClient.class);
+        if (Objects.isNull(shenyuSofaClient)) {
+            return null;
+        }
+        String produce = ShenyuClientConstants.MEDIA_TYPE_ALL_VALUE;
+        String consume = ShenyuClientConstants.MEDIA_TYPE_ALL_VALUE;
+        String[] values = new String[]{shenyuSofaClient.value()};
+        ApiHttpMethodEnum[] apiHttpMethodEnums = new ApiHttpMethodEnum[]{ApiHttpMethodEnum.NOT_HTTP};
+        String version = "v0.01";
+        return Sextet.with(values, consume, produce, apiHttpMethodEnums, RpcTypeEnum.SOFA, version);
+    }
+
     private void handler(final ServiceFactoryBean serviceBean) {
         Class<?> clazz;
         Object targetProxy;
diff --git a/shenyu-client/shenyu-client-tars/src/main/java/org/apache/shenyu/client/tars/TarsServiceBeanEventListener.java b/shenyu-client/shenyu-client-tars/src/main/java/org/apache/shenyu/client/tars/TarsServiceBeanEventListener.java
index 3d0ae11d5..00382a4ac 100644
--- a/shenyu-client/shenyu-client-tars/src/main/java/org/apache/shenyu/client/tars/TarsServiceBeanEventListener.java
+++ b/shenyu-client/shenyu-client-tars/src/main/java/org/apache/shenyu/client/tars/TarsServiceBeanEventListener.java
@@ -26,6 +26,7 @@ import org.apache.shenyu.client.core.exception.ShenyuClientIllegalArgumentExcept
 import org.apache.shenyu.client.tars.common.annotation.ShenyuTarsClient;
 import org.apache.shenyu.client.tars.common.annotation.ShenyuTarsService;
 import org.apache.shenyu.client.tars.common.dto.TarsRpcExt;
+import org.apache.shenyu.common.enums.ApiHttpMethodEnum;
 import org.apache.shenyu.common.enums.RpcTypeEnum;
 import org.apache.shenyu.common.utils.GsonUtils;
 import org.apache.shenyu.common.utils.IpUtils;
@@ -33,6 +34,7 @@ import org.apache.shenyu.register.client.api.ShenyuClientRegisterRepository;
 import org.apache.shenyu.register.common.config.PropertiesConfig;
 import org.apache.shenyu.register.common.dto.MetaDataRegisterDTO;
 import org.apache.shenyu.register.common.dto.URIRegisterDTO;
+import org.javatuples.Sextet;
 import org.springframework.aop.support.AopUtils;
 import org.springframework.context.ApplicationContext;
 import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
@@ -41,6 +43,7 @@ import org.springframework.lang.NonNull;
 import org.springframework.lang.Nullable;
 import org.springframework.util.ReflectionUtils;
 
+import java.lang.annotation.Annotation;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -76,6 +79,20 @@ public class TarsServiceBeanEventListener extends AbstractContextRefreshedEventL
         publisher.start(shenyuClientRegisterRepository);
     }
 
+    @Override
+    protected Sextet<String[], String, String, ApiHttpMethodEnum[], RpcTypeEnum, String> buildApiDocSextet(final Method method, final Annotation annotation) {
+        ShenyuTarsClient shenyuTarsClient = AnnotatedElementUtils.findMergedAnnotation(method, ShenyuTarsClient.class);
+        if (Objects.isNull(shenyuTarsClient)) {
+            return null;
+        }
+        String produce = ShenyuClientConstants.MEDIA_TYPE_ALL_VALUE;
+        String consume = ShenyuClientConstants.MEDIA_TYPE_ALL_VALUE;
+        String[] values = new String[]{shenyuTarsClient.value()};
+        ApiHttpMethodEnum[] apiHttpMethodEnums = new ApiHttpMethodEnum[]{ApiHttpMethodEnum.NOT_HTTP};
+        String version = "v0.01";
+        return Sextet.with(values, consume, produce, apiHttpMethodEnums, RpcTypeEnum.TARS, version);
+    }
+
     @Override
     protected Map<String, Object> getBeans(final ApplicationContext context) {
         return context.getBeansWithAnnotation(ShenyuTarsService.class);
diff --git a/shenyu-client/shenyu-client-tars/src/test/java/org/apache/shenyu/client/tars/TarsServiceBeanPostProcessorTest.java b/shenyu-client/shenyu-client-tars/src/test/java/org/apache/shenyu/client/tars/TarsServiceBeanPostProcessorTest.java
index 17bc19052..ddd4f4cae 100644
--- a/shenyu-client/shenyu-client-tars/src/test/java/org/apache/shenyu/client/tars/TarsServiceBeanPostProcessorTest.java
+++ b/shenyu-client/shenyu-client-tars/src/test/java/org/apache/shenyu/client/tars/TarsServiceBeanPostProcessorTest.java
@@ -88,7 +88,7 @@ public final class TarsServiceBeanPostProcessorTest {
         registerUtilsMockedStatic.when(() -> RegisterUtils.doLogin(any(), any(), any())).thenReturn(Optional.of("token"));
         TarsServiceBeanEventListener tarsServiceBeanEventListener = buildTarsServiceBeanEventListener(true);
         tarsServiceBeanEventListener.onApplicationEvent(contextRefreshedEvent);
-        verify(applicationContext, times(1)).getBeansWithAnnotation(any());
+        verify(applicationContext, times(2)).getBeansWithAnnotation(any());
         registerUtilsMockedStatic.close();
     }
 
@@ -97,7 +97,7 @@ public final class TarsServiceBeanPostProcessorTest {
         registerUtilsMockedStatic.when(() -> RegisterUtils.doLogin(any(), any(), any())).thenReturn(Optional.of("token"));
         TarsServiceBeanEventListener tarsServiceBeanEventListener = buildTarsServiceBeanEventListener(false);
         tarsServiceBeanEventListener.onApplicationEvent(contextRefreshedEvent);
-        verify(applicationContext, times(1)).getBeansWithAnnotation(any());
+        verify(applicationContext, times(2)).getBeansWithAnnotation(any());
         registerUtilsMockedStatic.close();
     }
 
diff --git a/shenyu-client/shenyu-client-websocket/shenyu-client-spring-websocket/src/main/java/org/apache/shenyu/client/spring/websocket/init/SpringWebSocketClientEventListener.java b/shenyu-client/shenyu-client-websocket/shenyu-client-spring-websocket/src/main/java/org/apache/shenyu/client/spring/websocket/init/SpringWebSocketClientEventListener.java
index 91463cc07..60d38c2f5 100644
--- a/shenyu-client/shenyu-client-websocket/shenyu-client-spring-websocket/src/main/java/org/apache/shenyu/client/spring/websocket/init/SpringWebSocketClientEventListener.java
+++ b/shenyu-client/shenyu-client-websocket/shenyu-client-spring-websocket/src/main/java/org/apache/shenyu/client/spring/websocket/init/SpringWebSocketClientEventListener.java
@@ -21,17 +21,19 @@ import org.apache.commons.lang3.ArrayUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.shenyu.client.core.client.AbstractContextRefreshedEventListener;
 import org.apache.shenyu.client.core.constant.ShenyuClientConstants;
+import org.apache.shenyu.client.core.utils.PortUtils;
 import org.apache.shenyu.client.spring.websocket.annotation.ShenyuServerEndpoint;
 import org.apache.shenyu.client.spring.websocket.annotation.ShenyuSpringWebSocketClient;
+import org.apache.shenyu.common.enums.ApiHttpMethodEnum;
 import org.apache.shenyu.common.enums.RpcTypeEnum;
 import org.apache.shenyu.common.exception.ShenyuException;
 import org.apache.shenyu.common.utils.IpUtils;
 import org.apache.shenyu.common.utils.PathUtils;
-import org.apache.shenyu.client.core.utils.PortUtils;
 import org.apache.shenyu.register.client.api.ShenyuClientRegisterRepository;
 import org.apache.shenyu.register.common.config.PropertiesConfig;
 import org.apache.shenyu.register.common.dto.MetaDataRegisterDTO;
 import org.apache.shenyu.register.common.dto.URIRegisterDTO;
+import org.javatuples.Sextet;
 import org.springframework.beans.factory.support.BeanDefinitionBuilder;
 import org.springframework.beans.factory.support.DefaultListableBeanFactory;
 import org.springframework.context.ApplicationContext;
@@ -81,6 +83,20 @@ public class SpringWebSocketClientEventListener extends AbstractContextRefreshed
         mappingAnnotation.add(ShenyuSpringWebSocketClient.class);
     }
 
+    @Override
+    protected Sextet<String[], String, String, ApiHttpMethodEnum[], RpcTypeEnum, String> buildApiDocSextet(final Method method, final Annotation annotation) {
+        ShenyuSpringWebSocketClient shenyuSpringWebSocketClient = AnnotatedElementUtils.findMergedAnnotation(method, ShenyuSpringWebSocketClient.class);
+        if (Objects.isNull(shenyuSpringWebSocketClient)) {
+            return null;
+        }
+        String produce = ShenyuClientConstants.MEDIA_TYPE_ALL_VALUE;
+        String consume = ShenyuClientConstants.MEDIA_TYPE_ALL_VALUE;
+        String[] values = new String[]{shenyuSpringWebSocketClient.value()};
+        ApiHttpMethodEnum[] apiHttpMethodEnums = new ApiHttpMethodEnum[]{ApiHttpMethodEnum.NOT_HTTP};
+        String version = "v0.01";
+        return Sextet.with(values, consume, produce, apiHttpMethodEnums, RpcTypeEnum.WEB_SOCKET, version);
+    }
+
     @Override
     protected Map<String, Object> getBeans(final ApplicationContext context) {
         // Filter out is not controller out
diff --git a/shenyu-common/src/main/java/org/apache/shenyu/common/constant/Constants.java b/shenyu-common/src/main/java/org/apache/shenyu/common/constant/Constants.java
index d94414d0f..55052d52d 100644
--- a/shenyu-common/src/main/java/org/apache/shenyu/common/constant/Constants.java
+++ b/shenyu-common/src/main/java/org/apache/shenyu/common/constant/Constants.java
@@ -537,6 +537,11 @@ public interface Constants {
      */
     String URI_PATH = "/shenyu-client/register-uri";
 
+
+    String API_DOC_TYPE = "apiDoc";
+
+    String API_DOC_PATH = "/shenyu-client/register-apiDoc";
+
     /**
      * When register by http, the login path.
      */
diff --git a/shenyu-common/src/main/java/org/apache/shenyu/common/enums/ApiHttpMethodEnum.java b/shenyu-common/src/main/java/org/apache/shenyu/common/enums/ApiHttpMethodEnum.java
new file mode 100644
index 000000000..1182b97b9
--- /dev/null
+++ b/shenyu-common/src/main/java/org/apache/shenyu/common/enums/ApiHttpMethodEnum.java
@@ -0,0 +1,132 @@
+/*
+ * 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.common.enums;
+
+import org.apache.shenyu.common.exception.ShenyuException;
+
+import java.util.Arrays;
+
+/**
+ * the api http method type.
+ */
+public enum ApiHttpMethodEnum {
+
+    /**
+     * get.
+     */
+    GET("GET", 0),
+
+    /**
+     * head.
+     */
+    HEAD("HEAD", 1),
+
+    /**
+     * post.
+     */
+    POST("POST", 2),
+
+    /**
+     * put.
+     */
+    PUT("PUT", 3),
+
+    /**
+     * put.
+     */
+    PATCH("PATCH", 4),
+
+    /**
+     * delete.
+     */
+    DELETE("DELETE", 5),
+
+    /**
+     * options.
+     */
+    OPTIONS("OPTIONS", 6),
+
+    /**
+     * trace.
+     */
+    TRACE("TRACE", 7),
+
+    /**
+     * not_http.
+     */
+    NOT_HTTP("NOT_HTTP", 8);
+
+    private final String name;
+
+    private final Integer value;
+
+    /**
+     * Construct.
+     *
+     * @param name  name
+     * @param value value
+     */
+    ApiHttpMethodEnum(final String name, final Integer value) {
+        this.name = name;
+        this.value = value;
+    }
+
+    /**
+     * get name.
+     *
+     * @return name
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * get value.
+     *
+     * @return value
+     */
+    public Integer getValue() {
+        return value;
+    }
+
+    /**
+     * getValueByName.
+     *
+     * @param name name
+     * @return value
+     */
+    public static Integer getValueByName(final String name) {
+        return Arrays.stream(ApiHttpMethodEnum.values())
+                .filter(e -> e.name.equals(name)).findFirst()
+                .map(item -> item.value)
+                .orElseThrow(() -> new ShenyuException(String.format(" this http method can not support %s", name)));
+    }
+
+    /**
+     * build ApiHttpMethodEnum by name .
+     *
+     * @param name name
+     * @return ApiHttpMethodEnum
+     */
+    public static ApiHttpMethodEnum of(final String name) {
+        return Arrays.stream(ApiHttpMethodEnum.values())
+                .filter(e -> e.name.equals(name)).findFirst()
+                .orElseThrow(() -> new ShenyuException(String.format(" this http method can not support %s", name)));
+    }
+
+}
diff --git a/shenyu-register-center/shenyu-register-client/shenyu-register-client-api/src/main/java/org/apache/shenyu/register/client/api/ShenyuClientRegisterRepository.java b/shenyu-common/src/main/java/org/apache/shenyu/common/enums/ApiSourceEnum.java
similarity index 50%
copy from shenyu-register-center/shenyu-register-client/shenyu-register-client-api/src/main/java/org/apache/shenyu/register/client/api/ShenyuClientRegisterRepository.java
copy to shenyu-common/src/main/java/org/apache/shenyu/common/enums/ApiSourceEnum.java
index 084eb5e4f..c35fa9c77 100644
--- a/shenyu-register-center/shenyu-register-client/shenyu-register-client-api/src/main/java/org/apache/shenyu/register/client/api/ShenyuClientRegisterRepository.java
+++ b/shenyu-common/src/main/java/org/apache/shenyu/common/enums/ApiSourceEnum.java
@@ -15,45 +15,68 @@
  * limitations under the License.
  */
 
-package org.apache.shenyu.register.client.api;
-
-import org.apache.shenyu.register.common.config.ShenyuRegisterCenterConfig;
-import org.apache.shenyu.register.common.dto.MetaDataRegisterDTO;
-import org.apache.shenyu.register.common.dto.URIRegisterDTO;
-import org.apache.shenyu.spi.SPI;
+package org.apache.shenyu.common.enums;
 
 /**
- * Shenyu client register repository.
+ * the api source.
  */
-@SPI
-public interface ShenyuClientRegisterRepository {
+public enum ApiSourceEnum {
 
     /**
-     * Init.
-     *
-     * @param config the config
+     * swagger.
      */
-    default void init(ShenyuRegisterCenterConfig config) {
-    }
-    
+    SWAGGER("swagger", 0),
+
+    /**
+     * annotation_generation.
+     */
+    ANNOTATION_GENERATION("annotation_generation", 1),
+
+    /**
+     * create_manually.
+     */
+    CREATE_MANUALLY("create_manually", 2),
+
+    /**
+     * import_swagger.
+     */
+    IMPORT_SWAGGER("import_swagger", 3),
+
     /**
-     * Persist metadata.
+     * import_yapi.
+     */
+    IMPORT_YAPI("import_yapi", 4);
+
+    private final String name;
+
+    private final Integer value;
+
+    /**
+     * Construct.
      *
-     * @param metadata metadata
+     * @param name  name
+     * @param value value
      */
-    void persistInterface(MetaDataRegisterDTO metadata);
-    
+    ApiSourceEnum(final String name, final Integer value) {
+        this.name = name;
+        this.value = value;
+    }
+
     /**
-     * Persist uri.
+     * get name .
      *
-     * @param registerDTO the register dto
+     * @return name
      */
-    default void persistURI(URIRegisterDTO registerDTO) {
+    public String getName() {
+        return name;
     }
-    
+
     /**
-     * Close.
+     * get value .
+     *
+     * @return value
      */
-    default void close() {
+    public Integer getValue() {
+        return value;
     }
 }
diff --git a/shenyu-register-center/shenyu-register-common/src/main/java/org/apache/shenyu/register/common/enums/EventType.java b/shenyu-common/src/main/java/org/apache/shenyu/common/enums/ApiStateEnum.java
similarity index 65%
copy from shenyu-register-center/shenyu-register-common/src/main/java/org/apache/shenyu/register/common/enums/EventType.java
copy to shenyu-common/src/main/java/org/apache/shenyu/common/enums/ApiStateEnum.java
index 5dbb7653c..a28033d1b 100644
--- a/shenyu-register-center/shenyu-register-common/src/main/java/org/apache/shenyu/register/common/enums/EventType.java
+++ b/shenyu-common/src/main/java/org/apache/shenyu/common/enums/ApiStateEnum.java
@@ -15,30 +15,45 @@
  * limitations under the License.
  */
 
-package org.apache.shenyu.register.common.enums;
+package org.apache.shenyu.common.enums;
 
 /**
- * The enum Event type.
+ * the api state.
  */
-public enum EventType {
-    
+public enum ApiStateEnum {
+
     /**
-     * Register event type.
+     * unpublished.
      */
-    REGISTER,
+    UNPUBLISHED(0),
 
     /**
-     * Updated event type.
+     * published.
      */
-    UPDATED,
+    PUBLISHED(1),
+
+    /**
+     * offline.
+     */
+    OFFLINE(2);
+
+    private final int state;
 
     /**
-     * Deleted event type.
+     * Construct.
+     *
+     * @param state state
      */
-    DELETED,
+    ApiStateEnum(final int state) {
+        this.state = state;
+    }
 
     /**
-     * Ignored event type.
+     * get the state.
+     *
+     * @return the state
      */
-    IGNORED
+    public int getState() {
+        return state;
+    }
 }
diff --git a/shenyu-register-center/shenyu-register-client/shenyu-register-client-api/src/main/java/org/apache/shenyu/register/client/api/FailbackRegistryRepository.java b/shenyu-register-center/shenyu-register-client/shenyu-register-client-api/src/main/java/org/apache/shenyu/register/client/api/FailbackRegistryRepository.java
index 7046edccf..3ba7f3add 100644
--- a/shenyu-register-center/shenyu-register-client/shenyu-register-client-api/src/main/java/org/apache/shenyu/register/client/api/FailbackRegistryRepository.java
+++ b/shenyu-register-center/shenyu-register-client/shenyu-register-client-api/src/main/java/org/apache/shenyu/register/client/api/FailbackRegistryRepository.java
@@ -21,6 +21,7 @@ import org.apache.shenyu.common.constant.Constants;
 import org.apache.shenyu.common.timer.Timer;
 import org.apache.shenyu.common.timer.WheelTimerFactory;
 import org.apache.shenyu.register.client.api.retry.FailureRegistryTask;
+import org.apache.shenyu.register.common.dto.ApiDocRegisterDTO;
 import org.apache.shenyu.register.common.dto.MetaDataRegisterDTO;
 import org.apache.shenyu.register.common.dto.URIRegisterDTO;
 import org.slf4j.Logger;
@@ -78,6 +79,26 @@ public abstract class FailbackRegistryRepository implements ShenyuClientRegister
             this.addFailureUriDataRegister(registerDTO);
         }
     }
+
+    /**
+     * Persist apiDoc.
+     * @param registerDTO registerDTO
+     */
+    @Override
+    public void persistApiDoc(final ApiDocRegisterDTO registerDTO) {
+        try {
+            this.doPersistApiDoc(registerDTO);
+        } catch (Exception ex) {
+            //TODO error retry
+            //If a failure occurs, it needs to be added to the retry list.
+        }
+    }
+
+    /**
+     * doPersistApiDoc.
+     * @param apiDocRegisterDTO apiDocRegisterDTO
+     */
+    protected abstract void doPersistApiDoc(ApiDocRegisterDTO apiDocRegisterDTO);
     
     /**
      * Add failure meta data register.
diff --git a/shenyu-register-center/shenyu-register-client/shenyu-register-client-api/src/main/java/org/apache/shenyu/register/client/api/ShenyuClientRegisterRepository.java b/shenyu-register-center/shenyu-register-client/shenyu-register-client-api/src/main/java/org/apache/shenyu/register/client/api/ShenyuClientRegisterRepository.java
index 084eb5e4f..5d56f4f5b 100644
--- a/shenyu-register-center/shenyu-register-client/shenyu-register-client-api/src/main/java/org/apache/shenyu/register/client/api/ShenyuClientRegisterRepository.java
+++ b/shenyu-register-center/shenyu-register-client/shenyu-register-client-api/src/main/java/org/apache/shenyu/register/client/api/ShenyuClientRegisterRepository.java
@@ -18,6 +18,7 @@
 package org.apache.shenyu.register.client.api;
 
 import org.apache.shenyu.register.common.config.ShenyuRegisterCenterConfig;
+import org.apache.shenyu.register.common.dto.ApiDocRegisterDTO;
 import org.apache.shenyu.register.common.dto.MetaDataRegisterDTO;
 import org.apache.shenyu.register.common.dto.URIRegisterDTO;
 import org.apache.shenyu.spi.SPI;
@@ -50,6 +51,13 @@ public interface ShenyuClientRegisterRepository {
      */
     default void persistURI(URIRegisterDTO registerDTO) {
     }
+
+    /**
+     * persistApiDoc.
+     * @param apiDocRegisterDTO apiDocRegisterDTO
+     */
+    default void persistApiDoc(ApiDocRegisterDTO apiDocRegisterDTO) {
+    }
     
     /**
      * Close.
diff --git a/shenyu-register-center/shenyu-register-client/shenyu-register-client-http/src/main/java/org/apache/shenyu/register/client/http/HttpClientRegisterRepository.java b/shenyu-register-center/shenyu-register-client/shenyu-register-client-http/src/main/java/org/apache/shenyu/register/client/http/HttpClientRegisterRepository.java
index a7fa59fab..03028aedd 100644
--- a/shenyu-register-center/shenyu-register-client/shenyu-register-client-http/src/main/java/org/apache/shenyu/register/client/http/HttpClientRegisterRepository.java
+++ b/shenyu-register-center/shenyu-register-client/shenyu-register-client-http/src/main/java/org/apache/shenyu/register/client/http/HttpClientRegisterRepository.java
@@ -26,6 +26,7 @@ import org.apache.shenyu.register.client.api.FailbackRegistryRepository;
 import org.apache.shenyu.register.client.http.utils.RegisterUtils;
 import org.apache.shenyu.register.client.http.utils.RuntimeUtils;
 import org.apache.shenyu.register.common.config.ShenyuRegisterCenterConfig;
+import org.apache.shenyu.register.common.dto.ApiDocRegisterDTO;
 import org.apache.shenyu.register.common.dto.MetaDataRegisterDTO;
 import org.apache.shenyu.register.common.dto.URIRegisterDTO;
 import org.apache.shenyu.register.common.enums.EventType;
@@ -34,6 +35,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.util.List;
+import java.util.Objects;
 import java.util.Optional;
 
 /**
@@ -46,6 +48,8 @@ public class HttpClientRegisterRepository extends FailbackRegistryRepository {
 
     private static URIRegisterDTO uriRegisterDTO;
 
+    private static ApiDocRegisterDTO apiDocRegisterDTO;
+
     private String username;
     
     private String password;
@@ -90,6 +94,17 @@ public class HttpClientRegisterRepository extends FailbackRegistryRepository {
         doRegister(registerDTO, Constants.URI_PATH, Constants.URI);
         uriRegisterDTO = registerDTO;
     }
+
+    /**
+     * doPersistApiDoc.
+     *
+     * @param registerDTO registerDTO
+     */
+    @Override
+    protected void doPersistApiDoc(final ApiDocRegisterDTO registerDTO) {
+        doRegister(registerDTO, Constants.API_DOC_PATH, Constants.API_DOC_TYPE);
+        apiDocRegisterDTO = registerDTO;
+    }
     
     @Override
     public void doPersistInterface(final MetaDataRegisterDTO metadata) {
@@ -98,10 +113,14 @@ public class HttpClientRegisterRepository extends FailbackRegistryRepository {
 
     @Override
     public void close() {
-        if (uriRegisterDTO != null) {
+        if (Objects.nonNull(uriRegisterDTO)) {
             uriRegisterDTO.setEventType(EventType.DELETED);
             doRegister(uriRegisterDTO, Constants.URI_PATH, Constants.URI);
         }
+        if (Objects.nonNull(apiDocRegisterDTO)) {
+            apiDocRegisterDTO.setEventType(EventType.OFFLINE);
+            doRegister(apiDocRegisterDTO, Constants.API_DOC_PATH, Constants.API_DOC_TYPE);
+        }
     }
 
     private void setAccessToken() {
diff --git a/shenyu-register-center/shenyu-register-common/src/main/java/org/apache/shenyu/register/common/dto/ApiDocRegisterDTO.java b/shenyu-register-center/shenyu-register-common/src/main/java/org/apache/shenyu/register/common/dto/ApiDocRegisterDTO.java
new file mode 100644
index 000000000..918a24e78
--- /dev/null
+++ b/shenyu-register-center/shenyu-register-common/src/main/java/org/apache/shenyu/register/common/dto/ApiDocRegisterDTO.java
@@ -0,0 +1,614 @@
+/*
+ * 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.register.common.dto;
+
+import org.apache.shenyu.register.common.enums.EventType;
+import org.apache.shenyu.register.common.type.DataType;
+import org.apache.shenyu.register.common.type.DataTypeParent;
+
+import java.util.Objects;
+
+/**
+ * The type Meta data dto.
+ */
+public class ApiDocRegisterDTO implements DataTypeParent {
+
+    /**
+     * the context_path.
+     */
+    private String contextPath;
+
+    /**
+     * the apiPath.
+     */
+    private String apiPath;
+
+    /**
+     * 0-get,1-head,2-post,3-put,4-patch,5-delete,6-options,7-trace.
+     */
+    private Integer httpMethod;
+
+    /**
+     * specify the submitted content type for processing requests, such as application/json, text/html;.
+     */
+    private String consume;
+
+    /**
+     * specify the content type to be returned. only when the (accept) type in the request header contains the specified type can it be returned;.
+     */
+    private String produce;
+
+    /**
+     * api version,for example V0.01.
+     */
+    private String version;
+
+    /**
+     * http,dubbo,sofa,tars,websocket,springCloud,motan,grpc.
+     */
+    private String rpcType;
+
+    /**
+     * 0-unpublished1-published2-offline.
+     */
+    private Integer state;
+
+    /**
+     * extended fields.
+     */
+    private String ext;
+
+    /**
+     * apiOwner.
+     */
+    private String apiOwner;
+
+    /**
+     * the api description.
+     */
+    private String apiDesc;
+
+    /**
+     * 0-swagger,1-annotation generation,2-create manuallym,3-import swagger,4-import yapi.
+     */
+    private Integer apiSource;
+
+    /**
+     * complete documentation of the api, including request parameters and response parameters.
+     */
+    private String document;
+
+    /**
+     * event type.
+     */
+    private EventType eventType;
+
+    @Override
+    public DataType getType() {
+        return DataType.API_DOC;
+    }
+
+    /**
+     * getContextPath.
+     *
+     * @return context path
+     */
+    public String getContextPath() {
+        return contextPath;
+    }
+
+    /**
+     * set context path.
+     *
+     * @param contextPath context path
+     */
+    public void setContextPath(final String contextPath) {
+        this.contextPath = contextPath;
+    }
+
+    /**
+     * getApiPath.
+     *
+     * @return apiPath
+     */
+    public String getApiPath() {
+        return apiPath;
+    }
+
+    /**
+     * setApiPath.
+     *
+     * @param apiPath apiPath
+     */
+    public void setApiPath(final String apiPath) {
+        this.apiPath = apiPath;
+    }
+
+    /**
+     * getHttpMethod.
+     *
+     * @return http method
+     */
+    public Integer getHttpMethod() {
+        return httpMethod;
+    }
+
+    /**
+     * setHttpMethod.
+     *
+     * @param httpMethod http method
+     */
+    public void setHttpMethod(final Integer httpMethod) {
+        this.httpMethod = httpMethod;
+    }
+
+    /**
+     * getConsume.
+     *
+     * @return consume
+     */
+    public String getConsume() {
+        return consume;
+    }
+
+    /**
+     * setConsume.
+     *
+     * @param consume consume
+     */
+    public void setConsume(final String consume) {
+        this.consume = consume;
+    }
+
+    /**
+     * getProduce.
+     *
+     * @return produce
+     */
+    public String getProduce() {
+        return produce;
+    }
+
+    /**
+     * setProduce.
+     *
+     * @param produce the produce
+     */
+    public void setProduce(final String produce) {
+        this.produce = produce;
+    }
+
+    /**
+     * getVersion.
+     *
+     * @return version
+     */
+    public String getVersion() {
+        return version;
+    }
+
+    /**
+     * setVersion.
+     *
+     * @param version the version
+     */
+    public void setVersion(final String version) {
+        this.version = version;
+    }
+
+    /**
+     * getRpcType.
+     *
+     * @return rpc type
+     */
+    public String getRpcType() {
+        return rpcType;
+    }
+
+    /**
+     * setRpcType.
+     *
+     * @param rpcType the rpc type
+     */
+    public void setRpcType(final String rpcType) {
+        this.rpcType = rpcType;
+    }
+
+    /**
+     * getState.
+     *
+     * @return state
+     */
+    public Integer getState() {
+        return state;
+    }
+
+    /**
+     * setState.
+     *
+     * @param state state
+     */
+    public void setState(final Integer state) {
+        this.state = state;
+    }
+
+    /**
+     * getExt.
+     *
+     * @return extension.
+     */
+    public String getExt() {
+        return ext;
+    }
+
+    /**
+     * setExt.
+     *
+     * @param ext extension
+     */
+    public void setExt(final String ext) {
+        this.ext = ext;
+    }
+
+    /**
+     * getApiOwner.
+     *
+     * @return apiOwner
+     */
+    public String getApiOwner() {
+        return apiOwner;
+    }
+
+    /**
+     * setApiOwner.
+     *
+     * @param apiOwner apiOwner
+     */
+    public void setApiOwner(final String apiOwner) {
+        this.apiOwner = apiOwner;
+    }
+
+    /**
+     * getApiDesc.
+     *
+     * @return apiDesc
+     */
+    public String getApiDesc() {
+        return apiDesc;
+    }
+
+    /**
+     * setApiDesc.
+     *
+     * @param apiDesc apiDesc
+     */
+    public void setApiDesc(final String apiDesc) {
+        this.apiDesc = apiDesc;
+    }
+
+    /**
+     * getApiSource.
+     *
+     * @return apiSource
+     */
+    public Integer getApiSource() {
+        return apiSource;
+    }
+
+    /**
+     * setSource.
+     *
+     * @param apiSource apiSource
+     */
+    public void setApiSource(final Integer apiSource) {
+        this.apiSource = apiSource;
+    }
+
+    /**
+     * getDocument.
+     *
+     * @return document
+     */
+    public String getDocument() {
+        return document;
+    }
+
+    /**
+     * setDocument.
+     *
+     * @param document document
+     */
+    public void setDocument(final String document) {
+        this.document = document;
+    }
+
+    /**
+     * getEventType.
+     * @return eventType
+     */
+    public EventType getEventType() {
+        return eventType;
+    }
+
+    /**
+     * setEventType.
+     * @param eventType eventType
+     */
+    public void setEventType(final EventType eventType) {
+        this.eventType = eventType;
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        ApiDocRegisterDTO that = (ApiDocRegisterDTO) o;
+        return Objects.equals(contextPath, that.contextPath) && Objects.equals(apiPath, that.apiPath) && Objects.equals(httpMethod, that.httpMethod)
+                && Objects.equals(consume, that.consume) && Objects.equals(produce, that.produce) && Objects.equals(version, that.version)
+                && Objects.equals(rpcType, that.rpcType) && Objects.equals(state, that.state) && Objects.equals(ext, that.ext) && Objects.equals(apiOwner, that.apiOwner)
+                && Objects.equals(apiDesc, that.apiDesc) && Objects.equals(apiSource, that.apiSource) && Objects.equals(document, that.document) && eventType == that.eventType;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(contextPath, apiPath, httpMethod, consume, produce, version, rpcType, state, ext, apiOwner, apiDesc, apiSource, document, eventType);
+    }
+
+    @Override
+    public String toString() {
+        return "ApiDocRegisterDTO{"
+                + "contextPath='"
+                + contextPath
+                + ", apiPath='"
+                + apiPath
+                + ", httpMethod="
+                + httpMethod
+                + ", consume='"
+                + consume
+                + ", produce='"
+                + produce
+                + ", version='"
+                + version
+                + ", rpcType='"
+                + rpcType
+                + ", state="
+                + state
+                + ", ext='"
+                + ext
+                + ", apiOwner='"
+                + apiOwner
+                + ", apiDesc='"
+                + apiDesc
+                + ", apiSource="
+                + apiSource
+                + ", document='"
+                + document
+                + ", eventType='"
+                + eventType
+                + '}';
+    }
+
+    /**
+     * builder.
+     * @return ApiDocRegisterDTOBuilder
+     */
+    public static ApiDocRegisterDTOBuilder builder() {
+        return new ApiDocRegisterDTOBuilder();
+    }
+
+    public static final class ApiDocRegisterDTOBuilder {
+
+        private String contextPath;
+
+        private String apiPath;
+
+        private Integer httpMethod;
+
+        private String consume;
+
+        private String produce;
+
+        private String version;
+
+        private String rpcType;
+
+        private Integer state;
+
+        private String ext;
+
+        private String apiOwner;
+
+        private String apiDesc;
+
+        private Integer apiSource;
+
+        private String document;
+
+        private EventType eventType;
+
+        private ApiDocRegisterDTOBuilder() {
+        }
+
+        /**
+         * build contextPath.
+         * @param contextPath contextPath
+         * @return ApiDocRegisterDTOBuilder
+         */
+        public ApiDocRegisterDTOBuilder contextPath(final String contextPath) {
+            this.contextPath = contextPath;
+            return this;
+        }
+
+        /**
+         * build apiPath.
+         * @param apiPath apiPath
+         * @return ApiDocRegisterDTOBuilder
+         */
+        public ApiDocRegisterDTOBuilder apiPath(final String apiPath) {
+            this.apiPath = apiPath;
+            return this;
+        }
+
+        /**
+         * build httpMethod.
+         * @param httpMethod httpMethod
+         * @return ApiDocRegisterDTOBuilder
+         */
+        public ApiDocRegisterDTOBuilder httpMethod(final Integer httpMethod) {
+            this.httpMethod = httpMethod;
+            return this;
+        }
+
+        /**
+         * build consume.
+         * @param consume consume
+         * @return ApiDocRegisterDTOBuilder
+         */
+        public ApiDocRegisterDTOBuilder consume(final String consume) {
+            this.consume = consume;
+            return this;
+        }
+
+        /**
+         * build produce.
+         * @param produce produce
+         * @return ApiDocRegisterDTOBuilder
+         */
+        public ApiDocRegisterDTOBuilder produce(final String produce) {
+            this.produce = produce;
+            return this;
+        }
+
+        /**
+         * build version.
+         * @param version version
+         * @return ApiDocRegisterDTOBuilder
+         */
+        public ApiDocRegisterDTOBuilder version(final String version) {
+            this.version = version;
+            return this;
+        }
+
+        /**
+         * build rpcType.
+         * @param rpcType rpcType
+         * @return ApiDocRegisterDTOBuilder
+         */
+        public ApiDocRegisterDTOBuilder rpcType(final String rpcType) {
+            this.rpcType = rpcType;
+            return this;
+        }
+
+        /**
+         * build state.
+         * @param state state
+         * @return ApiDocRegisterDTOBuilder
+         */
+        public ApiDocRegisterDTOBuilder state(final Integer state) {
+            this.state = state;
+            return this;
+        }
+
+        /**
+         * build ext.
+         * @param ext ext
+         * @return ApiDocRegisterDTOBuilder
+         */
+        public ApiDocRegisterDTOBuilder ext(final String ext) {
+            this.ext = ext;
+            return this;
+        }
+
+        /**
+         * build apiOwner.
+         * @param apiOwner apiOwner
+         * @return ApiDocRegisterDTOBuilder
+         */
+        public ApiDocRegisterDTOBuilder apiOwner(final String apiOwner) {
+            this.apiOwner = apiOwner;
+            return this;
+        }
+
+        /**
+         * build apiDesc.
+         * @param apiDesc apiDesc
+         * @return ApiDocRegisterDTOBuilder
+         */
+        public ApiDocRegisterDTOBuilder apiDesc(final String apiDesc) {
+            this.apiDesc = apiDesc;
+            return this;
+        }
+
+        /**
+         * build apiSource.
+         * @param apiSource apiSource
+         * @return ApiDocRegisterDTOBuilder
+         */
+        public ApiDocRegisterDTOBuilder apiSource(final Integer apiSource) {
+            this.apiSource = apiSource;
+            return this;
+        }
+
+        /**
+         * build document.
+         * @param document document
+         * @return ApiDocRegisterDTOBuilder
+         */
+        public ApiDocRegisterDTOBuilder document(final String document) {
+            this.document = document;
+            return this;
+        }
+
+        /**
+         * build eventType.
+         * @param eventType eventType
+         * @return ApiDocRegisterDTOBuilder
+         */
+        public ApiDocRegisterDTOBuilder eventType(final EventType eventType) {
+            this.eventType = eventType;
+            return this;
+        }
+
+        /**
+         * build.
+         * @return ApiDocRegisterDTO
+         */
+        public ApiDocRegisterDTO build() {
+            ApiDocRegisterDTO apiDocRegisterDTO = new ApiDocRegisterDTO();
+            apiDocRegisterDTO.setContextPath(contextPath);
+            apiDocRegisterDTO.setApiPath(apiPath);
+            apiDocRegisterDTO.setHttpMethod(httpMethod);
+            apiDocRegisterDTO.setConsume(consume);
+            apiDocRegisterDTO.setProduce(produce);
+            apiDocRegisterDTO.setVersion(version);
+            apiDocRegisterDTO.setRpcType(rpcType);
+            apiDocRegisterDTO.setState(state);
+            apiDocRegisterDTO.setExt(ext);
+            apiDocRegisterDTO.setApiOwner(apiOwner);
+            apiDocRegisterDTO.setApiDesc(apiDesc);
+            apiDocRegisterDTO.setApiSource(apiSource);
+            apiDocRegisterDTO.setDocument(document);
+            apiDocRegisterDTO.setEventType(eventType);
+            return apiDocRegisterDTO;
+        }
+    }
+}
diff --git a/shenyu-register-center/shenyu-register-common/src/main/java/org/apache/shenyu/register/common/enums/EventType.java b/shenyu-register-center/shenyu-register-common/src/main/java/org/apache/shenyu/register/common/enums/EventType.java
index 5dbb7653c..06265097d 100644
--- a/shenyu-register-center/shenyu-register-common/src/main/java/org/apache/shenyu/register/common/enums/EventType.java
+++ b/shenyu-register-center/shenyu-register-common/src/main/java/org/apache/shenyu/register/common/enums/EventType.java
@@ -40,5 +40,10 @@ public enum EventType {
     /**
      * Ignored event type.
      */
-    IGNORED
+    IGNORED,
+
+    /**
+     * offline event type.
+     */
+    OFFLINE
 }
diff --git a/shenyu-register-center/shenyu-register-common/src/main/java/org/apache/shenyu/register/common/type/DataType.java b/shenyu-register-center/shenyu-register-common/src/main/java/org/apache/shenyu/register/common/type/DataType.java
index 61fcbb757..46c8af7e5 100644
--- a/shenyu-register-center/shenyu-register-common/src/main/java/org/apache/shenyu/register/common/type/DataType.java
+++ b/shenyu-register-center/shenyu-register-common/src/main/java/org/apache/shenyu/register/common/type/DataType.java
@@ -31,4 +31,9 @@ public enum DataType {
      * Uri data type enum.
      */
     URI,
+
+    /**
+     * Api doc type enum.
+     */
+    API_DOC,
 }