package com.coding.asm.aop;
public class TestBean {
public void halloAop() {
System.out.println("Hello");
}
}
- 我希望在执行
helloAop
方法体之前和之后各插入Method before
和Method after!
两句话,也就是说在执行helloAop
方法体之前和之后各执行beforeInvoke
和afterInvoke
package com.coding.asm.aop;
public class AopInterceptor {
public static void beforeInvoke() {
System.out.println("Method before!");
};
public static void afterInvoke() {
System.out.println("Method after!");
};
}
package com.coding.asm.aop;
import com.coding.asm.generator.AsmUtils;
import com.coding.asm.generator.ClassType;
import com.coding.asm.generator.Method;
import com.coding.asm.generator.TypeDescriptor;
import org.apache.commons.lang3.StringUtils;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.commons.GeneratorAdapter;
import java.util.ArrayList;
public class AopClassAdapter extends ClassVisitor implements Opcodes {
private String suffix;
private AsmUtils asmUtils ;
public AopClassAdapter(int api,ClassWriter classWriter,String suffix) {
super(api, classWriter);
this.suffix = suffix;
asmUtils = new AsmUtils(classWriter);
}
public void visit(int version, int access, String name,
String signature, String superName, String[] interfaces) {
System.out.println("className:"+name);
String newClassName = StringUtils.isEmpty(suffix) ? name : name + suffix;
//更改类名,并使新类继承原有的类。
super.visit(version, access, newClassName, signature, name, interfaces);
//输出一个默认的构造方法
Method iterator = asmUtils.genMethod(Opcodes.ACC_PUBLIC,
"<init>",
new ClassType(TypeDescriptor.VOID),
new ArrayList() {{}}, null,null);
GeneratorAdapter construct = asmUtils.writeMethodHeader(iterator);
asmUtils.genDefaultConstructor(construct,name);
asmUtils.returnAndEndMethod(construct);
}
public MethodVisitor visitMethod(int access, String name,
String desc, String signature, String[] exceptions) {
// 只对halloAop方法执行代理
if (!name.equals("halloAop"))
return null;
MethodVisitor mv = super.visitMethod(access, name,
desc, signature, exceptions);
return new AopMethodVisitor(this.api, mv);
}
}
package com.coding.asm.aop;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
public class AopMethodVisitor extends MethodVisitor implements Opcodes {
public AopMethodVisitor(int api, MethodVisitor mv) {
super(api, mv);
}
/**
* 访问方法头,只访问一次
*/
public void visitCode() {
super.visitCode();
this.visitMethodInsn(INVOKESTATIC, "com/coding/asm/aop/AopInterceptor", "beforeInvoke", "()V");
}
public void visitInsn(int opcode) {
if (opcode == RETURN) {//在返回之前安插after 代码。
mv.visitMethodInsn(INVOKESTATIC, "com/coding/asm/aop/AopInterceptor", "afterInvoke", "()V");
}
super.visitInsn(opcode);
}
}
package com.coding.classloader;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.StringTokenizer;
public class BinaryClassLoader {
private final ArrayList m_bases;
public BinaryClassLoader() {
m_bases = new ArrayList();
}
public void addPaths(String list) {
StringTokenizer tkzr = new StringTokenizer(list, File.pathSeparator);
while (tkzr.hasMoreTokens()) {
File file = new File(tkzr.nextToken());
String spec = null;
if (file.isFile() && file.getName().toLowerCase().endsWith(".jar")) {
spec = "jar:file://" + file.getAbsolutePath() + "!/";
} else if (file.exists()) {
spec = "file://" + file.getAbsolutePath();
if (!spec.endsWith("/")) {
spec += '/';
}
}
if (spec != null) {
m_bases.add(spec);
System.out.println("add loader path:" + spec);
}
}
}
public byte[] getBytes(String name) {
String pname = name.replace('.', '/') + ".class";
for (int i = 0; i < m_bases.size(); i++) {
String base = (String) m_bases.get(i);
try {
URL url = new URL(base + pname);
InputStream is = url.openStream();
// read the entire content into byte array
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] buff = new byte[1024];
int length;
while ((length = is.read(buff)) >= 0) {
bos.write(buff, 0, length);
}
return bos.toByteArray();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
// normal event when not found relative to current base
} catch (IOException e) {
e.printStackTrace();
}
}
throw new IllegalArgumentException("Class not found: " + name);
}
/**
* 实际上是调用ClassLoader.defineClass()
* @param b class文件字节流
* @param classFullName eg:com.coding.asm.test.TestBean_Tmp
* @return
*/
public static Class loadClass(byte[] b,String classFullName) {
// Override defineClass (as it is protected) and define the class.
Class clazz = null;
try {
ClassLoader loader = ClassLoader.getSystemClassLoader();
Class cls = Class.forName("java.lang.ClassLoader");
java.lang.reflect.Method method =
cls.getDeclaredMethod(
"defineClass",
new Class[] { String.class, byte[].class, int.class, int.class });
// Protected method invocation.
method.setAccessible(true);
try {
Object[] args =
new Object[] { classFullName, b, Integer.valueOf(0), Integer.valueOf(b.length)};
clazz = (Class) method.invoke(loader, args);
} finally {
method.setAccessible(false);
}
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
return clazz;
}
}
package com.coding.asm.aop;
import com.coding.asm.generator.AsmUtils;
import com.coding.asm.reflection.AsmReflectionUtils;
import com.coding.classloader.BinaryClassLoader;
import com.coding.path.PathUtils;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes;
import java.io.InputStream;
import java.net.URL;
/**
* Created by micocube
* ProjectName: coding
* PackageName: com.coding.asm.test
* User: micocube
* Email: ldscube@gmail.com
* CreateTime: 2019/1/11上午11:13
* ModifyTime: 2019/1/11上午11:13
* Version: 0.1
* Description:
* asm5.0.3 支持的jdk版本不超过1.8
* Preference:
* java compiler:
* project bytecode version: 1.8
* target bytecode version: 1.8
* Project Structure:
* SDKs: 1.8
* Project:
* Project SDK:1.8
* Project language level:8
* Modules:Language level:8
* 否则会报错:
* Exception in thread "main" java.lang.IllegalArgumentException
* at org.objectweb.asm.ClassReader.<init>(Unknown Source)
* at org.objectweb.asm.ClassReader.<init>(Unknown Source)
* at org.objectweb.asm.ClassReader.<init>(Unknown Source)
* at com.coding.asm.test.AopTest.main(AopTest.java:30)
**/
public class AopTest {
public static void main(String[] args) throws Exception{
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
InputStream is = PathUtils.getClassInputStream(TestBean.class);
// System.out.println(new String(is.readAllBytes(),"UTF-8"));
ClassReader reader = new ClassReader(is);
reader.accept(new AopClassAdapter(Opcodes.ASM5,cw,"_Proxy"), 0);
//
byte[] code = cw.toByteArray();
new AsmUtils().writeClass("/Users/micocube/Documents/Utils4j/target/classes/com/coding/asm/aop/TestBean_Proxy.class",code);
Class bean_tmp = BinaryClassLoader.loadClass(code, "com.coding.asm.aop.TestBean_Proxy");
Object instance = bean_tmp.getConstructor().newInstance();
Method helloAop = bean_tmp.getDeclaredMethod("halloAop");
System.out.println(bean_tmp);
helloAop.invoke(instance);
}
}
className:com/coding/asm/aop/TestBean
Method:<init>###,Method Sign:()V###,Method desc:()V
[DEBUG-console] 2019/01/16,16:52:49.791|<init>: super class:com/coding/asm/aop/TestBean
class com.coding.asm.aop.TestBean_Proxy
Method before!
Hello
Method after!
package com.coding.asm.aop;
public class TestBean_Proxy extends TestBean {
public TestBean_Proxy() {
}
public void halloAop() {
AopInterceptor.beforeInvoke();
System.out.println("Hello Aop");
AopInterceptor.afterInvoke();
}
}
网友评论