基于javassist进行动态编程过程解析

今天在研究dubbo时,发现一个新的知识点,可以使用javassist包进行动态编程,hibernate也使用该包进行编程。晚上百度了很多资料,将它的特性以代码的形式展现出来。

package com.zhi.demo;

import java.lang.reflect.Field;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtField;
import javassist.CtMethod;
import javassist.CtNewConstructor;
import javassist.CtNewMethod;
import javassist.Loader;
import javassist.Modifier;
import javassist.bytecode.AccessFlag;

/**
 * Javassist动态编程测试
 *
 * @date 2019年03月11日23:00:33
 *
 */
public class JavassistTest {
  public static void main(String[] args) {
    try {
      test();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  private static void test() throws Exception {
    System.out.println("-------------------新增类------------------");
    ClassPool pool = ClassPool.getDefault();
    // 创建类
    CtClass ct = pool.makeClass("com.zhi.Person");
    // 让类实现Cloneable接口
    ct.setInterfaces(new CtClass[] { pool.makeInterface("java.lang.Cloneable") });

    // 添加一个int类型的共有属性
    CtField fieldId = new CtField(CtClass.intType, "id", ct);
    fieldId.setModifiers(AccessFlag.PUBLIC);
    ct.addField(fieldId);

    // 添加一个默认构造器
    CtConstructor constructor1 = CtNewConstructor.make("public Person(){this.id=1;}", ct);
    ct.addConstructor(constructor1);

    // 添加方法
    CtMethod helloM = CtNewMethod
        .make("public void hello(String des){System.out.println(\"执行hello方法,\"+des+\",我的id是\"+this.id);}", ct);
    ct.addMethod(helloM);

    // 将生成的.class文件保存到磁盘
    ct.writeFile();

    // 加载目标类,可用ct.toClass()或new Loader(pool).loadClass()
    Class<?> clazz = ct.toClass();
//    Class<?> clazz = new Loader(pool).loadClass("com.zhi.Person");

    // 输出类基本信息
    System.out.println("包名:" + clazz.getPackageName());
    System.out.println("类名:" + clazz.getName());
    System.out.println("简要类名:" + clazz.getSimpleName());
    System.out.println("限定符:" + Modifier.toString(clazz.getModifiers()));
    System.out.println("继承类:" + clazz.getSuperclass().getName());
    Field[] fields = clazz.getDeclaredFields();
    for (Field field : fields) {
      System.out.println("属性名称:" + field.getName() + ",属性类型:" + field.getType() + ",限定符:"
          + Modifier.toString(field.getModifiers()));
    }

    // 构造一个对象,并执行hello方法
    Object ob = clazz.getDeclaredConstructor().newInstance();
    clazz.getMethod("hello", String.class).invoke(ob, "张三");

    // 解冻(执行toClass后会自动冻结)
    ct.defrost();

    System.out.println("-------------------修改类------------------");

    // 添加一个String类型的私有属性
    CtField fieldName = new CtField(pool.get(String.class.getName()), "name", ct);
    fieldName.setModifiers(AccessFlag.PRIVATE);
    ct.addField(fieldName);

    // 添加带参的构造函数
    CtConstructor constructor2 = new CtConstructor(new CtClass[] { pool.get(String.class.getName()) }, ct);
    constructor2.setModifiers(Modifier.PUBLIC);
    constructor2.setBody("{this.name=$1;}");
    ct.addConstructor(constructor2);

    ct.addMethod(CtNewMethod.make("public void setName(String name){this.name=name;}", ct));
    ct.addMethod(CtNewMethod.make("public String getName(){return this.name;}", ct));

    ct.writeFile();

    // 加载类,若前面已用ct.toClass()进行加载,则这里不能再用ct.toClass()加载,否则会出错,同一个加载不能2次加载同一个类
    clazz = new Loader(pool).loadClass("com.zhi.Person");

    fields = clazz.getDeclaredFields();
    for (Field field : fields) {
      System.out.println("属性名称:" + field.getName() + ",属性类型:" + field.getType() + ",限定符:"
          + Modifier.toString(field.getModifiers()));
    }

    ob = clazz.getDeclaredConstructor(String.class).newInstance("马云");
    System.out.println("执行getName方法得到的值为:" + clazz.getMethod("getName").invoke(ob));
  }
}

执行上面代码输出结果为:

-------------------新增类------------------
包名:com.zhi
类名:com.zhi.Person
简要类名:Person
限定符:public
继承类:java.lang.Object
属性名称:id,属性类型:int,限定符:public
执行hello方法,张三,我的id是1
-------------------修改类------------------
属性名称:id,属性类型:int,限定符:public
属性名称:name,属性类型:class java.lang.String,限定符:private
执行getName方法得到的值为:马云

说明:

$0,$1,$2:分别代表this,第一个参数,第二个参数

$r:方法返回值的类型。

$_:方法返回值

依赖包

<dependency>
  <groupId>org.javassist</groupId>
  <artifactId>javassist</artifactId>
  <version>3.24.1-GA</version>
</dependency>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Java实现动态创建类操作示例

    本文实例讲述了Java实现动态创建类操作.分享给大家供大家参考,具体如下: Java可以创建动态类,学习看到,此处作为笔记. 代码如下: import java.io.IOException; import java.lang.reflect.Method; import java.net.URI; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import javax.tools.Java

  • java动态加载插件化编程详解

    前言 对于java程序员来说,插件化是一件很酷的功能,小二有幸在工作中实现了此功能. 背景: 需要将mysql的数据通过canal同步至kafka/mysql/hdfs等 实现 /** * Created by shengjk1 on 2017/12/11 */ public class PluginManager { private final static Logger logger = LoggerFactory.getLogger(SendMessageFactory.class); p

  • Java动态代理语法Proxy类原理详解

    1.前言 写动态代理的代码涉及了一个非常重要的类 Proxy,通过Proxy的静态方法newProxyInstance才会动态创建代理对象. 2.newProxyInstance方法 public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 三个参数分别表示: loader表示类加载器, interfaces表示代码要用来代理的接口 , h表示一个

  • Java封装数组之动态数组实现方法详解

    本文实例讲述了Java封装数组之动态数组实现方法.分享给大家供大家参考,具体如下: 前言:在此之前,我们封装的数组属于静态数组,也即数组空间固定长度,对于固定长度的数组当元素超过容量时会报数组空间不足.为了能更好的使用数组,我们来实现一个可以自动扩充容量的数组. 实现思路: 1.当数组容量达到事先定义值时创建一个空间是data数组两倍的newData数组(扩容): 2.把data数组中的元素全部赋值到newData数组中: 3.把data数组重新执行newData数组. 一.定义核心扩容方法 /

  • Javassist之一秒理解java动态编程

    概述 什么是动态编程?动态编程解决什么问题?Java中如何使用?什么原理?如何改进?(需要我们一起探索,由于自己也是比较菜,一般深入不到这个程度). 什么是动态编程 动态编程是相对于静态编程而言的,平时我们讨论比较多的就是静态编程语言,例如Java,与动态编程语言,例如JavaScript.那二者有什么明显的区别呢?简单的说就是在静态编程中,类型检查是在编译时完成的,而动态编程中类型检查是在运行时完成的.所谓动态编程就是绕过编译过程在运行时进行操作的技术,在Java中有如下几种方式: 反射 这个

  • Java动态代理静态代理实例分析

    代理模式:为其他对象提供一种代理以控制某个对象的访问.用在:在某些情况下,一个客户不想或者不能直接访问另一个对象,而代理对象可以在客户端和目标对象之前起到中介的作用,代理对象还可以完成它附加的操作. 例子:就像房东.租客.中介的关系.中介(代理对象)为房东(真实对象)出租房子,租客(客户)通过中介(代理对象)来找房子租房子,中介完成了租房以后可以收取中介费(附加操作). 先看看静态代理模式,通过上面对代理模式的理解,可以了解到代理模式:即不直接通过new一个真实对象来调用方法,而是通过代理对象来

  • java编程进行动态编译加载代码分享

    简述 该类使用javax.tools.ToolProvider自带的JavaCompiler进行编译,使用IO的File及NIO的Files进行对应的路径创建.读取及拷贝,使用正则表达式进行包名与目录的转换,我只是将这些东西做了个容错整合,没什么技术含量,就为个方便吧. 模块API class DynamicReactor://空参构造 public Class<?> dynamicCompile(String srcPath);//输入一个指定的源文件路径,若编译.拷贝成功则返回该类对应的C

  • 基于javassist进行动态编程过程解析

    今天在研究dubbo时,发现一个新的知识点,可以使用javassist包进行动态编程,hibernate也使用该包进行编程.晚上百度了很多资料,将它的特性以代码的形式展现出来. package com.zhi.demo; import java.lang.reflect.Field; import javassist.ClassPool; import javassist.CtClass; import javassist.CtConstructor; import javassist.CtFi

  • SpringBoot整合aop面向切面编程过程解析

    这篇文章主要介绍了SpringBoot整合aop面向切面编程过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是Spring框架中的一个重要内容,它通过对既有程序定义一个切入点,然后在其前后切入不同的执行内容,比如常见的有:打开数据库连接/关闭数据库连接.打开事务/关闭事务.记录日

  • 基于python调用psutil模块过程解析

    这篇文章主要介绍了基于python调用psutils模块过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 用Python来编写脚本简化日常的运维工作是Python的一个重要用途.在Linux下,有许多系统命令可以让我们时刻监控系统运行的状态,如ps,top,free等等.要获取这些系统信息,Python可以通过subprocess模块调用并获取结果.但这样做显得很麻烦,尤其是要写很多解析代码. 在Python中获取系统信息的另一个好办法是

  • spring boot基于DRUID实现数据源监控过程解析

    这篇文章主要介绍了spring boot基于DRUID实现数据源监控过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 随着需求和技术的日益革新,spring boot框架是越来越流行,她也越来越多地出现在我们的项目中,当然最主要的原因还是因为spring boot构建项目实在是太爽了,构建方便,开发简单,而且效率高.今天我们并不是来专门学习spring boot项目的,我们要讲的是数据源的加密和监控,监控到好说,就是不监控也没什么问题,但

  • 基于springboot处理date参数过程解析

    这篇文章主要介绍了基于springboot处理date参数过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 前言 最近在后台开发中遇到了时间参数的坑,就单独把这个问题提出来找时间整理了一下: 正文 测试方法 bean代码: public class DateModelNoAnnotation { private Integer id; private Date receiveDate; } controller代码: @RestContr

  • 基于SPRINGBOOT配置文件占位符过程解析

    这篇文章主要介绍了基于SPRINGBOOT配置文件占位符过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一.配置文件占位符 1.application.properties server.port=8088 debug=false product.id=ID:${random.uuid} product.name=da mao mao product.weight=${random.int} product.fristLinePrice

  • 如何基于SpringBoot部署外部Tomcat过程解析

    这篇文章主要介绍了SpringBoot以war包形式部署到外部Tomcat过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 SpringBoot 项目打包时能打成 .jar 与 .war包文件,.jar使用 java -jar xx.jar 就可以启动,而 .war 可以部署到tomcat的 webapps 中,随tomcat的启动而启动. SpringBoot 本身是内置tomcat的,如果想部署到外部tomcat, 就要做一些改变.

  • Java框架MyBatis接口编程过程解析

    要求: 1.配置文件的namespace名称空间指定为接口的全类名 2.配置文件中的id唯一标识与接口中的方法对应(返回值类型对应,方法名对应,参数个数和类型对应) 接口代码: package com.bird.mybatis.dao; import com.bird.mybatis.bean.Employee; public interface EmployeeMapper { public Employee getEmpById(Integer id); } 对应配置文件代码: <?xml

  • Python基于DB-API操作MySQL数据库过程解析

    Python提供了一个标准数据库API,称为DB-API,用于处理基于SQL的数据库. 与任何底层数据库的交互都可以使用DB-API,因为DB-API在代码与驱动程序之间提供了一个抽象层,可以根据需要替换底层数据库,而无需丢弃现有的代码. DB-API与底层数据库交互示例: ①代码 ⇆ ②使用DB-API ⇆ ③数据库驱动程序 ⇆ ④底层数据库(如MySQL等) 使用DB-API操作MySQL数据库例子 1.Windows安装MySQL数据库驱动程序MySQL-Connector/Python

  • 基于postman获取动态数据过程详解

    1.在 Tests 中处理 返回报文为 json 格式的 示例:因为充值记录接口中需要用到登录接口返回报文中的信息如下 以获取 token(JWT)和 uid 为例 在登录接口的tests中写入代码(因为登录接口报文信息中有返回 JWT 和 uid) 输入完上图中代码后,点击send请求接口,去全局变量中查看,是否成功获取JWT和uid的值并且设置了全局变量 在充值记录接口中需要用到JWT和uid的地方设置变量{{JWT}}和{{uid}} 请求完成后清除变量 通过批量执行用例的方法执行,且切换

随机推荐