import com.google.common.collect.Lists;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.io.IOUtils;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.TypePath;
import java.io.File;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
public class ServiceDiscovery {
public static List<ServiceGroup> discovery(File jar) {
List<ServiceGroup> serviceGroupList = Lists.newArrayList();
try {
JarFile jarFile = new JarFile(jar);
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry jarEntry = entries.nextElement();
if (jarEntry.getName().endsWith(".class")) {
//读取到内存中,然后用asm进行解析.判断是否为接口定义.
try (InputStream input = jarFile.getInputStream(jarEntry)) {
byte[] classBuff = new byte[(int) jarEntry.getSize()];
IOUtils.read(input, classBuff);
ClassReader reader = new ClassReader(classBuff);
if ((reader.getAccess() & Opcodes.ACC_INTERFACE) != 0) {
String serviceName = TypeDescToJavaType.pathToJavaType(jarEntry.getName());
System.out.println(serviceName);
ServiceDissect serviceDissect = new ServiceDissect(serviceName);
parseService(reader, serviceDissect, serviceName);
if (CollectionUtils.isNotEmpty(serviceDissect.getServiceGroup().getServices())) {
serviceGroupList.add(serviceDissect.getServiceGroup());
}
}
}
}
}
System.out.println("=========== 接口服务解析结果 ============");
serviceGroupList.forEach((s) -> System.out.println(s));
} catch (Exception e) {
e.printStackTrace();
}
return serviceGroupList;
}
/**
* 解析reader中每一个方法,对于public的方法,打印出来.
* @param reader
* @param serviceDissect
* @param serviceName
*/
private static void parseService(ClassReader reader, ServiceDissect serviceDissect, String serviceName) {
reader.accept(new ClassVisitor(Opcodes.ASM6) {
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
System.out.println(desc + "|" + visible);
return super.visitAnnotation(desc, visible);
}
@Override
public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
System.out.println("visitTypeAnnotation:" + desc + "|" + visible);
return super.visitTypeAnnotation(typeRef, typePath, desc, visible);
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
System.out.println("\n");
System.out.println(access + "|" + name + "|" + desc + "|" + signature);
int left = desc.indexOf('(');
int right = desc.indexOf(')');
serviceDissect.onMethodBegin(name, desc.substring(left + 1, right), desc.substring(right + 1), serviceName);
return new MethodAnnotationScanner(serviceDissect);
}
}, 0);
}
}
import java.util.List;
public class ServiceDissect {
private ServiceGroup serviceGroup;
private Service activeMethodMeta;
public ServiceDissect(String className) {
serviceGroup = new ServiceGroup(className);
}
public void onMethodBegin(String name, String param, String returnType, String serviceName) {
activeMethodMeta = new Service();
activeMethodMeta.setMethod(name);
String[] types = param.split(";");
List<JavaType> typeList = Lists.newArrayList();
for (String type : types) {
if (StringUtils.isNotEmpty(type)) {
typeList.add(TypeDescToJavaType.toJavaType(type));
}
}
activeMethodMeta.setParamTypes(typeList.toArray(new JavaType[typeList.size()]));
activeMethodMeta.setReturnType(TypeDescToJavaType.toJavaType(returnType));
activeMethodMeta.setServiceName(serviceName);
}
public void onMethodEnd() {
//默认的情况下认为是TR服务.
if (activeMethodMeta.getServiceType() == null) {
activeMethodMeta.setServiceType(ServiceType.TR);
}
//把当前服务加到服务列表中
serviceGroup.getServices().add(activeMethodMeta);
activeMethodMeta = null;
}
public void onRpcAnnotated() {
activeMethodMeta.setServiceType(ServiceType.RPC);
}
/**
* Getter method for property <tt>serviceGroup</tt>.
*
* @return property value of serviceGroup
*/
public ServiceGroup getServiceGroup() {
return serviceGroup;
}
public void onRpcName(String alias) {
activeMethodMeta.setAlias(alias);
}
}
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Opcodes;
public class AnnotationScanner extends AnnotationVisitor {
private ServiceDissect serviceDissect;
`
public AnnotationScanner(ServiceDissect serviceDissect) {
super(Opcodes.ASM6);
this.serviceDissect = serviceDissect;
}
@Override
public void visit(String name, Object value) {
//System.out.println("name:" + name + ",value:" + value);
if ("value".equals(name)){
serviceDissect.onRpcName(value.toString());
}
super.visit(name, value);
}
}
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
public class MethodAnnotationScanner extends MethodVisitor {
private ServiceDissect serviceDissect;
public MethodAnnotationScanner(ServiceDissect serviceDissect) {
super(Opcodes.ASM6);
this.serviceDissect = serviceDissect;
}
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
//System.out.println("visitAnnotation: desc=" + desc + " visible=" + visible);
if ("Lcom/888/888/999/annotation/OperationType;".equals(desc)) {
serviceDissect.onRpcAnnotated();
}
return new AnnotationScanner(serviceDissect);
}
@Override
public void visitEnd() {
//System.out.println("============End of Method==============");
serviceDissect.onMethodEnd();
super.visitEnd();
}
}
public class TypeDescToJavaType {
/**
* 把以/分隔的class替换成java类型.
* @param pathClass
* @return
*/
public static String pathToJavaType(String pathClass){
return pathClass.substring(0, pathClass.lastIndexOf('.')).replace('/', '.');
}
/**
* 把类型描述转换为JavaType
* @param typeDesc
* @return
*/
public static JavaType toJavaType(String typeDesc) {
JavaType javaType = new JavaType();
//先检查是否为数组
int i = 0;
char[] typeDescChar = typeDesc.toCharArray();
while (typeDescChar[i] == '[') {
javaType.setDemision(javaType.getDemision() + 1);
i++;
javaType.setArray(true);
}
String[][] primiTypeTypeMap = new String[][] {
{"Z", "Boolean"}, {"C", "Char"}, {"B", "Byte"}, {"S", "Short"},
{"I", "Integer"}, {"F", "Float"}, {"J", "Long"}, {"D", "Double"}};
if ('L' == typeDescChar[i]) {
javaType.setPrimitive(false);
int lastIdx = typeDesc.lastIndexOf(';') == -1 ? typeDesc.length() : typeDesc.lastIndexOf(';');
String type = typeDesc.substring(++i, lastIdx);
if (javaType.isArray()) {
StringBuilder sb = new StringBuilder(4);
for (int j = 0; j < javaType.getDemision(); j++) {
sb.append("[]");
}
javaType.setFullQualifiedName(type.replace('/', '.') + sb.toString());
} else {
javaType.setFullQualifiedName(type.replace('/', '.'));
}
return javaType;
} else {
for (int j = 0; j < primiTypeTypeMap.length; j++) {
if (primiTypeTypeMap[j][0].charAt(0) == typeDescChar[0]) {
javaType.setFullQualifiedName(primiTypeTypeMap[j][1]);
return javaType;
}
}
throw new RuntimeException("不能识别的TypeDescription!" + typeDesc);
}
}
}
import lombok.Data;
import lombok.ToString;
@Data
@ToString
public class Service {
/**
* 服务名称
*/
private String serviceName;
/**
* 方法名称
*/
private String method;
/**
* 参数类型定义
*/
private JavaType[] paramTypes;
/**
* 返回类型
*/
private JavaType returnType;
/**
* 接口类型
*/
private ServiceType serviceType;
/**
* 接口别名
*/
private String alias;
}
import com.google.common.collect.Lists;
import lombok.Data;
import java.util.List;
@Data
public class ServiceGroup {
public ServiceGroup(String serviceName) {
this.serviceName = serviceName;
}
/**
* 提供服务的类名
*/
private String serviceName;
/**
* 提供可调用的接口方法.
*/
private List<Service> services = Lists.newArrayList();
}
import lombok.Data;
@Data
public class JavaType {
/**
* 是否为基本类型
*/
private boolean isPrimitive;
/**
* 是否为数组类型
*/
private boolean isArray;
/**
* 数组的维度
*/
private int demision;
/**
* 类全名称
*/
private String fullQualifiedName;
}
List<Service> allService = Lists.newArrayList();
for (ArtifactResult artifactResult : artifactResults) {
List<ServiceGroup> serviceGroups = ServiceDiscovery.discovery(artifactResult.getArtifact().getFile());
//服务入库
for (ServiceGroup serviceGroup : serviceGroups) {
for Service service : serviceGroup.getServices()) {
Service dbService = new Service();
dbService.setServiceName(serviceGroup.getServiceName());
dbService.setMethod(service.getMethod());
dbService.setSutId(sutId);
dbService.setReturnType(service.getReturnType().getFullQualifiedName());
if (service.getParamTypes() != null) {
dbService.setParamTypes(StringUtils.join(Lists.newArrayList(
service.getParamTypes()).stream().map((s) -> s.getFullQualifiedName())
.collect(Collectors.toList()), ";"));
}
if (service.getServiceType() == ServiceType.RPC) {
dbService.setServiceType(ServiceType.RPC.getCode());
dbService.setDisplayName(service.getAlias().substring(service.getAlias().lastIndexOf('.') + 1));
} else if (service.getServiceType() == ServiceType.TR) {
dbService.setServiceType(ServiceType.TR.getCode());
dbService.setDisplayName(service.getMethod() + ":"
+ service.getServiceName().substring(service.getServiceName().lastIndexOf('.') + 1));
}
allService.add(dbService);
}
}
}