首页 > 编程语言 >java字节码编程技术(8/10) -Javassist

java字节码编程技术(8/10) -Javassist

时间:2023-04-15 21:31:31浏览次数:49  
标签:10 java System ctClass println new 编程技术 class out

Javassist

这个库和asm经常使用,它的性能稍差一点

<dependency>

<groupId>org.javassist</groupId>

<artifactId>javassist</artifactId>

<version>3.27.0-GA</version>

</dependency>

获取一个类加载器(ClassLoader),以加载指定的.jar或.class文件

private ClassLoader getLocaleClassLoader() throws Exception {

List<URL> classPathURLs = new ArrayList<>();

// 加载.class文件路径

File classesPath = new File("com.assist.TestHelloWorld2");

classPathURLs.add(classesPath.toURI().toURL());


// 获取所有的jar文件

File libPath = new File("com.assist.TestHelloWorld2");

File[] jarFiles = libPath.listFiles(new FilenameFilter() {

@Override

public boolean accept(File dir, String name) {

return name.endsWith(".jar");

}

});


// 将jar文件路径写入集合

for (File jarFile : jarFiles) {

classPathURLs.add(jarFile.toURI().toURL());

}


// 实例化类加载器

return new URLClassLoader(classPathURLs.toArray(new URL[classPathURLs.size()]));

}

获取类的类型信息

public static void test() throws NotFoundException {

// 获取默认类型池对象

ClassPool classPool = ClassPool.getDefault();


// 获取指定的类型

CtClass ctClass = classPool.get("java.lang.String");


System.out.println(ctClass.getName()); // 获取类名

System.out.println("\tpackage " + ctClass.getPackageName()); // 获取包名

System.out.print("\t" + Modifier.toString(ctClass.getModifiers()) + " class " + ctClass.getSimpleName()); // 获取限定符和简要类名

System.out.print(" extends " + ctClass.getSuperclass().getName()); // 获取超类

// 获取接口

if (ctClass.getInterfaces() != null) {

System.out.print(" implements ");

boolean first = true;

for (CtClass c : ctClass.getInterfaces()) {

if (first) {

first = false;

} else {

System.out.print(", ");

}

System.out.print(c.getName());

}

}

System.out.println();

}

修改类的信息

public void test() throws Exception {

// 获取本地类加载器

ClassLoader classLoader = getLocaleClassLoader();

// 获取要修改的类

Class<?> clazz = classLoader.loadClass("edu.alvin.reflect.TestLib");


// 实例化类型池对象

ClassPool classPool = ClassPool.getDefault();

// 设置类搜索路径

classPool.appendClassPath(new ClassClassPath(clazz));

// 从类型池中读取指定类型

CtClass ctClass = classPool.get(clazz.getName());


// 获取String类型参数集合

CtClass[] paramTypes = {classPool.get(String.class.getName())};

// 获取指定方法名称

CtMethod method = ctClass.getDeclaredMethod("show", paramTypes);

// 赋值方法到新方法中

CtMethod newMethod = CtNewMethod.copy(method, ctClass, null);

// 修改源方法名称

String oldName = method.getName() + "$Impl";

method.setName(oldName);


// 修改原方法

newMethod.setBody("{System.out.println(\"执行前\");" + oldName + "($$);System.out.println(\"执行后\");}");

// 将新方法添加到类中

ctClass.addMethod(newMethod);


// 加载重新编译的类

clazz = ctClass.toClass(); // 注意,这一行会将类冻结,无法在对字节码进行编辑

// 执行方法

clazz.getMethod("show", String.class).invoke(clazz.newInstance(), "hello");

ctClass.defrost(); // 解冻一个类,对应freeze方法

}

获取方法名称

public void test1() throws Exception {

// 获取本地类加载器

ClassLoader classLoader = getLocaleClassLoader();

// 获取要修改的类

Class<?> clazz = classLoader.loadClass("edu.alvin.reflect.TestLib");


// 实例化类型池

ClassPool classPool = ClassPool.getDefault();

classPool.appendClassPath(new ClassClassPath(clazz));

CtClass ctClass = classPool.get(clazz.getName());


// 获取方法

CtMethod method = ctClass.getDeclaredMethod("show",new CtClass[]{});

// 判断是否为静态方法

int staticIndex = Modifier.isStatic(method.getModifiers()) ? 0 : 1;


// 获取方法的参数

MethodInfo methodInfo = method.getMethodInfo();

CodeAttribute codeAttribute = methodInfo.getCodeAttribute();

LocalVariableAttribute localVariableAttribute = (LocalVariableAttribute)codeAttribute.getAttribute(LocalVariableAttribute.tag);


for (int i = 0; i < method.getParameterTypes().length; i++) {

System.out.println("第" + (i + 1) + "个参数名称为: " + localVariableAttribute.variableName(staticIndex + i));

}

}

动态创建类

public void test() throws Exception {

ClassPool classPool = ClassPool.getDefault();


// 创建一个类

CtClass ctClass = classPool.makeClass("edu.alvin.reflect.DynamiClass");

// 为类型设置接口

//ctClass.setInterfaces(new CtClass[] {classPool.get(Runnable.class.getName())});


// 为类型设置字段

CtField field = new CtField(classPool.get(String.class.getName()), "value", ctClass);

field.setModifiers(Modifier.PRIVATE);

// 添加getter和setter方法

ctClass.addMethod(CtNewMethod.setter("setValue", field));

ctClass.addMethod(CtNewMethod.getter("getValue", field));

ctClass.addField(field);


// 为类设置构造器

// 无参构造器

CtConstructor constructor = new CtConstructor(null, ctClass);

constructor.setModifiers(Modifier.PUBLIC);

constructor.setBody("{}");

ctClass.addConstructor(constructor);

// 参数构造器

constructor = new CtConstructor(new CtClass[] {classPool.get(String.class.getName())}, ctClass);

constructor.setModifiers(Modifier.PUBLIC);

constructor.setBody("{this.value=$1;}");

ctClass.addConstructor(constructor);


// 为类设置方法

CtMethod method = new CtMethod(CtClass.voidType, "run", null, ctClass);

method.setModifiers(Modifier.PUBLIC);

method.setBody("{System.out.println(\"执行结果\" + this.value);}");

ctClass.addMethod(method);


// 加载和执行生成的类

Class<?> clazz = ctClass.toClass();

Object obj = clazz.newInstance();

clazz.getMethod("setValue", String.class).invoke(obj, "hello");

clazz.getMethod("run").invoke(obj);


obj = clazz.getConstructor(String.class).newInstance("OK");

clazz.getMethod("run").invoke(obj);

}

创建代理类

public class TestProxy {

private String name;

private String value;


public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public String getValue() {

return value;

}

public void setValue(String value) {

this.value = value;

}

}

public static void test() throws Exception {

// 实例化代理类工厂

ProxyFactory factory = new ProxyFactory();


//设置父类,ProxyFactory将会动态生成一个类,继承该父类

factory.setSuperclass(TestProxy.class);


//设置过滤器,判断哪些方法调用需要被拦截

factory.setFilter(new MethodFilter() {

@Override

public boolean isHandled(Method m) {

return m.getName().startsWith("get");

}

});


Class<?> clazz = factory.createClass();

TestProxy proxy = (TestProxy) clazz.newInstance();

((ProxyObject)proxy).setHandler(new MethodHandler() {

@Override

public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) throws Throwable {

//拦截后前置处理,改写name属性的内容

//实际情况可根据需求修改

System.out.println(thisMethod.getName() + "被调用");

try {

Object ret = proceed.invoke(self, args);

System.out.println("返回值: " + ret);

return ret;

} finally {

System.out.println(thisMethod.getName() + "调用完毕");

}

}

});


proxy.setName("Alvin");

proxy.setValue("1000");

proxy.getName();

proxy.getValue();

}

创建一个类并添加方法

public class TestProxy {

public static void main(String[] args) throws NotFoundException,

IOException, CannotCompileException, InstantiationException,

IllegalAccessException, SecurityException, NoSuchMethodException,

IllegalArgumentException, InvocationTargetException {

// 用于取得字节码类,必须在当前的classpath中,使用全称

ClassPool pool = ClassPool.getDefault();

/**

* makeClass() cannot create a new interface; makeInterface() in

* ClassPool can do. Member methods in an interface can be created with

* abstractMethod() in CtNewMethod. Note that an interface method is an

* abstract method.

*/

CtClass ccClass = pool.makeClass("Point");

String bodyString = "{System.out.println(\"Call to method \");}";

//为新创建的类新加一个方法execute,无任何参数

CtMethod n1 = CtNewMethod.make(CtClass.voidType, "execute", null, null,

bodyString, ccClass);

ccClass.addMethod(n1);

//新加第二个方法

bodyString = "public Integer getNumber(Integer num);";

CtMethod n2 = CtNewMethod.make(bodyString, ccClass);//直接创建一个方法,带有一个int的参数和返回值

n2.setBody("{System.out.println(\"Point Call to method \");return $1;}");

ccClass.addMethod(n2);


/**

* 这里无法用new的形式来创建一个对象,因为已经classloader中不能有两个相同的对象,否则会报异常如下:

*Caused by: java.lang.LinkageError: loader (instance of sun/misc/Launcher$AppClassLoader):

*attempted duplicate class definition for name: "Point"

**/

Object oo = ccClass.toClass().newInstance();

Method mms = oo.getClass().getMethod("execute", null);

System.out.println("new class name is : " + oo.getClass().getName());

System.out.println("new class's method is : " + mms.invoke(oo, null));

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

//这一行代码将class冻结了,下面无法再对类多编辑或者修改,下面的setName会报异常如:

//Exception in thread "main" java.lang.RuntimeException: Point class is frozen

ccClass.freeze();

try{

ccClass.setName("Point2");

}catch (Exception e) {

System.out.println(e);

}

//对已经冻结的class解冻之后还可以继续编辑修改

ccClass.defrost();

System.out.println("------------- 上面的代码是对的,下面的代码将会无法执行出结果,会报错------------------------");

Class[] params = new Class[1];

Integer num = new Integer(0);

params[0] = num.getClass();

mms = oo.getClass().getMethod("getNumber",params);

System.out.println("new class name is : " + oo.getClass().getName());

System.out.println("new class's method is : " + mms.invoke(oo, 100));

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

}

}


















标签:10,java,System,ctClass,println,new,编程技术,class,out
From: https://blog.51cto.com/arch/6192467

相关文章

  • java.lang.NoSuchMethodException: com.innovation.web.BuyServlet.get(javax.servlet
    问题描述我将路径定义到相应的servlet的函数方法里面,然后就出现了这个问题,很明显的找不到相应的函数方法;问题解决将目光重新放到我定义的相关路径那里,发现我出于习惯,将servlet里面原本应该是名为checkIt的函数方法写成了get方法,改回去之后,这个问题也就解决啦!......
  • Java Stream API 操作完全攻略:让你的代码更加出色 (四)
    前言  JavaStream是一种强大的数据处理工具,可以帮助开发人员快速高效地处理和转换数据流。使用Stream操作可以大大简化代码,使其更具可读性和可维护性,从而提高开发效率。本文将为您介绍JavaStream操作的所有方面,包括range、range、iterate、generate等操作,让你的代码行......
  • eclpise断点调试Java代码
    Eclipse支持对Java代码进行Debug也就是在执行代码时暂停执行并可以观察相关的信息,比如栈中的变量,堆中的变量,执行的代码,方法调用栈等,这个暂停的位置就是断点一个简单的工程如果需要观察getMax方法的执行,可以在代码编辑器左边缘双击,增加断点,或者右键ToggleBre......
  • java -- 标记接口
    标记接口标记接口(MarkerInterface),又称标签接口(TagInterface)仅代表一个标记不包含任何方法标记接口是用来判断某个类是否具有某种能力Cloneable标记接口此类实现了Cloneable接口,以指示Object.clone方法可以合法地对该类实例进行按字段复制如果在没有实现Cloneable接......
  • Rust语言 学习10 测试
    一、编写测试cargo创建测试项目使用Clion打开工程,lib.rs代码如下然后运行这个测试看看效果增加一个单测#[test]fnnew_test(){panic!("maketestfail");}......
  • JAVA远程请求工具类
    importcom.alibaba.fastjson.JSONObject;importorg.apache.http.Consts;importorg.apache.http.HttpResponse;importorg.apache.http.HttpStatus;importorg.apache.http.NameValuePair;importorg.apache.http.client.entity.UrlEncodedFormEntity;importorg.apac......
  • js方法实现 10+ 100+ 1000+ 10000+
    将数字类型优化12=>10+120=>100+1200=>1000+10以内不管调用后赋值进行数字化item.read_num=Number(util.picture(item.read_num))直接cv代码数字优化自己调用定义函数**//浏览量优化functionpicture(num){if(num<10){returnnum;}va......
  • 1040. 移动石子直到连续 II
    题目链接:1040.移动石子直到连续II方法:找规律解题思路参考—【图解】下跳棋代码classSolution{public:vector<int>numMovesStonesII(vector<int>&stones){sort(stones.begin(),stones.end());intn=stones.size();inte1=stones......
  • Java笔记(16) Collection集合-->Set集合-->HashSet
    1.Set接口基本介绍Set是无序集合(添加和取出的顺序不一致,但取出的顺序是固定的),没有索引不允许重复元素,所以最多包含一个nullJDKAPI中Set接口的实现类有:Abstract,ConcurrentHashMap.KeySetView,ConcurrentSkipListSet,CopyOnWriteArraySet,EnumSet,HashSet,JobStateRea......
  • 10while
    循环:重复执行的事情特征:循环操作/循环体、循环条件程序中的循环=循环条件+循环操作while:先判断,后执行while(循环条件){循环操作;}inti=0;while(i<10000){System.out.println(i+"helloworld");i++;//更新变量......