动态生成类--javassist的使用

javassist简介

Javassist是⼀个开源的分析、编辑和创建Java字节码的类库。是由东京⼯业⼤学的数学和计算机科学系的 Shigeru Chiba (千叶 滋)所创建的。它已加⼊了开放源代码JBoss 应⽤服务器项⽬,通过使⽤
Javassist对字节码操作为JBoss实现动态"AOP"框架。
Javassist是可以动态编辑Java字节码的类库。它可以在Java程序运行时定义一个新的类,并加载到JVM中;还可以在JVM加载时修改一个类文件。Javassist不必关心字节码相关的规范也是可以编辑类文件的。

javassist使用

在Javassist中每个需要编辑的class都对应一个CtCLass实例,CtClass的含义是编译时的类(compile time class),这些类会存储在Class Pool中(Class poll是一个存储CtClass对象的容器)。

环境配置

为了减少演示的复杂度,我们都在Maven项目下进行,因为我们可以直接引入依赖就可以达到我们导包的目的,很方便,不用再去下载jar包,然后自己手动导入了。
导入依赖:版本号可以使用别的

	<dependency>
	 <groupId>org.javassist</groupId>
	 <artifactId>javassist</artifactId>
	 <version>3.29.1-GA</version>
	</dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.13.2</version>
      <scope>test</scope>
    </dependency>

使用javassist创建方法

步骤
1.获取类池
2.制造类
3.制造方法
4.将方法添加到类中
5.在内存中生成类,同时生成加载到JVM中

测试的时候可以使用反射机制创建对象

	@Test
    public void testGenerateFirstClass() throws Exception {
        //1.获取类池
        ClassPool pool = ClassPool.getDefault();
        //2.制造类
        CtClass ctClass = pool.makeClass("com.javassist.bank.dao.impl.AccountDaoImpl");
        //3.制造方法
        CtMethod ctMethod = CtMethod.make("public void insert(){System.out.println(123);}", ctClass);
        //4.将方法添加到类中
        ctClass.addMethod(ctMethod);
        //5.在内存中生成类,同时生成加载到JVM中
        ctClass.toClass();


        //反射机制创建对象,调方法
        Class<?> clazz = Class.forName("com.javassist.bank.dao.impl.AccountDaoImpl");
        //创建对象
        Object o = clazz.newInstance();
        Method insertMethod = clazz.getDeclaredMethod("insert");
        insertMethod.invoke(o);

    }

注意:运行的时候会出现InaccessibleObjectException,原因是jdk8版本之后有了java.base这个包,jdk8版本之前没有,导致找不到。
需要加这两个参数
–add-opens java.base/java.lang=ALL-UNNAMED
–add-opens java.base/sun.net.util=ALL-UNNAMED
请添加图片描述
注意配置完后是点击这个绿色小箭头运行,点击别的会新建一个junit
请添加图片描述
运行结果请添加图片描述

使用javassist和已有接口创建实现方法

创建一个接口

public interface AccountDao {
    void delete();
}

步骤
1.获取类池
2.制造类
3.制造接口
4.添加接口到类中(实现接口)
5.制造方法
6.实现接口里面的方法,将方法添加到类中
7.在内存中生成类,同时生成加载到JVM中。

    @Test
    public void testGenerateImpl() throws Exception {
        //1.获取类池
        ClassPool pool = ClassPool.getDefault();
        //2.制造类
        CtClass ctClass = pool.makeClass("com.javassist.bank.dao.impl.AccountDaoImpl");
        //3.制造接口
        CtClass ctInterface = pool.makeInterface("com.javassist.bank.dao.AccountDao");
        //4.添加接口到类中(实现接口)
        ctClass.addInterface(ctInterface);//相当于AccountDaoImpl implements AccountDao
        //5.制造方法
        CtMethod ctMethod = CtMethod.make("public void delete(){System.out.println(\"Hello detele\");}", ctClass);
        //6.实现接口里面的方法,将方法添加到类中
        ctClass.addMethod(ctMethod);
        //7.在内存中生成类,同时生成加载到JVM中,这里会返回一个class对象
        Class<?> clazz = ctClass.toClass();

        //8.创建对象并调用
        AccountDao accountDao = ((AccountDao) clazz.newInstance());
        accountDao.delete();
    }

运行结果
请添加图片描述

动态创建实现方法

以上是知道接口有哪个方法,而javassist是可以进行动态创建的,我们需要进行动态创建实现方法
接口:

public interface AccountDao {
    void delete();
    int insert(String actno);
    int update(String actno,Double balance);
    String selectByActno(String actno);
}

步骤

  • 1.获取类池
  • 2.制造类
  • 3.制造接口
  • 4.添加接口到类中(实现接口)
  • 5、获取接口中所有的方法
  • 6.通过遍历循环动态制造方法,并将方法添加到类中
    • 6.1通过StringBuffer动态制造方法
    • 6.2通过循环遍历动态获取参数类型
    • 6.3动态添加return语句
  • 7.在内存中生成类,同时生成加载到JVM中
    @Test
    public void testGenerateAccountDaoImpl() throws Exception {
        //1.获取类池
        ClassPool pool = ClassPool.getDefault();
        //2.制造类
        CtClass ctClass = pool.makeClass("com.javassist.bank.dao.impl.AccountDaoImpl");
        //3.制造接口
        CtClass ctInterface = pool.makeInterface("com.javassist.bank.dao.AccountDao");
        //4.添加接口到类中(实现接口)
        ctClass.addInterface(ctInterface);//相当于AccountDaoImpl implements AccountDao
        //5、获取接口中所有的方法
        Method[] methods = AccountDao.class.getDeclaredMethods();
        //6.通过遍历循环动态制造方法,并将方法添加到类中
        Arrays.stream(methods).forEach(method -> {
            try {
                //6.1通过StringBuffer动态制造方法
                StringBuffer methodCode = new StringBuffer();
                methodCode.append("public ");//接口一定是public
                methodCode.append(method.getReturnType().getName() + " ");//追加返回值类型
                methodCode.append(method.getName());//追加方法名
                methodCode.append("(");
                //6.2通过循环遍历动态获取参数类型
                Class<?>[] parameterTypes = method.getParameterTypes();
                for (int i = 0; i < parameterTypes.length; i++) {
                    Class<?> parameterType = parameterTypes[i];
                    methodCode.append(parameterType.getName() + " ");//追加参数类型
                    methodCode.append("arg" + i);//追加参数名
                    if (i != parameterTypes.length-1) {
                        methodCode.append(",");
                    }
                }
                methodCode.append(")");
                methodCode.append("{");
                methodCode.append("System.out.println(321);");
                //6.3动态添加return语句
                String returnSimpleName = method.getReturnType().getSimpleName();//获取返回值类型的简称,因为getReturnType()是带包名的
                if ("void".equals(returnSimpleName)) {

                }else if ("int".equals(returnSimpleName)){
                    methodCode.append("return 1;");
                }else if ("String".equals(returnSimpleName)){
                    methodCode.append("return \"Hello\";");
                }
                methodCode.append("}");
                System.out.println(methodCode);
                CtMethod ctMethod = CtMethod.make(methodCode.toString(), ctClass);
                ctClass.addMethod(ctMethod);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
        //7.在内存中生成类,同时生成加载到JVM中,这里会返回一个class对象
        Class<?> clazz = ctClass.toClass();
        //8.创建对象并调用
        AccountDao accountDao = ((AccountDao) clazz.newInstance());
        accountDao.insert("aaa");
        accountDao.delete();
        accountDao.selectByActno("aaaa");
        accountDao.update("aaa",20.6);
    }

运行结果请添加图片描述

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

忆亦何为

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值