java.lang.instrument实现aop

淩亂°似流年 2022-08-08 06:15 239阅读 0赞

在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:D:/workspace/agentDemo1/agentDemo1/WebContent/WEB-INF/lib/MyClassFileTransformer.jar

下面是代码示例:

首先转换器类:

  1. package org.aop.instrument;
  2. import java.io.IOException;
  3. import java.lang.instrument.ClassFileTransformer;
  4. import java.lang.instrument.IllegalClassFormatException;
  5. import java.lang.instrument.Instrumentation;
  6. import java.security.ProtectionDomain;
  7. import javassist.CannotCompileException;
  8. import javassist.ClassPool;
  9. import javassist.CtClass;
  10. import javassist.CtMethod;
  11. import javassist.NotFoundException;
  12. public class MyClassFileTransformer implements ClassFileTransformer {
  13. /**
  14. * 字节码加载到虚拟机前会进入这个方法
  15. */
  16. public byte[] transform(ClassLoader loader, String className,
  17. Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
  18. byte[] classfileBuffer) throws IllegalClassFormatException {
  19. System.out.println(className);
  20. // 如果加载Business类才拦截
  21. if (!"org/aop/model/Business".equals(className)) {
  22. return null;
  23. }
  24. //javassist的包名是用点分割的,需要转换下
  25. if (className.indexOf("/") != -1) {
  26. className = className.replaceAll("/", ".");
  27. }
  28. try {
  29. //通过包名获取类文件
  30. CtClass cc = ClassPool.getDefault().get(className);
  31. //获得指定方法名的方法
  32. CtMethod m = cc.getDeclaredMethod("doSomething");
  33. //在方法执行前插入代码
  34. m.insertBefore("{System.out.println(\"记录日志\"); }");
  35. return cc.toBytecode();
  36. } catch (NotFoundException e) {
  37. } catch (CannotCompileException e) {
  38. } catch (IOException e) {
  39. //忽略异常处理
  40. }
  41. return null;
  42. }
  43. public static void premain(String options, Instrumentation ins) {
  44. //注册我自己的字节码转换器
  45. ins.addTransformer(new MyClassFileTransformer());
  46. }
  47. }

驱动类:

  1. package org.aop.instrument;
  2. import org.aop.model.Business;
  3. public class Driver {
  4. public static void main(String args[]) {
  5. new Business().doSomething();
  6. new Business().doSomething2();
  7. }
  8. }

这是model类的接口

  1. package org.aop.model;
  2. public interface IBusiness {
  3. public void doSomething();
  4. }
  5. package org.aop.model;
  6. public interface IBusiness2 {
  7. public void doSomething2();
  8. }

这是model的实现类

  1. package org.aop.model;
  2. public class Business implements IBusiness, IBusiness2 {
  3. public void doSomething2() {
  4. System.out.println("执行业务逻辑2");
  5. }
  6. public void doSomething() {
  7. System.out.println("执行业务逻辑");
  8. }
  9. }

最后的运行结果如图:

SouthEast

除了这种方法实现还有使用cglib、javassist,以及动态代理,具体可以参考博文http://www.iteye.com/topic/1116696

根据这篇博文,我实现了这几种方式。代码可以在这里下载 http://download.csdn.net/detail/licheng989/8673977

发表评论

表情:
评论列表 (有 0 条评论,239人围观)

还没有评论,来说两句吧...

相关阅读

    相关 aop实现

    AOP(面向切面编程)是一种编程范式,它可以帮助开发人员在不修改原有代码的情况下为程序添加新的功能。 AOP通常使用“切面”来描述需要在程序中添加新功能的位置,并使用“通知”

    相关 Spring实现AOP

    先了解AOP的相关术语: 1. 通知(Advice): 通知定义了切面是什么以及何时使用。描述了切面要完成的工作和何时需要执行这个工作。 2. 连接点(Joinp