0 背景: 检测用户发表评论是否全是表情符,具体代码参考:https://blog.csdn.net/qfzhangwei/article/details/104138979 ,由于使用了正则匹配,用户输入小红旗时,遇到了匹配超长时间的问题。于是想看看那那个到底匹配了到多少次,但是用的Pattern类红的方法,没法直接统计调用次数,但是可以通过ASM 修改字节码。
1 修改的java代码
private int mcounter = 0;
public void do2() {
System.out.println(mcounter++);
}
2 获取ASM源代码 (工具ASMifierClassVisitor)
java -classpath /Users/sss/.m2/repository/org/glassfish/hk2/external/asm-all-repackaged/2.1.81/asm-all-repackaged-2.1.81.jar org.objectweb.asm.util.ASMifierClassVisitor /Users/sss/***/asm/AppendMethod/Cost.class
3 将方法的代码指令修改(需要根据修改的类做调整)
3 使用arthas 工具 jad 查看修改后source代码
5 占满一个核心
6 stack栈
7 核心代码:
public class Main {
public static void main(String[] args) throws IOException {
String text = "\uD83C\uDDF2\uD83C\uDDEA\uD83C\uDDE8\uD83C\uDDF3\uD83C\uDDE8\uD83C\uDDF3\uD83C\uDDE8\uD83C\uDDF3\uD83C\uDDE8\uD83C\uDDF3\uD83C\uDDE8\uD83C\uDDF3\uD83C\uDDE8\uD83C\uDDF3\uD83C\uDDE8\uD83C\uDDF3\uD83C\uDDE8\uD83C\uDDF3\uD83C\uDDE8\uD83C\uDDF3\uD83C\uDDE8\uD83C\uDDF3\uD83C\uDDE8\uD83C\uDDF3\uD83C\uDDE8\uD83C\uDDF3\uD83C\uDDE8\uD83C\uDDF3\uD83C\uDDE8\uD83C\uDDF3\uD83C\uDDE8\uD83C\uDDF3\uD83C\uDDE8\uD83C\uDDF3\uD83C\uDDE8\uD83C\uDDF3\uD83C\uDDE8\uD83C\uDDF3\uD83C\uDDE8\uD83C\uDDF3\uD83C\uDDE8\uD83C\uDDF3\uD83C\uDDE8\uD83C\uDDF3\uD83C\uDDE8\uD83C\uDDF3\uD83C\uDDE8\uD83C\uDDF3\uD83C\uDDE8\uD83C\uDDF3\uD83C\uDDE8\uD83C\uDDF3\uD83C\uDDE8\uD83C\uDDF3\uD83C\uDDE8\uD83C\uDDF3\uD83C\uDDE8\uD83C\uDDF3\uD83C\uDDEC\uD83C\uDDE7\uD83C\uDFF4\uDB40\uDC67\uDB40\uDC62\uDB40\uDC77\uDB40\uDC6C\uDB40\uDC73\uDB40\uDC7F\uD83C\uDFF4\uDB40\uDC67\uDB40\uDC62\uDB40\uDC73\uDB40\uDC63\uDB40\uDC74\uDB40\uDC7F\uD83C\uDFF4\uDB40\uDC67\uDB40\uDC62\uDB40\uDC65\uDB40\uDC6E\uDB40\uDC67\uDB40\uDC7F";
boolean allEmoji = EmojiUtil.isAllEmoji(text);
System.out.println(allEmoji);
}
public static void premain(String args, Instrumentation inst) {
inst.addTransformer(new MethodCallCountTransformerCustom());
}
}
// class
public class MethodCallCountTransformerCustom implements ClassFileTransformer {
@Override
public byte[] transform(ClassLoader loader,
String className,
Class<?> classBeingRedefined,
ProtectionDomain protectionDomain,
byte[] classfileBuffer){
try {
if (!(className).contains("java/util/regex/Pattern$Loop")) {
return classfileBuffer;
}else{
System.out.println(className);
}
ClassReader reader = new ClassReader(classfileBuffer);
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);
ClassAdapter adapter = new MethodCallClassAdapter(writer, className);
reader.accept(adapter, 0);
return writer.toByteArray();
}catch (Exception e){
return classfileBuffer;
}
}
}
// class adapter 字节码过滤器
public class MethodCallClassAdapter extends ClassAdapter {
private String className;
public MethodCallClassAdapter(ClassVisitor cv,String className) {
super(cv);
this.className = className;
}
@Override
public MethodVisitor visitMethod(final int access, final String name,
final String desc, final String signature, final String[] exceptions) {
MethodVisitor mv = cv.visitMethod(access, name, desc, signature,exceptions);
MethodVisitor wrappedMv = mv;
if (mv != null) {
if (name.equalsIgnoreCase("match")) {
System.out.println(name);
// 使用自定义 MethodVisitor,实际改写方法内容
wrappedMv = new AppendFieldToPatternMethodAdapter(mv);
}
}
return wrappedMv;
}
private String fName = "mcounter";
private boolean isFieldPresent;
@Override
public FieldVisitor visitField(int access, String name, String desc,
String signature, Object value) {
if (name.equals(fName)) {
isFieldPresent = true;
}
return cv.visitField(access, name, desc, signature, value);
}
@Override
public void visitEnd() {
if (!isFieldPresent) {
FieldVisitor fv = cv.visitField(Opcodes.ACC_PRIVATE, fName, "I", null, null);
if (fv != null) {
fv.visitEnd();
}
}
cv.visitEnd();
}
}
// write
import static org.objectweb.asm.Opcodes.*;
public class AppendFieldToPatternMethodAdapter extends MethodAdapter {
public AppendFieldToPatternMethodAdapter(MethodVisitor mv) {
super(mv);
}
@Override
public void visitEnd() {
super.visitEnd();
}
@Override
public void visitCode() {
// Pattern$Loop 类覆盖visitCode方法
mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
mv.visitVarInsn(ALOAD, 0);
mv.visitInsn(DUP);
mv.visitFieldInsn(GETFIELD, "java/util/regex/Pattern$Loop", "mcounter", "I");
mv.visitInsn(DUP_X1);
mv.visitInsn(ICONST_1);
mv.visitInsn(IADD);
mv.visitFieldInsn(PUTFIELD, "java/util/regex/Pattern$Loop", "mcounter", "I");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(I)V");
}
}
8 agent jar 参考 https://blog.csdn.net/qfzhangwei/article/details/105181355