maven依赖asm_maven 导入asm的依赖 、 简单入门

本文详细介绍了ASM项目的结构,包括核心项目及其组件。同时,解析了maven依赖asm的配置,指出不应使用asm-all,推荐引入asm-commons和asm-util。还介绍了IDEA中的ASM Bytecode outline和hexview插件,以及ASM的使用示例,包括core API和tree API的示例代码。最后,对比了ASM与bytebuddy,并建议先学习ASM基础。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

asm项目结构

1. 项目结构

1.1. asm的仓库

1.2 核心项目

1.2.1 org.objectweb.asm 和 org.objectweb.asm.signature

1.2.2 org.objectweb.asm.util

1.2.3 org.objectweb.asm.commons

1.2.4 org.objectweb.asm.tree

1.2.5 org.objectweb.asm.tree.analysis

1.3 其他项目

1.3.1 asm-all和asm-parent

1.4 maven依赖 asm的配置

2. IDEA的插件

2.1 ASM Bytecode outline 插件

2.1 hexview插件

3. asm的使用示例

3.1 源码 & 字节码

3.2 访问类的方法和字段

core API

tree API

3.3 添加一个字段

core API

tree API

3.4 新增方法

core API

tree API

3.5 删除字段和方法

core API

tree API

3.6 修改方法

core API

tree API

3.7 AdviceAdapter的使用

core API

tree API

3.8 try-catch

core API

4. bytebuddy的示例

1. 项目结构

1.1. asm的仓库

maven仓库

1.2 核心项目

1.2.1 org.objectweb.asm 和 org.objectweb.asm.signature

包定义了基于事件的API,并提供了类分析器和写入器组件。它们包含在 asm.jar 中。

1.2.2 org.objectweb.asm.util

包,位于asm-util.jar中,提供各种基于核心 API 的工具,可以在开发和调试 ASM 应用程序时使用。

1.2.3 org.objectweb.asm.commons

包提供了几个很有用的预定义类转换器,它们大多是基于核心 API 的。这个包包含在 asm-commons.jar中。

1.2.4 org.objectweb.asm.tree

包,位于asm-tree.jar 存档文件中,定义了基于对 象的 API,并提供了一些工具,用于在基于事件和基于对象的表示方法之间进行转换。

1.2.5 org.objectweb.asm.tree.analysis

包提供了一个类分析框架和几个预定义的 类 分析器,它们以树 API 为基础。这个包包含在 asm-analysis.jar 文件中。

1.3 其他项目

可以看出来1.2描述的几个包和1.1仓库是基本对应的。

但是除了asm-all和asm-parent,与asm-debug等。

1.3.1 asm-all和asm-parent

asm-all包含了asm-parent,asm-parent 包含了所有的依赖。

一般来讲,使用者希望导入一个总的jar,其中包含子项目的jar。但是asm-all目前只停留在version 5.2,而最新子项目版本已经是8.1,不推荐使用。

asm-all 的pom

4.0.0modelVersion>

org.ow2.asmgroupId>

asm-parentartifactId>

5.2version>

parent>

ASM Allname>

org.ow2.asmgroupId>

asm-allartifactId>

jarpackaging>

project>

asm-parent的pom

parent包含了子项目的依赖

asmartifactId>

${project.groupId}groupId>

${project.version}version>

dependency>

asm-treeartifactId>

${project.groupId}groupId>

${project.version}version>

dependency>

asm-analysisartifactId>

${project.groupId}groupId>

${project.version}version>

dependency>

asm-commonsartifactId>

${project.groupId}groupId>

${project.version}version>

dependency>

asm-utilartifactId>

${project.groupId}groupId>

${project.version}version>

dependency>

asm-xmlartifactId>

${project.groupId}groupId>

${project.version}version>

dependency>

dependencies>

dependencyManagement>

1.4 maven依赖 asm的配置

并不推荐使用1.3导入全部,因为版本太老了

这里开发者需要这么引入。asm-commons 和asm-util都包含了,基本的 core api ,tree api, 和analysis

8.0.1asm.version>

properties>

asmartifactId>

org.ow2.asmgroupId>

${asm.version}version>

dependency>

asm-treeartifactId>

org.ow2.asmgroupId>

${asm.version}version>

dependency>

asm-analysisartifactId>

org.ow2.asmgroupId>

${asm.version}version>

dependency>

asm-commonsartifactId>

org.ow2.asmgroupId>

${asm.version}version>

dependency>

asm-utilartifactId>

org.ow2.asmgroupId>

${asm.version}version>

dependency>

asm-xmlartifactId>

org.ow2.asmgroupId>

${asm.version}version>

dependency>

dependencies>

dependencyManagement>

asm-commonsartifactId>

org.ow2.asmgroupId>

${asm.version}version>

dependency>

asm-utilartifactId>

org.ow2.asmgroupId>

${asm.version}version>

dependency>

dependencies>

核心的包都具备了,是版本8.0.1

2. IDEA的插件

装两个插件。

ASM Bytecode outline 与hexview

2.1 ASM Bytecode outline 插件

源码&字节码

等价的ASM API

2.1 hexview插件

仅仅是以16进制显示.class文件

这个是真正的字节码,而asm插件中的字节码,是以人类可读的方式处理过。类似javap

3. asm的使用示例

demo源码

这一步门槛比较高,需要对java 字节码的知识。和ASM 有全面的了解。

java 字节码知识推荐 《深入理解jvm 字节码》和jvm 规范比对着看

ASM 推荐阅读官方指导手册,写的很容易懂。博客里提供了中英两版,比对者看。

《深入理解jvm 字节码》中的例子,使用基于事件的core api 和基于文档模型的tree API。如果具备字节码结构的知识、字节码指令知识、栈帧的模型的知识,去理解下面的例子非常容易,因为对类的加工,本质是增删改查字节码内容而已。

3.1 源码 & 字节码

源码

package com;

public class Application {

public int a = 0;

public int b = 1;

public void test01() {

}

public void test02() {

}

}

字节码

javap -verbose Application.class

编译后的类不包含package和import信息。

Classfile /Users/sunqiyuan/Desktop/Work/mycode/Javadetail/BYTECODE/bytecode/target/classes/com/Application.class

Last modified 2020-6-30; size 464 bytes

MD5 checksum 66668ae198d146acc35018549c757af7

Compiled from "Application.java"

public class com.Application

minor version: 0

major version: 52

flags: ACC_PUBLIC, ACC_SUPER

Constant pool:

#1 = Methodref #5.#20 // java/lang/Object."":()V

#2 = Fieldref #4.#21 // com/Application.a:I

#3 = Fieldref #4.#22 // com/Application.b:I

#4 = Class #23 // com/Application

#5 = Class #24 // java/lang/Object

#6 = Utf8 a

#7 = Utf8 I

#8 = Utf8 b

#9 = Utf8

#10 = Utf8 ()V

#11 = Utf8 Code

#12 = Utf8 LineNumberTable

#13 = Utf8 LocalVariableTable

#14 = Utf8 this

#15 = Utf8 Lcom/Application;

#16 = Utf8 test01

#17 = Utf8 test02

#18 = Utf8 SourceFile

#19 = Utf8 Application.java

#20 = NameAndType #9:#10 // "":()V

#21 = NameAndType #6:#7 // a:I

#22 = NameAndType #8:#7 // b:I

#23 = Utf8 com/Application

#24 = Utf8 java/lang/Object

{

public int a;

descriptor: I

flags: ACC_PUBLIC

public int b;

descriptor: I

flags: ACC_PUBLIC

public com.Application();

descriptor: ()V

flags: ACC_PUBLIC

Code:

stack=2, locals=1, args_size=1

0: aload_0

1: invokespecial #1 // Method java/lang/Object."":()V

4: aload_0

5: iconst_0

6: putfield #2 // Field a:I

9: aload_0

10: iconst_1

11: putfield #3 // Field b:I

14: return

LineNumberTable:

line 3: 0

line 4: 4

line 5: 9

LocalVariableTable:

Start Length Slot Name Signature

0 15 0 this Lcom/Application;

public void test01();

descriptor: ()V

flags: ACC_PUBLIC

Code:

stack=0, locals=1, args_size=1

0: return

LineNumberTable:

line 9: 0

LocalVariableTable:

Start Length Slot Name Signature

0 1 0 this Lcom/Application;

public void test02();

descriptor: ()V

flags: ACC_PUBLIC

Code:

stack=0, locals=1, args_size=1

0: return

LineNumberTable:

line 13: 0

LocalVariableTable:

Start Length Slot Name Signature

0 1 0 this Lcom/Application;

}

SourceFile: "Application.java"

3.2 访问类的方法和字段

core API

接受编译过的Application.class的byte[]。ClassVisitor中覆盖FieldVisitor和MethodVisitor方法,进行了方法和field的打印。

本类中ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG跳过对debug信息和方法Code属性的访问。

package com;

import org.objectweb.asm.*;

import static jdk.internal.org.objectweb.asm.Opcodes.ASM5;

/**

* 访问类的方法和区域

*/

public class B_visitContent extends ClassLoader {

public void visitByCoreAPI() throws Exception {

ClassReader cr = Tool.getClassReader();

// 使用 new ClassWriter(0) 时,不会自动计算任何东西。必须自行计算帧、局部变量与操作数栈的大小

ClassWriter cw = new ClassWriter(0);

ClassVisitor cv = new ClassVisitor(ASM5, cw) {

@Override

public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {

System.out.println("field in visitor: " + name);

return super.visitField(access, name, descriptor, signature, value);

}

@Override

public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {

System.out.println("method in visitor: " + name);

return super.visitMethod(access, name, descriptor, signature, exceptions);

}

};

/*

ClassReader.SKIP_DEBUG 跳过类文件中的调试信息,比如行号信息(LineNumberTable)

ClassReader.SKIP_CODE 跳过方法体中的Code属性,比如(方法字节码、异常表等信息)

ClassReader.SKIP_DEBUG 展开StackMapTable属性

ClassReader.SKIP_DEBUG 跳过StackMapTable属性

*/

cr.accept(cv, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG);

}

public static void main(String[] args) throws Exception{

new B_visitContent().visitByCoreAPI();

}

}

打印结果

field in visitor: a

field in visitor: b

method in visitor: method in visitor: test01

method in visitor: test02

tree API

等同于上面的例子

package com;

import org.objectweb.asm.*;

import org.objectweb.asm.tree.ClassNode;

import org.objectweb.asm.tree.FieldNode;

import org.objectweb.asm.tree.MethodNode;

import java.util.List;

import static jdk.internal.org.objectweb.asm.Opcodes.ASM5;

/**

* 访问类的方法和区域

*/

public class B_visitContent extends ClassLoader {

public void visitByTreeAPI() throws Exception {

ClassReader cr = Tool.getClassReader();

// 使用 new ClassWriter(0) 时,不会自动计算任何东西。必须自行计算帧、局部变量与操作数栈的大小

ClassNode cn = new ClassNode();

/*

ClassReader.SKIP_DEBUG 跳过类文件中的调试信息,比如行号信息(LineNumberTable)

ClassReader.SKIP_CODE 跳过方法体中的Code属性,比如(方法字节码、异常表等信息)

ClassReader.SKIP_DEBUG 展开StackMapTable属性

ClassReader.SKIP_DEBUG 跳过StackMapTable属性

*/

cr.accept(cn, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG);

List fields = cn.fields;

for (int i = 0; i

FieldNode fn = fields.get(i);

System.out.println("field in visitor: " + fn.name);

}

List methods = cn.methods;

for (int i = 0; i

MethodNode mn = methods.get(i);

System.out.println("method in visitor: " + mn.name);

}

// 写,非必要

ClassWriter cw = new ClassWriter(0);

cr.accept(cw,0);

byte[] bytesModified = cw.toByteArray();

}

public static void main(String[] args) throws Exception{

new B_visitContent().visitByTreeAPI();

}

}

打印

field in visitor: a

field in visitor: b

method in visitor:

method in visitor: test01

method in visitor: test02

3.3 添加一个字段

为Application.class添加一个public String name= "demo";字段。通过打印class文件,来展示修改

core API

核心的操作是visitField()+visitEnd()

package com;

import org.objectweb.asm.*;

import static org.objectweb.asm.Opcodes.ASM5;

public class C_addField {

public void addFieldByCoreAPI() throws Exception {

ClassReader cr = Tool.getClassReader();

ClassWriter cw = new ClassWriter(0);

ClassVisitor cv = new ClassVisitor(ASM5, cw) {

@Override

public void visitEnd() {

// visitEnd是访问类,访问的最后一个事件。在这个事件前添加变量就可以

super.visitEnd();

/**

* field的模板 public Listlist = null;

*

* Opcodes.ACC_PUBLIC public 权限标志

* "name" 变量名

* "Ljava/lang/String" 变量返回值。字节码中,类型都是以L开头+类的全名(用/代替.)

* null 泛型的标识

* "demo" 值

*/

FieldVisitor fv = cv.visitField(Opcodes.ACC_PUBLIC, "name", "Ljava/lang/String;", null, "demo");

if (fv != null) {

System.out.println("add");

fv.visitEnd();

}

}

};

//cr.accept(cv,ClassReader.SKIP_CODE|ClassReader.SKIP_DEBUG);

cr.accept(cv,0);

byte[] bytesModifield = cw.toByteArray();

Tool.save(this.getClass(),Application.class,bytesModifield);

}

public void addFiledByTreeAPI() {

}

public static void main(String[] args) throws Exception {

new C_addField().addFieldByCoreAPI();

}

}

字节码

javap -verbose C_addField_Application.class

可以看到有name字段出现

Classfile /Users/sunqiyuan/Desktop/Work/mycode/Javadetail/BYTECODE/bytecode/target/classes/com/C_addField_Application.class

Last modified 2020-7-1; size 3150 bytes

MD5 checksum 906f08c3db7beb47033fa2b8c176d9c7

Compiled from "Application.java"

public class com.Application

minor version: 0

major version: 52

flags: ACC_PUBLIC, ACC_SUPER

Constant pool:

#1 = Utf8 com/Application

#2 = Class #1 // com/Application

#3 = Utf8 java/lang/Object

#4 = Class #3 // java/lang/Object

#5 = Utf8 Application.java

#6 = Utf8 a

#7 = Utf8 I

#8 = Utf8 b

#9 = Utf8

#10 = Utf8 ()V

#11 = NameAndType #9:#10 // "":()V

#12 = Methodref #4.#11 // java/lang/Object."":()V

#13 = NameAndType #6:#7 // a:I

#14 = Fieldref #2.#13 // com/Application.a:I

#15 = NameAndType #8:#7 // b:I

#16 = Fieldref #2.#15 // com/Application.b:I

#17 = Utf8 this

#18 = Utf8 Lcom/Application;

#19 = Utf8 test01

#20 = Utf8 test02

#21 = Utf8 name

#22 = Utf8 Ljava/lang/String;

#23 = Utf8 demo

#24 = String #23 // demo

#25 = Utf8 ConstantValue

#26 = Utf8 Code

#27 = Utf8 LineNumberTable

#28 = Utf8 LocalVariableTable

#29 = Utf8 SourceFile

{

public int a;

descriptor: I

flags: ACC_PUBLIC

public int b;

descriptor: I

flags: ACC_PUBLIC

// 就是里

public java.lang.String name;

descriptor: Ljava/lang/String;

flags: ACC_PUBLIC

ConstantValue: String demo

public com.Application();

descriptor: ()V

flags: ACC_PUBLIC

Code:

stack=2, locals=1, args_size=1

0: aload_0

1: invokespecial #12 // Method java/lang/Object."":()V

4: aload_0

5: iconst_0

6: putfield #14 // Field a:I

9: aload_0

10: iconst_1

11: putfield #16 // Field b:I

14: return

LineNumberTable:

line 3: 0

line 4: 4

line 5: 9

LocalVariableTable:

Start Length Slot Name Signature

0 15 0 this Lcom/Application;

public void test01();

descriptor: ()V

flags: ACC_PUBLIC

Code:

stack=0, locals=1, args_size=1

0: return

LineNumberTable:

line 9: 0

LocalVariableTable:

Start Length Slot Name Signature

0 1 0 this Lcom/Application;

public void test02();

descriptor: ()V

flags: ACC_PUBLIC

Code:

stack=0, locals=1, args_size=1

0: return

LineNumberTable:

line 13: 0

LocalVariableTable:

Start Length Slot Name Signature

0 1 0 this Lcom/Application;

}

SourceFile: "Application.java"

tree API

使用起来更简单,输出的字节码等同上面。

package com;

import org.objectweb.asm.*;

import org.objectweb.asm.tree.ClassNode;

import org.objectweb.asm.tree.FieldNode;

import static org.objectweb.asm.Opcodes.ASM5;

public class C_addField {

public void addFiledByTreeAPI() throws Exception {

ClassReader cr = Tool.getClassReader();

ClassNode cn = new ClassNode();

cr.accept(cn,ASM5);

// 新的field

FieldNode fn = new FieldNode(Opcodes.ACC_PUBLIC,"name","Ljava/lang/String;",null,"demo");

cn.fields.add(fn);

//

ClassWriter cw =new ClassWriter(0);

cn.accept(cw);

byte[] bytesModified = cw.toByteArray();

Tool.save(this.getClass(),Application.class,bytesModified);

}

public static void main(String[] args) throws Exception {

new C_addField().addFiledByTreeAPI();

}

}

字节码

等同于core

3.4 新增方法

为Application.java添加一个方法public void hello(int age, int name)。

core API

核心的方法是visitMethod

package com;

import org.objectweb.asm.*;

import org.objectweb.asm.tree.ClassNode;

import org.objectweb.asm.tree.FieldNode;

import static org.objectweb.asm.Opcodes.ASM5;

public class D_addMethod {

public void addMethodByCoreAPI() throws Exception {

ClassReader cr = Tool.getClassReader();

ClassWriter cw = new ClassWriter(0);

ClassVisitor cv = new ClassVisitor(ASM5, cw) {

@Override

public void visitEnd() {

// visitEnd是访问类,访问的最后一个事件。在这个事件前添加变量就可以

super.visitEnd();

/**

* method的模板 public Listhello(int i );

*

* Opcodes.ACC_PUBLIC public 权限标志

* "hello" 变量名

* "(ILjava/lang/String;)V" 方法类型, ()代表参数:I int 'Ljava/lang/String;' String ; V代表返回值void

* null 泛型的标识

* null 异常数组

*/

MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC, "hello", "(ILjava/lang/String;)V", null, null);

if (mv != null) {

mv.visitEnd();

}

}

};

//cr.accept(cv,ClassReader.SKIP_CODE|ClassReader.SKIP_DEBUG);

cr.accept(cv, 0);

byte[] bytesModifield = cw.toByteArray();

Tool.save(this.getClass(), Application.class, bytesModifield);

}

public static void main(String[] args) throws Exception {

new D_addMethod().addMethodByCoreAPI();

}

}

字节码

新增了hello方法

Classfile /Users/sunqiyuan/Desktop/Work/mycode/Javadetail/BYTECODE/bytecode/target/classes/com/D_addMethod_Application.class

Last modified 2020-7-1; size 505 bytes

MD5 checksum 9ce9e7b87f84dd4a8df95f4e4407eea5

Compiled from "Application.java"

public class com.Application

minor version: 0

major version: 52

flags: ACC_PUBLIC, ACC_SUPER

Constant pool:

#1 = Utf8 com/Application

#2 = Class #1 // com/Application

#3 = Utf8 java/lang/Object

#4 = Class #3 // java/lang/Object

#5 = Utf8 Application.java

#6 = Utf8 a

#7 = Utf8 I

#8 = Utf8 b

#9 = Utf8

#10 = Utf8 ()V

#11 = NameAndType #9:#10 // "":()V

#12 = Methodref #4.#11 // java/lang/Object."":()V

#13 = NameAndType #6:#7 // a:I

#14 = Fieldref #2.#13 // com/Application.a:I

#15 = NameAndType #8:#7 // b:I

#16 = Fieldref #2.#15 // com/Application.b:I

#17 = Utf8 this

#18 = Utf8 Lcom/Application;

#19 = Utf8 test01

#20 = Utf8 test02

#21 = Utf8 hello

#22 = Utf8 (ILjava/lang/String;)V

#23 = Utf8 Code

#24 = Utf8 LineNumberTable

#25 = Utf8 LocalVariableTable

#26 = Utf8 SourceFile

{

public int a;

descriptor: I

flags: ACC_PUBLIC

public int b;

descriptor: I

flags: ACC_PUBLIC

public com.Application();

descriptor: ()V

flags: ACC_PUBLIC

Code:

stack=2, locals=1, args_size=1

0: aload_0

1: invokespecial #12 // Method java/lang/Object."":()V

4: aload_0

5: iconst_0

6: putfield #14 // Field a:I

9: aload_0

10: iconst_1

11: putfield #16 // Field b:I

14: return

LineNumberTable:

line 3: 0

line 4: 4

line 5: 9

LocalVariableTable:

Start Length Slot Name Signature

0 15 0 this Lcom/Application;

public void test01();

descriptor: ()V

flags: ACC_PUBLIC

Code:

stack=0, locals=1, args_size=1

0: return

LineNumberTable:

line 9: 0

LocalVariableTable:

Start Length Slot Name Signature

0 1 0 this Lcom/Application;

public void test02();

descriptor: ()V

flags: ACC_PUBLIC

Code:

stack=0, locals=1, args_size=1

0: return

LineNumberTable:

line 13: 0

LocalVariableTable:

Start Length Slot Name Signature

0 1 0 this Lcom/Application;

// hello

public void hello(int, java.lang.String);

descriptor: (ILjava/lang/String;)V

flags: ACC_PUBLIC

}

SourceFile: "Application.java"

tree API

package com;

import org.objectweb.asm.*;

import org.objectweb.asm.tree.ClassNode;

import org.objectweb.asm.tree.MethodNode;

import static org.objectweb.asm.Opcodes.ASM5;

public class D_addMethod {

public void addMethodByTreeAPI() throws Exception {

ClassReader cr = Tool.getClassReader();

ClassNode cn = new ClassNode();

cr.accept(cn, ASM5);

// 新的field

MethodNode fn = new MethodNode(Opcodes.ACC_PUBLIC, "hello", "(ILjava/lang/String;)V", null, null);

cn.methods.add(fn);

// 打印

ClassWriter cw = new ClassWriter(0);

cn.accept(cw);

byte[] bytesModified = cw.toByteArray();

Tool.save(this.getClass(), Application.class, bytesModified);

}

public static void main(String[] args) throws Exception {

new D_addMethod().addMethodByCoreAPI();

}

}

字节码

等同于core

3.5 删除字段和方法

core API

删除public int a = 0 和public void test01()。直接返回null即可。

package com;

import org.objectweb.asm.*;

import org.objectweb.asm.tree.ClassNode;

import org.objectweb.asm.tree.MethodNode;

import static org.objectweb.asm.Opcodes.ASM5;

public class E_removeContent {

public void removeContentByCoreAPI() throws Exception {

ClassReader cr = Tool.getClassReader();

ClassWriter cw = new ClassWriter(0);

ClassVisitor cv = new ClassVisitor(ASM5, cw) {

@Override

public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {

if (name.equals("a")) {

return null;

}

return super.visitField(access, name, descriptor, signature, value);

}

@Override

public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {

if (name.equals("test01")) {

return null;

}

return super.visitMethod(access, name, descriptor, signature, exceptions);

}

};

//cr.accept(cv,ClassReader.SKIP_CODE|ClassReader.SKIP_DEBUG);

cr.accept(cv, 0);

byte[] bytesModifield = cw.toByteArray();

Tool.save(this.getClass(), Application.class, bytesModifield);

}

public static void main(String[] args) throws Exception {

new E_removeContent().removeContentByCoreAPI();

}

}

字节码

Classfile /Users/sunqiyuan/Desktop/Work/mycode/Javadetail/BYTECODE/bytecode/target/classes/com/E_removeContent_Application.class

Last modified 2020-7-1; size 390 bytes

MD5 checksum 3ad649468cd26da2758944804ce99b0b

Compiled from "Application.java"

public class com.Application

minor version: 0

major version: 52

flags: ACC_PUBLIC, ACC_SUPER

Constant pool:

#1 = Utf8 com/Application

#2 = Class #1 // com/Application

#3 = Utf8 java/lang/Object

#4 = Class #3 // java/lang/Object

#5 = Utf8 Application.java

#6 = Utf8 b

#7 = Utf8 I

#8 = Utf8

#9 = Utf8 ()V

#10 = NameAndType #8:#9 // "":()V

#11 = Methodref #4.#10 // java/lang/Object."":()V

#12 = Utf8 a

#13 = NameAndType #12:#7 // a:I

#14 = Fieldref #2.#13 // com/Application.a:I

#15 = NameAndType #6:#7 // b:I

#16 = Fieldref #2.#15 // com/Application.b:I

#17 = Utf8 this

#18 = Utf8 Lcom/Application;

#19 = Utf8 test02

#20 = Utf8 Code

#21 = Utf8 LineNumberTable

#22 = Utf8 LocalVariableTable

#23 = Utf8 SourceFile

{

public int b;

descriptor: I

flags: ACC_PUBLIC

public com.Application();

descriptor: ()V

flags: ACC_PUBLIC

Code:

stack=2, locals=1, args_size=1

0: aload_0

1: invokespecial #11 // Method java/lang/Object."":()V

4: aload_0

5: iconst_0

6: putfield #14 // Field a:I

9: aload_0

10: iconst_1

11: putfield #16 // Field b:I

14: return

LineNumberTable:

line 3: 0

line 4: 4

line 5: 9

LocalVariableTable:

Start Length Slot Name Signature

0 15 0 this Lcom/Application;

public void test02();

descriptor: ()V

flags: ACC_PUBLIC

Code:

stack=0, locals=1, args_size=1

0: return

LineNumberTable:

line 13: 0

LocalVariableTable:

Start Length Slot Name Signature

0 1 0 this Lcom/Application;

}

SourceFile: "Application.java"

tree API

package com;

import org.objectweb.asm.*;

import org.objectweb.asm.tree.ClassNode;

import org.objectweb.asm.tree.FieldNode;

import org.objectweb.asm.tree.MethodNode;

import java.util.List;

import static org.objectweb.asm.Opcodes.ASM5;

public class E_removeContent {

public void removeContentByTreeAPI() throws Exception {

ClassReader cr = Tool.getClassReader();

ClassNode cn = new ClassNode();

cr.accept(cn, ASM5);

// 删除 a

List fields = cn.fields;

for (int i = 0; i < fields.size(); i++) {

FieldNode fn = fields.get(i);

if("a".equals(fn.name)){

fields.remove(fn);

}

}

// 删除 method

List methods = cn.methods;

for (int i = 0; i < methods.size(); i++) {

MethodNode mn = methods.get(i);

if("test01".equals(mn.name)){

methods.remove(mn);

}

}

// 打印

ClassWriter cw = new ClassWriter(0);

cn.accept(cw);

byte[] bytesModified = cw.toByteArray();

Tool.save(this.getClass(), Application.class, bytesModified);

}

public static void main(String[] args) throws Exception {

new E_removeContent().removeContentByTreeAPI();

}

}

3.6 修改方法

public void test01()

修改为

public int test01(int n) {

test02();

return a + b + n ;

}

注意修改方法的区别是,Code属性中包含字节码指令,还要计算操作数栈栈深,和本地变量。所以Code属性以visitCode开始,和visitEnd是结束,调用visitMaxs会自动计算栈大小。

这里困难的是Code属性的操作,不过不用担心,前面的插件有用。

core API

package com;

import org.objectweb.asm.*;

import org.objectweb.asm.tree.ClassNode;

import org.objectweb.asm.tree.FieldNode;

import org.objectweb.asm.tree.MethodNode;

import java.util.List;

import static org.objectweb.asm.Opcodes.ASM5;

public class F_modifyMethod {

public void modifyMethodByCoreAPI() throws Exception {

ClassReader cr = Tool.getClassReader();

ClassWriter cw = new ClassWriter(0);

ClassVisitor cv = new ClassVisitor(ASM5, cw) {

@Override

public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {

if (name.equals("test01")) {

MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC, name, "(I)I", null, exceptions);

mv.visitCode();

mv.visitVarInsn(Opcodes.ALOAD, 0);

mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "com/Application", "test02", "()V", false);

mv.visitVarInsn(Opcodes.ALOAD, 0);

mv.visitFieldInsn(Opcodes.GETFIELD, "com/Application", "a", "I");

mv.visitVarInsn(Opcodes.ALOAD, 0);

mv.visitFieldInsn(Opcodes.GETFIELD, "com/Application", "b", "I");

mv.visitInsn(Opcodes.IADD);

mv.visitVarInsn(Opcodes.ILOAD, 1);

mv.visitInsn(Opcodes.IADD);

mv.visitInsn(Opcodes.IRETURN);

mv.visitMaxs(2, 2);

mv.visitEnd();

return mv;

}

return super.visitMethod(access, name, descriptor, signature, exceptions);

}

};

//cr.accept(cv,ClassReader.SKIP_CODE|ClassReader.SKIP_DEBUG);

cr.accept(cv, 0);

byte[] bytesModifield = cw.toByteArray();

Tool.save(this.getClass(), Application.class, bytesModifield);

}

public static void main(String[] args) throws Exception {

new F_modifyMethod().modifyMethodByCoreAPI();

}

}

字节码

Classfile /Users/sunqiyuan/Desktop/Work/mycode/Javadetail/BYTECODE/bytecode/target/classes/com/F_modifyMethod_Application.class

Last modified 2020-7-1; size 497 bytes

MD5 checksum 9791aab52aff864e3abc02c4d8fb65b3

Compiled from "Application.java"

public class com.Application

minor version: 0

major version: 52

flags: ACC_PUBLIC, ACC_SUPER

Constant pool:

#1 = Utf8 com/Application

#2 = Class #1 // com/Application

#3 = Utf8 java/lang/Object

#4 = Class #3 // java/lang/Object

#5 = Utf8 Application.java

#6 = Utf8 a

#7 = Utf8 I

#8 = Utf8 b

#9 = Utf8

#10 = Utf8 ()V

#11 = NameAndType #9:#10 // "":()V

#12 = Methodref #4.#11 // java/lang/Object."":()V

#13 = NameAndType #6:#7 // a:I

#14 = Fieldref #2.#13 // com/Application.a:I

#15 = NameAndType #8:#7 // b:I

#16 = Fieldref #2.#15 // com/Application.b:I

#17 = Utf8 this

#18 = Utf8 Lcom/Application;

#19 = Utf8 test01

#20 = Utf8 (I)I

#21 = Utf8 test02

#22 = NameAndType #21:#10 // test02:()V

#23 = Methodref #2.#22 // com/Application.test02:()V

#24 = Utf8 Code

#25 = Utf8 LineNumberTable

#26 = Utf8 LocalVariableTable

#27 = Utf8 SourceFile

{

public int a;

descriptor: I

flags: ACC_PUBLIC

public int b;

descriptor: I

flags: ACC_PUBLIC

public com.Application();

descriptor: ()V

flags: ACC_PUBLIC

Code:

stack=2, locals=1, args_size=1

0: aload_0

1: invokespecial #12 // Method java/lang/Object."":()V

4: aload_0

5: iconst_0

6: putfield #14 // Field a:I

9: aload_0

10: iconst_1

11: putfield #16 // Field b:I

14: return

LineNumberTable:

line 3: 0

line 4: 4

line 5: 9

LocalVariableTable:

Start Length Slot Name Signature

0 15 0 this Lcom/Application;

public int test01(int);

descriptor: (I)I

flags: ACC_PUBLIC

Code:

stack=0, locals=1, args_size=2

0: aload_0

1: invokevirtual #23 // Method test02:()V

4: aload_0

5: getfield #14 // Field a:I

8: aload_0

9: getfield #16 // Field b:I

12: iadd

13: iload_1

14: iadd

15: ireturn

16: return

LineNumberTable:

line 9: 16

LocalVariableTable:

Start Length Slot Name Signature

16 1 0 this Lcom/Application;

public void test02();

descriptor: ()V

flags: ACC_PUBLIC

Code:

stack=0, locals=1, args_size=1

0: return

LineNumberTable:

line 13: 0

LocalVariableTable:

Start Length Slot Name Signature

0 1 0 this Lcom/Application;

}

SourceFile: "Application.java"

用反编译软件查看,符合预期。

package com;

public class Application {

public int a = 0;

public int b = 1;

public Application() {

}

public int test01(int var1) {

this.test02();

return this.a + this.b + var1;

}

public void test02() {

}

}

tree API

package com;

import org.objectweb.asm.*;

import org.objectweb.asm.tree.ClassNode;

import org.objectweb.asm.tree.MethodNode;

import java.util.List;

import static org.objectweb.asm.Opcodes.ASM5;

public class F_modifyMethod {

public void modifyMethodByTreeAPI() throws Exception {

ClassReader cr = Tool.getClassReader();

ClassNode cn = new ClassNode();

cr.accept(cn, ASM5);

//new 方法

MethodNode newmn = new MethodNode(Opcodes.ACC_PUBLIC, "test01", "(I)I", null, null);

newmn.visitCode();

newmn.visitVarInsn(Opcodes.ALOAD, 0);

newmn.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "com/Application", "test02", "()V", false);

newmn.visitVarInsn(Opcodes.ALOAD, 0);

newmn.visitFieldInsn(Opcodes.GETFIELD, "com/Application", "a", "I");

newmn.visitVarInsn(Opcodes.ALOAD, 0);

newmn.visitFieldInsn(Opcodes.GETFIELD, "com/Application", "b", "I");

newmn.visitInsn(Opcodes.IADD);

newmn.visitVarInsn(Opcodes.ILOAD, 1);

newmn.visitInsn(Opcodes.IADD);

newmn.visitInsn(Opcodes.IRETURN);

newmn.visitMaxs(2, 2);

newmn.visitEnd();

// 替换

List methods = cn.methods;

for (int i = 0; i < methods.size(); i++) {

MethodNode mn = methods.get(i);

if ("test01".equals(mn.name)) {

methods.set(i,newmn);

break;

}

}

// 打印

ClassWriter cw = new ClassWriter(0);

cn.accept(cw);

byte[] bytesModified = cw.toByteArray();

Tool.save(this.getClass(), Application.class, bytesModified);

}

public static void main(String[] args) throws Exception {

new F_modifyMethod().modifyMethodByTreeAPI();

}

}

3.7 AdviceAdapter的使用

AdviceAdapter是一个抽象类,继承自MethodVisitor,可以很方便的在方法前和方法后插入代码。核心的两个方法如下

onMethodEnter方法开始或者构造器方法中父类的构造器调用以后被回调

onMethodExit:正常退出和异常退出时被调用。正常退出指的是遇到RETURN、ARETURN、LRETURN等方法正常返回的情况。异常退出指的是遇到ATHROW指令,有异常抛出方法返回的情况。比如opcode == Opcodes.ATHROW

现在就是为方法调用添加进入和退出方法时的打印。

原始方法

public void test01() {

System.out.println("mid");

}

修改后

public void test01() {

System.out.println("enter method");

System.out.println("mid");

System.out.println("out method -- normal ");

}

core API

package com;

import org.objectweb.asm.*;

import org.objectweb.asm.commons.AdviceAdapter;

import org.objectweb.asm.tree.ClassNode;

import org.objectweb.asm.tree.MethodNode;

import java.util.List;

import static org.objectweb.asm.Opcodes.ASM5;

import static org.objectweb.asm.Opcodes.ASM7;

public class G_adviceMethod {

public void adviceMethodByCoreAPI() throws Exception {

ClassReader cr = Tool.getClassReader();

ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);

ClassVisitor cv = new ClassVisitor(ASM7, cw) {

@Override

public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {

MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);

if (!"test01".equals(name)) {

return mv;

}

// 修改test01 进入方法

return new AdviceAdapter(ASM7, mv, access, name, descriptor) {

@Override

protected void onMethodEnter() {

super.onMethodEnter();

mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");

mv.visitLdcInsn("enter method");

mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);

}

// 退出方法

@Override

protected void onMethodExit(int opcode) {

super.onMethodExit(opcode);

mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");

// 异常

if (opcode == Opcodes.ATHROW) {

mv.visitLdcInsn("out method -- exception");

} else {

mv.visitLdcInsn("out method -- normal ");

}

mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);

}

};

}

};

//cr.accept(cv,ClassReader.SKIP_CODE|ClassReader.SKIP_DEBUG);

cr.accept(cv, 0);

byte[] bytesModifield = cw.toByteArray();

Tool.save(this.getClass(), Application.class, bytesModifield);

}

public static void main(String[] args) throws Exception {

G_adviceMethod advice = new G_adviceMethod();

// 修改方法

advice.adviceMethodByCoreAPI();

// 调用类

new Application().test01();

}

}

bytecode

开始和结束加入了额外的方法

Classfile /Users/sunqiyuan/Desktop/Work/mycode/Javadetail/BYTECODE/bytecode/target/classes/com/G_adviceMethod_Application.class

Last modified 2020-7-1; size 773 bytes

MD5 checksum 0700ead97bf0b298541bce4618de4e4e

Compiled from "Application.java"

public class com.Application

minor version: 0

major version: 52

flags: ACC_PUBLIC, ACC_SUPER

Constant pool:

#1 = Utf8 com/Application

#2 = Class #1 // com/Application

#3 = Utf8 java/lang/Object

#4 = Class #3 // java/lang/Object

#5 = Utf8 Application.java

#6 = Utf8 a

#7 = Utf8 I

#8 = Utf8 b

#9 = Utf8

#10 = Utf8 ()V

#11 = NameAndType #9:#10 // "":()V

#12 = Methodref #4.#11 // java/lang/Object."":()V

#13 = NameAndType #6:#7 // a:I

#14 = Fieldref #2.#13 // com/Application.a:I

#15 = NameAndType #8:#7 // b:I

#16 = Fieldref #2.#15 // com/Application.b:I

#17 = Utf8 this

#18 = Utf8 Lcom/Application;

#19 = Utf8 test01

#20 = Utf8 java/lang/System

#21 = Class #20 // java/lang/System

#22 = Utf8 out

#23 = Utf8 Ljava/io/PrintStream;

#24 = NameAndType #22:#23 // out:Ljava/io/PrintStream;

#25 = Fieldref #21.#24 // java/lang/System.out:Ljava/io/PrintStream;

#26 = Utf8 enter method

#27 = String #26 // enter method

#28 = Utf8 java/io/PrintStream

#29 = Class #28 // java/io/PrintStream

#30 = Utf8 println

#31 = Utf8 (Ljava/lang/String;)V

#32 = NameAndType #30:#31 // println:(Ljava/lang/String;)V

#33 = Methodref #29.#32 // java/io/PrintStream.println:(Ljava/lang/String;)V

#34 = Utf8 mid

#35 = String #34 // mid

#36 = Utf8 out method -- normal

#37 = String #36 // out method -- normal

#38 = Utf8 test02

#39 = Utf8 Code

#40 = Utf8 LineNumberTable

#41 = Utf8 LocalVariableTable

#42 = Utf8 SourceFile

{

public int a;

descriptor: I

flags: ACC_PUBLIC

public int b;

descriptor: I

flags: ACC_PUBLIC

public com.Application();

descriptor: ()V

flags: ACC_PUBLIC

Code:

stack=2, locals=1, args_size=1

0: aload_0

1: invokespecial #12 // Method java/lang/Object."":()V

4: aload_0

5: iconst_0

6: putfield #14 // Field a:I

9: aload_0

10: iconst_1

11: putfield #16 // Field b:I

14: return

LineNumberTable:

line 3: 0

line 4: 4

line 5: 9

LocalVariableTable:

Start Length Slot Name Signature

0 15 0 this Lcom/Application;

public void test01();

descriptor: ()V

flags: ACC_PUBLIC

Code:

stack=2, locals=1, args_size=1

0: getstatic #25 // Field java/lang/System.out:Ljava/io/PrintStream;

3: ldc #27 // String enter method

5: invokevirtual #33 // Method java/io/PrintStream.println:(Ljava/lang/String;)V

8: getstatic #25 // Field java/lang/System.out:Ljava/io/PrintStream;

11: ldc #35 // String mid

13: invokevirtual #33 // Method java/io/PrintStream.println:(Ljava/lang/String;)V

16: getstatic #25 // Field java/lang/System.out:Ljava/io/PrintStream;

19: ldc #37 // String out method -- normal

21: invokevirtual #33 // Method java/io/PrintStream.println:(Ljava/lang/String;)V

24: return

LineNumberTable:

line 8: 8

line 9: 16

LocalVariableTable:

Start Length Slot Name Signature

8 17 0 this Lcom/Application;

public void test02();

descriptor: ()V

flags: ACC_PUBLIC

Code:

stack=0, locals=1, args_size=1

0: return

LineNumberTable:

line 13: 0

LocalVariableTable:

Start Length Slot Name Signature

0 1 0 this Lcom/Application;

}

SourceFile: "Application.java"

ring;)V

40: getstatic #25 // Field java/lang/System.out:Ljava/io/PrintStream;

43: ldc #27 // String enter method

45: invokevirtual #33 // Method java/io/PrintStream.println:(Ljava/lang/String;)V

48: getstatic #25 // Field java/lang/System.out:Ljava/io/PrintStream;

51: ldc #27 // String enter method

53: invokevirtual #33 // Method java/io/PrintStream.println:(Ljava/lang/String;)V

56: getstatic #25 // Field java/lang/System.out:Ljava/io/PrintStream;

59: ldc #35 // String mid

61: invokevirtual #33 // Method java/io/PrintStream.println:(Ljava/lang/String;)V

64: getstatic #25 // Field java/lang/System.out:Ljava/io/PrintStream;

67: ldc #37 // String out method -- normal

69: invokevirtual #33 // Method java/io/PrintStream.println:(Ljava/lang/String;)V

72: getstatic #25 // Field java/lang/System.out:Ljava/io/PrintStream;

75: ldc #37 // String out method -- normal

77: invokevirtual #33 // Method java/io/PrintStream.println:(Ljava/lang/String;)V

80: getstatic #25 // Field java/lang/System.out:Ljava/io/PrintStream;

83: ldc #37 // String out method -- normal

85: invokevirtual #33 // Method java/io/PrintStream.println:(Ljava/lang/String;)V

88: getstatic #25 // Field java/lang/System.out:Ljava/io/PrintStream;

91: ldc #37 // String out method -- normal

93: invokevirtual #33 // Method java/io/PrintStream.println:(Ljava/lang/String;)V

96: getstatic #25 // Field java/lang/System.out:Ljava/io/PrintStream;

99: ldc #37 // String out method -- normal

101: invokevirtual #33 // Method java/io/PrintStream.println:(Ljava/lang/String;)V

104: getstatic #25 // Field java/lang/System.out:Ljava/io/PrintStream;

107: ldc #37 // String out method -- normal

109: invokevirtual #33 // Method java/io/PrintStream.println:(Ljava/lang/String;)V

112: getstatic #25 // Field java/lang/System.out:Ljava/io/PrintStream;

115: ldc #37 // String out method -- normal

117: invokevirtual #33 // Method java/io/PrintStream.println:(Ljava/lang/String;)V

120: return

LineNumberTable:

line 8: 56

line 9: 64

LocalVariableTable:

Start Length Slot Name Signature

56 65 0 this Lcom/Application;

public void test02();

descriptor: ()V

flags: ACC_PUBLIC

Code:

stack=0, locals=1, args_size=1

0: return

LineNumberTable:

line 13: 0

LocalVariableTable:

Start Length Slot Name Signature

0 1 0 this Lcom/Application;

}

SourceFile: "Application.java"

tree API

涉及MethodVisitor和MethodNode的相互转换。比较麻烦coreAPI比较简单

3.8 try-catch

很显然上一个小节的代码无法在代码抛出未捕获异常时输出err quit,比如把foo代码做细微修改,如下所示。

public void test01() {

System.out.println("step 1");

int a = 1 / 0;

System.out.println("step 2");

}

经过上个例子的字节码改写以后,执行的结果输出如下所示。

java -cp . Application

enter method

step 1

Exception in thread "main" java.lang.ArithmeticException: / by zero

at Application.test01(Application.java:24)

at Application.main(Application.java:8)

可以看到并没有如期输出“error exit foo”,因为在字节码中并没有出现显式的ATHROW指令抛出异常,自然无法添加相应的输出语句。为了达到这个效果,需要把方法体用try/finally语句块包裹起来。

这里需要介绍ASM的Label类,与它的英文含义一样,可以给字节码指令地址打标签,标记特定的字节码位置,用于后续跳转等。新增一个Label可以用MethodVisitor的visitLabel方法,如下所示。

Label startLabel = new Label();

mv.visitLabel(startLabel);

前面章节介绍过,JVM的异常处理是通过异常表来实现的,try-catch-finally语句块实际上是标定了异常处理的范围。ASM中可以用visitTryCatchBlock方法来给一段代码块增加异常表,它的方法签名如下所示。

public void visitTryCatchBlock(Label start, Label end, Label handler, String type)

其中start、end表示异常表开始和结束的位置,handler表示异常发生后需要跳转到哪里继续执行,可以理解为catch语句块开始的位置,type是异常的类型。

为了给整个方法体包裹try-catch语句,start Label应该放在方法visitCode之后,end Label则放在visitMaxs调用之前,代码如下所示。

core API

源码

public void test01() {

System.out.println("mid");

}

结果

public void test01() {

try {

System.out.println("enter method");

System.out.println("mid");

System.out.println("normal exit method");

} catch (Throwable var2) {

System.out.println("error exit method");

throw var2;

}

}

实现

package com;

import org.objectweb.asm.*;

import org.objectweb.asm.commons.AdviceAdapter;

import static org.objectweb.asm.Opcodes.ASM7;

public class H_addTrycatch {

public void addTrycatchByCoreAPI() throws Exception {

ClassReader cr = Tool.getClassReader();

ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);

ClassVisitor cv = new ClassVisitor(ASM7, cw) {

@Override

public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {

MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);

if (!"test01".equals(name)) {

return mv;

}

// 开始的标签

// 修改test01 进入方法

return new AdviceAdapter(ASM7, mv, access, name, descriptor) {

Label startLabel = new Label();

Label endLable = new Label();

@Override

protected void onMethodEnter() {

super.onMethodEnter();

// mark start

mv.visitLabel(startLabel);

mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");

mv.visitLdcInsn("enter method");

mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);

}

@Override

public void visitMaxs(int maxStack, int maxLocals) {

// // mark end

Label endLable = new Label();

// /**

// * startLabel 开始的标签

// * endLable 结束的标签

// * endLable 跳转的位置

// */

mv.visitTryCatchBlock(startLabel, endLable, endLable, null);

mv.visitLabel(endLable);

// // 打印异常

finallyBlock(Opcodes.ATHROW);

// // 抛出异常

mv.visitInsn(ATHROW);

super.visitMaxs(maxStack, maxLocals);

}

private void finallyBlock(int opcode) {

mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");

if (opcode == Opcodes.ATHROW) {

mv.visitLdcInsn("error exit method");

} else {

mv.visitLdcInsn("normal exit method");

}

mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);

}

// 退出方法

@Override

protected void onMethodExit(int opcode) {

super.onMethodExit(opcode);

finallyBlock(opcode);

}

};

}

};

//cr.accept(cv,ClassReader.SKIP_CODE|ClassReader.SKIP_DEBUG);

cr.accept(cv, 0);

byte[] bytesModifield = cw.toByteArray();

Tool.save(this.getClass(), Application.class, bytesModifield);

}

public static void main(String[] args) throws Exception {

H_addTrycatch tc = new H_addTrycatch();

// 修改方法

tc.addTrycatchByCoreAPI();

// 调用类

new Application().test01();

}

}

字节码

Classfile /Users/sunqiyuan/Desktop/Work/mycode/Javadetail/BYTECODE/bytecode/target/classes/com/H_addTrycatch_Application.class

Last modified 2020-7-1; size 767 bytes

MD5 checksum d0368db93d0ee61fa5b689cc76356c0a

Compiled from "Application.java"

public class com.Application

minor version: 0

major version: 52

flags: ACC_PUBLIC, ACC_SUPER

Constant pool:

#1 = Utf8 com/Application

#2 = Class #1 // com/Application

#3 = Utf8 java/lang/Object

#4 = Class #3 // java/lang/Object

#5 = Utf8 Application.java

#6 = Utf8 a

#7 = Utf8 I

#8 = Utf8 b

#9 = Utf8

#10 = Utf8 ()V

#11 = NameAndType #9:#10 // "":()V

#12 = Methodref #4.#11 // java/lang/Object."":()V

#13 = NameAndType #6:#7 // a:I

#14 = Fieldref #2.#13 // com/Application.a:I

#15 = NameAndType #8:#7 // b:I

#16 = Fieldref #2.#15 // com/Application.b:I

#17 = Utf8 this

#18 = Utf8 Lcom/Application;

#19 = Utf8 test01

#20 = Utf8 java/lang/System

#21 = Class #20 // java/lang/System

#22 = Utf8 out

#23 = Utf8 Ljava/io/PrintStream;

#24 = NameAndType #22:#23 // out:Ljava/io/PrintStream;

#25 = Fieldref #21.#24 // java/lang/System.out:Ljava/io/PrintStream;

#26 = Utf8 enter method

#27 = String #26 // enter method

#28 = Utf8 java/io/PrintStream

#29 = Class #28 // java/io/PrintStream

#30 = Utf8 println

#31 = Utf8 (Ljava/lang/String;)V

#32 = NameAndType #30:#31 // println:(Ljava/lang/String;)V

#33 = Methodref #29.#32 // java/io/PrintStream.println:(Ljava/lang/String;)V

#34 = Utf8 mid

#35 = String #34 // mid

#36 = Utf8 normal exit method

#37 = String #36 // normal exit method

#38 = Utf8 error exit method

#39 = String #38 // error exit method

#40 = Utf8 java/lang/Throwable

#41 = Class #40 // java/lang/Throwable

#42 = Utf8 test02

#43 = Utf8 Code

#44 = Utf8 LineNumberTable

#45 = Utf8 LocalVariableTable

#46 = Utf8 StackMapTable

#47 = Utf8 SourceFile

{

public int a;

descriptor: I

flags: ACC_PUBLIC

public int b;

descriptor: I

flags: ACC_PUBLIC

public com.Application();

descriptor: ()V

flags: ACC_PUBLIC

Code:

stack=2, locals=1, args_size=1

0: aload_0

1: invokespecial #12 // Method java/lang/Object."":()V

4: aload_0

5: iconst_0

6: putfield #14 // Field a:I

9: aload_0

10: iconst_1

11: putfield #16 // Field b:I

14: return

LineNumberTable:

line 3: 0

line 4: 4

line 5: 9

LocalVariableTable:

Start Length Slot Name Signature

0 15 0 this Lcom/Application;

public void test01();

descriptor: ()V

flags: ACC_PUBLIC

Code:

stack=3, locals=1, args_size=1

0: getstatic #25 // Field java/lang/System.out:Ljava/io/PrintStream;

3: ldc #27 // String enter method

5: invokevirtual #33 // Method java/io/PrintStream.println:(Ljava/lang/String;)V

8: getstatic #25 // Field java/lang/System.out:Ljava/io/PrintStream;

11: ldc #35 // String mid

13: invokevirtual #33 // Method java/io/PrintStream.println:(Ljava/lang/String;)V

16: getstatic #25 // Field java/lang/System.out:Ljava/io/PrintStream;

19: ldc #37 // String normal exit method

21: invokevirtual #33 // Method java/io/PrintStream.println:(Ljava/lang/String;)V

24: return

25: getstatic #25 // Field java/lang/System.out:Ljava/io/PrintStream;

28: ldc #39 // String error exit method

30: invokevirtual #33 // Method java/io/PrintStream.println:(Ljava/lang/String;)V

33: athrow

Exception table:

from to target type

0 25 25 any

StackMapTable: number_of_entries = 1

frame_type = 89 /* same_locals_1_stack_item */

stack = [ class java/lang/Throwable ]

LineNumberTable:

line 8: 8

line 9: 16

LocalVariableTable:

Start Length Slot Name Signature

8 17 0 this Lcom/Application;

public void test02();

descriptor: ()V

flags: ACC_PUBLIC

Code:

stack=0, locals=1, args_size=1

0: return

LineNumberTable:

line 13: 0

LocalVariableTable:

Start Length Slot Name Signature

0 1 0 this Lcom/Application;

}

SourceFile: "Application.java"

4. bytebuddy的示例

直接看bytebuddy官网用处不大,介绍文档还是比较简陋的。我是文档和源码比对者读的。

bytebuddy是基于ASM写的一个工具。也是用来对类进行加工的。很多API的模型继承与ASM,直接阅读bytebuddy官方文档和源码是十分费解的。建议先学习ASM。

下面用bytebuddy演示一个等价的例子。

运行后报错:"C:\Program Files\Java\jdk-11\bin\java.exe" -XX:TieredStopAtLevel=1 -noverify -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dspring.jmx.enabled=true -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true "-Dmanagement.endpoints.jmx.exposure.include=*" "-javaagent:D:\IntelliJ IDEA 2023.2.5\lib\idea_rt.jar=7344:D:\IntelliJ IDEA 2023.2.5\bin" -Dfile.encoding=UTF-8 -classpath D:\A-work\cas-sso-demo\cas-server\target\classes;D:\IDEA\maven\maven_repository\org\apereo\cas\cas-server-webapp\6.6.14\cas-server-webapp-6.6.14.war;D:\IDEA\maven\maven_repository\org\apereo\cas\cas-server-support-jdbc\6.6.14\cas-server-support-jdbc-6.6.14.jar;D:\IDEA\maven\maven_repository\javax\xml\bind\jaxb-api\2.3.1\jaxb-api-2.3.1.jar;D:\IDEA\maven\maven_repository\javax\xml\ws\jaxws-api\2.3.1\jaxws-api-2.3.1.jar;D:\IDEA\maven\maven_repository\org\glassfish\main\javaee-api\javax.jws\3.1.2.2\javax.jws-3.1.2.2.jar;D:\IDEA\maven\maven_repository\org\glassfish\main\javaee-api\javax.jms\3.1.2.2\javax.jms-3.1.2.2.jar;D:\IDEA\maven\maven_repository\javax\xml\soap\javax.xml.soap-api\1.4.0\javax.xml.soap-api-1.4.0.jar;D:\IDEA\maven\maven_repository\org\glassfish\jaxb\jaxb-runtime\2.3.6\jaxb-runtime-2.3.6.jar;D:\IDEA\maven\maven_repository\com\sun\istack\istack-commons-runtime\4.1.1\istack-commons-runtime-4.1.1.jar;D:\IDEA\maven\maven_repository\io\swagger\core\v3\swagger-annotations\2.2.2\swagger-annotations-2.2.2.jar;D:\IDEA\maven\maven_repository\org\slf4j\slf4j-api\1.7.36\slf4j-api-1.7.36.jar;D:\IDEA\maven\maven_repository\org\slf4j\jul-to-slf4j\1.7.36\jul-to-slf4j-1.7.36.jar;D:\IDEA\maven\maven_repository\com\google\guava\guava\30.1.1-jre\guava-30.1.1-jre.jar;D:\IDEA\maven\maven_repository\com\google\guava\failureaccess\1.0.1\failureaccess-1.0.1.jar;D:\IDEA\maven\maven_repository\com\google\guava\listenablefuture\9999.0-empty-to-avoid-conflict-with-guava\listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar;D:\IDEA\maven\maven_repository\com\google\code\findbugs\jsr305\3.0.2\jsr305-3.0.2.jar;D:\IDEA\maven\maven_repository\org\checkerframework\checker-qual\3.8.0\checker-qual-3.8.0.jar;D:\IDEA\maven\maven_repository\com\google\j2objc\j2objc-annotations\1.3\j2objc-annotations-1.3.jar;D:\IDEA\maven\maven_repository\de\cronn\reflection-util\2.14.0\reflection-util-2.14.0.jar;D:\IDEA\maven\maven_repository\net\bytebuddy\byte-buddy\1.12.12\byte-buddy-1.12.12.jar;D:\IDEA\maven\maven_repository\org\objenesis\objenesis\3.2\objenesis-3.2.jar;D:\IDEA\maven\maven_repository\org\springmodules\spring-modules-cache\0.8\spring-modules-cache-0.8.jar;D:\IDEA\maven\maven_repository\commons-attributes\commons-attributes-api\2.1\commons-attributes-api-2.1.jar;D:\IDEA\maven\maven_repository\qdox\qdox\1.5\qdox-1.5.jar;D:\IDEA\maven\maven_repository\commons-attributes\commons-attributes-compiler\2.1\commons-attributes-compiler-2.1.jar;D:\IDEA\maven\maven_repository\concurrent\concurrent\1.3.4\concurrent-1.3.4.jar;D:\IDEA\maven\maven_repository\cglib\cglib-nodep\2.1_3\cglib-nodep-2.1_3.jar;D:\IDEA\maven\maven_repository\geronimo-spec\geronimo-spec-jta\1.0.1B-rc4\geronimo-spec-jta-1.0.1B-rc4.jar;D:\IDEA\maven\maven_repository\opensymphony\oscache\2.1.1\oscache-2.1.1.jar;D:\IDEA\maven\maven_repository\oro\oro\2.0.8\oro-2.0.8.jar;D:\IDEA\maven\maven_repository\commons-io\commons-io\2.11.0\commons-io-2.11.0.jar;D:\IDEA\maven\maven_repository\org\apache\commons\commons-jexl3\3.2.1\commons-jexl3-3.2.1.jar;D:\IDEA\maven\maven_repository\org\apache\commons\commons-text\1.10.0\commons-text-1.10.0.jar;D:\IDEA\maven\maven_repository\org\apache\commons\commons-pool2\2.11.1\commons-pool2-2.11.1.jar;D:\IDEA\maven\maven_repository\commons-cli\commons-cli\1.5.0\commons-cli-1.5.0.jar;D:\IDEA\maven\maven_repository\commons-beanutils\commons-beanutils\1.9.4\commons-beanutils-1.9.4.jar;D:\IDEA\maven\maven_repository\commons-validator\commons-validator\1.7\commons-validator-1.7.jar;D:\IDEA\maven\maven_repository\commons-codec\commons-codec\1.15\commons-codec-1.15.jar;D:\IDEA\maven\maven_repository\org\apache\commons\commons-lang3\3.12.0\commons-lang3-3.12.0.jar;D:\IDEA\maven\maven_repository\commons-lang\commons-lang\2.6\commons-lang-2.6.jar;D:\IDEA\maven\maven_repository\org\jooq\jool\0.9.14\jool-0.9.14.jar;D:\IDEA\maven\maven_repository\commons-collections\commons-collections\3.2.2\commons-collections-3.2.2.jar;D:\IDEA\maven\maven_repository\org\apache\commons\commons-collections4\4.4\commons-collections4-4.4.jar;D:\IDEA\maven\maven_repository\org\apereo\inspektr\inspektr-audit\1.8.21.GA\inspektr-audit-1.8.21.GA.jar;D:\IDEA\maven\maven_repository\org\apereo\inspektr\inspektr-common\1.8.21.GA\inspektr-common-1.8.21.GA.jar;D:\IDEA\maven\maven_repository\org\apereo\inspektr\inspektr-support-spring\1.8.21.GA\inspektr-support-spring-1.8.21.GA.jar;D:\IDEA\maven\maven_repository\org\apereo\service\persondir\person-directory-impl\2.0.13\person-directory-impl-2.0.13.jar;D:\IDEA\maven\maven_repository\aopalliance\aopalliance\1.0\aopalliance-1.0.jar;D:\IDEA\maven\maven_repository\org\apereo\service\persondir\person-directory-api\2.0.13\person-directory-api-2.0.13.jar;D:\IDEA\maven\maven_repository\com\microsoft\alm\oauth2-useragent\0.11.3\oauth2-useragent-0.11.3.jar;D:\IDEA\maven\maven_repository\org\springframework\spring-aop\5.3.22\spring-aop-5.3.22.jar;D:\IDEA\maven\maven_repository\org\springframework\spring-beans\5.3.22\spring-beans-5.3.22.jar;D:\IDEA\maven\maven_repository\org\springframework\spring-context\5.3.22\spring-context-5.3.22.jar;D:\IDEA\maven\maven_repository\org\springframework\spring-context-support\5.3.22\spring-context-support-5.3.22.jar;D:\IDEA\maven\maven_repository\org\springframework\retry\spring-retry\1.3.3\spring-retry-1.3.3.jar;D:\IDEA\maven\maven_repository\org\springframework\spring-core\5.3.22\spring-core-5.3.22.jar;D:\IDEA\maven\maven_repository\org\springframework\spring-jcl\5.3.22\spring-jcl-5.3.22.jar;D:\IDEA\maven\maven_repository\org\springframework\data\spring-data-commons\2.7.2\spring-data-commons-2.7.2.jar;D:\IDEA\maven\maven_repository\org\springframework\spring-jms\5.3.22\spring-jms-5.3.22.jar;D:\IDEA\maven\maven_repository\org\springframework\spring-messaging\5.3.22\spring-messaging-5.3.22.jar;D:\IDEA\maven\maven_repository\org\springframework\spring-expression\5.3.22\spring-expression-5.3.22.jar;D:\IDEA\maven\maven_repository\org\springframework\spring-jdbc\5.3.22\spring-jdbc-5.3.22.jar;D:\IDEA\maven\maven_repository\org\springframework\spring-orm\5.3.22\spring-orm-5.3.22.jar;D:\IDEA\maven\maven_repository\org\springframework\spring-tx\5.3.22\spring-tx-5.3.22.jar;D:\IDEA\maven\maven_repository\org\springframework\spring-web\5.3.22\spring-web-5.3.22.jar;D:\IDEA\maven\maven_repository\org\springframework\spring-webmvc\5.3.22\spring-webmvc-5.3.22.jar;D:\IDEA\maven\maven_repository\com\fasterxml\jackson\core\jackson-databind\2.13.4\jackson-databind-2.13.4.jar;D:\IDEA\maven\maven_repository\com\fasterxml\jackson\core\jackson-core\2.13.4\jackson-core-2.13.4.jar;D:\IDEA\maven\maven_repository\com\fasterxml\jackson\datatype\jackson-datatype-guava\2.13.4\jackson-datatype-guava-2.13.4.jar;D:\IDEA\maven\maven_repository\com\fasterxml\jackson\core\jackson-annotations\2.13.4\jackson-annotations-2.13.4.jar;D:\IDEA\maven\maven_repository\com\fasterxml\jackson\jaxrs\jackson-jaxrs-json-provider\2.13.4\jackson-jaxrs-json-provider-2.13.4.jar;D:\IDEA\maven\maven_repository\com\fasterxml\jackson\jaxrs\jackson-jaxrs-base\2.13.4\jackson-jaxrs-base-2.13.4.jar;D:\IDEA\maven\maven_repository\com\fasterxml\jackson\module\jackson-module-jaxb-annotations\2.13.4\jackson-module-jaxb-annotations-2.13.4.jar;D:\IDEA\maven\maven_repository\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.13.4\jackson-datatype-jsr310-2.13.4.jar;D:\IDEA\maven\maven_repository\com\fasterxml\jackson\module\jackson-module-parameter-names\2.13.4\jackson-module-parameter-names-2.13.4.jar;D:\IDEA\maven\maven_repository\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.13.4\jackson-datatype-jdk8-2.13.4.jar;D:\IDEA\maven\maven_repository\org\hjson\hjson\3.0.1\hjson-3.0.1.jar;D:\IDEA\maven\maven_repository\com\fasterxml\jackson\dataformat\jackson-dataformat-yaml\2.13.4\jackson-dataformat-yaml-2.13.4.jar;D:\IDEA\maven\maven_repository\com\fasterxml\jackson\dataformat\jackson-dataformat-xml\2.13.4\jackson-dataformat-xml-2.13.4.jar;D:\IDEA\maven\maven_repository\org\codehaus\woodstox\stax2-api\4.2.1\stax2-api-4.2.1.jar;D:\IDEA\maven\maven_repository\com\fasterxml\woodstox\woodstox-core\6.3.1\woodstox-core-6.3.1.jar;D:\IDEA\maven\maven_repository\com\fasterxml\jackson\dataformat\jackson-dataformat-properties\2.13.4\jackson-dataformat-properties-2.13.4.jar;D:\IDEA\maven\maven_repository\org\apache\httpcomponents\httpclient\4.5.13\httpclient-4.5.13.jar;D:\IDEA\maven\maven_repository\org\apache\httpcomponents\httpcore\4.4.15\httpcore-4.4.15.jar;D:\IDEA\maven\maven_repository\org\quartz-scheduler\quartz\2.3.2\quartz-2.3.2.jar;D:\IDEA\maven\maven_repository\com\mchange\mchange-commons-java\0.2.15\mchange-commons-java-0.2.15.jar;D:\IDEA\maven\maven_repository\org\apache\bval\bval-jsr\2.0.6\bval-jsr-2.0.6.jar;D:\IDEA\maven\maven_repository\javax\persistence\javax.persistence-api\2.2\javax.persistence-api-2.2.jar;D:\IDEA\maven\maven_repository\org\apache\groovy\groovy-jsr223\4.0.4\groovy-jsr223-4.0.4.jar;D:\IDEA\maven\maven_repository\org\apache\groovy\groovy-json\4.0.4\groovy-json-4.0.4.jar;D:\IDEA\maven\maven_repository\org\apache\groovy\groovy-xml\4.0.4\groovy-xml-4.0.4.jar;D:\IDEA\maven\maven_repository\org\apache\groovy\groovy\4.0.4\groovy-4.0.4.jar;D:\IDEA\maven\maven_repository\org\apache\groovy\groovy-datetime\4.0.4\groovy-datetime-4.0.4.jar;D:\IDEA\maven\maven_repository\org\apache\groovy\groovy-templates\4.0.4\groovy-templates-4.0.4.jar;D:\IDEA\maven\maven_repository\org\apache\groovy\groovy-sql\4.0.4\groovy-sql-4.0.4.jar;D:\IDEA\maven\maven_repository\org\apache\groovy\groovy-groovysh\4.0.4\groovy-groovysh-4.0.4.jar;D:\IDEA\maven\maven_repository\jline\jline\2.14.6\jline-2.14.6.jar;D:\IDEA\maven\maven_repository\com\github\ben-manes\caffeine\caffeine\3.1.1\caffeine-3.1.1.jar;D:\IDEA\maven\maven_repository\com\google\errorprone\error_prone_annotations\2.14.0\error_prone_annotations-2.14.0.jar;D:\IDEA\maven\maven_repository\com\github\ben-manes\caffeine\guava\3.1.1\guava-3.1.1.jar;D:\IDEA\maven\maven_repository\org\springframework\cloud\spring-cloud-starter-bootstrap\3.1.3\spring-cloud-starter-bootstrap-3.1.3.jar;D:\IDEA\maven\maven_repository\org\springframework\cloud\spring-cloud-starter\3.1.3\spring-cloud-starter-3.1.3.jar;D:\IDEA\maven\maven_repository\org\springframework\cloud\spring-cloud-commons\3.1.3\spring-cloud-commons-3.1.3.jar;D:\IDEA\maven\maven_repository\org\springframework\cloud\spring-cloud-context\3.1.3\spring-cloud-context-3.1.3.jar;D:\IDEA\maven\maven_repository\org\springframework\boot\spring-boot-starter-aop\2.7.3\spring-boot-starter-aop-2.7.3.jar;D:\IDEA\maven\maven_repository\org\springframework\boot\spring-boot-starter-web\2.7.3\spring-boot-starter-web-2.7.3.jar;D:\IDEA\maven\maven_repository\org\springframework\boot\spring-boot-autoconfigure\2.7.3\spring-boot-autoconfigure-2.7.3.jar;D:\IDEA\maven\maven_repository\org\springframework\boot\spring-boot\2.7.3\spring-boot-2.7.3.jar;D:\IDEA\maven\maven_repository\org\springframework\boot\spring-boot-properties-migrator\2.7.3\spring-boot-properties-migrator-2.7.3.jar;D:\IDEA\maven\maven_repository\org\springframework\boot\spring-boot-configuration-metadata\2.7.3\spring-boot-configuration-metadata-2.7.3.jar;D:\IDEA\maven\maven_repository\org\springframework\boot\spring-boot-starter-actuator\2.7.3\spring-boot-starter-actuator-2.7.3.jar;D:\IDEA\maven\maven_repository\org\springframework\boot\spring-boot-actuator-autoconfigure\2.7.3\spring-boot-actuator-autoconfigure-2.7.3.jar;D:\IDEA\maven\maven_repository\io\micrometer\micrometer-core\1.9.3\micrometer-core-1.9.3.jar;D:\IDEA\maven\maven_repository\org\hdrhistogram\HdrHistogram\2.1.12\HdrHistogram-2.1.12.jar;D:\IDEA\maven\maven_repository\org\latencyutils\LatencyUtils\2.0.3\LatencyUtils-2.0.3.jar;D:\IDEA\maven\maven_repository\org\springframework\boot\spring-boot-starter-validation\2.7.3\spring-boot-starter-validation-2.7.3.jar;D:\IDEA\maven\maven_repository\org\springframework\boot\spring-boot-actuator\2.7.3\spring-boot-actuator-2.7.3.jar;D:\IDEA\maven\maven_repository\org\springframework\security\spring-security-core\5.7.3\spring-security-core-5.7.3.jar;D:\IDEA\maven\maven_repository\org\springframework\security\spring-security-rsa\1.0.11.RELEASE\spring-security-rsa-1.0.11.RELEASE.jar;D:\IDEA\maven\maven_repository\org\springframework\security\spring-security-cas\5.7.3\spring-security-cas-5.7.3.jar;D:\IDEA\maven\maven_repository\org\springframework\security\spring-security-web\5.7.3\spring-security-web-5.7.3.jar;D:\IDEA\maven\maven_repository\org\springframework\integration\spring-integration-core\5.5.14\spring-integration-core-5.5.14.jar;D:\IDEA\maven\maven_repository\io\projectreactor\reactor-core\3.4.21\reactor-core-3.4.21.jar;D:\IDEA\maven\maven_repository\org\reactivestreams\reactive-streams\1.0.4\reactive-streams-1.0.4.jar;D:\IDEA\maven\maven_repository\org\springframework\integration\spring-integration-jmx\5.5.14\spring-integration-jmx-5.5.14.jar;D:\IDEA\maven\maven_repository\org\springframework\webflow\spring-webflow\2.5.1.RELEASE\spring-webflow-2.5.1.RELEASE.jar;D:\IDEA\maven\maven_repository\org\springframework\webflow\spring-binding\2.5.1.RELEASE\spring-binding-2.5.1.RELEASE.jar;D:\IDEA\maven\maven_repository\javax\el\javax.el-api\3.0.0\javax.el-api-3.0.0.jar;D:\IDEA\maven\maven_repository\org\glassfish\web\el-impl\2.2\el-impl-2.2.jar;D:\IDEA\maven\maven_repository\javax\servlet\javax.servlet-api\4.0.1\javax.servlet-api-4.0.1.jar;D:\IDEA\maven\maven_repository\javax\annotation\javax.annotation-api\1.3.2\javax.annotation-api-1.3.2.jar;D:\IDEA\maven\maven_repository\org\aspectj\aspectjrt\1.9.9.1\aspectjrt-1.9.9.1.jar;D:\IDEA\maven\maven_repository\org\aspectj\aspectjweaver\1.9.9.1\aspectjweaver-1.9.9.1.jar;D:\IDEA\maven\maven_repository\javax\validation\validation-api\2.0.1.Final\validation-api-2.0.1.Final.jar;D:\IDEA\maven\maven_repository\org\apereo\cas\cas-server-core-authentication-api\6.6.14\cas-server-core-authentication-api-6.6.14.jar;D:\IDEA\maven\maven_repository\org\apereo\cas\cas-server-core-api-services\6.6.14\cas-server-core-api-services-6.6.14.jar;D:\IDEA\maven\maven_repository\org\apereo\cas\cas-server-core-api-ticket\6.6.14\cas-server-core-api-ticket-6.6.14.jar;D:\IDEA\maven\maven_repository\org\apereo\cas\cas-server-core-authentication-mfa-api\6.6.14\cas-server-core-authentication-mfa-api-6.6.14.jar;D:\IDEA\maven\maven_repository\org\apereo\cas\cas-server-core-configuration-api\6.6.14\cas-server-core-configuration-api-6.6.14.jar;D:\IDEA\maven\maven_repository\org\yaml\snakeyaml\1.31\snakeyaml-1.31.jar;D:\IDEA\maven\maven_repository\org\apereo\cas\cas-server-core-util-api\6.6.14\cas-server-core-util-api-6.6.14.jar;D:\IDEA\maven\maven_repository\org\apereo\cas\cas-server-core-api-configuration-model\6.6.14\cas-server-core-api-configuration-model-6.6.14.jar;D:\IDEA\maven\maven_repository\org\springframework\boot\spring-boot-configuration-processor\2.7.3\spring-boot-configuration-processor-2.7.3.jar;D:\IDEA\maven\maven_repository\org\jsoup\jsoup\1.15.3\jsoup-1.15.3.jar;D:\IDEA\maven\maven_repository\org\json\json\20160810\json-20160810.jar;D:\IDEA\maven\maven_repository\org\apereo\cas\cas-server-core-api-mfa\6.6.14\cas-server-core-api-mfa-6.6.14.jar;D:\IDEA\maven\maven_repository\org\apereo\cas\cas-server-core-api-web\6.6.14\cas-server-core-api-web-6.6.14.jar;D:\IDEA\maven\maven_repository\org\bitbucket\b_c\jose4j\0.8.0\jose4j-0.8.0.jar;D:\IDEA\maven\maven_repository\org\pac4j\pac4j-config\5.4.6\pac4j-config-5.4.6.jar;D:\IDEA\maven\maven_repository\org\pac4j\pac4j-javaee\5.4.6\pac4j-javaee-5.4.6.jar;D:\IDEA\maven\maven_repository\org\pac4j\pac4j-http\5.4.6\pac4j-http-5.4.6.jar;D:\IDEA\maven\maven_repository\org\pac4j\pac4j-core\5.4.6\pac4j-core-5.4.6.jar;D:\IDEA\maven\maven_repository\org\pac4j\spring-webmvc-pac4j\6.0.3\spring-webmvc-pac4j-6.0.3.jar;D:\IDEA\maven\maven_repository\com\nimbusds\nimbus-jose-jwt\9.24.3\nimbus-jose-jwt-9.24.3.jar;D:\IDEA\maven\maven_repository\com\nimbusds\oauth2-oidc-sdk\9.42\oauth2-oidc-sdk-9.42.jar;D:\IDEA\maven\maven_repository\com\nimbusds\content-type\2.2\content-type-2.2.jar;D:\IDEA\maven\maven_repository\com\nimbusds\lang-tag\1.7\lang-tag-1.7.jar;D:\IDEA\maven\maven_repository\net\minidev\json-smart\2.4.9\json-smart-2.4.9.jar;D:\IDEA\maven\maven_repository\net\minidev\accessors-smart\2.4.9\accessors-smart-2.4.9.jar;D:\IDEA\maven\maven_repository\org\ow2\asm\asm\9.3\asm-9.3.jar;D:\IDEA\maven\maven_repository\com\github\stephenc\jcip\jcip-annotations\1.0-1\jcip-annotations-1.0-1.jar;D:\IDEA\maven\maven_repository\com\vdurmont\semver4j\3.1.0\semver4j-3.1.0.jar;D:\IDEA\maven\maven_repository\com\github\oshi\oshi-core\6.2.2\oshi-core-6.2.2.jar;D:\IDEA\maven\maven_repository\org\apache\velocity\velocity-engine-core\2.3\velocity-engine-core-2.3.jar;D:\IDEA\maven\maven_repository\org\apereo\cas\cas-server-support-jdbc-authentication\6.6.14\cas-server-support-jdbc-authentication-6.6.14.jar;D:\IDEA\maven\maven_repository\org\apache\shiro\shiro-core\1.9.1\shiro-core-1.9.1.jar;D:\IDEA\maven\maven_repository\org\apache\shiro\shiro-lang\1.9.1\shiro-lang-1.9.1.jar;D:\IDEA\maven\maven_repository\org\apache\shiro\shiro-cache\1.9.1\shiro-cache-1.9.1.jar;D:\IDEA\maven\maven_repository\org\apache\shiro\shiro-crypto-hash\1.9.1\shiro-crypto-hash-1.9.1.jar;D:\IDEA\maven\maven_repository\org\apache\shiro\shiro-crypto-core\1.9.1\shiro-crypto-core-1.9.1.jar;D:\IDEA\maven\maven_repository\org\apache\shiro\shiro-crypto-cipher\1.9.1\shiro-crypto-cipher-1.9.1.jar;D:\IDEA\maven\maven_repository\org\apache\shiro\shiro-config-core\1.9.1\shiro-config-core-1.9.1.jar;D:\IDEA\maven\maven_repository\org\apache\shiro\shiro-config-ogdl\1.9.1\shiro-config-ogdl-1.9.1.jar;D:\IDEA\maven\maven_repository\org\apache\shiro\shiro-event\1.9.1\shiro-event-1.9.1.jar;D:\IDEA\maven\maven_repository\org\apereo\cas\cas-server-support-jpa-util\6.6.14\cas-server-support-jpa-util-6.6.14.jar;D:\IDEA\maven\maven_repository\com\zaxxer\HikariCP\5.0.1\HikariCP-5.0.1.jar;D:\IDEA\maven\maven_repository\org\apereo\cas\cas-server-support-jdbc-drivers\6.6.14\cas-server-support-jdbc-drivers-6.6.14.jar;D:\IDEA\maven\maven_repository\org\apereo\cas\cas-server-core-api\6.6.14\cas-server-core-api-6.6.14.jar;D:\IDEA\maven\maven_repository\org\hsqldb\hsqldb\2.7.0\hsqldb-2.7.0.jar;D:\IDEA\maven\maven_repository\org\postgresql\postgresql\42.5.0\postgresql-42.5.0.jar;D:\IDEA\maven\maven_repository\org\mariadb\jdbc\mariadb-java-client\3.0.7\mariadb-java-client-3.0.7.jar;D:\IDEA\maven\maven_repository\net\sourceforge\jtds\jtds\1.3.1\jtds-1.3.1.jar;D:\IDEA\maven\maven_repository\com\microsoft\sqlserver\mssql-jdbc\10.2.1.jre11\mssql-jdbc-10.2.1.jre11.jar;D:\IDEA\maven\maven_repository\com\oracle\ojdbc\ojdbc10\19.3.0.0\ojdbc10-19.3.0.0.jar;D:\IDEA\maven\maven_repository\com\oracle\ojdbc\ucp\19.3.0.0\ucp-19.3.0.0.jar;D:\IDEA\maven\maven_repository\com\oracle\ojdbc\oraclepki\19.3.0.0\oraclepki-19.3.0.0.jar;D:\IDEA\maven\maven_repository\com\oracle\ojdbc\osdt_cert\19.3.0.0\osdt_cert-19.3.0.0.jar;D:\IDEA\maven\maven_repository\com\oracle\ojdbc\osdt_core\19.3.0.0\osdt_core-19.3.0.0.jar;D:\IDEA\maven\maven_repository\com\oracle\ojdbc\simplefan\19.3.0.0\simplefan-19.3.0.0.jar;D:\IDEA\maven\maven_repository\com\oracle\ojdbc\ons\19.3.0.0\ons-19.3.0.0.jar;D:\IDEA\maven\maven_repository\com\h2database\h2\1.4.197\h2-1.4.197.jar;D:\IDEA\maven\maven_repository\org\apereo\cas\cas-server-support-redis-ticket-registry\6.6.14\cas-server-support-redis-ticket-registry-6.6.14.jar;D:\IDEA\maven\maven_repository\org\apereo\cas\cas-server-core-api-util\6.6.14\cas-server-core-api-util-6.6.14.jar;D:\IDEA\maven\maven_repository\io\github\classgraph\classgraph\4.8.149\classgraph-4.8.149.jar;D:\IDEA\maven\maven_repository\org\springframework\data\spring-data-redis\2.7.2\spring-data-redis-2.7.2.jar;D:\IDEA\maven\maven_repository\org\springframework\data\spring-data-keyvalue\2.7.2\spring-data-keyvalue-2.7.2.jar;D:\IDEA\maven\maven_repository\org\springframework\spring-oxm\5.3.22\spring-oxm-5.3.22.jar;D:\IDEA\maven\maven_repository\org\springframework\integration\spring-integration-redis\5.5.14\spring-integration-redis-5.5.14.jar;D:\IDEA\maven\maven_repository\io\lettuce\lettuce-core\6.2.0.RELEASE\lettuce-core-6.2.0.RELEASE.jar;D:\IDEA\maven\maven_repository\io\netty\netty-common\4.1.79.Final\netty-common-4.1.79.Final.jar;D:\IDEA\maven\maven_repository\io\netty\netty-handler\4.1.79.Final\netty-handler-4.1.79.Final.jar;D:\IDEA\maven\maven_repository\io\netty\netty-resolver\4.1.79.Final\netty-resolver-4.1.79.Final.jar;D:\IDEA\maven\maven_repository\io\netty\netty-buffer\4.1.79.Final\netty-buffer-4.1.79.Final.jar;D:\IDEA\maven\maven_repository\io\netty\netty-transport-native-unix-common\4.1.79.Final\netty-transport-native-unix-common-4.1.79.Final.jar;D:\IDEA\maven\maven_repository\io\netty\netty-codec\4.1.79.Final\netty-codec-4.1.79.Final.jar;D:\IDEA\maven\maven_repository\io\netty\netty-transport\4.1.79.Final\netty-transport-4.1.79.Final.jar;D:\IDEA\maven\maven_repository\org\apereo\cas\cas-server-core-logging\6.6.14\cas-server-core-logging-6.6.14.jar;D:\IDEA\maven\maven_repository\org\apereo\cas\cas-server-core-api-cookie\6.6.14\cas-server-core-api-cookie-6.6.14.jar;D:\IDEA\maven\maven_repository\org\apereo\cas\cas-server-core-logging-api\6.6.14\cas-server-core-logging-api-6.6.14.jar;D:\IDEA\maven\maven_repository\org\apereo\cas\cas-server-core-cookie-api\6.6.14\cas-server-core-cookie-api-6.6.14.jar;D:\IDEA\maven\maven_repository\org\apereo\cas\cas-server-core-web-api\6.6.14\cas-server-core-web-api-6.6.14.jar;D:\IDEA\maven\maven_repository\org\springframework\boot\spring-boot-starter-log4j2\2.7.3\spring-boot-starter-log4j2-2.7.3.jar;D:\IDEA\maven\maven_repository\org\apache\logging\log4j\log4j-jul\2.17.2\log4j-jul-2.17.2.jar;D:\IDEA\maven\maven_repository\org\apache\logging\log4j\log4j-api\2.18.0\log4j-api-2.18.0.jar;D:\IDEA\maven\maven_repository\org\apache\logging\log4j\log4j-core\2.18.0\log4j-core-2.18.0.jar;D:\IDEA\maven\maven_repository\org\apache\logging\log4j\log4j-jcl\2.18.0\log4j-jcl-2.18.0.jar;D:\IDEA\maven\maven_repository\org\apache\logging\log4j\log4j-web\2.18.0\log4j-web-2.18.0.jar;D:\IDEA\maven\maven_repository\org\apache\logging\log4j\log4j-slf4j-impl\2.18.0\log4j-slf4j-impl-2.18.0.jar;D:\IDEA\maven\maven_repository\org\apache\logging\log4j\log4j-layout-template-json\2.18.0\log4j-layout-template-json-2.18.0.jar;D:\IDEA\maven\maven_repository\com\lmax\disruptor\3.4.4\disruptor-3.4.4.jar;D:\IDEA\maven\maven_repository\org\apereo\cas\cas-server-core-tickets-api\6.6.14\cas-server-core-tickets-api-6.6.14.jar;D:\IDEA\maven\maven_repository\org\apereo\cas\cas-server-core-api-logout\6.6.14\cas-server-core-api-logout-6.6.14.jar;D:\IDEA\maven\maven_repository\org\apereo\cas\cas-server-core-services-authentication\6.6.14\cas-server-core-services-authentication-6.6.14.jar;D:\IDEA\maven\maven_repository\org\apereo\cas\cas-server-core-services\6.6.14\cas-server-core-services-6.6.14.jar;D:\IDEA\maven\maven_repository\org\apereo\cas\cas-server-core-api-audit\6.6.14\cas-server-core-api-audit-6.6.14.jar;D:\IDEA\maven\maven_repository\org\apereo\cas\cas-server-core-services-api\6.6.14\cas-server-core-services-api-6.6.14.jar;D:\IDEA\maven\maven_repository\org\apereo\cas\cas-server-core-services-registry\6.6.14\cas-server-core-services-registry-6.6.14.jar;D:\IDEA\maven\maven_repository\org\apereo\cas\cas-server-core-authentication-attributes\6.6.14\cas-server-core-authentication-attributes-6.6.14.jar;D:\IDEA\maven\maven_repository\org\apereo\cas\cas-server-core-events-api\6.6.14\cas-server-core-events-api-6.6.14.jar;D:\IDEA\maven\maven_repository\org\apereo\cas\cas-server-core-notifications\6.6.14\cas-server-core-notifications-6.6.14.jar;D:\IDEA\maven\maven_repository\org\springframework\boot\spring-boot-starter-mail\2.7.3\spring-boot-starter-mail-2.7.3.jar;D:\IDEA\maven\maven_repository\com\sun\mail\jakarta.mail\1.6.7\jakarta.mail-1.6.7.jar;D:\IDEA\maven\maven_repository\com\sun\activation\jakarta.activation\1.2.1\jakarta.activation-1.2.1.jar;D:\IDEA\maven\maven_repository\org\apereo\cas\cas-server-support-redis-core\6.6.14\cas-server-support-redis-core-6.6.14.jar;D:\IDEA\maven\maven_repository\com\mysql\mysql-connector-j\8.0.33\mysql-connector-j-8.0.33.jar;D:\IDEA\maven\maven_repository\com\google\protobuf\protobuf-java\3.21.9\protobuf-java-3.21.9.jar;D:\IDEA\maven\maven_repository\org\springframework\boot\spring-boot-starter-data-redis\2.7.18\spring-boot-starter-data-redis-2.7.18.jar;D:\IDEA\maven\maven_repository\org\springframework\boot\spring-boot-starter\2.7.18\spring-boot-starter-2.7.18.jar;D:\IDEA\maven\maven_repository\org\springframework\boot\spring-boot-starter-logging\2.7.18\spring-boot-starter-logging-2.7.18.jar;D:\IDEA\maven\maven_repository\ch\qos\logback\logback-classic\1.2.12\logback-classic-1.2.12.jar;D:\IDEA\maven\maven_repository\ch\qos\logback\logback-core\1.2.12\logback-core-1.2.12.jar;D:\IDEA\maven\maven_repository\org\apache\logging\log4j\log4j-to-slf4j\2.17.2\log4j-to-slf4j-2.17.2.jar;D:\IDEA\maven\maven_repository\org\springframework\boot\spring-boot-starter-tomcat\2.7.18\spring-boot-starter-tomcat-2.7.18.jar;D:\IDEA\maven\maven_repository\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;D:\IDEA\maven\maven_repository\org\apache\tomcat\embed\tomcat-embed-core\9.0.83\tomcat-embed-core-9.0.83.jar;D:\IDEA\maven\maven_repository\org\apache\tomcat\embed\tomcat-embed-el\9.0.83\tomcat-embed-el-9.0.83.jar;D:\IDEA\maven\maven_repository\org\apache\tomcat\embed\tomcat-embed-websocket\9.0.83\tomcat-embed-websocket-9.0.83.jar;D:\IDEA\maven\maven_repository\org\apereo\cas\cas-server-core-configuration\6.6.14\cas-server-core-configuration-6.6.14.jar;D:\IDEA\maven\maven_repository\org\apereo\cas\cas-server-core-api-configuration\6.6.14\cas-server-core-api-configuration-6.6.14.jar;D:\IDEA\maven\maven_repository\org\apereo\cas\cas-server-core-api-authentication\6.6.14\cas-server-core-api-authentication-6.6.14.jar;D:\IDEA\maven\maven_repository\org\apereo\cas\cas-server-core-api-protocol\6.6.14\cas-server-core-api-protocol-6.6.14.jar;D:\IDEA\maven\maven_repository\org\apereo\cas\cas-server-core-api-monitor\6.6.14\cas-server-core-api-monitor-6.6.14.jar;D:\IDEA\maven\maven_repository\org\apereo\cas\cas-server-core-api-webflow\6.6.14\cas-server-core-api-webflow-6.6.14.jar;D:\IDEA\maven\maven_repository\org\apereo\cas\cas-server-core-api-events\6.6.14\cas-server-core-api-events-6.6.14.jar;D:\IDEA\maven\maven_repository\org\apereo\cas\cas-server-core-api-validation\6.6.14\cas-server-core-api-validation-6.6.14.jar;D:\IDEA\maven\maven_repository\org\jasypt\jasypt\1.9.3\jasypt-1.9.3.jar;D:\IDEA\maven\maven_repository\org\bouncycastle\bcpkix-jdk15on\1.70\bcpkix-jdk15on-1.70.jar;D:\IDEA\maven\maven_repository\org\bouncycastle\bcutil-jdk15on\1.70\bcutil-jdk15on-1.70.jar;D:\IDEA\maven\maven_repository\org\cryptacular\cryptacular\1.2.5\cryptacular-1.2.5.jar;D:\IDEA\maven\maven_repository\org\bouncycastle\bcprov-jdk18on\1.71\bcprov-jdk18on-1.71.jar;D:\IDEA\maven\maven_repository\org\bouncycastle\bcprov-jdk15on\1.70\bcprov-jdk15on-1.70.jar;D:\IDEA\maven\maven_repository\org\springframework\security\spring-security-crypto\5.7.8\spring-security-crypto-5.7.8.jar;D:\IDEA\maven\maven_repository\jakarta\xml\bind\jakarta.xml.bind-api\2.3.3\jakarta.xml.bind-api-2.3.3.jar;D:\IDEA\maven\maven_repository\jakarta\activation\jakarta.activation-api\1.2.2\jakarta.activation-api-1.2.2.jar com.example.casserver.CasServerApplication SLF4J: Class path contains multiple SLF4J bindings. SLF4J: Found binding in [jar:file:/D:/IDEA/maven/maven_repository/org/apache/logging/log4j/log4j-slf4j-impl/2.18.0/log4j-slf4j-impl-2.18.0.jar!/org/slf4j/impl/StaticLoggerBinder.class] SLF4J: Found binding in [jar:file:/D:/IDEA/maven/maven_repository/ch/qos/logback/logback-classic/1.2.12/logback-classic-1.2.12.jar!/org/slf4j/impl/StaticLoggerBinder.class] SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation. SLF4J: Actual binding is of type [org.apache.logging.slf4j.Log4jLoggerFactory] Exception in thread "main" java.lang.ExceptionInInitializerError at com.example.casserver.CasServerApplication.main(CasServerApplication.java:10) Caused by: org.apache.logging.log4j.LoggingException: log4j-slf4j-impl cannot be present with log4j-to-slf4j at org.apache.logging.slf4j.Log4jLoggerFactory.validateContext(Log4jLoggerFactory.java:60) at org.apache.logging.slf4j.Log4jLoggerFactory.newLogger(Log4jLoggerFactory.java:44) at org.apache.logging.slf4j.Log4jLoggerFactory.newLogger(Log4jLoggerFactory.java:33) at org.apache.logging.log4j.spi.AbstractLoggerAdapter.getLogger(AbstractLoggerAdapter.java:53) at org.apache.logging.slf4j.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:33) at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:363) at org.apache.commons.logging.LogAdapter$Slf4jAdapter.createLocationAwareLog(LogAdapter.java:130) at org.apache.commons.logging.LogAdapter.createLog(LogAdapter.java:91) at org.apache.commons.logging.LogFactory.getLog(LogFactory.java:67) at org.apache.commons.logging.LogFactory.getLog(LogFactory.java:59) at org.springframework.boot.SpringApplication.<clinit>(SpringApplication.java:179) ... 1 more Process finished with exit code 1
最新发布
07-03
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值