Provided 4 types match for enhance class:

* byName
* byClassAnnotationMatch
* byMethodAnnotationMatch
* byHierarchyMatch
This commit is contained in:
wusheng 2017-07-13 21:26:44 +08:00
parent 28b6d8faa4
commit ea7db2090a
9 changed files with 199 additions and 67 deletions

View File

@ -64,7 +64,7 @@ public abstract class AbstractClassEnhancePluginDefine {
DynamicType.Builder<?> newClassBuilder, ClassLoader classLoader) throws PluginException;
/**
* Define the classname of target class.
* Define the {@link ClassMatch} for filtering class.
*
* @return {@link ClassMatch}
*/

View File

@ -1,18 +1,16 @@
package org.skywalking.apm.agent.core.plugin;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import net.bytebuddy.description.NamedElement;
import net.bytebuddy.description.annotation.AnnotationDescription;
import net.bytebuddy.description.annotation.AnnotationList;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.skywalking.apm.agent.core.plugin.bytebuddy.AbstractJunction;
import org.skywalking.apm.agent.core.plugin.match.AnnotationMatch;
import org.skywalking.apm.agent.core.plugin.match.ClassAnnotationMatch;
import org.skywalking.apm.agent.core.plugin.match.ClassMatch;
import org.skywalking.apm.agent.core.plugin.match.IndirectMatch;
import org.skywalking.apm.agent.core.plugin.match.NameMatch;
import static net.bytebuddy.matcher.ElementMatchers.isInterface;
@ -36,7 +34,7 @@ public class PluginFinder {
continue;
}
if (match instanceof NameMatch) {
if (match instanceof IndirectMatch) {
NameMatch nameMatch = (NameMatch)match;
nameMatchDefine.put(nameMatch.getClassName(), plugin);
} else {
@ -53,17 +51,9 @@ public class PluginFinder {
}
for (AbstractClassEnhancePluginDefine pluginDefine : signatureMatchDefine) {
ClassMatch classMatch = pluginDefine.enhanceClass();
if (classMatch instanceof AnnotationMatch) {
AnnotationMatch annotationMatch = (AnnotationMatch)classMatch;
List<String> annotationList = Arrays.asList(annotationMatch.getAnnotations());
AnnotationList declaredAnnotations = typeDescription.getDeclaredAnnotations();
for (AnnotationDescription annotation : declaredAnnotations) {
annotationList.remove(annotation.getAnnotationType().getActualName());
}
if (annotationList.isEmpty()) {
return pluginDefine;
}
IndirectMatch match = (IndirectMatch)pluginDefine.enhanceClass();
if (match.isMatch(typeDescription)) {
return pluginDefine;
}
}
@ -80,8 +70,8 @@ public class PluginFinder {
judge = judge.and(not(isInterface()));
for (AbstractClassEnhancePluginDefine define : signatureMatchDefine) {
ClassMatch match = define.enhanceClass();
if (match instanceof AnnotationMatch) {
judge = judge.or(((AnnotationMatch)match).buildJunction());
if (match instanceof ClassAnnotationMatch) {
judge = judge.or(((ClassAnnotationMatch)match).buildJunction());
}
}
return judge;

View File

@ -1,40 +0,0 @@
package org.skywalking.apm.agent.core.plugin.match;
import net.bytebuddy.matcher.ElementMatcher;
import static net.bytebuddy.matcher.ElementMatchers.isAnnotatedWith;
import static net.bytebuddy.matcher.ElementMatchers.isInterface;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.not;
/**
* @author wusheng
*/
public class AnnotationMatch extends ClassMatch {
private String[] annotations;
public AnnotationMatch(String[] annotations) {
this.annotations = annotations;
}
public ElementMatcher.Junction buildJunction() {
ElementMatcher.Junction junction = null;
for (String annotation : annotations) {
if (junction == null) {
junction = buildEachAnnotation(annotation);
} else {
junction = junction.and(buildEachAnnotation(annotation));
}
}
junction = junction.and(not(isInterface()));
return junction;
}
private ElementMatcher.Junction buildEachAnnotation(String annotationName) {
return isAnnotatedWith(named(annotationName));
}
public String[] getAnnotations() {
return annotations;
}
}

View File

@ -0,0 +1,64 @@
package org.skywalking.apm.agent.core.plugin.match;
import java.util.Arrays;
import java.util.List;
import net.bytebuddy.description.annotation.AnnotationDescription;
import net.bytebuddy.description.annotation.AnnotationList;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
import static net.bytebuddy.matcher.ElementMatchers.isAnnotatedWith;
import static net.bytebuddy.matcher.ElementMatchers.isInterface;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.not;
/**
* Match the class by the given annotations in class.
*
* @author wusheng
*/
public class ClassAnnotationMatch implements IndirectMatch {
private String[] annotations;
private ClassAnnotationMatch(String[] annotations) {
if (annotations == null || annotations.length == 0) {
throw new IllegalArgumentException("annotations is null");
}
this.annotations = annotations;
}
@Override
public ElementMatcher.Junction buildJunction() {
ElementMatcher.Junction junction = null;
for (String annotation : annotations) {
if (junction == null) {
junction = buildEachAnnotation(annotation);
} else {
junction = junction.and(buildEachAnnotation(annotation));
}
}
junction = junction.and(not(isInterface()));
return junction;
}
@Override
public boolean isMatch(TypeDescription typeDescription) {
List<String> annotationList = Arrays.asList(annotations);
AnnotationList declaredAnnotations = typeDescription.getDeclaredAnnotations();
for (AnnotationDescription annotation : declaredAnnotations) {
annotationList.remove(annotation.getAnnotationType().getActualName());
}
if (annotationList.isEmpty()) {
return true;
}
return false;
}
private ElementMatcher.Junction buildEachAnnotation(String annotationName) {
return isAnnotatedWith(named(annotationName));
}
public static ClassMatch byClassAnnotationMatch(String[] annotations) {
return new ClassAnnotationMatch(annotations);
}
}

View File

@ -3,5 +3,5 @@ package org.skywalking.apm.agent.core.plugin.match;
/**
* @author wusheng
*/
public abstract class ClassMatch {
public interface ClassMatch {
}

View File

@ -1,22 +1,52 @@
package org.skywalking.apm.agent.core.plugin.match;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
import static net.bytebuddy.matcher.ElementMatchers.hasSuperType;
import static net.bytebuddy.matcher.ElementMatchers.isInterface;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.not;
/**
* Match the class by the given super class or interfaces.
*
* @author wusheng
*/
public class HierarchyMatch extends ClassMatch {
public class HierarchyMatch implements IndirectMatch {
private String[] parentTypes;
public HierarchyMatch(String[] parentTypes) {
private HierarchyMatch(String[] parentTypes) {
if (parentTypes == null || parentTypes.length == 0) {
throw new IllegalArgumentException("parentTypes is null");
}
this.parentTypes = parentTypes;
}
@Override
public ElementMatcher.Junction buildJunction() {
return null;
ElementMatcher.Junction junction = null;
for (String superTypeName : parentTypes) {
if (junction == null) {
junction = buildEachAnnotation(superTypeName);
} else {
junction = junction.and(buildEachAnnotation(superTypeName));
}
}
junction = junction.and(not(isInterface()));
return junction;
}
private ElementMatcher.Junction buildEachParent(String parentType) {
return null;
private ElementMatcher.Junction buildEachAnnotation(String superTypeName) {
return hasSuperType(named(superTypeName));
}
@Override
public boolean isMatch(TypeDescription typeDescription) {
return false;
}
public static ClassMatch byHierarchyMatch(String[] parentTypes) {
return new HierarchyMatch(parentTypes);
}
}

View File

@ -0,0 +1,15 @@
package org.skywalking.apm.agent.core.plugin.match;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
/**
* All implementations can't direct match the class like {@link NameMatch} did.
*
* @author wusheng
*/
public interface IndirectMatch extends ClassMatch {
ElementMatcher.Junction buildJunction();
boolean isMatch(TypeDescription typeDescription);
}

View File

@ -0,0 +1,71 @@
package org.skywalking.apm.agent.core.plugin.match;
import java.util.Arrays;
import java.util.List;
import net.bytebuddy.description.annotation.AnnotationDescription;
import net.bytebuddy.description.annotation.AnnotationList;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
import static net.bytebuddy.matcher.ElementMatchers.declaresMethod;
import static net.bytebuddy.matcher.ElementMatchers.isAnnotatedWith;
import static net.bytebuddy.matcher.ElementMatchers.isInterface;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.not;
/**
* Match the class, which has methods with the certain annotations.
* This is a very complex match.
*
* @author wusheng
*/
public class MethodAnnotationMatch implements IndirectMatch {
private String[] annotations;
private MethodAnnotationMatch(String[] annotations) {
if (annotations == null || annotations.length == 0) {
throw new IllegalArgumentException("annotations is null");
}
this.annotations = annotations;
}
@Override
public ElementMatcher.Junction buildJunction() {
ElementMatcher.Junction junction = null;
for (String annotation : annotations) {
if (junction == null) {
junction = buildEachAnnotation(annotation);
} else {
junction = junction.and(buildEachAnnotation(annotation));
}
}
junction = declaresMethod(junction).and(not(isInterface()));
return junction;
}
@Override
public boolean isMatch(TypeDescription typeDescription) {
for (MethodDescription.InDefinedShape methodDescription : typeDescription.getDeclaredMethods()) {
List<String> annotationList = Arrays.asList(annotations);
AnnotationList declaredAnnotations = methodDescription.getDeclaredAnnotations();
for (AnnotationDescription annotation : declaredAnnotations) {
annotationList.remove(annotation.getAnnotationType().getActualName());
}
if (annotationList.isEmpty()) {
return true;
}
}
return false;
}
private ElementMatcher.Junction buildEachAnnotation(String annotationName) {
return isAnnotatedWith(named(annotationName));
}
public static ClassMatch byMethodAnnotationMatch(String[] annotations) {
return new MethodAnnotationMatch(annotations);
}
}

View File

@ -1,12 +1,14 @@
package org.skywalking.apm.agent.core.plugin.match;
/**
* Match the class with an explicit class name.
*
* @author wusheng
*/
public class NameMatch extends ClassMatch {
public class NameMatch implements ClassMatch {
private String className;
public NameMatch(String className) {
private NameMatch(String className) {
this.className = className;
}