java.lang.instrument实现aop
在jdk1.5之后引入了instrument包,关于这个包的介绍可以看官方文档http://docs.oracle.com/javase/8/docs/api/java/lang/instrument/package-summary.html
JVM运行的是二进制文件,我们可以通过instrument包的使用,在JVM运行之前修改JVM本要运行的二进制文件。
首先需要编写一个转换器类,它实现java.lang.instrument.ClassFileTransformer类。我们将这个类命名为MyClassFileTransformer,实现transform方法,同时写一个premain方法,有了这个方法,jvm就会在执行main之前按照transform来修改二进制文件。
我们还需要将这个类打成jar包命名为MyClassFileTransformer.jar,我将这个jar放到D:/workspace/agentDemo1/agentDemo1/WebContent/WEB-INF/lib/下。很重要的一点是修改jar包里面的MANIFEST.MF文件,在文件中加入Premain-Class: MyClassFileTransformer.jar。在运行main方法时配置-javaagent/workspace/agentDemo1/agentDemo1/WebContent/WEB-INF/lib/MyClassFileTransformer.jar
下面是代码示例:
首先转换器类:
package org.aop.instrument;
import java.io.IOException;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.NotFoundException;
public class MyClassFileTransformer implements ClassFileTransformer {
/**
* 字节码加载到虚拟机前会进入这个方法
*/
public byte[] transform(ClassLoader loader, String className,
Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
byte[] classfileBuffer) throws IllegalClassFormatException {
System.out.println(className);
// 如果加载Business类才拦截
if (!"org/aop/model/Business".equals(className)) {
return null;
}
//javassist的包名是用点分割的,需要转换下
if (className.indexOf("/") != -1) {
className = className.replaceAll("/", ".");
}
try {
//通过包名获取类文件
CtClass cc = ClassPool.getDefault().get(className);
//获得指定方法名的方法
CtMethod m = cc.getDeclaredMethod("doSomething");
//在方法执行前插入代码
m.insertBefore("{System.out.println(\"记录日志\"); }");
return cc.toBytecode();
} catch (NotFoundException e) {
} catch (CannotCompileException e) {
} catch (IOException e) {
//忽略异常处理
}
return null;
}
public static void premain(String options, Instrumentation ins) {
//注册我自己的字节码转换器
ins.addTransformer(new MyClassFileTransformer());
}
}
驱动类:
package org.aop.instrument;
import org.aop.model.Business;
public class Driver {
public static void main(String args[]) {
new Business().doSomething();
new Business().doSomething2();
}
}
这是model类的接口
package org.aop.model;
public interface IBusiness {
public void doSomething();
}
package org.aop.model;
public interface IBusiness2 {
public void doSomething2();
}
这是model的实现类
package org.aop.model;
public class Business implements IBusiness, IBusiness2 {
public void doSomething2() {
System.out.println("执行业务逻辑2");
}
public void doSomething() {
System.out.println("执行业务逻辑");
}
}
最后的运行结果如图:
除了这种方法实现还有使用cglib、javassist,以及动态代理,具体可以参考博文http://www.iteye.com/topic/1116696
根据这篇博文,我实现了这几种方式。代码可以在这里下载 http://download.csdn.net/detail/licheng989/8673977
还没有评论,来说两句吧...