0
点赞
收藏
分享

微信扫一扫

javassist动态生成类

1. 使⽤javassist⽣成类   58

来⾃百度百科:Javassist是⼀个开源的分析、编辑和创建Java字节码的类库。是由东京⼯业⼤学的数学和计算机科学系的 Shigeru Chiba (千叶 滋)所创建的。它已加⼊了开放源代码JBoss 应⽤服务器项⽬,通过使⽤Javassist对字节码操作为JBoss实现动态"AOP"框架。

2. Javassist的使⽤    59 

我们要使⽤javassist,⾸先要引⼊它的依赖

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

3. 案例演示   59

3.1 注意高于jdk8版本的   59

运⾏要注意:加两个参数,要不然会有异常。 

--add-opens java.base/java.lang=ALL-UNNAMED 

--add-opens java.base/sun.net.util=ALL-UNNAMED

javassist动态生成类_System

3.2 案例演示javassist生成类 59

代码在com.powernode.bank.dao.AccountDao

JavassistTest中的testGenerateFirstClass方法

//案例演示javassist生成类 59
    @Test
    public void testGenerateFirstClass() throws Exception{
        // 获取类池,这个类池就是用来给我生成class的
        ClassPool pool = ClassPool.getDefault();
        // 制造类(需要告诉javassist,类名是啥)
        CtClass ctClass = pool.makeClass("com.powernode.bank.dao.impl.AccountDaoImpl");
        // 制造方法
        String methodCode = "public void insert(){System.out.println(123);}";
        CtMethod ctMethod = CtMethod.make(methodCode, ctClass);
        // 将方法添加到类中
        ctClass.addMethod(ctMethod);
        // 在内存中生成类class
        ctClass.toClass();


        // 类加载到JVM当中,返回AccountDaoImpl类的字节码
        Class clazz = Class.forName("com.powernode.bank.dao.impl.AccountDaoImpl");
        // 创建对象
        Object obj = clazz.newInstance();
        // 获取AccountDaoImpl中的insert方法
        Method insertMethod = clazz.getDeclaredMethod("insert");
        // 调用方法insert
        insertMethod.invoke(obj);
    }

javassist动态生成类_java_02

3.3 演示javassist实现接口  60

com.powernode.bank.dao

AccountDao

package com.powernode.bank.dao;

//这是一个接口看看javassist能不能实现  60
public interface AccountDao {
    void delete();
}

代码在com.powernode.bank.dao.AccountDao

JavassistTest中的testGenerateImpl方法

//演示javassist实现接口  60
    @Test
    public void testGenerateImpl() throws Exception{
        // 获取类池
        ClassPool pool = ClassPool.getDefault();
        // 制造类
        CtClass ctClass = pool.makeClass("com.powernode.bank.dao.impl.AccountDaoImpl");
        // 制造接口
        CtClass ctInterface = pool.makeInterface("com.powernode.bank.dao.AccountDao");
        // 添加接口到类中
        ctClass.addInterface(ctInterface); // AccountDaoImpl implements AccountDao
        // 实现接口中的方法
        // 制造方法
        CtMethod ctMethod = CtMethod.make("public void delete(){System.out.println(\"hello delete!\");}", ctClass);
        // 将方法添加到类中
        ctClass.addMethod(ctMethod);
        // 在内存中生成类,同时将生成的类加载到JVM当中。
        Class clazz = ctClass.toClass();
        // 创建对象这里进行了强转为AccountDao类型了,所以创建出来的对象可以直接调方法了
        AccountDao accountDao = (AccountDao)clazz.newInstance();
        accountDao.delete();
    }

javassist动态生成类_System_03

3.4 演示javassist动态实现接口类  61

代码在com.powernode.bank.dao.AccountDao

JavassistTest中的testGenerateAccountDaoImpl方法

//演示javassist动态实现接口类  61
    @Test
    public void testGenerateAccountDaoImpl() throws Exception{
        // 获取类池
        ClassPool pool = ClassPool.getDefault();
        // 制造类
        CtClass ctClass = pool.makeClass("com.powernode.bank.dao.impl.AccountDaoImpl");
        // 制造接口
        CtClass ctInterface = pool.makeInterface("com.powernode.bank.dao.AccountDao");
        // 实现接口
        ctClass.addInterface(ctInterface);
        // 实现接口中所有的方法
        // 获取接口中所有的方法
        Method[] methods = AccountDao.class.getDeclaredMethods();
        Arrays.stream(methods).forEach(method -> {
            // method是接口中的抽象方法
            // 把method抽象方法给实现了。
            try {
                // public void delete(){}
                // public int update(String actno, Double balance){}
                StringBuilder methodCode = new StringBuilder();
                methodCode.append("public "); // 追加修饰符列表
                methodCode.append(method.getReturnType().getName()); // 追加返回值类型
                methodCode.append(" ");
                methodCode.append(method.getName()); //追加方法名
                methodCode.append("(");
                // 拼接参数 String actno, Double balance
                Class[] parameterTypes = method.getParameterTypes();
                for (int i = 0; i < parameterTypes.length; i++) {
                    Class parameterType = parameterTypes[i];
                    methodCode.append(parameterType.getName());
                    methodCode.append(" ");
                    methodCode.append("arg" + i);
                    if(i != parameterTypes.length - 1){
                        methodCode.append(",");
                    }
                }
                methodCode.append("){System.out.println(11111); ");
                // 动态的添加return语句
                String returnTypeSimpleName = method.getReturnType().getSimpleName();
                if ("void".equals(returnTypeSimpleName)) {

                }else if("int".equals(returnTypeSimpleName)){
                    methodCode.append("return 1;");
                }else if("String".equals(returnTypeSimpleName)){
                    methodCode.append("return \"hello\";");
                }
                methodCode.append("}");
                System.out.println(methodCode);
                //给ctClass制造方法
                CtMethod ctMethod = CtMethod.make(methodCode.toString(), ctClass);
                //将方法添加到类中 
                ctClass.addMethod(ctMethod);
            } catch (Exception e) {
                e.printStackTrace();
            }

        });

        // 在内存中生成class,并且加载到JVM当中
        Class clazz = ctClass.toClass();
        // 创建对象
        AccountDao accountDao = (AccountDao) clazz.newInstance();
        // 调用方法
        accountDao.insert("aaaaa");
        accountDao.delete();
        accountDao.update("aaaa", 1000.0);
        accountDao.selectByActno("aaaa");
    }

4. 代码   58-61

代码在com.powernode.javassist

JavassistTest

package com.powernode.javassist;

import com.powernode.bank.dao.AccountDao;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import org.junit.Test;

import java.lang.reflect.Method;
import java.util.Arrays;

//案例演示javassist  59
public class JavassistTest {

    //演示javassist动态实现接口类  61
    @Test
    public void testGenerateAccountDaoImpl() throws Exception{
        // 获取类池
        ClassPool pool = ClassPool.getDefault();
        // 制造类
        CtClass ctClass = pool.makeClass("com.powernode.bank.dao.impl.AccountDaoImpl");
        // 制造接口
        CtClass ctInterface = pool.makeInterface("com.powernode.bank.dao.AccountDao");
        // 实现接口
        ctClass.addInterface(ctInterface);
        // 实现接口中所有的方法
        // 获取接口中所有的方法
        Method[] methods = AccountDao.class.getDeclaredMethods();
        Arrays.stream(methods).forEach(method -> {
            // method是接口中的抽象方法
            // 把method抽象方法给实现了。
            try {
                // public void delete(){}
                // public int update(String actno, Double balance){}
                StringBuilder methodCode = new StringBuilder();
                methodCode.append("public "); // 追加修饰符列表
                methodCode.append(method.getReturnType().getName()); // 追加返回值类型
                methodCode.append(" ");
                methodCode.append(method.getName()); //追加方法名
                methodCode.append("(");
                // 拼接参数 String actno, Double balance
                Class[] parameterTypes = method.getParameterTypes();
                for (int i = 0; i < parameterTypes.length; i++) {
                    Class parameterType = parameterTypes[i];
                    methodCode.append(parameterType.getName());
                    methodCode.append(" ");
                    methodCode.append("arg" + i);
                    if(i != parameterTypes.length - 1){
                        methodCode.append(",");
                    }
                }
                methodCode.append("){System.out.println(11111); ");
                // 动态的添加return语句
                String returnTypeSimpleName = method.getReturnType().getSimpleName();
                if ("void".equals(returnTypeSimpleName)) {

                }else if("int".equals(returnTypeSimpleName)){
                    methodCode.append("return 1;");
                }else if("String".equals(returnTypeSimpleName)){
                    methodCode.append("return \"hello\";");
                }
                methodCode.append("}");
                System.out.println(methodCode);
                //给ctClass制造方法
                CtMethod ctMethod = CtMethod.make(methodCode.toString(), ctClass);
                //将方法添加到类中
                ctClass.addMethod(ctMethod);
            } catch (Exception e) {
                e.printStackTrace();
            }

        });

        // 在内存中生成class,并且加载到JVM当中
        Class clazz = ctClass.toClass();
        // 创建对象
        AccountDao accountDao = (AccountDao) clazz.newInstance();
        // 调用方法
        accountDao.insert("aaaaa");
        accountDao.delete();
        accountDao.update("aaaa", 1000.0);
        accountDao.selectByActno("aaaa");
    }



    //演示javassist实现接口  60
    @Test
    public void testGenerateImpl() throws Exception{
        // 获取类池
        ClassPool pool = ClassPool.getDefault();
        // 制造类
        CtClass ctClass = pool.makeClass("com.powernode.bank.dao.impl.AccountDaoImpl");
        // 制造接口
        CtClass ctInterface = pool.makeInterface("com.powernode.bank.dao.AccountDao");
        // 添加接口到类中
        ctClass.addInterface(ctInterface); // AccountDaoImpl implements AccountDao
        // 实现接口中的方法
        // 制造方法
        CtMethod ctMethod = CtMethod.make("public void delete(){System.out.println(\"hello delete!\");}", ctClass);
        // 将方法添加到类中
        ctClass.addMethod(ctMethod);
        // 在内存中生成类,同时将生成的类加载到JVM当中。
        Class clazz = ctClass.toClass();
        // 创建对象这里进行了强转为AccountDao类型了,所以创建出来的对象可以直接调方法了
        AccountDao accountDao = (AccountDao)clazz.newInstance();
        accountDao.delete();
    }


    //案例演示javassist生成类 59
    @Test
    public void testGenerateFirstClass() throws Exception{
        // 获取类池,这个类池就是用来给我生成class的
        ClassPool pool = ClassPool.getDefault();
        // 制造类(需要告诉javassist,类名是啥)
        CtClass ctClass = pool.makeClass("com.powernode.bank.dao.impl.AccountDaoImpl");
        // 制造方法
        String methodCode = "public void insert(){System.out.println(123);}";
        CtMethod ctMethod = CtMethod.make(methodCode, ctClass);
        // 将方法添加到类中
        ctClass.addMethod(ctMethod);
        // 在内存中生成类class
        ctClass.toClass();


        // 类加载到JVM当中,返回AccountDaoImpl类的字节码
        Class clazz = Class.forName("com.powernode.bank.dao.impl.AccountDaoImpl");
        // 创建对象
        Object obj = clazz.newInstance();
        // 获取AccountDaoImpl中的insert方法
        Method insertMethod = clazz.getDeclaredMethod("insert");
        // 调用方法insert
        insertMethod.invoke(obj);
    }
}

com.powernode.bank.dao

接口AccountDao

package com.powernode.bank.dao;

//这是一个接口看看javassist能不能实现  60
public interface AccountDao {
    void delete();
    int insert(String actno);
    int update(String actno, Double balance);
    String selectByActno(String actno);
}

配置文件pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.powernode</groupId>
    <artifactId>course11</artifactId>
    <version>1.0-SNAPSHOT</version>

    <packaging>jar</packaging>

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

    <properties>
        <!--    编译代码使用的jdk版本-->
        <maven.compiler.source>1.8</maven.compiler.source>
        <!--    运行程序使用的jdk版本-->
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>


</project>

举报

相关推荐

0 条评论