mybatis学习笔记之使用javassist生成类

文章目录

  • 使用javassist动态生成类
  • 使用javassist动态生成类并实现接口
  • 实现接口中所有的方法
  • 工具类GenerateDaoProxy的编写

使用javassist动态生成类

    @Test
    public void testGennerateFirstClass() throws Exception{
        //获取类池,这个类池就是用来生成class的
        ClassPool pool = ClassPool.getDefault();
        //制造类(需要告诉javassist,类名是啥)
        CtClass ctClass = pool.makeClass("类名");
        //制造方法
        String methodCode = "publi coid insert(){System.out.println(123);}";
        CtMethod ctMethod = CtMethod.make(methodCode, ctClass);
        //将方法添加到类中
        ctClass.addMethod(ctMethod);
        //在内存中生成class
        ctClass.toClass();

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

使用javassist动态生成类并实现接口

    @Test
    public void testGenerateImpl() throws Exception{
        //获取类池
        ClassPool pool = ClassPool.getDefault();
        //制造类
        CtClass ctClass = pool.makeClass("类地址")//制造接口
        CtClass ctInterface = pool.makeInterface("类接口地址");
        // 添加接口到类中
        ctClass.addInterface(ctInterface);
        //实现接口中的方法
        //制造方法
        CtMethod ctMethod = CtMethod.make("条件执行语句",ctClass);
        //将方法添加到类中
        ctClass.addMethod(ctMethod);
        //在内存中生成类,同时将生成的类加载到JVM当中。
        Class<?> clazz = ctClass.toClass();
        AccountDao accountDao = (AccountDao) clazz.newInstance();
        accountDao.delete();
    }

实现接口中所有的方法

public class javassistTest {
    @Test
    public void testGenerateAccountDaoImpl() throws Exception{
        //获取类池
        ClassPool pool = ClassPool.getDefault();
        //制造类
        CtClass ctClass = pool.makeClass("类名地址");
        //制造接口
        CtClass ctInterface = pool.makeInterface("接口地址");
        //实现接口
        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<?>[] paramterTypes = method.getParameterTypes();
                for (int i = 0; i < paramterTypes.length; i++) {
                    Class<?> parameterType = paramterTypes[i];
                    methodCode.append(parameterType.getName());
                    methodCode.append(" ");
                    methodCode.append("arg" + i);
                    if(i != paramterTypes.length - 1){
                        methodCode.append(",");
                    }
                }
                methodCode.append("){System.out.println(1111);return 1;}}");
                //动态的添加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);
                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();
        //调用方法
        //...
     }

工具类GenerateDaoProxy的编写

package com.example.bank.utils;

import org.apache.ibatis.javassist.ClassPool;
import org.apache.ibatis.javassist.CtClass;
import org.apache.ibatis.javassist.CtMethod;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.session.SqlSession;

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

public class GenerateDaoProxy{
    public static Object generate(SqlSession sqlSession, Class daoInterface){
        //获取类池
        ClassPool pool = ClassPool.getDefault();
        //制造类
        CtClass ctClass = pool.makeClass(daoInterface.getName() + "Proxy");
        //制造接口
        CtClass ctInterface = pool.makeInterface(daoInterface.getName());
        //实现接口
        ctClass.addInterface(ctInterface);
        //实现接口中所有的方法
        Method[] methods = daoInterface.getDeclaredMethods();
        Arrays.stream(methods).forEach(method -> {
            //method是抽象方法
            //将method这个抽象方法进行实现
            try{
                // Account selectBtActno(String actno);
                //public Account selectByActno(String arg0, int arg1, int arg2){代码; }
                StringBuilder methodCode = new StringBuilder();
                methodCode.append("public ");
                methodCode.append(method.getReturnType().getName());
                methodCode.append(" ");
                methodCode.append(method.getName());
                methodCode.append("(");
                //需要方法的形式参数列表
                Class<?>[] paramterTypes = method.getParameterTypes();
                for(int i = 0; i < paramterTypes.length; i++){
                    Class<?> paramterType = paramterTypes[i];
                    methodCode.append(paramterType.getName());
                    methodCode.append(" ");
                    methodCode.append("arg" + i);
                    if(i != paramterTypes.length - 1){
                        methodCode.append(",");
                    }
                }
                methodCode.append(")");
                methodCode.append("{");
                //需要方法体当中的代码
                methodCode.append("org.apache.ibatis.session.SqlSession sqlSession = com.example.bank.utils.SqlSessionUtil.openSession();");
                //需要知道是什么类型的sql语句
                //sql语句的id是框架使用者提供的,具有多变性,等于我框架的开发人员来说,我不知道
                //既然我框架开发者不知道sqlId,怎么办呢?mybatis框架的开发者于是就出台了一个归档,凡是使用GenerateDaoProxy机制的。
                //sqlId都不能随便写,namespace必须是dao接口的全限定名称,id必须是dao接口中的方法名
                String sqlId = daoInterface.getName() + "." + method.getName();
                SqlCommandType sqlCommandType = sqlSession.getConfiguration().getMappedStatement(sqlId).getSqlCommandType();
                if(sqlCommandType == SqlCommandType.INSERT){

                }
                if(sqlCommandType == SqlCommandType.DELETE){

                }
                if(sqlCommandType == SqlCommandType.UPDATE){
                    methodCode.append("return sqlSession.update(\""+sqlId+"\",arg0);");
                }
                if(sqlCommandType == SqlCommandType.SELECT){
                    String returnType = method.getReturnType().getName();
                    methodCode.append("return ("+returnType+") sqlSession.selectOne(\""+sqlId+"\",arg0);");
                }
                methodCode.append("}");
                CtMethod ctMethod = CtMethod.make(methodCode.toString(), ctClass);
                ctClass.addMethod(ctMethod);
            }catch(Exception e){
                e.printStackTrace();
            }
        });

        //创建对象
        Object obj = null;
        try{
            Class<?> clazz = ctClass.toClass();
            obj = clazz.newInstance();
        } catch (Exception e){
            e.printStackTrace();
        }
        return obj;
    }
}

你可能感兴趣的:(mybatis学习笔记,mybatis,学习,笔记)