diff --git a/zyplayer-doc-dubbo/pom.xml b/zyplayer-doc-dubbo/pom.xml
index 01da3e52..6c58128e 100644
--- a/zyplayer-doc-dubbo/pom.xml
+++ b/zyplayer-doc-dubbo/pom.xml
@@ -50,6 +50,11 @@
zyplayer-doc-core
${zyplayer.doc.version}
+
+ com.zyplayer
+ zyplayer-doc-annotation
+ 1.0.6
+
org.apache.curator
curator-recipes
diff --git a/zyplayer-doc-dubbo/src/main/java/com/zyplayer/doc/dubbo/framework/bean/DubboDocInfo.java b/zyplayer-doc-dubbo/src/main/java/com/zyplayer/doc/dubbo/framework/bean/DubboDocInfo.java
index 0d521136..523c8fe5 100644
--- a/zyplayer-doc-dubbo/src/main/java/com/zyplayer/doc/dubbo/framework/bean/DubboDocInfo.java
+++ b/zyplayer-doc-dubbo/src/main/java/com/zyplayer/doc/dubbo/framework/bean/DubboDocInfo.java
@@ -24,6 +24,7 @@ public class DubboDocInfo {
private String paramDesc;
private Object paramValue;
private Integer required;
+ private List params;
public String getParamName() {
return paramName;
@@ -64,6 +65,14 @@ public class DubboDocInfo {
public void setRequired(Integer required) {
this.required = required;
}
+
+ public List getParams() {
+ return params;
+ }
+
+ public void setParams(List params) {
+ this.params = params;
+ }
}
public Integer getVersion() {
diff --git a/zyplayer-doc-dubbo/src/main/java/com/zyplayer/doc/dubbo/framework/bean/DubboResponseInfo.java b/zyplayer-doc-dubbo/src/main/java/com/zyplayer/doc/dubbo/framework/bean/DubboResponseInfo.java
new file mode 100644
index 00000000..1e7bce9c
--- /dev/null
+++ b/zyplayer-doc-dubbo/src/main/java/com/zyplayer/doc/dubbo/framework/bean/DubboResponseInfo.java
@@ -0,0 +1,87 @@
+package com.zyplayer.doc.dubbo.framework.bean;
+
+import java.util.List;
+
+/**
+ * 请求参数对象
+ *
+ * @author 暮光:城中城
+ * @since 2019年2月10日
+ */
+public class DubboResponseInfo {
+ private String name;
+ private String type;
+ private String desc;
+ private Object value;
+
+ private String interfaceType;
+ private DubboResponseInfo keyInfo;
+ private List params;
+
+ public DubboResponseInfo(String type) {
+ this.type = type;
+ }
+
+ public DubboResponseInfo(String name, String type, String desc, Object value) {
+ this.name = name;
+ this.type = type;
+ this.desc = desc;
+ this.value = value;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ public void setDesc(String desc) {
+ this.desc = desc;
+ }
+
+ public Object getValue() {
+ return value;
+ }
+
+ public void setValue(Object value) {
+ this.value = value;
+ }
+
+ public List getParams() {
+ return params;
+ }
+
+ public void setParams(List params) {
+ this.params = params;
+ }
+
+ public DubboResponseInfo getKeyInfo() {
+ return keyInfo;
+ }
+
+ public void setKeyInfo(DubboResponseInfo keyInfo) {
+ this.keyInfo = keyInfo;
+ }
+
+ public String getInterfaceType() {
+ return interfaceType;
+ }
+
+ public void setInterfaceType(String interfaceType) {
+ this.interfaceType = interfaceType;
+ }
+}
diff --git a/zyplayer-doc-dubbo/src/main/java/com/zyplayer/doc/dubbo/framework/bean/InterfaceType.java b/zyplayer-doc-dubbo/src/main/java/com/zyplayer/doc/dubbo/framework/bean/InterfaceType.java
new file mode 100644
index 00000000..c4cee117
--- /dev/null
+++ b/zyplayer-doc-dubbo/src/main/java/com/zyplayer/doc/dubbo/framework/bean/InterfaceType.java
@@ -0,0 +1,5 @@
+package com.zyplayer.doc.dubbo.framework.bean;
+
+public enum InterfaceType {
+ map, list, set, arr
+}
diff --git a/zyplayer-doc-dubbo/src/main/java/com/zyplayer/doc/dubbo/framework/constant/BaseType.java b/zyplayer-doc-dubbo/src/main/java/com/zyplayer/doc/dubbo/framework/constant/BaseType.java
new file mode 100644
index 00000000..d01a3322
--- /dev/null
+++ b/zyplayer-doc-dubbo/src/main/java/com/zyplayer/doc/dubbo/framework/constant/BaseType.java
@@ -0,0 +1,39 @@
+package com.zyplayer.doc.dubbo.framework.constant;
+
+import org.apache.commons.lang.StringUtils;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class BaseType {
+
+ private static final Set baseType = new HashSet() {{
+ add("java.lang.Boolean");
+ add("java.lang.Character");
+ add("java.lang.Byte");
+ add("java.lang.Short");
+ add("java.lang.Integer");
+ add("java.lang.Long");
+ add("java.lang.Float");
+ add("java.lang.Double");
+ add("java.lang.String");
+ add("java.lang.Void");
+ add("boolean");
+ add("char");
+ add("byte");
+ add("short");
+ add("int");
+ add("long");
+ add("float");
+ add("double");
+ add("void");
+ }};
+
+ public static boolean isBaseType(String type) {
+ if (type == null || StringUtils.startsWith(type, "java.lang")) {
+ return true;
+ }
+ return baseType.contains(type);
+ }
+
+}
diff --git a/zyplayer-doc-dubbo/src/main/java/com/zyplayer/doc/dubbo/framework/service/ClassLoadService.java b/zyplayer-doc-dubbo/src/main/java/com/zyplayer/doc/dubbo/framework/service/ClassLoadService.java
new file mode 100644
index 00000000..88d74c1f
--- /dev/null
+++ b/zyplayer-doc-dubbo/src/main/java/com/zyplayer/doc/dubbo/framework/service/ClassLoadService.java
@@ -0,0 +1,233 @@
+package com.zyplayer.doc.dubbo.framework.service;
+
+import com.alibaba.fastjson.JSON;
+import com.zyplayer.doc.annotation.DocMethod;
+import com.zyplayer.doc.annotation.DocParam;
+import com.zyplayer.doc.dubbo.framework.bean.DubboResponseInfo;
+import com.zyplayer.doc.dubbo.framework.bean.InterfaceType;
+import com.zyplayer.doc.dubbo.framework.constant.BaseType;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.lang.reflect.*;
+import java.net.JarURLConnection;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.*;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+public class ClassLoadService {
+ private static Logger logger = LoggerFactory.getLogger(ClassLoadService.class);
+
+// public static void main(String[] args) throws Exception {
+// String serviceName = "com.zyplayer.dubbo.service.AnnotateService";
+// String jarGroup = "com.zyplayer";
+// String jarArtifact = "dubbo-api";
+// String jarVersion = "1.0";
+// String basePath = "file:D:/maven/repository";
+//// String basePath = "http://nexus.dmall.com:8081/nexus/content/groups/public";
+// new ClassLoadService().loadServerMethod(serviceName, basePath, jarGroup, jarArtifact, jarVersion);
+// }
+
+ public static void main(String[] args) throws Exception {
+ String serviceName = "com.dmall.data.service.dubbo.DataIndicatorsService";
+ String jarGroup = "com.dmall.data";
+ String jarArtifact = "data-api-client";
+ String jarVersion = "1.0.9.SNAPSHOTS";
+ String basePath = "http://nexus.dmall.com:8081/nexus/content/groups/public";
+ new ClassLoadService().loadServerMethod(serviceName, basePath, jarGroup, jarArtifact, jarVersion);
+ }
+
+ public void loadServerMethod(String serverName, String basePath, String jarGroup, String jarArtifact, String jarVersion) throws Exception {
+ // jar:file:D:/maven/repository/com/zyplayer/dubbo-api/1.0/dubbo-api-1.0.jar!/
+ String jarPath = jarGroup.replaceAll("\\.", "/") + "/" + jarArtifact + "/" + jarVersion + "/" + jarArtifact + "-" + jarVersion + ".jar";
+ URL jarUrl = new URL("jar:" + basePath + "/" + jarPath + "!/");
+ JarFile jar = ((JarURLConnection) jarUrl.openConnection()).getJarFile();
+ JarEntry jarEntry = jar.getJarEntry(serverName.replaceAll("\\.", "/") + ".class");
+ if (jarEntry == null) {
+ logger.info("未找到类");
+ return;
+ }
+ URL fileUrl = new URL(basePath + "/" + jarPath);
+ URLClassLoader classLoader = new URLClassLoader(new URL[]{fileUrl}, Thread.currentThread().getContextClassLoader());
+ Class> clazz = classLoader.loadClass(serverName);
+ Method[] methods = clazz.getMethods();
+ for (Method method : methods) {
+ Map docParamMap = new HashMap<>();
+ DocParam[] annotation = method.getAnnotationsByType(DocParam.class);
+ if (annotation != null) {
+ for (DocParam docParam : annotation) {
+ docParamMap.put(docParam.name(), docParam.value());
+ }
+ }
+ String methodDesc = null;
+ Class> returnType = method.getReturnType();
+ DubboResponseInfo responseInfo = this.getInfoByClass(classLoader, returnType, 0);
+ DocMethod docMethod = method.getAnnotation(DocMethod.class);
+ if (docMethod != null) {
+ methodDesc = docMethod.value();
+ responseInfo.setDesc(docMethod.response());
+ }
+ String methodName = method.getName();
+ Type[] parameterTypes = method.getGenericParameterTypes();
+ Parameter[] parameters = method.getParameters();
+ List paramList = new LinkedList<>();
+ for (int i = 0; i < parameterTypes.length; i++) {
+ DubboResponseInfo responseInfoParam = this.getInfoByType(classLoader, parameterTypes[i], parameters[i].getType(), 0);
+ String desc = docParamMap.get(parameters[i].getName());
+ if (StringUtils.isNotBlank(desc)) {
+ responseInfoParam.setDesc(desc);
+ }
+ responseInfoParam.setName(parameters[i].getName());
+ paramList.add(responseInfoParam);
+ }
+ logger.info("methodName:{},methodDesc:{},paramList:{},responseInfo:{}", methodName, methodDesc, JSON.toJSONString(paramList), JSON.toJSONString(responseInfo));
+ }
+ }
+
+ private DubboResponseInfo getInfoByType(URLClassLoader classLoader, String resultType, Integer recursion) {
+ DubboResponseInfo dubboResponseInfo = new DubboResponseInfo(resultType);
+ if (BaseType.isBaseType(resultType)) {
+ return dubboResponseInfo;
+ }
+ try {
+ Class> clazz = classLoader.loadClass(resultType);
+ DubboResponseInfo responseInfo = this.getInfoByClass(classLoader, clazz, recursion);
+ if (responseInfo.getDesc() == null) {
+ responseInfo.setDesc(dubboResponseInfo.getDesc());
+ }
+ return responseInfo;
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ }
+ return dubboResponseInfo;
+ }
+
+ private DubboResponseInfo getInfoByType(URLClassLoader classLoader, Type type, Class> typeClazz, Integer recursion) throws Exception {
+ String typeName = type.getTypeName();
+ DubboResponseInfo dubboResponseInfo = new DubboResponseInfo(typeName);
+ dubboResponseInfo.setName(type.getTypeName());
+ if (BaseType.isBaseType(typeName)) {
+ return dubboResponseInfo;
+ }
+ Class> clazz = null;
+ if (typeClazz.isArray()) {
+ dubboResponseInfo.setInterfaceType(InterfaceType.arr.name());
+ clazz = typeClazz.getComponentType();
+ } else if (typeClazz.isAssignableFrom(Map.class)) {
+ dubboResponseInfo.setInterfaceType(InterfaceType.map.name());
+ if (type instanceof ParameterizedType) {
+ Type[] actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments();
+ Class> clazzKey = classLoader.loadClass(actualTypeArguments[0].getTypeName());
+ dubboResponseInfo.setKeyInfo(this.getInfoByClass(classLoader, clazzKey, recursion));
+ clazz = classLoader.loadClass(actualTypeArguments[1].getTypeName());
+ }
+ } else if (typeClazz.isAssignableFrom(List.class) || typeClazz.isAssignableFrom(Set.class)) {
+ if (type instanceof ParameterizedType) {
+ String typeNameSub = ((ParameterizedType) type).getActualTypeArguments()[0].getTypeName();
+ clazz = classLoader.loadClass(typeNameSub);
+ }
+ if (typeClazz.isAssignableFrom(List.class)) {
+ dubboResponseInfo.setInterfaceType(InterfaceType.list.name());
+ } else if (typeClazz.isAssignableFrom(Set.class)) {
+ dubboResponseInfo.setInterfaceType(InterfaceType.set.name());
+ }
+ } else {
+ clazz = classLoader.loadClass(typeName);
+ }
+ if (clazz != null) {
+ DubboResponseInfo responseInfo = this.getInfoByClass(classLoader, clazz, recursion);
+ responseInfo.setName(typeName);
+ // 字段注释 优先于 类上的注释
+ if (StringUtils.isNotBlank(dubboResponseInfo.getDesc())) {
+ responseInfo.setDesc(dubboResponseInfo.getDesc());
+ }
+ responseInfo.setKeyInfo(dubboResponseInfo.getKeyInfo());
+ responseInfo.setInterfaceType(dubboResponseInfo.getInterfaceType());
+ return responseInfo;
+ }
+ return dubboResponseInfo;
+ }
+
+ private DubboResponseInfo getInfoByField(URLClassLoader classLoader, Field field, Integer recursion) throws Exception {
+ String typeName = field.getType().getTypeName();
+ DubboResponseInfo dubboResponseInfo = new DubboResponseInfo(typeName);
+ dubboResponseInfo.setName(field.getName());
+ DocParam docResponse = field.getAnnotation(DocParam.class);
+ if (docResponse != null) {
+ dubboResponseInfo.setDesc(docResponse.value());
+ }
+ if (BaseType.isBaseType(typeName)) {
+ return dubboResponseInfo;
+ }
+ Class> clazz = null;
+ if (field.getType().isArray()) {
+ dubboResponseInfo.setInterfaceType(InterfaceType.arr.name());
+ clazz = field.getType().getComponentType();
+ } else if (field.getType().isAssignableFrom(Map.class)) {
+ dubboResponseInfo.setInterfaceType(InterfaceType.map.name());
+ Type genericType = field.getGenericType();
+ if (genericType instanceof ParameterizedType) {
+ Type[] actualTypeArguments = ((ParameterizedType) genericType).getActualTypeArguments();
+ Class> clazzKey = classLoader.loadClass(actualTypeArguments[0].getTypeName());
+ dubboResponseInfo.setKeyInfo(this.getInfoByClass(classLoader, clazzKey, recursion));
+ clazz = classLoader.loadClass(actualTypeArguments[1].getTypeName());
+ }
+ } else if (field.getType().isAssignableFrom(List.class) || field.getType().isAssignableFrom(Set.class)) {
+ Type genericType = field.getGenericType();
+ if (genericType instanceof ParameterizedType) {
+ String typeNameSub = ((ParameterizedType) genericType).getActualTypeArguments()[0].getTypeName();
+ clazz = classLoader.loadClass(typeNameSub);
+ }
+ if (field.getType().isAssignableFrom(List.class)) {
+ dubboResponseInfo.setInterfaceType(InterfaceType.list.name());
+ } else if (field.getType().isAssignableFrom(Set.class)) {
+ dubboResponseInfo.setInterfaceType(InterfaceType.set.name());
+ }
+ } else {
+ clazz = classLoader.loadClass(typeName);
+ }
+ if (clazz != null) {
+ DubboResponseInfo responseInfo = this.getInfoByClass(classLoader, clazz, recursion);
+ responseInfo.setName(field.getName());
+ // 字段注释 优先于 类上的注释
+ if (StringUtils.isNotBlank(dubboResponseInfo.getDesc())) {
+ responseInfo.setDesc(dubboResponseInfo.getDesc());
+ }
+ responseInfo.setKeyInfo(dubboResponseInfo.getKeyInfo());
+ responseInfo.setInterfaceType(dubboResponseInfo.getInterfaceType());
+ return responseInfo;
+ }
+ return dubboResponseInfo;
+ }
+
+ private DubboResponseInfo getInfoByClass(URLClassLoader classLoader, Class> clazz, Integer recursion) {
+ DubboResponseInfo dubboResponseInfo = new DubboResponseInfo(clazz.getTypeName());
+ DocParam docResponse = clazz.getAnnotation(DocParam.class);
+ if (docResponse != null) {
+ dubboResponseInfo.setDesc(docResponse.value());
+ }
+ if (BaseType.isBaseType(clazz.getTypeName())) {
+ return dubboResponseInfo;
+ }
+ recursion++;
+ // 默认最大支持3个层级,感觉已经满足了
+ if (recursion > 3) {
+ return dubboResponseInfo;
+ }
+ List paramList = new LinkedList<>();
+ Field[] fieldArr = clazz.getDeclaredFields();
+ for (Field field : fieldArr) {
+ field.setAccessible(true);
+ try {
+ paramList.add(this.getInfoByField(classLoader, field, recursion));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ dubboResponseInfo.setParams(paramList);
+ return dubboResponseInfo;
+ }
+}
diff --git a/zyplayer-doc-manage/src/main/resources/application.yml b/zyplayer-doc-manage/src/main/resources/application.yml
index 5f9cc568..fc124b58 100644
--- a/zyplayer-doc-manage/src/main/resources/application.yml
+++ b/zyplayer-doc-manage/src/main/resources/application.yml
@@ -64,7 +64,7 @@ zyplayer:
dubbo:
# 优先使用zookeeper,未配置时找nacos的配置
zookeeper:
-# url: 127.0.0.1:2181
+ url: 127.0.0.1:2181
# 服务参数那些信息的服务地址,dubbo7.0新特性
# metadata-url: 127.0.0.1:2181
nacos:
diff --git a/zyplayer-doc-other/pom.xml b/zyplayer-doc-other/pom.xml
index a8910c9d..6a66f4ef 100644
--- a/zyplayer-doc-other/pom.xml
+++ b/zyplayer-doc-other/pom.xml
@@ -14,6 +14,7 @@
zyplayer-doc-test
+ zyplayer-doc-annotation
diff --git a/zyplayer-doc-other/zyplayer-doc-annotation/pom.xml b/zyplayer-doc-other/zyplayer-doc-annotation/pom.xml
new file mode 100644
index 00000000..6b0cc57f
--- /dev/null
+++ b/zyplayer-doc-other/zyplayer-doc-annotation/pom.xml
@@ -0,0 +1,44 @@
+
+
+ 4.0.0
+
+ com.zyplayer
+ zyplayer-doc-annotation
+ 1.0.6
+ jar
+ zyplayer-doc-annotation
+
+
+ UTF-8
+ UTF-8
+ 1.8
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 1.8
+ 1.8
+ UTF-8
+
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+
+
+ attach-sources
+
+ jar
+
+
+
+
+
+
+
diff --git a/zyplayer-doc-other/zyplayer-doc-annotation/src/main/java/com/zyplayer/doc/annotation/DocMethod.java b/zyplayer-doc-other/zyplayer-doc-annotation/src/main/java/com/zyplayer/doc/annotation/DocMethod.java
new file mode 100644
index 00000000..3a4bb1f9
--- /dev/null
+++ b/zyplayer-doc-other/zyplayer-doc-annotation/src/main/java/com/zyplayer/doc/annotation/DocMethod.java
@@ -0,0 +1,19 @@
+package com.zyplayer.doc.annotation;
+
+import java.lang.annotation.*;
+
+@Target({ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface DocMethod {
+
+ /**
+ * @return 方法的说明
+ */
+ String value();
+
+ /**
+ * @return 返回结果的说明
+ */
+ String response() default "";
+}
diff --git a/zyplayer-doc-other/zyplayer-doc-annotation/src/main/java/com/zyplayer/doc/annotation/DocParam.java b/zyplayer-doc-other/zyplayer-doc-annotation/src/main/java/com/zyplayer/doc/annotation/DocParam.java
new file mode 100644
index 00000000..e7421758
--- /dev/null
+++ b/zyplayer-doc-other/zyplayer-doc-annotation/src/main/java/com/zyplayer/doc/annotation/DocParam.java
@@ -0,0 +1,20 @@
+package com.zyplayer.doc.annotation;
+
+import java.lang.annotation.*;
+
+@Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Repeatable(DocParams.class)
+public @interface DocParam {
+
+ /**
+ * @return 说明
+ */
+ String value();
+
+ /**
+ * @return 字段名
+ */
+ String name() default "";
+}
diff --git a/zyplayer-doc-other/zyplayer-doc-annotation/src/main/java/com/zyplayer/doc/annotation/DocParams.java b/zyplayer-doc-other/zyplayer-doc-annotation/src/main/java/com/zyplayer/doc/annotation/DocParams.java
new file mode 100644
index 00000000..3001b33b
--- /dev/null
+++ b/zyplayer-doc-other/zyplayer-doc-annotation/src/main/java/com/zyplayer/doc/annotation/DocParams.java
@@ -0,0 +1,14 @@
+package com.zyplayer.doc.annotation;
+
+import java.lang.annotation.*;
+
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface DocParams {
+
+ /**
+ * @return 多个参数说明
+ */
+ DocParam[] value();
+}