`

CLASS 文件使用例子四--AOP字节码增强探索二

    博客分类:
  • JVM
阅读更多

上一篇中我们分析了

 

 

public class HelloWorld{    
    public static void main(String [] arvgs){  
        System.out.println("before log");    
      System.out.println("hello world");  
      System.out.println("after log");    
   }    
} 

 和

 

public class HelloWorld{    
    public static void main(String [] arvgs){  
      System.out.println("hello world");   
  }    
} 

 的class文件,最后我们是希望通过直接操作class文件能将简单版本(第二段代码)的行为修改为复杂版本(第一段代码);接下去我们看一下要做的事情:

 

根据上一篇的分析,我们只需要做两件事情,第一步是要新增4个常量,其中两个为constant_UTF8类型;两个为constant_String ,对应到新增的before log和after log;第二步是要修改main 函数,改变他的行为;

 

为了方便查阅:我先把简单版本初始的class文件给出:

 

 

00000000h: CA FE BA BE 00 00 00 32 00 1D 0A 00 06 00 0F 09 ; 漱壕...2........
00000010h: 00 10 00 11 08 00 12 0A 00 13 00 14 07 00 15 07 ; ................
00000020h: 00 16 01 00 06 3C 69 6E 69 74 3E 01 00 03 28 29 ; .....<init>...()
00000030h: 56 01 00 04 43 6F 64 65 01 00 0F 4C 69 6E 65 4E ; V...Code...LineN
00000040h: 75 6D 62 65 72 54 61 62 6C 65 01 00 04 6D 61 69 ; umberTable...mai
00000050h: 6E 01 00 16 28 5B 4C 6A 61 76 61 2F 6C 61 6E 67 ; n...([Ljava/lang
00000060h: 2F 53 74 72 69 6E 67 3B 29 56 01 00 0A 53 6F 75 ; /String;)V...Sou
00000070h: 72 63 65 46 69 6C 65 01 00 0F 48 65 6C 6C 6F 57 ; rceFile...HelloW
00000080h: 6F 72 6C 64 2E 6A 61 76 61 0C 00 07 00 08 07 00 ; orld.java.......
00000090h: 17 0C 00 18 00 19 01 00 0B 68 65 6C 6C 6F 20 77 ; .........hello w
000000a0h: 6F 72 6C 64 07 00 1A 0C 00 1B 00 1C 01 00 0A 48 ; orld...........H
000000b0h: 65 6C 6C 6F 57 6F 72 6C 64 01 00 10 6A 61 76 61 ; elloWorld...java
000000c0h: 2F 6C 61 6E 67 2F 4F 62 6A 65 63 74 01 00 10 6A ; /lang/Object...j
000000d0h: 61 76 61 2F 6C 61 6E 67 2F 53 79 73 74 65 6D 01 ; ava/lang/System.
000000e0h: 00 03 6F 75 74 01 00 15 4C 6A 61 76 61 2F 69 6F ; ..out...Ljava/io
000000f0h: 2F 50 72 69 6E 74 53 74 72 65 61 6D 3B 01 00 13 ; /PrintStream;...
00000100h: 6A 61 76 61 2F 69 6F 2F 50 72 69 6E 74 53 74 72 ; java/io/PrintStr
00000110h: 65 61 6D 01 00 07 70 72 69 6E 74 6C 6E 01 00 15 ; eam...println...
00000120h: 28 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 ; (Ljava/lang/Stri
00000130h: 6E 67 3B 29 56 00 21 00 05 00 06 00 00 00 00 00 ; ng;)V.!.........
00000140h: 02 00 01 00 07 00 08 00 01 00 09 00 00 00 1D 00 ; ................
00000150h: 01 00 01 00 00 00 05 2A B7 00 01 B1 00 00 00 01 ; .......*?.?...
00000160h: 00 0A 00 00 00 06 00 01 00 00 00 01 00 09 00 0B ; ................
00000170h: 00 0C 00 01 00 09 00 00 00 25 00 02 00 01 00 00 ; .........%......
00000180h: 00 09 B2 00 02 12 03 B6 00 04 B1 00 00 00 01 00 ; ..?...?.?....
00000190h: 0A 00 00 00 0A 00 02 00 00 00 03 00 08 00 04 00 ; ................
000001a0h: 01 00 0D 00 00 00 02 00 0E                      ; .........

 

 

 

接下去我们开始修改:

1、修改常量池大小,由28修改为32,就是将0x 1D 修改为 21;

2、找到常量池的结束点:0X 3B 29 56 ;在后面增加4个常量:

     08 00 1F

     08 00 20

     01 00 0A  62 5 66 6F 72 65 20 6C 6F 67

     01 00 09  61 66 74 65 72 20 6C 6F 67

第一个常量表示constant_String 类型 引用到第31号常量

第二个常量表示constant_String 类型 引用到第32号常量

第三个常量表示constant_UTF8 类型 值为 before log

第四个常量表示constant_UTF8 类型 值为 after log

 

然后找到main方法:

3、首先找到code处;B2 00 02 12 03 B6 00 04 B1;从上一篇可以发现这段code其实就是System.out.println("hello world");

于是我们在其前后要各增加一段代码:

在前面增加 B2 00 02 12 1D B6 00 04 表示  System.out.println("before log")

在后面增加 B2 00 02 12 1E B6 00 04 表示  System.out.println("after log")

总体就是 B2 00 02 12 03 B6 00 04 B1  改为 B2 00 02 12 1D B6 00 04 B2 00 02 12 03 B6 00 04 B2 00 02 12 1E B6 00 04 B1

 

4、可以发现第三步将代码量增加了16个长度,所以需要修改两处地方,第一次是code的长度由9变为25 (也就是ox09--->ox 19);第二处就是main的长度由37变为53(也就是 ox 25--->ox 35)

 

经过上面的4步就完成了整个修改;最终如下:

 

 

 

00000000h: CA FE BA BE 00 00 00 32 00 21 0A 00 06 00 0F 09 ; 漱壕...2.!......
00000010h: 00 10 00 11 08 00 12 0A 00 13 00 14 07 00 15 07 ; ................
00000020h: 00 16 01 00 06 3C 69 6E 69 74 3E 01 00 03 28 29 ; .....<init>...()
00000030h: 56 01 00 04 43 6F 64 65 01 00 0F 4C 69 6E 65 4E ; V...Code...LineN
00000040h: 75 6D 62 65 72 54 61 62 6C 65 01 00 04 6D 61 69 ; umberTable...mai
00000050h: 6E 01 00 16 28 5B 4C 6A 61 76 61 2F 6C 61 6E 67 ; n...([Ljava/lang
00000060h: 2F 53 74 72 69 6E 67 3B 29 56 01 00 0A 53 6F 75 ; /String;)V...Sou
00000070h: 72 63 65 46 69 6C 65 01 00 0F 48 65 6C 6C 6F 57 ; rceFile...HelloW
00000080h: 6F 72 6C 64 2E 6A 61 76 61 0C 00 07 00 08 07 00 ; orld.java.......
00000090h: 17 0C 00 18 00 19 01 00 0B 68 65 6C 6C 6F 20 77 ; .........hello w
000000a0h: 6F 72 6C 64 07 00 1A 0C 00 1B 00 1C 01 00 0A 48 ; orld...........H
000000b0h: 65 6C 6C 6F 57 6F 72 6C 64 01 00 10 6A 61 76 61 ; elloWorld...java
000000c0h: 2F 6C 61 6E 67 2F 4F 62 6A 65 63 74 01 00 10 6A ; /lang/Object...j
000000d0h: 61 76 61 2F 6C 61 6E 67 2F 53 79 73 74 65 6D 01 ; ava/lang/System.
000000e0h: 00 03 6F 75 74 01 00 15 4C 6A 61 76 61 2F 69 6F ; ..out...Ljava/io
000000f0h: 2F 50 72 69 6E 74 53 74 72 65 61 6D 3B 01 00 13 ; /PrintStream;...
00000100h: 6A 61 76 61 2F 69 6F 2F 50 72 69 6E 74 53 74 72 ; java/io/PrintStr
00000110h: 65 61 6D 01 00 07 70 72 69 6E 74 6C 6E 01 00 15 ; eam...println...
00000120h: 28 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 ; (Ljava/lang/Stri
00000130h: 6E 67 3B 29 56 08 00 1F 08 00 20 01 00 0A 62 65 ; ng;)V..... ...be
00000140h: 66 6F 72 65 20 6C 6F 67 01 00 09 61 66 74 65 72 ; fore log...after
00000150h: 20 6C 6F 67 00 21 00 05 00 06 00 00 00 00 00 02 ;  log.!..........
00000160h: 00 01 00 07 00 08 00 01 00 09 00 00 00 1D 00 01 ; ................
00000170h: 00 01 00 00 00 05 2A B7 00 01 B1 00 00 00 01 00 ; ......*?.?....
00000180h: 0A 00 00 00 06 00 01 00 00 00 01 00 09 00 0B 00 ; ................
00000190h: 0C 00 01 00 09 00 00 00 35 00 02 00 01 00 00 00 ; ........5.......
000001a0h: 19 B2 00 02 12 1D B6 00 04 B2 00 02 12 03 B6 00 ; .?...?.?...?
000001b0h: 04 B2 00 02 12 1E B6 00 04 B1 00 00 00 01 00 0A ; .?...?.?.....
000001c0h: 00 00 00 0A 00 02 00 00 00 03 00 08 00 04 00 01 ; ................
000001d0h: 00 0D 00 00 00 02 00 0E                         ; ........

 

运行结果如下:


 

 

具体的修改点可以查看下图

 

 

 

 

本站支持 pay for your wishes

  • 大小: 6.8 KB
  • 大小: 145.5 KB
分享到:
评论

相关推荐

    spring-boot aop

    默认情况下,Spring使用基于Java的代理,但对于需要在静态方法或非Spring管理对象上应用AOP的情况,可能需要使用CGLIB或AspectJ字节码代理。 5. **理解代理行为**:理解Spring AOP代理的工作方式很重要,因为这可能...

    Aop配置示例

    在Spring中,AOP主要通过两种方式实现:基于代理的AOP(Proxy-based AOP)和基于ASM字节码操作的AOP(Class-based AOP)。基于代理的AOP通常用于接口,而基于字节码的AOP则可以应用于类。在"SpringAopMvcDemo"中,...

    java字节码例子 可以动态修改类 bcel

    代理类的字节码生成后,可以使用`bcel`的ClassGen和ClassWriter类来构建并写入到Class文件中。 `bcel`库主要包含以下几个关键组件: 1. `ClassPath`:管理类路径,用于查找和加载类文件。 2. `Repository`:存储和...

    反射实现 AOP 动态代理模式(Spring AOP 的实现 原理) - Java 例子 -

    它不仅可以处理接口代理,还可以处理基于类的代理,支持CGLIB库生成字节码实现。此外,Spring AOP还提供了一套强大的切点表达式和注解,使得切点和通知的定义更加简洁直观。 总结来说,Spring AOP通过动态代理实现...

    spring_aop例子

    Spring AOP有两种主要的实现方式:代理模式和AspectJ字节码增强。代理模式包括JDK动态代理和CGLIB代理,适用于接口或无接口的类。AspectJ则是在编译时或运行时通过字节码操作来实现切面,提供更强大的功能。 三、切...

    bytebuddy 字节码增强 创建注解

    在Java开发中,有时我们需要在运行时动态地修改或增强类的行为,这通常是通过字节码操作来实现的。ByteBuddy是一个强大的字节码库,它允许开发者在不使用Java代理(Java Proxy)或者ASM等底层字节码库的情况下,便捷...

    springAop与spring定时器

    基于代理的AOP主要使用JDK动态代理或CGLIB库来创建代理对象,而基于字节码的AOP则使用AspectJ库,可以在编译时或运行时修改字节码来实现切面。 `@Aspect`注解用于定义一个切面,其中可以包含多个通知方法。`@Before...

    Spring 动态代理和aop切面编程例子

    而CGLIB则是通过字节码技术生成一个类的子类来实现代理,因此即使目标类没有接口也能进行代理。Spring会根据目标对象是否实现了接口自动选择合适的代理方式。 AOP,全称Aspect Oriented Programming,是一种编程...

    AOP 的利器 ASM 3.0

    本文将详细介绍一种轻量级的Java字节码操控框架——ASM 3.0,并探讨其如何帮助实现AOP。 #### 什么是ASM? ASM是一个用于动态生成或增强现有Java类的字节码操控框架。它可以被用来直接修改`.class`文件,也可以在...

    java字节码框架ASM操作字节码的方法浅析

    在上面的例子中,当向`Bazhang`类中添加新的`newFunc`方法时,我们需要使用`ClassWriter`来拼接新的字节码。 在实际使用中,你可以创建一个`ClassReader`实例来读取类的字节码,然后使用`accept`方法将解析出的信息...

    SpringBoot第 9 讲:SpringBoot+AOP

    Spring AOP有两种实现方式:代理模式(Proxy-based AOP)和基于ASM的字节码增强(Bytecode-based AOP)。代理模式主要通过JDK动态代理或CGLIB实现,适用于接口或非最终类。字节码增强则在运行时修改类的字节码,...

    spring aop 所需jar包

    2. **aspectjweaver.jar**:AspectJ Weaver,它是AspectJ编译器的一部分,负责在程序加载到JVM之前或运行时进行字节码增强。字节码增强是一种技术,它能够在类加载到JVM之前修改类的字节码,从而实现切面的织入。`...

    使用Javassist对.class文件进行修改.doc

    在给定的例子中,展示了如何使用 Javassist 修改已有的 `.class` 文件中的方法。以下是一些关键知识点: 1. **ClassPool**: `ClassPool` 类是 Javassist 的核心组件,它管理着一系列的 `CtClass` 对象,这些对象...

    SpringAOP 的使用(两种方式)

    CGLIB代理是在运行时动态生成字节码实现的。 #### 2. 基于注解的AOP Spring 2.5引入了基于注解的AOP,简化了配置和使用。主要涉及以下注解: - `@Aspect`:声明一个类为切面,包含通知和切入点。 - `@Before`:...

    AOP的实现机制.pdf

    在实际的AOP实现中,有两个主要的技术:代理模式和字节码操作。 - **代理模式**:通过在目标对象周围创建一个代理对象来实现AOP。当调用目标对象的方法时,代理会先执行通知,然后转发调用给目标对象。Java中的动态...

    spring AspectJ aop学习

    而基于字节码的方式则利用AspectJ的编译器或 weaving agent,在运行时对字节码进行增强,实现切面逻辑。 AspectJ是AOP的一个强大实现,它提供了完整的语言支持,可以定义切面、切点、通知等概念。在Spring中,通过...

    一个牛逼的 Java 字节码类库!(csdn)————程序.pdf

    Java 字节码是Java平台的一种低级表示形式,它是由JVM(Java虚拟机)理解和执行的二进制代码。字节码使得Java程序具有跨平台性,因为不同的操作系统上的JVM可以解析并运行相同的字节码。在Java中,我们可以通过API来...

    java 代理例子 -javaagent,premain方式实现

    Java代理是一种在运行时增强或拦截对象方法调用的技术,它可以让我们在不修改原有代码的情况下,为类添加新的功能或...同时,由于涉及到字节码操作,这部分代码通常比较复杂,需要对Java虚拟机和字节码有一定的理解。

Global site tag (gtag.js) - Google Analytics