jvm加载java的过程主要是:
编写java文件-》进行java文件的编译-》生成.class字节码文件-》jvm通过类加载器去加载生成的二进制文件
java编译器将源码文件编译称为二进制的.class文件
为什么要进行字节码增强操作?
不想修改源码,但是又想加入新功能,让程序按照我们的预期去运行,可以通过编译过程和加载过程中去做
相应的操作,
简单来讲就是:将生成的.class文件修改或者替换称为我们需要的目标.class文件。
需要依赖第三方的工具去实现字节码增强
这里使用javassist实现;
步骤:
/** * 步骤1:编写你最初的业务类,实现业务功能 */ public class BaseService { public void basePrint(Map map){ System.out.println(map.toString()); } }
/** * 步骤2:编写你需要的对业务类进行增强的类或者内容 */ public class ExBaseService { public static void exPrint(Map map){ System.out.println("exbaseService增强的功能==需要增强的方法之前"); } public static void exPrintL(Map map){ System.out.println("exbaseService增强的功能==需要增强的方法之后"); } }
/** * 步骤3:编写增强的工具类,之后直接调用后再使用原来的业务类方法就实现增强了 * ClassPool其实是一张保存了CtClass信息的哈希表,key=类的全限定类名,value=类名对应的CtClass对象。 * 当需要对某个类修改的时候,通过方法getCtClass(className)从classpool获取到相应的CtClass * CtClass:编译时的类信息,一个class文件在代码中的抽象表现形式,全限定类名可以获取CtClass对象,用于表示这个类文件 * CtMethod: 类中的方法 定义或修改 * CtField: 类中的属性 定义或修改 * * javassist 增强代码片段是字符串编写,以$开头用于表示方法或构造函数参数或方法返回值 */ public class ServiceUtils { public static void done() throws NotFoundException, CannotCompileException { ClassPool classPool = ClassPool.getDefault();//获取默认的类池 //通过全限定类名从类池获取对应需要增强的类 CtClass base = classPool.getOrNull("com.quan.security.intecepter.BaseService"); if (base == null){ System.out.println("can not found"); return; } //通过方法getDeclaredMethod和类中需要增强的方法名字得到CtMethod类型的方法抽象 CtMethod basemethod = base.getDeclaredMethod("basePrint"); //组合增强字符串,使用$1获取方法的参数。 StringBuffer sbf = new StringBuffer(); sbf.append("{"); sbf.append("com.quan.security.intecepter.ExBaseService.exPrint($1);"); sbf.append("}"); //进行增强,调用之前增强 basemethod.insertBefore(sbf.toString()); StringBuffer sbf2 = new StringBuffer(); sbf2.append("{"); sbf2.append("com.quan.security.intecepter.ExBaseService.exPrintL($1);"); sbf2.append("}"); //进行增强,调用需要增强方法之后增强 basemethod.insertAfter(sbf2.toString()); //替换增强后的字节码 base.toClass(); } }
public class IntecepterTest { /** * 调用增强工具类,使最初的业务类进行增强, * 随后调用业务类,查看是否增强 * @param args */ public static void main(String[] args) { try { ServiceUtils.done(); } catch (NotFoundException e) { e.printStackTrace(); } catch (CannotCompileException e) { e.printStackTrace(); } BaseService baseService = new BaseService(); Map<String,String> map1 = new HashMap<>(); map1.put("name","quan"); baseService.basePrint(map1); } }
结果:
exbaseService增强的功能==需要增强的方法之前 {name=quan} exbaseService增强的功能==需要增强的方法之后
原文:https://www.cnblogs.com/java-quan/p/13534603.html