1. 对接口预先添加一个自定义注解:@ServiceType
2. 系统启动时,通过Spring扫描有包含注解:@ServiceType的接口,然后通过ASM类库修改接口字节码
3. 用到一些辅助工具:java命令,asm-util.jar,asm.jar
============================================================
具体操作:
IIndividualTax接口代码如下(import相关代码省略):
@ServiceType
public interface IIndividualTax {
BusinessResponse request(BusinessRequest request) throws GatewayException;
}
目的是要在IIndividualTax 接口上添加注解,并且删掉ServiceType注解,以及在方法request上添加注解,最终想要运行时的代码如下(import相关代码省略):
@Path("it")
@Consumes({"application/json", "text/xml"})
@Produces({"application/json; charset=UTF-8", "text/xml; charset=UTF-8"})
public abstract interface IIndividualTax
{
@POST
@Path("request")
BusinessResponse request(BusinessRequest paramBusinessRequest) throws GatewayException;
}
首先:java -classpath D:\;D:\asm-util-5.1.jar;D:\asm-5.1.jar;. org.objectweb.asm.util.ASMifier cn.com.*.*.gateway.service.IIndividualTax
运行这个命令,需要注意的是classpath参数以及,在当前cmd位置下要有IIndividualTax这个类的全包路径
借助ASMifier类,可以看到这个接口IIndividualTax修改前完整的字节码,如下:
package asm.*****************************.service;
import java.util.*;
import org.objectweb.asm.*;
public class IIndividualTaxDump implements Opcodes {
public static byte[] dump () throws Exception {
ClassWriter cw = new ClassWriter(0);
FieldVisitor fv;
MethodVisitor mv;
AnnotationVisitor av0;
cw.visit(V1_7, ACC_PUBLIC + ACC_ABSTRACT + ACC_INTERFACE, "cn/com/*/*/gateway/service/IIndividualTax", null, "java/lang/Object", null);
{
av0 = cw.visitAnnotation("Lcn/com/*/*/gateway/service/ServiceType;", false);
av0.visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "request", "(Lcn/com/*/*/gateway/dto/BusinessRequest;)Lcn/com/*/*/gateway/dto/BusinessResponse;", null, new String[] { "cn/com/*/*/gateway/exception/GatewayException" });
mv.visitEnd();
}
cw.visitEnd();
return cw.toByteArray();
}
}
=================================================================================================================
在次运行:java -classpath D:\;D:\asm-util-5.1.jar;D:\asm-5.1.jar;. org.objectweb.asm.util.ASMifier cn.com.*.*.gateway.service.IIndividualTax,查看想要修改后接口完整的字节码,如下:
package asm.*************************************service;
import java.util.*;
import org.objectweb.asm.*;
public class IIndividualTaxDump implements Opcodes {
public static byte[] dump () throws Exception {
ClassWriter cw = new ClassWriter(0);
FieldVisitor fv;
MethodVisitor mv;
AnnotationVisitor av0;
cw.visit(V1_7, ACC_PUBLIC + ACC_ABSTRACT + ACC_INTERFACE, "cn/com/*/*/gateway/service/IIndividualTax", null, "java/lang/Object", null);
{
av0 = cw.visitAnnotation("Ljavax/ws/rs/Path;", true);
av0.visit("value", "it");
av0.visitEnd();
}
{
av0 = cw.visitAnnotation("Ljavax/ws/rs/Consumes;", true);
{
AnnotationVisitor av1 = av0.visitArray("value");
av1.visit(null, "application/json");
av1.visit(null, "text/xml");
av1.visitEnd();
}
av0.visitEnd();
}
{
av0 = cw.visitAnnotation("Ljavax/ws/rs/Produces;", true);
{
AnnotationVisitor av1 = av0.visitArray("value");
av1.visit(null, "application/json; charset=UTF-8");
av1.visit(null, "text/xml; charset=UTF-8");
av1.visitEnd();
}
av0.visitEnd();
}
{
av0 = cw.visitAnnotation("Lcn/com/*/*/gateway/service/ServiceType;", false);
av0.visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "request", "(Lcn/com/*/*/gateway/dto/BusinessRequest;)Lcn/com/*/*/gateway/dto/BusinessResponse;", null, new String[] { "cn/com/*/*/gateway/exception/GatewayException" });
{
av0 = mv.visitAnnotation("Ljavax/ws/rs/POST;", true);
av0.visitEnd();
}
{
av0 = mv.visitAnnotation("Ljavax/ws/rs/Path;", true);
av0.visit("value", "request");
av0.visitEnd();
}
mv.visitEnd();
}
cw.visitEnd();
return cw.toByteArray();
}
}
===================================================================================================================
对于新手玩ASM不熟悉的情况,通过对比上面的二段字节码存在的差异,用ASM提供的API进行码代码,生成运行时的关键代码如下:
public class TaxVisitor extends ClassVisitor implements Opcodes{
public TaxVisitor(int api, ClassVisitor cv) {
super(api, cv);
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
if (name.equals("request")) {
AnnotationVisitor av1 = mv.visitAnnotation("Ljavax/ws/rs/POST;", true);//在request上添加@POST注解,对比看上面红色粗体类源码
AnnotationVisitor av2 = mv.visitAnnotation("Ljavax/ws/rs/Path;", true);//同上
av2.visit("value", "request");
av2.visitEnd();//这些api用法,查看asm相关说明
av1.visitEnd();
}
return mv;
}
@Override
public AnnotationVisitor visitAnnotation(String name, boolean arg1) {
if (name.equals("Lcn/com/*/*/gateway/service/ServiceType;")) {
return null;//返回null说明,要删掉接口上@ServiceType注解
}
return super.visitAnnotation(name, arg1);
}
}
=====================================================================================================
public class AsmTest extends ClassLoader{
public static void main(String[] args) throws Exception {
ClassReader cr=new ClassReader(IIndividualTax.class.getName());
ClassWriter cw=new ClassWriter(ClassWriter.COMPUTE_MAXS);
AnnotationVisitor av0 = cw.visitAnnotation("Ljavax/ws/rs/Path;", true);//在接口上添加注解@Path
av0.visit("value", "it");
av0.visitEnd();
AnnotationVisitor av1 = cw.visitAnnotation("Ljavax/ws/rs/Consumes;", true);//在接口上添加注解@Consumes
AnnotationVisitor av2 = av1.visitArray("value");
av2.visit(null, "application/json");
av2.visit(null, "text/xml");
av2.visitEnd();
av1.visitEnd();
AnnotationVisitor av3 = cw.visitAnnotation("Ljavax/ws/rs/Produces;", true);//在接口上添加注解@Produces
AnnotationVisitor av4 = av3.visitArray("value");
av4.visit(null, "application/json; charset=UTF-8");
av4.visit(null, "text/xml; charset=UTF-8");
av4.visitEnd();
av3.visitEnd();
TaxVisitor myv=new TaxVisitor(Opcodes.ASM4,cw);
cr.accept(myv, 0);
byte[] code=cw.toByteArray();//最终想要类的字节码
AsmTest loader=new AsmTest();
Class<?> appClass=loader.defineClass(null, code, 0,code.length);//字节码加载到jvm
System.out.println(AnnotationUtils.findAnnotation(appClass, Path.class));
FileOutputStream fos = new FileOutputStream(appClass.getResource("").getPath()+"/IIndividualTax.class");//覆盖当前class文件
fos.write(code);
fos.close();
}
}
注意:对类或接口的字节码的修改必须用ClassWriter的实例进行api相关操作,对类的方法,属性字节码操作需要通过对应的Visitor操作,最终调用visitEnd()
相关推荐
一个简单的通过ASM修改字节码实现AOP功能的实例,简单易懂,可运行...
ASM操作字节码,动态生成Java类class文件,模拟Spring的AOP实现原理。
ASM 4 的中文文档 网上的博文都是从这上边摘得,大家下载下来学学就会了,这个是最全的了。我就是通过这个学会的。
ASM Java字节码操作框架PPT,结合已有AOP实现方法,对比所有对Java字节码操作方法做比较
Javassist 提供了java类库,用于方便操控Java字节码。功能包括:运行时创建java class,修改class。与其他同类工具(asm等)...通过java代码层,开发者即时对字节码不是很熟悉,也可以非常方便快速的完成字节码的修改。
内容包含ASM4.0中文手册,以及四种ASM常见的字节码操作应用范例,包含最新版本的ASM9.2的jar包,包含asm-9.2.jar,asm-commons-9.2.jar,asm-util-9.2.jar。 学习文章地址 ...
ASM 帮助文档(java字节码操作) 对字节码进行操作的jar包。
埋点计时Gradle插件,利用ASM插入字节码,对指定包名内的类或指定注解的方法,打印其方法的耗时时间。
字节码生成库是生成和转换java字节码的高级api。
C32Asm【用于修改特征码】
ASM是一个通用的Java字节码操作和分析框架。它可以用于修改现有类或直接以二进制形式动态生成类。ASM提供了一些常见的字节码转换和分析算法,可以从中构建自定义复杂转换和代码分析工具。ASM提供与其他Java字节码...
这个库主要用于在运行时动态修改类的行为,例如创建新的类、方法或字段,或者修改现有的类、方法或字段。 asm-commons-3.3.1.jar的主要功能包括: 1. 读取和写入Java字节码:可以读取已经编译好的Java类文件,也可以...
ASM 是一个 Java 字节码操控框架。它能被用来动态生成类或者增强既有类的功能。ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为。Java class 被存储在严格格式定义的 .class ...
Java的asm文档,来自官方。asm4-guide.pdf。ASM 是一个 Java 字节码操控框架。它能被用来动态生成类或者增强既有类的功能。ASM 可以直接产生二进制 class 文件,也可以在...说白了asm是直接通过字节码来修改class文件。
C32Asm现具有如下功能: 快速静态反编译PE格式文件(Exe、Dll等) 提供Hex文件编辑功能,功能强大 提供内存Dump、内存编辑、PE文件Dump、PE内存ImageSize修正等多种实用功能 提供内存反汇编功能,提供汇编语句直接修改...
友情提示:本软件是学习免杀和木马免杀修改特征码必备的工具,杀软可能会报毒,郑重声明软件为绿色无后门无木马,报毒是因为杀软把黑软都列入黑名单,运行前请关闭杀软在做运行,不符合以上条件请不要下载
c32asm16进制修改 修改特征码帮手很强大
ASM是一个java字节码操纵框架,它能被用来动态生成类或者增强既有类的功能。ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为。Java class 被存储在严格格式定义的 .class...
ASM是一个通用的Java字节码操作和分析框架。 它可以用于修改现有类或直接以二进制形式动态生成类。 ASM提供了一些常见的字节码转换和分析算法,可以从中构建自定义复杂转换和代码分析工具。 ASM提供与其他Java字节码...