测试加载外部jar读取类信息
This commit is contained in:
@@ -50,6 +50,11 @@
|
||||
<artifactId>zyplayer-doc-core</artifactId>
|
||||
<version>${zyplayer.doc.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.zyplayer</groupId>
|
||||
<artifactId>zyplayer-doc-annotation</artifactId>
|
||||
<version>1.0.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.curator</groupId>
|
||||
<artifactId>curator-recipes</artifactId>
|
||||
|
||||
@@ -24,6 +24,7 @@ public class DubboDocInfo {
|
||||
private String paramDesc;
|
||||
private Object paramValue;
|
||||
private Integer required;
|
||||
private List<DubboDocParam> params;
|
||||
|
||||
public String getParamName() {
|
||||
return paramName;
|
||||
@@ -64,6 +65,14 @@ public class DubboDocInfo {
|
||||
public void setRequired(Integer required) {
|
||||
this.required = required;
|
||||
}
|
||||
|
||||
public List<DubboDocParam> getParams() {
|
||||
return params;
|
||||
}
|
||||
|
||||
public void setParams(List<DubboDocParam> params) {
|
||||
this.params = params;
|
||||
}
|
||||
}
|
||||
|
||||
public Integer getVersion() {
|
||||
|
||||
@@ -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<DubboResponseInfo> 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<DubboResponseInfo> getParams() {
|
||||
return params;
|
||||
}
|
||||
|
||||
public void setParams(List<DubboResponseInfo> 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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.zyplayer.doc.dubbo.framework.bean;
|
||||
|
||||
public enum InterfaceType {
|
||||
map, list, set, arr
|
||||
}
|
||||
@@ -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<String> baseType = new HashSet<String>() {{
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<String, String> 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<DubboResponseInfo> 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<DubboResponseInfo> 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;
|
||||
}
|
||||
}
|
||||
@@ -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:
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
<modules>
|
||||
<module>zyplayer-doc-test</module>
|
||||
<module>zyplayer-doc-annotation</module>
|
||||
</modules>
|
||||
|
||||
|
||||
|
||||
44
zyplayer-doc-other/zyplayer-doc-annotation/pom.xml
Normal file
44
zyplayer-doc-other/zyplayer-doc-annotation/pom.xml
Normal file
@@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.zyplayer</groupId>
|
||||
<artifactId>zyplayer-doc-annotation</artifactId>
|
||||
<version>1.0.6</version>
|
||||
<packaging>jar</packaging>
|
||||
<name>zyplayer-doc-annotation</name>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<java.version>1.8</java.version>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
<encoding>UTF-8</encoding>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-sources</id>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -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 "";
|
||||
}
|
||||
@@ -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 "";
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
Reference in New Issue
Block a user