【字节码增强ASM3.0】Java正则引发的思考--测试困惑--有解了

155 阅读2分钟

1 表情符号源代码

https://github.com/zly394/EmojiRegex/blob/master/src/main/java/com/zly/utils/EmojiRegexUtil.java

2 测试用例

import java.lang.instrument.Instrumentation;

public class Main2 {
    public static void main(String[] args) {
        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 MethodCallCountTransformer());
    }

}

// 增强类

import org.objectweb.asm.ClassAdapter;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;

public class MethodCallCountTransformer implements ClassFileTransformer {


    @Override
    public byte[] transform(ClassLoader loader,
                            String className,
                            Class<?> classBeingRedefined,
                            ProtectionDomain protectionDomain,
                            byte[] classfileBuffer) throws
            IllegalClassFormatException {
        try {
            if (!"java/util/regex/Pattern$CharProperty".equals(className)
                    &&
                    !"java/util/regex/Pattern$BmpCharProperty".equals(className)) {
                return classfileBuffer;
            }
            ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);
            ClassAdapter adapter = new MethodCallClassAdapter(writer, className);
            ClassReader reader = new ClassReader(classfileBuffer);
            reader.accept(adapter, 0);
            return writer.toByteArray();
        }catch (Exception e){
            return classfileBuffer;
        }
    }

}

// MethodCallClassAdapter
import org.objectweb.asm.ClassAdapter;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;

public class MethodCallClassAdapter extends ClassAdapter {
    private String className;
    public MethodCallClassAdapter(ClassVisitor cv, String className) {
        //Responsechain 的下一个 ClassVisitor,这里我们将传入 ClassWriter,
        // 负责改写后代码的输出
        super(cv);
        this.className = className;
    }

    // 重写 visitMethod,访问到 "operation" 方法时,
    // 给出自定义 MethodVisitor,实际改写方法内容
    @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) {
            // 对于 "operation" 方法
            if (name.equals("match")) {
                // 使用自定义 MethodVisitor,实际改写方法内容
                wrappedMv = new CountCallMethodAdapter(mv,name,name);
            }
        }
        return wrappedMv;
    }
}

// MethodAdapter

import org.objectweb.asm.MethodAdapter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
 
public class CountCallMethodAdapter extends MethodAdapter {
    private String methodName;
 
    private String className;
 
    public CountCallMethodAdapter(MethodVisitor visitor, String className, String methodName) {
        super(visitor);
 
        this.methodName = methodName;
        this.className = className;
    }
 
    @Override
    public void visitCode() {
        visitMethodInsn(Opcodes.INVOKESTATIC, "com/you/gbrank/asm/counter/Counter", "printAndIncCount", "()V");
    }
}

3 Counter 类

import java.util.concurrent.atomic.AtomicInteger;
 
public class Counter {
    private static AtomicInteger methodCallCount = new AtomicInteger(0);
    public static void checkSecurity() {
        System.out.println("SecurityChecker.checkSecurity ...");
        //TODO real security check
    }
    public static void printAndIncCount() {
        System.out.println(methodCallCount.incrementAndGet());
    }
    public static void printAndIncCount1(String className, String methodName) {
        System.out.println(methodCallCount.get());
        System.out.println(className + "." + methodName + " called, total times " + methodCallCount.incrementAndGet());
    }
}

4 结果:

增强没有效果,没有任何日志打印。 MARK

5 解决方案:

blog.csdn.net/qfzhangwei/… 给出了一个解决方案