一、前言:
简单理解就是在原来方法的前后添加新的代码(扩展之前方法的代码)
这个是springAOP切面的基础
(springAOP切面就是给原有代码前后增加新代码)(为了更方便扩充新功能<只编写下边main中代码>)
<Spring则是只需要编写"切面类" 就可以了>
二、代码:
2.1.导包:
<dependencies>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
<version>9.1</version>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.28.0-GA</version>
</dependency>
</dependencies>
2.2.代码:
package com.java.jvm.bytecode.service;
/**
* 定义一个普通的业务对象,我们现在要通过一定
* 的技术对这个对象的方法进行功能增强。
* 例如:
* 1)在方法体代码执行之前做一些事情
* 2)在方法体代码执行之后做一些事情
*/
public class ResourceService {
public void handle(){
System.out.println("ResourceService--handle");
}
}
package com.java.jvm.bytecode;
import com.java.jvm.bytecode.service.ResourceService;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
/*
基于此类为com.java.jvm. bytecode . service. ResourceService做功能增强
思考:
1)对目标类中的方法要进行功能增强的一个基本步骤是怎样的?
1.1)如何获取目标类(基于CtLassPool获取)
1.2)如何获取目标方法(基FctClass获取)
1.3)如何为方法进行功能增强(基FCtMethod实现)
*/
public class JavassistDemo {
public static void main(String[] args) throws Exception {//被AppClassLoader已经加载了
ResourceService rs1=new ResourceService();//加上这一行代码后边的Javassist就会报异常
//.CannotCompileException: by java.lang.ClassFormatError: loader (instance of
// sun/misc/Launcher$AppClassLoader):
// attempted duplicate class definition for name:
// "com/java/jvm/bytecode/service/ResourceService"
//大概意思是AppClassLoader类加载器视图加载已经加载过的一个类, 所以不能实现已经加载过的类,就不能替换
//某个class已经运行(已经加载), 再次加载进行加强Javassist是行不通的
//1.获取目标类(目标类的信息会封装到CtClass对象中)//本行代码会加载ResourceService
CtClass ctclass= ClassPool.getDefault().get(
"com.java.jvm.bytecode.service.ResourceService");
//2.获取目标方法信息
CtMethod targetMethod=ctclass.getDeclaredMethod("handle");
//3./3.执行方法功能增强
//注意:{System.out.println("start");} 表示代码块
//本案例执行一次会增强一次,执行第二次会增强第二次
targetMethod.insertBefore("{System.out.println(\"start\");}");
// insertAfter的时候会自动添加一行Object var2=null;(以后待研究)
targetMethod.insertAfter("{System.out.println(\"end\");}");
//4.创建新的字节码对象
Class<?> aclass= ctclass.toClass();
ResourceService rs=(ResourceService)aclass.newInstance();
rs.handle();
//原本的f_javassist_demo/target/classes/com/java/jvm/bytecode/
//下的serviceResourceService.class字节码是2022-05-21 16:02生成的
//执行了下边的writeFile()生成事件就变成了2022-05-21 16:03
//将新的字节码对象以class文件的形式存储到磁盘
ctclass.writeFile("f_javassist_demo/target/classes");
}
}
2.3.结果分析:
//上边案例执行之后ResourceService生成的字节码反编译之后如下
public void handle(){
System.out.println("start");
System.out.println("handle()");
Object var2=null;
System.out.println("end");
}
2022-05-21 16:02 ZhaoYQ